From 45f06f50da6c32fd2f76b8a9de0673d5dd2e3675 Mon Sep 17 00:00:00 2001 From: Marco Arnulfo Date: Fri, 23 Oct 2026 22:05:24 +0200 Subject: [PATCH] Conditional formatting: New Rule keeps the range it was opened for when pointing on another sheet (#2348) --- crates/ui-egui/src/dialogs.rs | 15 +++++++++++++-- crates/ui-egui/tests/it/cf_rule_pick.rs | 17 +++++++++++++++++ 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/crates/ui-egui/src/dialogs.rs b/crates/ui-egui/src/dialogs.rs index 8be7f55cb..95855e56a 100644 --- a/crates/ui-egui/src/dialogs.rs +++ b/crates/ui-egui/src/dialogs.rs @@ -63,6 +63,9 @@ struct RefPick { anchor: CellRef, /// Give the box the keyboard back, caret after the reference, on the next frame. refocus: bool, + /// The selection the rule applies to, fixed when the dialog opened as Excel's "Applies to": + /// pointing on another sheet must not move the rule there. + applies_to: String, } impl Dialog { @@ -749,8 +752,12 @@ impl Dialog { json!({"preset": "lightRedFillDarkRedText", "period": "today"}), ); if ty == "expression" { - let sheet = app.session.active().map(|doc| doc.wb.active_sheet).unwrap_or(0); - d.pick = Some(RefPick { key: "formula", sheet, caret: 0, point: None, anchor: CellRef::new(0, 0), refocus: false }); + let (sheet, applies_to) = app + .session + .active() + .map(|doc| (doc.wb.active_sheet, doc.selection.ranges.iter().map(RangeRef::a1).collect::>().join(","))) + .unwrap_or_default(); + d.pick = Some(RefPick { key: "formula", sheet, caret: 0, point: None, anchor: CellRef::new(0, 0), refocus: false, applies_to }); } d.values.insert("type".into(), json!(ty)); d.values.insert("operator".into(), p("operator")); @@ -1177,6 +1184,10 @@ pub(crate) fn build_params(d: &Dialog) -> Json { rule.insert(k.clone(), val.clone()); } v = json!({"rule": Json::Object(rule)}); + if let Some(pick) = d.pick.as_ref().filter(|pick| !pick.applies_to.is_empty()) { + v["sheet"] = json!(pick.sheet); + v["range"] = json!(pick.applies_to); + } } "series" => { if let Some(s) = d.values.get("stop").and_then(Json::as_str).and_then(|s| s.parse::().ok()) { diff --git a/crates/ui-egui/tests/it/cf_rule_pick.rs b/crates/ui-egui/tests/it/cf_rule_pick.rs index dc004ff25..642a91a18 100644 --- a/crates/ui-egui/tests/it/cf_rule_pick.rs +++ b/crates/ui-egui/tests/it/cf_rule_pick.rs @@ -158,3 +158,20 @@ fn other_dialogs_leave_grid_clicks_alone() { click(&mut h, "B2"); assert_eq!(selection(&h), "B2", "a box that is not a formula does not take references"); } + +#[test] +fn pointing_on_another_sheet_keeps_the_rule_on_the_sheet_it_was_opened_for() { + let mut h = harness(); + type_text(&mut h, "="); + h.state_mut().session.execute("sheet.activate", json!({"sheet": 1})).unwrap(); + h.run_steps(3); + click(&mut h, "A1"); + assert_eq!(formula(&h), "=Sheet2!$A$1"); + h.key_press(Key::Enter); + h.run_steps(4); + assert!(h.state().dialog.is_none(), "Enter confirmed the rule"); + let wb = &h.state().session.active().unwrap().wb; + assert!(wb.sheet(1).unwrap().cond_formats.is_empty(), "nothing lands on the sheet pointed at"); + let cf = wb.sheet(0).unwrap().cond_formats.last().expect("the rule is on the sheet the dialog was opened on"); + assert_eq!(cf.ranges.iter().map(|r| r.a1()).collect::>(), ["F8:G9"]); +}