wip: handle ranges and multiple columns or rows

This commit is contained in:
Jeremy Wall 2025-01-28 21:10:39 -05:00
parent b6b98bc099
commit aa0a1512f6
2 changed files with 103 additions and 64 deletions

View File

@ -465,35 +465,54 @@ impl<'ws> Workspace<'ws> {
Ok(Some(Cmd::Quit)) => { Ok(Some(Cmd::Quit)) => {
Ok(Some(ExitCode::SUCCESS)) Ok(Some(ExitCode::SUCCESS))
} }
Ok(Some(Cmd::ColorRows(_count, _color))) => { Ok(Some(Cmd::ColorRows(_count, color))) => {
let row_count = _count.unwrap_or(1);
let row = self.book.location.row; let row = self.book.location.row;
let mut style = if let Some(style) = self.book.get_row_style(self.book.current_sheet, row)? { for r in row..(row+row_count) {
style let mut style = if let Some(style) = self.book.get_row_style(self.book.current_sheet, r)? {
} else { style
self.book.create_style() } else {
}; self.book.create_style()
style.fill.bg_color = Some(_color.to_string()); };
self.book.set_row_style(&style, self.book.current_sheet, row)?; style.fill.bg_color = Some(color.to_string());
self.book.set_row_style(&style, self.book.current_sheet, r)?;
}
Ok(None) Ok(None)
} }
Ok(Some(Cmd::ColorColumns(_count, _color))) => { Ok(Some(Cmd::ColorColumns(_count, color))) => {
let col_count = _count.unwrap_or(1);
let col = self.book.location.col; let col = self.book.location.col;
let mut style = if let Some(style) = self.book.get_column_style(self.book.current_sheet, col)? { for c in col..(col+col_count) {
style let mut style = if let Some(style) = self.book.get_column_style(self.book.current_sheet, c)? {
} else { style
self.book.create_style() } else {
}; self.book.create_style()
style.fill.bg_color = Some(_color.to_string()); };
self.book.set_col_style(&style, self.book.current_sheet, col)?; style.fill.bg_color = Some(color.to_string());
self.book.set_col_style(&style, self.book.current_sheet, c)?;
}
Ok(None) Ok(None)
} }
Ok(Some(Cmd::ColorCell(color))) => { Ok(Some(Cmd::ColorCell(color))) => {
let address = self.book.location.clone(); if let Some((start, end)) = self.state.range_select.get_range() {
let sheet = self.book.current_sheet; for ri in start.row..=end.row {
let mut style = self.book.get_cell_style(sheet, &address) for ci in start.col..=end.col {
.expect("I think this should be impossible.").clone(); let address = Address { row: ri, col: ci };
style.fill.bg_color = Some(color.to_string()); let sheet = self.book.current_sheet;
self.book.set_cell_style(&style, sheet, &address)?; let mut style = self.book.get_cell_style(sheet, &address)
.expect("I think this should be impossible.").clone();
style.fill.bg_color = Some(color.to_string());
self.book.set_cell_style(&style, sheet, &address)?;
}
}
} else {
let address = self.book.location.clone();
let sheet = self.book.current_sheet;
let mut style = self.book.get_cell_style(sheet, &address)
.expect("I think this should be impossible.").clone();
style.fill.bg_color = Some(color.to_string());
self.book.set_cell_style(&style, sheet, &address)?;
}
Ok(None) Ok(None)
} }
Ok(None) => { Ok(None) => {
@ -630,6 +649,9 @@ impl<'ws> Workspace<'ws> {
} }
self.exit_range_select_mode()?; self.exit_range_select_mode()?;
} }
KeyCode::Char(':') => {
self.enter_command_mode();
}
_ => { _ => {
// moop // moop
} }

View File

@ -192,18 +192,25 @@ impl<'ws> Viewport<'ws> {
.flex(Flex::Start)) .flex(Flex::Start))
} }
fn compute_cell_style<'widget>(&self, ri: usize, ci: usize, mut cell: Cell<'widget>) -> Cell<'widget> { fn compute_cell_style<'widget>(
let style = self.book.get_cell_style(self.book.current_sheet, &Address { row: ri, col: ci, }); &self,
let bg_color = map_color(style.as_ref().map(|s| s.fill.bg_color.as_ref()).flatten(), Color::Rgb(35, 33, 54)); ri: usize,
let fg_color = map_color(style.as_ref().map(|s| s.fill.fg_color.as_ref()).flatten(), Color::White); ci: usize,
if let Some((start, end)) = mut cell: Cell<'widget>,
&self.range_selection.map_or(None, |r| r.get_range()) ) -> Cell<'widget> {
{ let style = self
if ri >= start.row .book
&& ri <= end.row .get_cell_style(self.book.current_sheet, &Address { row: ri, col: ci });
&& ci >= start.col let bg_color = map_color(
&& ci <= end.col style.as_ref().map(|s| s.fill.bg_color.as_ref()).flatten(),
{ Color::Rgb(35, 33, 54),
);
let fg_color = map_color(
style.as_ref().map(|s| s.fill.fg_color.as_ref()).flatten(),
Color::White,
);
if let Some((start, end)) = &self.range_selection.map_or(None, |r| r.get_range()) {
if ri >= start.row && ri <= end.row && ci >= start.col && ci <= end.col {
// This is a selected range // This is a selected range
cell = cell.fg(Color::Black).bg(Color::LightBlue) cell = cell.fg(Color::Black).bg(Color::LightBlue)
} }
@ -220,40 +227,50 @@ impl<'ws> Viewport<'ws> {
} }
pub(crate) fn map_color(color: Option<&String>, otherwise: Color) -> Color { pub(crate) fn map_color(color: Option<&String>, otherwise: Color) -> Color {
color.map(|s| match s.to_lowercase().as_str() { color
"red" => Color::Red, .map(|s| match s.to_lowercase().as_str() {
"blue" => Color::Blue, "red" => Color::Red,
"green" => Color::Green, "blue" => Color::Blue,
"magenta" => Color::Magenta, "green" => Color::Green,
"cyan" => Color::Cyan, "magenta" => Color::Magenta,
"white" => Color::White, "cyan" => Color::Cyan,
"yellow" => Color::Yellow, "white" => Color::White,
"black" => Color::Black, "yellow" => Color::Yellow,
"gray" | "grey" => Color::Gray, "black" => Color::Black,
"lightred" => Color::LightRed, "gray" | "grey" => Color::Gray,
"lightblue" => Color::LightBlue, "lightred" => Color::LightRed,
"lightgreen" => Color::LightGreen, "lightblue" => Color::LightBlue,
"lightmagenta" => Color::LightMagenta, "lightgreen" => Color::LightGreen,
"lightcyan" => Color::LightCyan, "lightmagenta" => Color::LightMagenta,
"lightyellow" => Color::LightYellow, "lightcyan" => Color::LightCyan,
"darkgrey" | "darkgray" => Color::DarkGray, "lightyellow" => Color::LightYellow,
candidate => { "darkgrey" | "darkgray" => Color::DarkGray,
// TODO(jeremy): Should we support more syntaxes than hex string? candidate => {
// hsl(...) ?? // TODO(jeremy): Should we support more syntaxes than hex string?
// rgb(...) ?? // hsl(...) ??
if candidate.starts_with("#") { // rgb(...) ??
if let Ok(rgb) = colorsys::Rgb::from_hex_str(candidate) { if candidate.starts_with("#") {
// Note that the colorsys rgb model clamps the f64 values to no more if let Ok(rgb) = colorsys::Rgb::from_hex_str(candidate) {
// than 255.0 so the below casts are safe. // Note that the colorsys rgb model clamps the f64 values to no more
Color::Rgb(rgb.red() as u8, rgb.green() as u8, rgb.blue() as u8) // than 255.0 so the below casts are safe.
Color::Rgb(rgb.red() as u8, rgb.green() as u8, rgb.blue() as u8)
} else {
otherwise
}
} else if candidate.starts_with("rgb(") {
if let Ok(rgb) = <colorsys::Rgb as std::str::FromStr>::from_str(candidate) {
// Note that the colorsys rgb model clamps the f64 values to no more
// than 255.0 so the below casts are safe.
Color::Rgb(rgb.red() as u8, rgb.green() as u8, rgb.blue() as u8)
} else {
otherwise
}
} else { } else {
otherwise otherwise
} }
} else {
otherwise
} }
} })
}).unwrap_or(otherwise) .unwrap_or(otherwise)
} }
impl<'ws> StatefulWidget for Viewport<'ws> { impl<'ws> StatefulWidget for Viewport<'ws> {