From d0f6f6cf9ba860fbd43eb2f22051cb1f74f4411f Mon Sep 17 00:00:00 2001 From: dotCooCoo Date: Sat, 14 Nov 2026 19:49:56 -0800 Subject: [PATCH] Swatch Conflict: OK pastes nothing after another document became active An immediate paste that asks about swatch conflicts now records the document it asked in. When another document is active at OK, the dialog closes as Cancel does and pastes nothing, as Delete Brush does (dialogs/brush_delete.rs). A deferred paste still goes back to the document it was given in. --- crates/ui-egui/src/dialogs/swatch_conflict.rs | 16 +++++++++++++--- crates/ui-egui/src/tests/clipboard.rs | 16 ++++++++++++++++ 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/crates/ui-egui/src/dialogs/swatch_conflict.rs b/crates/ui-egui/src/dialogs/swatch_conflict.rs index 490646e852..fb8b528b01 100644 --- a/crates/ui-egui/src/dialogs/swatch_conflict.rs +++ b/crates/ui-egui/src/dialogs/swatch_conflict.rs @@ -5,7 +5,8 @@ //! //! Fields: `conflicts` (as `clipboard.conflicts` lists them: `[{name, document, clipboard, spot}]`), //! `index` (the one asked about), `choice` (`merge` or `add`), `applyToAll`, `choices` (the -//! answers so far, by swatch name), `__command` and `__params` (the paste to run). +//! answers so far, by swatch name), `__command` and `__params` (the paste to run), and `__doc` +//! (the uid of the document it asks about). use egui::vec2; use serde_json::{Map, Value, json}; @@ -39,7 +40,7 @@ pub fn ask(app: &mut VectorcraftApp, command: &str, params: &Value) -> Option Option &[Value] { d.fields.get("conflicts").and_then(Value::as_array).map_or(&[], Vec::as_slice) } @@ -102,8 +106,14 @@ fn body(_: &mut VectorcraftApp, ui: &mut egui::Ui, d: &mut Dialog) -> bool { false } -/// Record the answer; ask about the next conflict, or paste once every one is answered. +/// Record the answer; ask about the next conflict, or paste once every one is answered. When +/// another document has become the active one since an immediate paste asked, it closes as Cancel +/// does and pastes nothing (a deferred paste goes back to its own document). fn confirm(app: &mut VectorcraftApp, d: &Dialog) -> DialogResult { + if d.fields.get("__deferredPaste").is_none() && d.fields.get(DOC).and_then(Value::as_u64) != app.session.active().map(|doc| doc.uid) { + app.ui.dialog = None; + return Ok(json!({})); + } let choice = d.str("choice"); if !matches!(choice.as_str(), "merge" | "add") { return Err(format!("choice must be \"merge\" or \"add\", not `{choice}`")); diff --git a/crates/ui-egui/src/tests/clipboard.rs b/crates/ui-egui/src/tests/clipboard.rs index d3b0c25a65..1892df67be 100644 --- a/crates/ui-egui/src/tests/clipboard.rs +++ b/crates/ui-egui/src/tests/clipboard.rs @@ -104,6 +104,22 @@ fn apply_to_all_answers_the_rest_and_cancel_pastes_nothing() { assert!(app.ui.dialog.is_none()); } +#[test] +fn ok_pastes_nothing_after_another_document_became_active() { + let mut app = conflicting(); + run(&mut app, "edit.paste", json!({})); + set(&mut app, "applyToAll", json!(true)); + app.run("document.activate", json!({"index": 0})).unwrap(); + let before = objects(&app); + let undo = app.session.active().unwrap().history.undo.len(); + dialogs::confirm(&mut app).unwrap(); + assert!(app.ui.dialog.is_none(), "it closes as Cancel does"); + assert_eq!(objects(&app), before, "the document made active pastes nothing"); + assert_eq!(app.session.active().unwrap().history.undo.len(), undo); + app.run("document.activate", json!({"index": 1})).unwrap(); + assert!(objects(&app).is_empty(), "the document it asked in pastes nothing"); +} + #[test] fn paste_goes_to_the_centre_of_the_view() { let mut app = VectorcraftApp::new(Session::new(), Default::default());