From c09e1d3ebedbce1e08ce2c723a13734f17914a89 Mon Sep 17 00:00:00 2001 From: dotCooCoo Date: Wed, 11 Nov 2026 00:33:28 -0800 Subject: [PATCH] Scripts: closing the quit question when the script it asked about has ended A window-close request while a script waits at its alert, confirm or prompt opens the quit question over that dialog, and Cancel shows the script's dialog again. When the run then ended another way (script.stop, or the run finishing), the quit question stayed open, and Cancel showed a dialog for a script that was no longer running. The running-script poll now closes the quit question once the run ends, and forgets the script's dialog under it once the run no longer waits at that dialog. --- crates/ui-egui/src/dialogs/script_run.rs | 16 +++++++++++++ crates/ui-egui/src/script_runs.rs | 2 ++ crates/ui-egui/src/tests/script_dialogs.rs | 26 ++++++++++++++++++++++ 3 files changed, 44 insertions(+) diff --git a/crates/ui-egui/src/dialogs/script_run.rs b/crates/ui-egui/src/dialogs/script_run.rs index eb89bd174..8f5e3b109 100644 --- a/crates/ui-egui/src/dialogs/script_run.rs +++ b/crates/ui-egui/src/dialogs/script_run.rs @@ -182,6 +182,22 @@ pub(crate) fn ask_to_close(app: &mut VectorcraftApp) { app.ui.dialog = Some(Dialog::new(CLOSE_KIND, fields)); } +/// Closes the question quitting asks once the run it asks about has ended, and forgets the +/// script's dialog it was asked over once the run no longer waits at that dialog, so Cancel does +/// not show it again. +pub(crate) fn settle_close(app: &mut VectorcraftApp) { + if !app.ui.dialog.as_ref().is_some_and(|d| d.kind == CLOSE_KIND) { + return; + } + if !app.session.script_running() { + app.ui.dialog = None; + } else if app.session.script_dialog().is_none() + && let Some(d) = app.ui.dialog.as_mut() + { + d.fields.remove(super::PARENT); + } +} + /// Shows the dialog the running script waits at. pub(crate) fn open_notice(app: &mut VectorcraftApp, d: &ScriptDialog) { let fields = json!({ diff --git a/crates/ui-egui/src/script_runs.rs b/crates/ui-egui/src/script_runs.rs index 65a9dc9eb..02c222974 100644 --- a/crates/ui-egui/src/script_runs.rs +++ b/crates/ui-egui/src/script_runs.rs @@ -15,6 +15,7 @@ pub fn poll(app: &mut VectorcraftApp) { if !app.session.script_running() { return; } + script_run::settle_close(app); if ask(app) { return; } @@ -31,6 +32,7 @@ pub fn poll(app: &mut VectorcraftApp) { if app.ui.dialog.as_ref().is_some_and(|d| d.kind == script_run::GROWTH_KIND) { app.ui.dialog = None; } + script_run::settle_close(app); match result { Ok(_) => app.status(format!("Ran {name}")), Err(e) => failed(app, e.to_string()), diff --git a/crates/ui-egui/src/tests/script_dialogs.rs b/crates/ui-egui/src/tests/script_dialogs.rs index da09c777b..b3750001a 100644 --- a/crates/ui-egui/src/tests/script_dialogs.rs +++ b/crates/ui-egui/src/tests/script_dialogs.rs @@ -220,6 +220,32 @@ fn close_while_notification_waits_abandons_or_resumes() { assert_eq!(app.ui.status, "The script was stopped and its changes were undone"); } +#[test] +fn close_question_ends_with_a_run_stopped_another_way() { + let mut app = app(); + start(&mut app, &format!("{DRAW} vc.log(prompt('Name', ''));")); + assert!(until_dialog(&mut app)); + dialogs::script_run::ask_to_close(&mut app); + assert_eq!(app.ui.dialog.as_ref().unwrap().kind, CLOSE_KIND); + assert_eq!(app.run("script.stop", json!({})).unwrap()["stopped"], true); + script_runs::poll(&mut app); + assert!(!app.session.script_running()); + assert!(app.ui.dialog.is_none(), "the question about a run that has ended closes"); + dialogs::cancel(&mut app); + assert!(app.ui.dialog.is_none(), "Cancel does not show the stopped script's dialog again"); + assert_eq!(objects(&app), 0); + // Asked to stop, the run no longer waits at its dialog before its next slice ends it. + let mut app = self::app(); + start(&mut app, &format!("{DRAW} vc.log(prompt('Name', ''));")); + assert!(until_dialog(&mut app)); + dialogs::script_run::ask_to_close(&mut app); + app.run("script.stop", json!({})).unwrap(); + dialogs::script_run::settle_close(&mut app); + assert_eq!(app.ui.dialog.as_ref().unwrap().kind, CLOSE_KIND, "the run has not ended yet"); + dialogs::cancel(&mut app); + assert!(app.ui.dialog.is_none(), "Cancel does not show a dialog the run no longer waits at"); +} + #[test] fn notification_layout_with_long_text_and_small_window() { let mut app = app();