mirror of
https://github.com/storytold/deckcraft.git
synced 2026-10-24 10:37:03 -06:00
Table: split and cell fill stay inside the table (#400)
This commit is contained in:
@@ -205,7 +205,11 @@ fn cell_fill(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
with_table(s, p, "table.cellFill", move |t| {
|
||||
let list: Vec<(usize, usize)> = match (&cells, sel) {
|
||||
(Some(c), _) => c.clone(),
|
||||
(None, Some((_, a, b))) => (a.0.min(b.0)..=a.0.max(b.0)).flat_map(|r| (a.1.min(b.1)..=a.1.max(b.1)).map(move |c| (r, c))).collect(),
|
||||
(None, Some((_, a, b))) => {
|
||||
// The selection can name cells outside the table; only walk the ones that exist.
|
||||
let (r1, c1) = (a.0.max(b.0).min(t.n_rows().saturating_sub(1)), a.1.max(b.1).min(t.n_cols().saturating_sub(1)));
|
||||
(a.0.min(b.0)..=r1).flat_map(|r| (a.1.min(b.1)..=c1).map(move |c| (r, c))).collect()
|
||||
}
|
||||
_ => (0..t.n_rows()).flat_map(|r| (0..t.n_cols()).map(move |c| (r, c))).collect(),
|
||||
};
|
||||
for (r, c) in list {
|
||||
|
||||
@@ -835,3 +835,17 @@ fn slide_ranges_parse_like_powerpoints_print_box() {
|
||||
let opts = cmd::file::pdf_options(&json!({"slides": [0, 7, 1]}), 2).unwrap();
|
||||
assert_eq!(opts.slides, Some(vec![0, 1]), "indices past the end are dropped");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cell_fill_walks_only_the_cells_a_huge_selection_covers() {
|
||||
// A selection may reach far past the table; filling it touches the real cells and nothing more.
|
||||
let mut s = session();
|
||||
let id = s.execute("insert.table", &json!({"rows": 2, "cols": 2, "rect": [100.0, 100.0, 200.0, 40.0]})).unwrap()["id"].clone();
|
||||
s.execute("table.selectCells", &json!({"id": id, "from": [1, 1], "to": [1_000_000_000u64, 1_000_000_000u64]})).unwrap();
|
||||
s.execute("table.cellFill", &json!({"none": true})).unwrap();
|
||||
let st = s.doc().unwrap();
|
||||
let sh = st.shapes().iter().find(|sh| json!(sh.id) == id).unwrap();
|
||||
let deckcraft_model::ShapeKind::Table(t) = &sh.kind else { panic!("not a table") };
|
||||
let fills: Vec<bool> = [(0, 0), (0, 1), (1, 0), (1, 1)].iter().map(|&(r, c)| t.cell(r, c).is_some_and(|x| x.fill.is_some())).collect();
|
||||
assert_eq!(fills, [false, false, false, true]);
|
||||
}
|
||||
|
||||
@@ -178,8 +178,9 @@ impl Table {
|
||||
if gs == 1 && rs == 1 {
|
||||
return false;
|
||||
}
|
||||
for rr in r..r + rs {
|
||||
for cc in c..c + gs {
|
||||
// Spans come from the file and may reach past the table; only walk the cells that exist.
|
||||
for rr in r..r.saturating_add(rs).min(self.rows.len()) {
|
||||
for cc in c..c.saturating_add(gs).min(self.cols.len()) {
|
||||
if let Some(x) = self.cell_mut(rr, cc) {
|
||||
x.h_merge = false;
|
||||
x.v_merge = false;
|
||||
@@ -349,4 +350,15 @@ mod tests {
|
||||
assert!(!one.delete_row(0) && !one.delete_col(0));
|
||||
assert!(table_styles().len() > 30);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn split_ignores_spans_past_the_table() {
|
||||
let mut t = Table::new(2, 2, 100.0, 10.0);
|
||||
if let Some(c) = t.cell_mut(0, 0) {
|
||||
c.grid_span = u32::MAX;
|
||||
c.row_span = u32::MAX;
|
||||
}
|
||||
assert!(t.split(0, 0));
|
||||
assert_eq!(t.cell(0, 0).map(|c| (c.grid_span, c.row_span)), Some((1, 1)));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user