UI: a reference box's pick ends when the box leaves the screen

Choosing another step or inspector tab hid the picking box but left the pick in place, so a grid
selection made later for another reason landed in the box when its step was shown again, and the
draft was dirtied with a reference nobody chose. A pick now ends in any frame that does not draw
its box.
This commit is contained in:
prxnvt
2026-10-25 06:48:57 -04:00
parent 3d6a09ec75
commit cec19d6af6
2 changed files with 38 additions and 8 deletions
+10
View File
@@ -99,6 +99,9 @@ pub struct RefPick {
pub home: Option<(usize, String, String)>,
/// The reference box the window is collapsed to (only that box shows).
pub collapsed: Option<String>,
/// Whether the picking box was drawn this frame: a pick ends with a box that left the screen
/// (another step or tab was chosen), or a later selection would land in it unseen.
pub drawn: bool,
}
// ---------------------------------------------------------------- step paths
@@ -752,6 +755,7 @@ pub fn window(app: &mut SheetApp, ctx: &egui::Context, d: &mut Dialog, open: &mu
let dirty_mark = if ed.dirty { " •" } else { "" };
let screen = ctx.content_rect();
let mut win_open = true;
ed.refs.drawn = false;
egui::Window::new(format!("Macro: {}{dirty_mark}", ed.draft.name))
.id(Id::new("gridcraft.macro_editor"))
.collapsible(false)
@@ -769,6 +773,9 @@ pub fn window(app: &mut SheetApp, ctx: &egui::Context, d: &mut Dialog, open: &mu
}
body(app, ui, d, &mut ed);
});
if ed.refs.pick.is_some() && !ed.refs.drawn {
ed.refs.pick = None;
}
if !win_open {
if app.session.macro_debug.is_some() {
ed.ask_stop = true;
@@ -840,6 +847,9 @@ fn ref_edit(app: &SheetApp, ui: &mut Ui, d: &mut Dialog, refs: &mut RefPick, key
let mut s = d.values.get(key).and_then(Json::as_str).unwrap_or("").to_string();
let sel = selection_ref(app, refs.home.as_ref().map(|h| h.0));
let picking = refs.pick.as_deref() == Some(key);
if picking {
refs.drawn = true;
}
ui.horizontal(|ui| {
let r = ui.add(egui::TextEdit::singleline(&mut s).desired_width(width - 30.0).id_salt(("refedit", key)));
if r.gained_focus() || (r.clicked() && !picking) {
+28 -8
View File
@@ -162,6 +162,32 @@ fn run_to_here_then_stop_asks_whether_to_keep_the_changes() {
}
}
/// Step 3's Cell box is picking from the grid, with the selection it last saw (A1).
fn pick_step_3_cell(h: &mut Harness) {
let refs = &mut h.state_mut().macros.editor.as_mut().unwrap().refs;
refs.pick = Some("ref:3:cell".into());
refs.seen = "$A$1".into();
}
#[test]
fn a_pick_ends_when_its_box_leaves_the_screen() {
// Choosing another step hides the picking box; a selection made meanwhile must not land in
// it when the step is shown again.
let mut h = harness();
three(&mut h);
click(&mut h, "Step 3: Set A3 to A3");
pick_step_3_cell(&mut h);
h.run_steps(2);
click(&mut h, "Step 1: Set A1 to A1");
assert!(h.state().macros.editor.as_ref().unwrap().refs.pick.is_none(), "the pick ends with its box");
h.state_mut().run("selection.set", json!({"range": "F9"})).unwrap();
h.run_steps(2);
click(&mut h, "Step 3: Set A3 to A3");
let ed = h.state().macros.editor.as_ref().unwrap();
assert!(!ed.dirty, "the draft stays clean");
assert_eq!(draft_cells(&h), ["A1", "A2", "A3"]);
}
#[test]
fn debugging_never_writes_the_selection_into_a_reference_box() {
// A reference box that was picking from the grid stays out of it once an action starts, and
@@ -169,13 +195,7 @@ fn debugging_never_writes_the_selection_into_a_reference_box() {
let mut h = harness();
three(&mut h);
click(&mut h, "Step 3: Set A3 to A3");
// The step's Cell box is picking, with the selection it last saw (A1).
let pick = |h: &mut Harness| {
let refs = &mut h.state_mut().macros.editor.as_mut().unwrap().refs;
refs.pick = Some("ref:3:cell".into());
refs.seen = "$A$1".into();
};
pick(&mut h);
pick_step_3_cell(&mut h);
h.run_steps(2);
assert_eq!(draft_cells(&h), ["A1", "A2", "A3"]);
click(&mut h, "Run to Here");
@@ -184,7 +204,7 @@ fn debugging_never_writes_the_selection_into_a_reference_box() {
assert!(ed.refs.pick.is_none(), "the action ends the pick");
assert!(!ed.dirty);
// A box focused while debugging does not take the selection either.
pick(&mut h);
pick_step_3_cell(&mut h);
h.state_mut().run("selection.set", json!({"range": "F9"})).unwrap();
h.run_steps(3);
let ed = h.state().macros.editor.as_ref().unwrap();