mirror of
https://github.com/storytold/deckcraft.git
synced 2026-10-28 04:27:06 -06:00
Tables: Tab and Shift+Tab skip cells hidden under a merge
Tab moved into the cells covered by a merged cell, editing text that is never drawn. It now goes to the next visible cell; Tab in the last visible cell still adds a row, and Shift+Tab in the first cell stays.
This commit is contained in:
@@ -285,15 +285,22 @@ impl Session {
|
||||
let Some(t) = st.selection.text.clone() else { return Ok(Value::Null) };
|
||||
let Some((r, c)) = t.cell else { return Ok(Value::Null) };
|
||||
let Some(deckcraft_model::ShapeKind::Table(tb)) = st.shape(t.shape).map(|s| s.kind.clone()) else { return Ok(Value::Null) };
|
||||
let (nr, nc) = (tb.n_rows(), tb.n_cols());
|
||||
let (nr, nc) = (tb.n_rows(), tb.n_cols().max(1));
|
||||
let idx = r * nc + c;
|
||||
if !back && idx + 1 >= nr * nc {
|
||||
// Tab in the last cell adds a row.
|
||||
self.execute("table.insertRowBelow", &json!({"id": t.shape, "row": r}))?;
|
||||
return self.execute("text.edit", &json!({"id": t.shape, "cell": [r + 1, 0]}));
|
||||
}
|
||||
let ni = if back { idx.saturating_sub(1) } else { idx + 1 };
|
||||
self.execute("text.edit", &json!({"id": t.shape, "cell": [ni / nc.max(1), ni % nc.max(1)]}))?;
|
||||
// Cells hidden under a merged cell are skipped.
|
||||
let visible = |i: &usize| tb.cell(i / nc, i % nc).is_some_and(|x| !x.is_covered());
|
||||
let next = if back { (0..idx).rev().find(visible) } else { (idx + 1..nr * nc).find(visible) };
|
||||
let ni = match next {
|
||||
Some(ni) => ni,
|
||||
None if !back => {
|
||||
// Tab in the last cell adds a row.
|
||||
let last = nr.saturating_sub(1);
|
||||
self.execute("table.insertRowBelow", &json!({"id": t.shape, "row": last}))?;
|
||||
return self.execute("text.edit", &json!({"id": t.shape, "cell": [last + 1, 0]}));
|
||||
}
|
||||
None => idx,
|
||||
};
|
||||
self.execute("text.edit", &json!({"id": t.shape, "cell": [ni / nc, ni % nc]}))?;
|
||||
self.execute("text.selectAll", &json!({}))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -676,6 +676,25 @@ fn rotated_tables_hit_the_cell_under_the_pointer() {
|
||||
assert_eq!(text_sel(&s).and_then(|t| t.cell), Some((1, 1)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tab_moves_between_cells_skipping_merged_ones() {
|
||||
let mut s = session();
|
||||
let id = table_at(&mut s, &[100.0, 100.0, 100.0], json!([["a", "b", "c"], ["d", "e", "f"]]));
|
||||
s.execute("table.merge", &json!({"id": id, "from": [0, 0], "to": [0, 1]})).unwrap();
|
||||
s.execute("text.edit", &json!({"id": id, "cell": [0, 0]})).unwrap();
|
||||
let cell = |s: &Session| text_sel(s).and_then(|t| t.cell);
|
||||
let shift = Mods { shift: true, ..Default::default() };
|
||||
s.key("Tab", Mods::default()).unwrap();
|
||||
assert_eq!(cell(&s), Some((0, 2)), "the cell under the merge is skipped");
|
||||
s.key("Tab", shift).unwrap();
|
||||
assert_eq!(cell(&s), Some((0, 0)));
|
||||
s.key("Tab", shift).unwrap();
|
||||
assert_eq!(cell(&s), Some((0, 0)), "Shift+Tab in the first cell stays");
|
||||
s.execute("text.edit", &json!({"id": id, "cell": [1, 2]})).unwrap();
|
||||
s.key("Tab", Mods::default()).unwrap();
|
||||
assert_eq!((cell(&s), table_of(&s, id).n_rows()), (Some((2, 0)), 3), "Tab in the last cell adds a row");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn right_to_left_paragraphs() {
|
||||
let mut s = session();
|
||||
|
||||
Reference in New Issue
Block a user