mirror of
https://github.com/storytold/gridcraft.git
synced 2026-11-10 04:19:48 -06:00
Rewrite rule formulas for the new top-left cell when cells are removed from a rule
Clearing validation from cells (or setting a new rule, or pasting a validation over them) and Clear Rules on selected cells shrink a rule's areas. When that removes the rule's top-left cell, the relative formulas were left written for the old cell, so the cells left checked other cells: clearing A1 off a custom `A1>10` on A1:A9 made A2 check A1. Rewrite the relative references of validation formulas, and of conditional format expressions and comparison values, for the new top-left cell. Absolute references and literal lists stay as they are.
This commit is contained in:
@@ -38,11 +38,18 @@ fn subtract_range(r: RangeRef, cut: &RangeRef) -> Vec<RangeRef> {
|
||||
}
|
||||
|
||||
/// Removes the cells of `cuts` from every validation, keeping the rest of each rule's ranges.
|
||||
/// When the rule's top-left cell goes, its relative formulas are rewritten for the new top-left
|
||||
/// cell, so the cells left keep checking the same cells.
|
||||
pub(in super::super) fn remove_validation_cells(validations: &mut Vec<Validation>, cuts: &[RangeRef]) {
|
||||
for dv in validations.iter_mut() {
|
||||
let before = RangeRef::top_left(&dv.ranges);
|
||||
for cut in cuts {
|
||||
dv.ranges = dv.ranges.iter().flat_map(|r| subtract_range(*r, cut)).collect();
|
||||
}
|
||||
if let (Some(from), Some(to)) = (before, RangeRef::top_left(&dv.ranges)) {
|
||||
dv.f1 = move_rule_formula(&dv.f1, from, to);
|
||||
dv.f2 = dv.f2.take().map(|f| move_rule_formula(&f, from, to));
|
||||
}
|
||||
}
|
||||
validations.retain(|d| !d.ranges.is_empty());
|
||||
}
|
||||
|
||||
@@ -1730,7 +1730,13 @@ fn clear_cf(s: &mut Session, p: &Json) -> Result<Json> {
|
||||
sh.cond_formats.clear();
|
||||
} else {
|
||||
for cf in sh.cond_formats.iter_mut() {
|
||||
let before = RangeRef::top_left(&cf.ranges);
|
||||
cf.ranges.retain(|r| !ranges.iter().any(|x| x.intersects(r)));
|
||||
// The relative formulas are written for the top-left cell: when it goes, they're
|
||||
// rewritten for the new one, so the areas left keep reading the same cells.
|
||||
if let (Some(from), Some(to)) = (before, RangeRef::top_left(&cf.ranges)) {
|
||||
rebase_cf_formulas(&mut cf.rule, from, to);
|
||||
}
|
||||
}
|
||||
sh.cond_formats.retain(|c| !c.ranges.is_empty());
|
||||
}
|
||||
@@ -1738,6 +1744,19 @@ fn clear_cf(s: &mut Session, p: &Json) -> Result<Json> {
|
||||
})
|
||||
}
|
||||
|
||||
/// Moves the relative references of a rule's per-cell formulas written for `from` to `to`.
|
||||
fn rebase_cf_formulas(rule: &mut CfRule, from: CellRef, to: CellRef) {
|
||||
let mv = |f: &str| crate::cmd::data::move_rule_formula(f, from, to);
|
||||
match rule {
|
||||
CfRule::CellIs { a, b, .. } => {
|
||||
*a = mv(a);
|
||||
*b = b.as_deref().map(mv);
|
||||
}
|
||||
CfRule::Expression { formula, .. } => *formula = mv(formula),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn manage_cf(s: &mut Session, p: &Json) -> Result<Json> {
|
||||
let sheet = target_sheet(s, p)?;
|
||||
if p.get("delete").is_none() && p.get("moveUp").is_none() && p.get("moveDown").is_none() {
|
||||
|
||||
Reference in New Issue
Block a user