mirror of
https://github.com/storytold/gridcraft.git
synced 2026-10-30 05:37:00 -06:00
UI: the control channel's dialog cancel closes the macro step editor as its own close does
ui.dialog.cancel emptied the dialog slot, so with the step editor open it went without its cleanup: the draft stayed behind, the Check overlays stayed on the grid, the selection the reference boxes moved was not put back and a debug run went on with no controls. The cancel now closes the editor the way its close button does, and is refused, with the reason, while the editor holds unsaved steps or a debug run, which only its window asks about.
This commit is contained in:
@@ -320,6 +320,13 @@ pub fn handle(app: &mut SheetApp, ctx: &egui::Context, method: &str, p: &Json) -
|
||||
None => err("no dialog is open"),
|
||||
},
|
||||
"ui.dialog.cancel" => {
|
||||
// The macro step editor's draft, overlays and debug run go with its own close.
|
||||
if app.dialog.as_ref().is_some_and(|d| d.name == "macroEditor") {
|
||||
return match crate::macro_editor::close_now(app) {
|
||||
Ok(()) => ok(Json::Null),
|
||||
Err(e) => err(e),
|
||||
};
|
||||
}
|
||||
app.dialog = None;
|
||||
ok(Json::Null)
|
||||
}
|
||||
|
||||
@@ -838,6 +838,26 @@ pub fn window(app: &mut SheetApp, ctx: &egui::Context, d: &mut Dialog, open: &mu
|
||||
}
|
||||
}
|
||||
|
||||
/// Closes the step editor at once for a caller outside its window (the control channel's
|
||||
/// `ui.dialog.cancel`), with the cleanup its own close does. Refused while it holds a debug run
|
||||
/// or unsaved steps, which only its window asks about.
|
||||
pub fn close_now(app: &mut SheetApp) -> Result<(), String> {
|
||||
if app.session.macro_debug.is_some() {
|
||||
return Err("A macro is being debugged: stop it first (macro.debug {\"action\": \"stop\"}).".into());
|
||||
}
|
||||
if app.macros.editor.as_ref().is_some_and(|ed| ed.dirty) {
|
||||
return Err("The macro step editor has unsaved steps: save them or close the editor in its window.".into());
|
||||
}
|
||||
if let Some(ed) = app.macros.editor.take()
|
||||
&& app.session.active().is_some_and(|d| d.uid == ed.doc)
|
||||
{
|
||||
restore_home(app, &ed.refs);
|
||||
}
|
||||
app.grid.macro_overlay = None;
|
||||
app.dialog = None;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- reference boxes
|
||||
|
||||
/// A range as an absolute reference: `$B$2:$D$9`.
|
||||
|
||||
@@ -402,3 +402,30 @@ fn the_editor_works_only_on_the_workbook_it_opened_in() {
|
||||
assert!(h.state().macros.editor.is_none());
|
||||
assert!(h.state().dialog.as_ref().is_none_or(|d| d.name() != "macroEditor"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn the_control_channels_cancel_closes_the_editor_as_its_own_close_does() {
|
||||
let mut h = harness();
|
||||
three(&mut h);
|
||||
let ctx = h.ctx.clone();
|
||||
let reply = |o: gridcraft_ui_egui::control::Outcome| match o {
|
||||
gridcraft_ui_egui::control::Outcome::Done(v) => v,
|
||||
_ => json!(null),
|
||||
};
|
||||
// Unsaved steps are only the editor's to ask about: cancel is refused and keeps them.
|
||||
h.state_mut().macros.editor.as_mut().unwrap().dirty = true;
|
||||
let r = reply(gridcraft_ui_egui::control::handle(h.state_mut(), &ctx, "ui.dialog.cancel", &json!({})));
|
||||
assert!(r.get("error").is_some(), "{r}");
|
||||
assert!(h.state().macros.editor.is_some());
|
||||
// A saved editor closes, and takes its overlays with it.
|
||||
h.state_mut().macros.editor.as_mut().unwrap().dirty = false;
|
||||
h.get_by_label("Check").click();
|
||||
h.run_steps(3);
|
||||
assert!(h.state().grid.macro_overlay.is_some());
|
||||
let r = reply(gridcraft_ui_egui::control::handle(h.state_mut(), &ctx, "ui.dialog.cancel", &json!({})));
|
||||
assert!(r.get("error").is_none(), "{r}");
|
||||
h.run_steps(2);
|
||||
assert!(h.state().dialog.is_none());
|
||||
assert!(h.state().macros.editor.is_none());
|
||||
assert!(h.state().grid.macro_overlay.is_none());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user