From dc6440d5238aa02cdfe536669c0891eb8b04261b Mon Sep 17 00:00:00 2001 From: dotCooCoo Date: Sat, 31 Oct 2026 13:02:13 -0700 Subject: [PATCH] Fix #2960: Recolor Artwork keeps its Preserve checkboxes between uses Recolor Artwork opened with Preserve White and Black on and Grays off every time, so clearing them had to be repeated on each use. OK on art now keeps the three checkboxes in the UI state (recolor_preserve, saved with the other remembered dialog fields), and the dialog opens with them. Cancel leaves them as the last OK set them. --- crates/ui-egui/src/dialogs/recolor.rs | 18 ++++++++++++++---- crates/ui-egui/src/state.rs | 5 +++++ crates/ui-egui/src/tests/recolor.rs | 21 +++++++++++++++++++++ 3 files changed, 40 insertions(+), 4 deletions(-) diff --git a/crates/ui-egui/src/dialogs/recolor.rs b/crates/ui-egui/src/dialogs/recolor.rs index 6050af15a..bdd509409 100644 --- a/crates/ui-egui/src/dialogs/recolor.rs +++ b/crates/ui-egui/src/dialogs/recolor.rs @@ -2,8 +2,9 @@ //! previewed live (engine: `recolor.reduce`, `recolor.randomize`, `recolor.apply`). //! //! Assign tab: Colors (Auto, or a count: similar colours merge into rows), Preserve White, Black and -//! Grays, the rows (click to select, Shift or Cmd/Ctrl-click to add; a row's arrow excludes or -//! includes it; the hex field edits its new colour, and a double-click on it opens the Color Picker, +//! Grays (they open as OK on art last left them), the rows (click to select, Shift or Cmd/Ctrl-click +//! to add; a row's arrow excludes or includes it; the hex field edits its new colour, and a +//! double-click on it opens the Color Picker, //! whose OK sets it in the model it was picked in), Merge and Separate, Randomize order or //! saturation and brightness, Reset, the Method and Limit to Library (its folder button imports a //! library file and limits to it; a library's colours apply as its swatches: a spot colour stays a @@ -100,9 +101,12 @@ pub fn open(app: &mut VectorcraftApp, p: &Value) -> Result { }; // Without art the rows are the group's colours, as they are. let start: Vec = if art { vec![] } else { assign.iter().map(|k| json!({"from": [k], "to": k})).collect() }; + // The Preserve checkboxes as they were last confirmed (#2960). + let kept = |k: &str, default: bool| app.ui.recolor_preserve.get(k).and_then(Value::as_bool).unwrap_or(default); let fields = json!({ "rows": start, "colors": count, "method": Method::ScaleTints.id(), - "preserveWhite": true, "preserveBlack": true, "preserveGrays": false, "limitTo": limit, + "preserveWhite": kept("preserveWhite", true), "preserveBlack": kept("preserveBlack", true), + "preserveGrays": kept("preserveGrays", false), "limitTo": limit, "group": group, "groupName": if new_group { Some(NEW_GROUP) } else { group }, "tab": "assign", "rule": Harmony::Complementary.id(), "linked": true, "preview": true, "__art": art, "__assign": assign, "__newGroup": new_group, }); @@ -277,7 +281,13 @@ fn confirm(app: &mut VectorcraftApp, d: &Dialog) -> Result { let colors: Vec = rows(&d).into_iter().filter(|r| !excluded(r)).map(|r| r["to"].clone()).collect(); return form::commit_preview(app, "swatch.newGroup", json!({"name": d.str("groupName"), "colors": colors, "keepModel": true})); } - form::commit_preview(app, CMD, apply_params(&d)) + let r = form::commit_preview(app, CMD, apply_params(&d))?; + // The Preserve checkboxes (shown with art) open as confirmed here next time (#2960). + if d.bool("__art") { + app.ui.recolor_preserve = + json!({"preserveWhite": d.bool("preserveWhite"), "preserveBlack": d.bool("preserveBlack"), "preserveGrays": d.bool("preserveGrays")}); + } + Ok(r) } /// The preset the fields match: an n-colour job (n rows, Scale Tints), a library, or Custom. diff --git a/crates/ui-egui/src/state.rs b/crates/ui-egui/src/state.rs index 2b5c9c379..63a4f0390 100644 --- a/crates/ui-egui/src/state.rs +++ b/crates/ui-egui/src/state.rs @@ -563,6 +563,10 @@ pub struct UiState { /// The Average & Join fields confirmed last (`to`; null: never used): its dialog opens on them. #[serde(default)] pub average_join: Value, + /// The Recolor Artwork Preserve checkboxes confirmed last (`preserveWhite`, `preserveBlack`, + /// `preserveGrays`; null: never used): its dialog opens with them (#2960). + #[serde(default)] + pub recolor_preserve: Value, /// The Simplify dialog's fields confirmed last with "Open this dialog with these settings next /// time" ticked (null: not ticked): Object › Path › Simplify opens the dialog on them instead /// of the Simplify slider. @@ -904,6 +908,7 @@ impl Default for UiState { eps_options: Value::Null, offset_path: Value::Null, average_join: Value::Null, + recolor_preserve: Value::Null, simplify: Value::Null, move_options: Value::Null, transform_each: Value::Null, diff --git a/crates/ui-egui/src/tests/recolor.rs b/crates/ui-egui/src/tests/recolor.rs index 8d38d8d2f..1abefd25c 100644 --- a/crates/ui-egui/src/tests/recolor.rs +++ b/crates/ui-egui/src/tests/recolor.rs @@ -238,6 +238,27 @@ fn each_recolor_hex_field_has_its_row_number() { assert!(h.query_by_role_and_label(egui::accesskit::Role::TextInput, "Color").is_none(), "no ambiguous Color field"); } +/// #2960: the Preserve checkboxes open as OK last left them; Cancel keeps what OK left. +#[test] +fn the_preserve_checkboxes_open_as_they_were_last_confirmed() { + let mut app = app(); + art(&mut app, &["#ff0000", "#ffffff", "#000000", "#808080"]); + let preserve = |app: &VectorcraftApp| ["preserveWhite", "preserveBlack", "preserveGrays"].map(|k| field(app, k)); + app.run("ui.recolorDialog", json!({})).unwrap(); + assert_eq!(preserve(&app), [json!(true), json!(true), json!(false)], "a first open"); + set(&mut app, "preserveWhite", json!(false)); + set(&mut app, "preserveBlack", json!(false)); + set(&mut app, "preserveGrays", json!(true)); + dialogs::confirm(&mut app).unwrap(); + app.run("select.all", json!({})).unwrap(); + app.run("ui.recolorDialog", json!({})).unwrap(); + assert_eq!(preserve(&app), [json!(false), json!(false), json!(true)], "as confirmed"); + set(&mut app, "preserveWhite", json!(true)); + dialogs::cancel(&mut app); + app.run("ui.recolorDialog", json!({})).unwrap(); + assert_eq!(preserve(&app), [json!(false), json!(false), json!(true)], "Cancel keeps what OK left"); +} + /// The rect of the widget drawn `size` big (the wheel is 220 across, its Brightness slider 220 by 22). fn widget_of_size(h: &egui_kittest::Harness<'_, VectorcraftApp>, size: egui::Vec2) -> Rect { h.ctx