mirror of
https://github.com/zaphar/sheetsui.git
synced 2025-07-23 21:39:51 -04:00
merge: feat: italic and bold cell styling
adds navigation keybinds for #24
This commit is contained in:
commit
15f12ef8e7
@ -29,6 +29,7 @@ will clear the numeric prefix if you want to cancel it.
|
|||||||
**Modifying the Sheet or Cells**
|
**Modifying the Sheet or Cells**
|
||||||
|
|
||||||
* `e` or `i` will enter CellEdit mode for the current cell.
|
* `e` or `i` will enter CellEdit mode for the current cell.
|
||||||
|
* 'I' will toggle italic on the cell. 'B' will toggle bold.
|
||||||
* `Ctrl-h` will shorten the width of the column you are on.
|
* `Ctrl-h` will shorten the width of the column you are on.
|
||||||
* `Ctrl-l` will lengthen the width of the column you are on.
|
* `Ctrl-l` will lengthen the width of the column you are on.
|
||||||
|
|
||||||
|
Binary file not shown.
@ -343,12 +343,6 @@ impl Book {
|
|||||||
sheet: u32,
|
sheet: u32,
|
||||||
col_idx: usize,
|
col_idx: usize,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
// TODO(jeremy): This is a little hacky and the underlying model
|
|
||||||
// supports a better mechanism but UserModel doesn't support it yet.
|
|
||||||
// https://github.com/ironcalc/IronCalc/issues/273
|
|
||||||
// https://github.com/ironcalc/IronCalc/pull/276 is the coming fix.
|
|
||||||
// NOTE(jwall): Because of the number of cells required to modify
|
|
||||||
// this is crazy slow
|
|
||||||
let area = self.get_col_range(sheet, col_idx);
|
let area = self.get_col_range(sheet, col_idx);
|
||||||
self.set_cell_style(style, &area)?;
|
self.set_cell_style(style, &area)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -373,10 +367,6 @@ impl Book {
|
|||||||
sheet: u32,
|
sheet: u32,
|
||||||
row_idx: usize,
|
row_idx: usize,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
// TODO(jeremy): This is a little hacky and the underlying model
|
|
||||||
// supports a better mechanism but UserModel doesn't support it yet.
|
|
||||||
// https://github.com/ironcalc/IronCalc/issues/273
|
|
||||||
// https://github.com/ironcalc/IronCalc/pull/276 is the coming fix.
|
|
||||||
let area = self.get_row_range(sheet, row_idx);
|
let area = self.get_row_range(sheet, row_idx);
|
||||||
self.set_cell_style(style, &area)?;
|
self.set_cell_style(style, &area)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -669,6 +669,16 @@ impl<'ws> Workspace<'ws> {
|
|||||||
self.state.reset_n_prefix();
|
self.state.reset_n_prefix();
|
||||||
self.state.char_queue.clear();
|
self.state.char_queue.clear();
|
||||||
}
|
}
|
||||||
|
KeyCode::Char('B') => {
|
||||||
|
let address = self.book.location.clone();
|
||||||
|
let style = self.book.get_cell_style(self.book.current_sheet, &address).map(|s| s.font.b);
|
||||||
|
self.toggle_bool_style(style, "font.b", &address)?;
|
||||||
|
}
|
||||||
|
KeyCode::Char('I') => {
|
||||||
|
let address = self.book.location.clone();
|
||||||
|
let style = self.book.get_cell_style(self.book.current_sheet, &address).map(|s| s.font.i);
|
||||||
|
self.toggle_bool_style(style, "font.i", &address)?;
|
||||||
|
}
|
||||||
KeyCode::Char(d) if d.is_ascii_digit() => {
|
KeyCode::Char(d) if d.is_ascii_digit() => {
|
||||||
self.handle_numeric_prefix(d);
|
self.handle_numeric_prefix(d);
|
||||||
}
|
}
|
||||||
@ -840,6 +850,24 @@ impl<'ws> Workspace<'ws> {
|
|||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn toggle_bool_style(&mut self, current_val: Option<bool>, path: &str, address: &Address) -> Result<(), anyhow::Error> {
|
||||||
|
let value = if let Some(b_val) = current_val {
|
||||||
|
if b_val { "false" } else { "true" }
|
||||||
|
} else {
|
||||||
|
"true"
|
||||||
|
};
|
||||||
|
self.book.set_cell_style(
|
||||||
|
&[(path, value)],
|
||||||
|
&Area {
|
||||||
|
sheet: self.book.current_sheet,
|
||||||
|
row: address.row as i32,
|
||||||
|
column: address.col as i32,
|
||||||
|
width: 1,
|
||||||
|
height: 1,
|
||||||
|
})?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn paste_range(&mut self) -> Result<(), anyhow::Error> {
|
fn paste_range(&mut self) -> Result<(), anyhow::Error> {
|
||||||
match &self.state.clipboard {
|
match &self.state.clipboard {
|
||||||
Some(ClipboardContents::Cell(contents)) => {
|
Some(ClipboardContents::Cell(contents)) => {
|
||||||
|
@ -193,15 +193,28 @@ impl<'ws> Viewport<'ws> {
|
|||||||
ci: usize,
|
ci: usize,
|
||||||
mut cell: Cell<'widget>,
|
mut cell: Cell<'widget>,
|
||||||
) -> Cell<'widget> {
|
) -> Cell<'widget> {
|
||||||
let style = self
|
// TODO(zaphar): Should probably create somekind of formatter abstraction.
|
||||||
|
if let Some(style) = self
|
||||||
.book
|
.book
|
||||||
.get_cell_style(self.book.current_sheet, &Address { row: ri, col: ci });
|
.get_cell_style(self.book.current_sheet, &Address { row: ri, col: ci }) {
|
||||||
|
cell = self.compute_cell_colors(&style, ri, ci, cell);
|
||||||
|
cell = if style.font.b {
|
||||||
|
cell.bold()
|
||||||
|
} else { cell };
|
||||||
|
cell = if style.font.i {
|
||||||
|
cell.italic()
|
||||||
|
} else { cell };
|
||||||
|
}
|
||||||
|
cell
|
||||||
|
}
|
||||||
|
|
||||||
|
fn compute_cell_colors<'widget>(&self, style: &ironcalc::base::types::Style, ri: usize, ci: usize, mut cell: Cell<'widget>) -> Cell<'widget> {
|
||||||
let bg_color = map_color(
|
let bg_color = map_color(
|
||||||
style.as_ref().map(|s| s.fill.bg_color.as_ref()).flatten(),
|
style.fill.bg_color.as_ref(),
|
||||||
Color::Rgb(35, 33, 54),
|
Color::Rgb(35, 33, 54),
|
||||||
);
|
);
|
||||||
let fg_color = map_color(
|
let fg_color = map_color(
|
||||||
style.as_ref().map(|s| s.fill.fg_color.as_ref()).flatten(),
|
style.fill.fg_color.as_ref(),
|
||||||
Color::White,
|
Color::White,
|
||||||
);
|
);
|
||||||
if let Some((start, end)) = &self.range_selection.map_or(None, |r| r.get_range()) {
|
if let Some((start, end)) = &self.range_selection.map_or(None, |r| r.get_range()) {
|
||||||
@ -212,12 +225,12 @@ impl<'ws> Viewport<'ws> {
|
|||||||
} else {
|
} else {
|
||||||
cell = cell.bg(bg_color).fg(fg_color);
|
cell = cell.bg(bg_color).fg(fg_color);
|
||||||
}
|
}
|
||||||
match (self.book.location.row == ri, self.book.location.col == ci) {
|
cell = match (self.book.location.row == ri, self.book.location.col == ci) {
|
||||||
(true, true) => cell.fg(Color::White).bg(Color::Rgb(57, 61, 71)),
|
(true, true) => cell.fg(Color::White).bg(Color::Rgb(57, 61, 71)),
|
||||||
// TODO(zaphar): Support ironcalc style options
|
// TODO(zaphar): Support ironcalc style options
|
||||||
_ => cell,
|
_ => cell,
|
||||||
}
|
};
|
||||||
.bold()
|
cell
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -320,7 +320,7 @@ fn test_input_navitation_enter_key() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_input_navitation_tab_key() {
|
fn test_input_navitation_tab_key() {
|
||||||
let mut ws = new_workspace();
|
let mut ws = new_workspace();
|
||||||
let col = dbg!(ws.book.location.col);
|
let col = ws.book.location.col;
|
||||||
assert_eq!(Some(&Modality::Navigate), ws.state.modality_stack.last());
|
assert_eq!(Some(&Modality::Navigate), ws.state.modality_stack.last());
|
||||||
script()
|
script()
|
||||||
.tab()
|
.tab()
|
||||||
@ -352,7 +352,7 @@ fn test_input_navitation_shift_enter_key() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_input_navitation_shift_tab_key() {
|
fn test_input_navitation_shift_tab_key() {
|
||||||
let mut ws = new_workspace();
|
let mut ws = new_workspace();
|
||||||
let col = dbg!(ws.book.location.col);
|
let col = ws.book.location.col;
|
||||||
assert_eq!(Some(&Modality::Navigate), ws.state.modality_stack.last());
|
assert_eq!(Some(&Modality::Navigate), ws.state.modality_stack.last());
|
||||||
script()
|
script()
|
||||||
.tab()
|
.tab()
|
||||||
@ -931,7 +931,6 @@ fn test_edit_mode_paste() {
|
|||||||
assert_eq!(Some(&Modality::Navigate), ws.state.modality_stack.last());
|
assert_eq!(Some(&Modality::Navigate), ws.state.modality_stack.last());
|
||||||
ws.state.range_select.start = Some(Address { row: 1, col: 1 });
|
ws.state.range_select.start = Some(Address { row: 1, col: 1 });
|
||||||
ws.state.range_select.end = Some(Address { row: 2, col: 2 });
|
ws.state.range_select.end = Some(Address { row: 2, col: 2 });
|
||||||
dbg!(ws.selected_range_to_string());
|
|
||||||
script()
|
script()
|
||||||
.char('e')
|
.char('e')
|
||||||
.ctrl('p')
|
.ctrl('p')
|
||||||
@ -1130,7 +1129,6 @@ macro_rules! assert_range_copy {
|
|||||||
Some(&Modality::RangeSelect),
|
Some(&Modality::RangeSelect),
|
||||||
ws.state.modality_stack.iter().last()
|
ws.state.modality_stack.iter().last()
|
||||||
);
|
);
|
||||||
dbg!(ws.state.range_select.get_range());
|
|
||||||
$script.run(&mut ws).expect("failed to run script");
|
$script.run(&mut ws).expect("failed to run script");
|
||||||
assert!(ws.state.clipboard.is_some());
|
assert!(ws.state.clipboard.is_some());
|
||||||
match ws.state.clipboard.unwrap() {
|
match ws.state.clipboard.unwrap() {
|
||||||
@ -1234,7 +1232,13 @@ fn test_color_row() {
|
|||||||
for ci in [1, book::LAST_COLUMN] {
|
for ci in [1, book::LAST_COLUMN] {
|
||||||
let style = ws
|
let style = ws
|
||||||
.book
|
.book
|
||||||
.get_cell_style(ws.book.current_sheet, &Address { row: 1, col: ci as usize })
|
.get_cell_style(
|
||||||
|
ws.book.current_sheet,
|
||||||
|
&Address {
|
||||||
|
row: 1,
|
||||||
|
col: ci as usize,
|
||||||
|
},
|
||||||
|
)
|
||||||
.expect("failed to get style");
|
.expect("failed to get style");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
"#800000",
|
"#800000",
|
||||||
@ -1259,7 +1263,13 @@ fn test_color_col() {
|
|||||||
for ri in [1, book::LAST_ROW] {
|
for ri in [1, book::LAST_ROW] {
|
||||||
let style = ws
|
let style = ws
|
||||||
.book
|
.book
|
||||||
.get_cell_style(ws.book.current_sheet, &Address { row: ri as usize, col: 1 })
|
.get_cell_style(
|
||||||
|
ws.book.current_sheet,
|
||||||
|
&Address {
|
||||||
|
row: ri as usize,
|
||||||
|
col: 1,
|
||||||
|
},
|
||||||
|
)
|
||||||
.expect("failed to get style");
|
.expect("failed to get style");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
"#800000",
|
"#800000",
|
||||||
@ -1272,6 +1282,53 @@ fn test_color_col() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_bold_text() {
|
||||||
|
let mut ws = new_workspace();
|
||||||
|
let before_style = ws
|
||||||
|
.book
|
||||||
|
.get_cell_style(0, &Address { row: 1, col: 1 })
|
||||||
|
.expect("Failed to get style");
|
||||||
|
assert!(!before_style.font.b);
|
||||||
|
script()
|
||||||
|
.char('B')
|
||||||
|
.run(&mut ws)
|
||||||
|
.expect("Unable to run script");
|
||||||
|
let style = ws
|
||||||
|
.book
|
||||||
|
.get_cell_style(0, &Address { row: 1, col: 1 })
|
||||||
|
.expect("Failed to get style");
|
||||||
|
assert!(style.font.b);
|
||||||
|
script()
|
||||||
|
.char('B')
|
||||||
|
.run(&mut ws)
|
||||||
|
.expect("Unable to run script");
|
||||||
|
assert!(!before_style.font.b);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_italic_text() {
|
||||||
|
let mut ws = new_workspace();
|
||||||
|
let before_style = ws
|
||||||
|
.book
|
||||||
|
.get_cell_style(0, &Address { row: 1, col: 1 })
|
||||||
|
.expect("Failed to get style");
|
||||||
|
assert!(!before_style.font.i);
|
||||||
|
script()
|
||||||
|
.char('I')
|
||||||
|
.run(&mut ws)
|
||||||
|
.expect("Unable to run script");
|
||||||
|
let style = ws
|
||||||
|
.book
|
||||||
|
.get_cell_style(0, &Address { row: 1, col: 1 })
|
||||||
|
.expect("Failed to get style");
|
||||||
|
assert!(style.font.i);
|
||||||
|
script()
|
||||||
|
.char('I')
|
||||||
|
.run(&mut ws)
|
||||||
|
.expect("Unable to run script");
|
||||||
|
assert!(!before_style.font.i);
|
||||||
|
}
|
||||||
|
|
||||||
fn new_workspace<'a>() -> Workspace<'a> {
|
fn new_workspace<'a>() -> Workspace<'a> {
|
||||||
Workspace::new_empty("en", "America/New_York").expect("Failed to get empty workbook")
|
Workspace::new_empty("en", "America/New_York").expect("Failed to get empty workbook")
|
||||||
|
Loading…
x
Reference in New Issue
Block a user