From b9f9099d91712833025e56edc85aa5d07b9812ff Mon Sep 17 00:00:00 2001 From: dotCooCoo Date: Thu, 29 Oct 2026 14:35:57 +0700 Subject: [PATCH] Flare: preview options and restore defaults with Alt or Option Squashed from #4446 onto main. --- crates/ui-egui/src/dialogs.rs | 54 ++++++- crates/ui-egui/src/dialogs/flare_options.rs | 158 ++++++++++++++++++-- crates/ui-egui/src/dialogs/tests.rs | 34 +++++ crates/ui-egui/src/i18n/bg.tsv | 1 + crates/ui-egui/src/i18n/cs.tsv | 1 + crates/ui-egui/src/i18n/da.tsv | 1 + crates/ui-egui/src/i18n/de.tsv | 1 + crates/ui-egui/src/i18n/el.tsv | 1 + crates/ui-egui/src/i18n/es.tsv | 1 + crates/ui-egui/src/i18n/fi.tsv | 1 + crates/ui-egui/src/i18n/fr.tsv | 1 + crates/ui-egui/src/i18n/hu.tsv | 1 + crates/ui-egui/src/i18n/id.tsv | 1 + crates/ui-egui/src/i18n/it.tsv | 1 + crates/ui-egui/src/i18n/ja.tsv | 1 + crates/ui-egui/src/i18n/ka.tsv | 1 + crates/ui-egui/src/i18n/ko.tsv | 1 + crates/ui-egui/src/i18n/nl.tsv | 1 + crates/ui-egui/src/i18n/pl.tsv | 1 + crates/ui-egui/src/i18n/pt-br.tsv | 1 + crates/ui-egui/src/i18n/ru.tsv | 1 + crates/ui-egui/src/i18n/sv.tsv | 1 + crates/ui-egui/src/i18n/tr.tsv | 1 + crates/ui-egui/src/i18n/uk.tsv | 1 + crates/ui-egui/src/i18n/vi.tsv | 1 + crates/ui-egui/src/i18n/zh-hans.tsv | 1 + crates/ui-egui/src/i18n/zh-hant.tsv | 1 + crates/ui-egui/src/menus/run.rs | 1 + crates/ui-egui/src/menus/state.rs | 1 + crates/ui-egui/src/menus/ui_commands.rs | 8 +- docs/gaps.md | 3 +- docs/mcp.md | 5 +- docs/roadmap.md | 1 + docs/target-app-parity.md | 2 + docs/ui-parity.md | 1 + 35 files changed, 273 insertions(+), 19 deletions(-) diff --git a/crates/ui-egui/src/dialogs.rs b/crates/ui-egui/src/dialogs.rs index b28fc6e1a..1e96e74d3 100644 --- a/crates/ui-egui/src/dialogs.rs +++ b/crates/ui-egui/src/dialogs.rs @@ -177,6 +177,10 @@ pub(crate) struct DialogSpec { /// A button left of Cancel, as (label, field), that sets `field: true` and confirms, as OK /// does otherwise (Transform Each's Copy). pub alternate: Option<(&'static str, &'static str)>, + /// Puts the fields back to their defaults. While Alt (Option on macOS) is held, the Cancel + /// button of a dialog with an `ok` reads Reset; Reset (or `ui.dialogReset`) runs this and the + /// dialog stays open. + pub reset: Option, pub min_width: f32, pub max_width: Option, /// The body runs a live preview interaction that Cancel rolls back. @@ -212,6 +216,7 @@ impl DialogSpec { ok: Some("OK"), discard: None, alternate: None, + reset: None, min_width: 320.0, max_width: None, preview: false, @@ -379,14 +384,15 @@ registry! { ShortcutImport: [shortcut_import::KIND] => DialogSpec::window(shortcut_import::show, shortcut_import::confirm), } -/// The button labels the shared dialog frame can show (OK, discard and the fixed Cancel/Close), -/// so the catalog tests can insist they are translated. +/// The button labels the shared dialog frame can show (OK, discard, the fixed Cancel/Close and +/// Reset), so the catalog tests can insist they are translated. pub fn button_labels() -> Vec<&'static str> { let mut v = vec!["Cancel", "Close"]; for spec in std::iter::once(&DialogSpec::FORM).chain(DialogKind::ALL.iter().map(|k| k.spec())) { v.extend(spec.ok); v.extend(spec.discard); v.extend(spec.alternate.map(|(label, _)| label)); + v.extend(spec.reset.map(|_| "Reset")); } v.sort_unstable(); v.dedup(); @@ -455,7 +461,10 @@ pub(crate) fn parent(d: &Dialog) -> Option { pub fn cancel(app: &mut VectorcraftApp) { missing_fonts::requeue_replaced(app); if let Some(d) = app.ui.dialog.take() { - if spec(&d.kind).preview { + // Toolbar-only Flare options start no preview and must not cancel a gesture + // that was already active before opening them. + let owns_preview = d.kind != flare_options::KIND || d.fields.contains_key(form::PREVIEWED); + if spec(&d.kind).preview && owns_preview { let _ = app.session.cancel_interaction(); } app.ui.dialog = parent(&d); @@ -463,6 +472,23 @@ pub fn cancel(app: &mut VectorcraftApp) { settle(app); } +/// Whether the open dialog has a Reset ([`DialogSpec::reset`]). +pub(crate) fn can_reset(app: &VectorcraftApp) -> bool { + app.ui.dialog.as_ref().is_some_and(|d| spec(&d.kind).reset.is_some()) +} + +/// Reset (`ui.dialogReset`, or Cancel while Alt or Option is held): the open dialog's fields go +/// back to their defaults and it stays open → the dialog; an error when no dialog is open or the +/// open one has no Reset. +pub(crate) fn reset(app: &mut VectorcraftApp) -> DialogResult { + let Some(mut d) = app.ui.dialog.clone() else { return Err("no dialog open".into()) }; + let Some(reset) = spec(&d.kind).reset else { return Err("the open dialog has no Reset".into()) }; + reset(app, &mut d); + let out = serde_json::to_value(&d).unwrap_or_default(); + app.ui.dialog = Some(d); + Ok(out) +} + /// Apply the open dialog (OK). pub fn confirm(app: &mut VectorcraftApp) -> DialogResult { missing_fonts::requeue_replaced(app); @@ -538,6 +564,7 @@ pub fn show(app: &mut VectorcraftApp, ctx: &egui::Context) { let mut ok = false; let mut ok_enabled = true; let mut cancel = false; + let mut reset = false; let mut discard = false; let mut alternate = false; // Opened as a save panel closed: the Enter that closed it isn't this dialog's, until it is let go. @@ -598,8 +625,21 @@ pub fn show(app: &mut VectorcraftApp, ctx: &egui::Context) { ok = true; } ui.add_space(8.0); - if widgets::secondary_button(ui, if spec.ok.is_some() { "Cancel" } else { "Close" }).clicked() { - cancel = true; + // While Alt (Option) is held, Cancel reads Reset on a dialog that has one. + let resets = spec.ok.is_some() && spec.reset.is_some() && ui.input(|i| i.modifiers.alt); + let label = if resets { + "Reset" + } else if spec.ok.is_some() { + "Cancel" + } else { + "Close" + }; + if widgets::secondary_button(ui, label).clicked() { + if resets { + reset = true; + } else { + cancel = true; + } } if let Some((label, _)) = spec.alternate { ui.add_space(8.0); @@ -625,6 +665,10 @@ pub fn show(app: &mut VectorcraftApp, ctx: &egui::Context) { app.ui.dialog = Some(d); if cancel { self::cancel(app); + } else if reset { + if let Err(e) = self::reset(app) { + app.status(e); + } } else if ok && let Err(e) = confirm(app) { app.status(e); } diff --git a/crates/ui-egui/src/dialogs/flare_options.rs b/crates/ui-egui/src/dialogs/flare_options.rs index 44ae5eb58..b94f6a7c2 100644 --- a/crates/ui-egui/src/dialogs/flare_options.rs +++ b/crates/ui-egui/src/dialogs/flare_options.rs @@ -1,13 +1,15 @@ //! Flare Tool Options (double-click the Flare tool, or click with it): the options the Flare tool //! keeps, which draw the next flare dragged out, last across tool switches and are saved with the //! preferences. OK sets them with `tool.setOption {tool: "flare", values}`; opened by a click, it -//! then draws a flare there with them (`shape.flare`, on the active perspective plane while the -//! grid shows). +//! accepts a flare preview there with them (`shape.flare`, on the active perspective plane while the +//! grid shows). While Alt (Option on macOS) is held, Cancel reads Reset, which puts every option +//! back to the tool's default and leaves the dialog open (`ui.dialogReset`). A click-opened +//! dialog previews its settings live; Reset refreshes that preview and Cancel rolls it back. //! //! Fields: the options (`vectorcraft_tools::extra::FLARE_OPTIONS`): `diameter` and `pathLength` //! (points), `opacity`, `brightness`, `growth`, `fuzziness`, `longest`, `rayFuzziness` and //! `largest` (%), `rays` and `rings` (counts), `direction` (degrees); `raysOn` and `ringsOn`; and -//! `x`, `y` where a click opened it. +//! `x`, `y` where a click opened it, with `preview` on initially for that click. use serde_json::{Map, Value, json}; use vectorcraft_geom::Point; @@ -21,7 +23,15 @@ use crate::{VectorcraftApp, widgets}; /// The dialog kind of the Flare Tool Options. pub const KIND: &str = "flareOptions"; -pub(super) const SPEC: DialogSpec = DialogSpec { heading: |_| tl!("Flare Tool Options").into(), body, confirm, min_width: 440.0, ..DialogSpec::FORM }; +pub(super) const SPEC: DialogSpec = DialogSpec { + heading: |_| tl!("Flare Tool Options").into(), + body, + confirm, + reset: Some(reset), + preview: true, + min_width: 440.0, + ..DialogSpec::FORM +}; /// Width of the label column and of the fields. const LABEL_W: f32 = 78.0; @@ -35,6 +45,7 @@ pub fn open(app: &mut VectorcraftApp, at: Option) -> Value { _ => Map::new(), }; if let Some(p) = at { + fields.insert("preview".into(), json!(true)); fields.insert("x".into(), json!(p.x)); fields.insert("y".into(), json!(p.y)); } @@ -102,23 +113,53 @@ fn body(app: &mut VectorcraftApp, ui: &mut egui::Ui, d: &mut Dialog) -> bool { }); ui.end_row(); }); + if let Some((cmd, params)) = preview_command(app, d) { + form::preview(app, ui, d, "Flare", &cmd, params); + } false } +/// A click-created flare previews at that original click; toolbar options draw no artwork. +fn preview_command(app: &VectorcraftApp, d: &Dialog) -> Option<(String, Value)> { + let at = Point::new(d.fields.get("x")?.as_f64().filter(|v| v.is_finite())?, d.fields.get("y")?.as_f64().filter(|v| v.is_finite())?); + // Use the same clamping and whole-count conversion as accepted tool settings. + let mut tool = vectorcraft_tools::create("flare"); + for (key, default, ..) in FLARE_OPTIONS { + tool.set_option(key, &json!(d.f64(key, default))); + } + for key in ["raysOn", "ringsOn"] { + tool.set_option(key, &json!(d.bool(key))); + } + let params = flare_params(&tool.options(), at); + Some(vectorcraft_engine::perspective_click(&app.session, "shape.flare", ¶ms, at).unwrap_or_else(|| ("shape.flare".into(), params))) +} + +/// Reset (Cancel with Alt or Option held): every option goes back to the Flare tool's default +/// (`FLARE_OPTIONS`, with Rays and Rings on). The dialog keeps a click's `x` and `y`, so OK still draws there. +fn reset(_: &VectorcraftApp, d: &mut Dialog) { + if let Value::Object(defaults) = vectorcraft_tools::create("flare").options() { + d.fields.extend(defaults); + } +} + /// OK: set the tool's options; opened by a click, draw a flare there with them. fn confirm(app: &mut VectorcraftApp, d: &Dialog) -> DialogResult { + let command = preview_command(app, d); + if command.is_none() && (d.fields.contains_key("x") || d.fields.contains_key("y") || d.fields.contains_key(form::PREVIEWED)) { + return Err("Flare click coordinates must be finite numbers".into()); + } let mut values: Map = FLARE_OPTIONS.iter().filter(|(k, ..)| d.fields.contains_key(*k)).map(|(k, default, ..)| (k.to_string(), json!(d.f64(k, *default)))).collect(); for key in ["raysOn", "ringsOn"] { values.insert(key.into(), json!(d.bool(key))); } - let at = d.fields.get("x").and_then(Value::as_f64).zip(d.fields.get("y").and_then(Value::as_f64)).map(|(x, y)| Point::new(x, y)); - let options = run_and_close(app, "tool.setOption", json!({ "tool": "flare", "values": values }))?; - let Some(at) = at else { return Ok(options) }; - let params = flare_params(&options, at); - match vectorcraft_engine::perspective_click(&app.session, "shape.flare", ¶ms, at) { - Some((id, p)) => app.run(&id, p), - None => app.run("shape.flare", params), + if let Some((cmd, params)) = command { + // Accept the preview once; option persistence follows successful artwork creation. + let result = form::commit_preview(app, &cmd, params)?; + app.run("tool.setOption", json!({ "tool": "flare", "values": values }))?; + Ok(result) + } else { + run_and_close(app, "tool.setOption", json!({ "tool": "flare", "values": values })) } } @@ -148,6 +189,81 @@ mod tests { children.iter().filter_map(|c| c.name.clone()).collect() } + /// Invalid control-channel coordinates must not turn a click dialog into toolbar options. + #[test] + fn invalid_click_coordinates_keep_the_dialog_and_preview_cancellable() { + for (key, value) in [("x", Value::Null), ("y", Value::Null), ("x", json!("invalid"))] { + let mut app = app(); + let original = app.session.doc().unwrap().doc.layers.clone(); + let depth = app.session.doc().unwrap().history.undo.len(); + let options = app.session.tool_options_of("flare"); + open(&mut app, Some(Point::new(220.0, 330.0))); + painted(&mut app); + let preview = app.session.doc().unwrap().doc.layers.clone(); + let d = app.ui.dialog.as_mut().unwrap(); + d.fields.insert(key.into(), value); + d.fields.insert("rings".into(), json!(4)); + assert_eq!(super::super::confirm(&mut app).unwrap_err(), "Flare click coordinates must be finite numbers"); + assert!(app.ui.dialog.is_some()); + assert!(app.session.in_interaction()); + assert_eq!(app.session.doc().unwrap().doc.layers, preview); + assert_eq!(app.session.doc().unwrap().history.undo.len(), depth); + assert_eq!(app.session.tool_options_of("flare"), options); + super::super::cancel(&mut app); + assert!(!app.session.in_interaction()); + assert_eq!(app.session.doc().unwrap().doc.layers, original); + } + } + + #[test] + fn cancelling_toolbar_options_preserves_an_existing_interaction() { + let mut app = app(); + app.session.begin_interaction("Existing gesture").unwrap(); + app.session.preview("shape.rectangle", &json!({"x":10,"y":10,"width":40,"height":40})).unwrap(); + let previewed = app.session.doc().unwrap().doc.layers.clone(); + open(&mut app, None); + painted(&mut app); + super::super::cancel(&mut app); + assert!(app.session.in_interaction()); + assert_eq!(app.session.doc().unwrap().doc.layers, previewed); + app.session.cancel_interaction().unwrap(); + } + + #[test] + fn reset_updates_live_preview_and_cancel_discards_art_and_options() { + let mut app = app(); + app.run("tool.setOption", json!({"tool":"flare", "values":{"rings":3}})).unwrap(); + let original = app.session.doc().unwrap().doc.layers.clone(); + let depth = app.session.doc().unwrap().history.undo.len(); + let options = app.session.tool_options_of("flare"); + open(&mut app, Some(Point::new(220.0, 330.0))); + let text = painted(&mut app); + assert!(text.contains("Preview")); + assert_eq!(flare_parts(&app).iter().filter(|s| *s == "Ring").count(), 3); + assert_eq!(app.session.doc().unwrap().history.undo.len(), depth); + app.ui.dialog.as_mut().unwrap().fields.insert("rings".into(), json!(4.0)); + painted(&mut app); + assert_eq!(flare_parts(&app).iter().filter(|s| *s == "Ring").count(), 4); + app.run("ui.dialogReset", json!({})).unwrap(); + painted(&mut app); + assert_eq!(flare_parts(&app).iter().filter(|s| *s == "Ring").count(), 10); + assert_eq!(app.session.tool_options_of("flare"), options, "preview doesn't persist options"); + super::super::cancel(&mut app); + assert_eq!(app.session.doc().unwrap().doc.layers, original); + assert_eq!(app.session.doc().unwrap().history.undo.len(), depth); + assert_eq!(app.session.tool_options_of("flare"), options); + // Accepting the same reset preview produces one flare and one Undo step. + open(&mut app, Some(Point::new(220.0, 330.0))); + painted(&mut app); + app.run("ui.dialogReset", json!({})).unwrap(); + painted(&mut app); + super::super::confirm(&mut app).unwrap(); + assert_eq!(app.session.doc().unwrap().history.undo.len(), depth + 1); + assert_eq!(flare_parts(&app).iter().filter(|s| *s == "Ring").count(), 10); + app.run("edit.undo", json!({})).unwrap(); + assert_eq!(app.session.doc().unwrap().doc.layers, original); + } + #[test] fn the_toolbar_opens_the_options_and_ok_keeps_them_for_the_next_drag() { let mut app = app(); @@ -200,4 +316,24 @@ mod tests { let o = app.session.tool_options_of("flare"); assert_eq!((o["opacity"].as_f64(), o["diameter"].as_f64()), (Some(100.0), Some(0.0))); } + + #[test] + fn ui_dialog_reset_puts_the_defaults_back_and_keeps_where_a_click_opened_it() { + let mut app = app(); + assert_eq!(app.run("ui.dialogReset", json!({})).unwrap_err(), "no dialog open"); + app.run("tool.setOption", json!({"tool": "flare", "values": {"rings": 3, "raysOn": false, "largest": 120}})).unwrap(); + crate::dialogs::open_tool_dialog(&mut app, "flare", json!({"x": 300, "y": 300})); + let d = app.run("ui.dialogReset", json!({})).unwrap(); + assert_eq!((d["kind"].as_str(), d["fields"]["rings"].as_f64(), d["fields"]["raysOn"].as_bool()), (Some(KIND), Some(10.0), Some(true))); + let d = app.ui.dialog.as_ref().expect("the dialog stays open"); + assert_eq!((d.f64("largest", 0.0), d.f64("x", 0.0), d.f64("y", 0.0)), (50.0, 300.0, 300.0)); + // The tool keeps its options until OK, which draws the flare with the defaults where the click was. + assert_eq!(app.session.tool_options_of("flare")["rings"].as_u64(), Some(3)); + super::super::confirm(&mut app).unwrap(); + let parts = flare_parts(&app); + assert_eq!((parts.iter().filter(|p| *p == "Ring").count(), parts.iter().any(|p| p == "Rays")), (10, true), "{parts:?}"); + // A dialog without a Reset refuses it. + app.ui.dialog = Some(Dialog::new("move", json!({"dx": 1}))); + assert_eq!(app.run("ui.dialogReset", json!({})).unwrap_err(), "the open dialog has no Reset"); + } } diff --git a/crates/ui-egui/src/dialogs/tests.rs b/crates/ui-egui/src/dialogs/tests.rs index 5be090dc6..cd3871f0e 100644 --- a/crates/ui-egui/src/dialogs/tests.rs +++ b/crates/ui-egui/src/dialogs/tests.rs @@ -1661,6 +1661,40 @@ fn free_distort_reset_puts_the_corners_back() { assert_eq!((effects.len(), effects[0].params["corners"].clone()), (1, rest)); } +/// While Alt is held, the Flare Tool Options' Cancel button reads Reset; Reset puts every option +/// back to the tool's default and leaves the dialog open, letting Alt go shows Cancel again, and OK +/// keeps the defaults. +#[test] +fn flare_options_alt_turns_cancel_into_reset() { + let mut app = app(); + app.run("tool.options", json!({"tool": "flare"})).unwrap(); + let d = app.ui.dialog.as_mut().unwrap(); + for (k, v) in [("diameter", json!(250)), ("rays", json!(4)), ("ringsOn", json!(false)), ("growth", json!(80))] { + d.fields.insert(k.into(), v); + } + let mut f = Frames::new(); + f.button(&mut app, "Cancel"); + f.run(&mut app, vec![egui::Event::ModifiersChanged(egui::Modifiers::ALT)]); + let reset = f.button(&mut app, "Reset"); + let texts = f.texts(&mut app); + assert!(!texts.iter().any(|(t, _)| t == "Cancel"), "Reset takes Cancel's place: {texts:?}"); + f.press(&mut app, reset, true); + f.press(&mut app, reset, false); + let d = app.ui.dialog.as_ref().expect("Reset leaves the dialog open"); + assert_eq!( + (d.f64("diameter", 0.0), d.f64("rays", 0.0), d.bool("ringsOn"), d.f64("growth", 0.0), d.f64("direction", 0.0)), + (100.0, 15.0, true, 20.0, 45.0) + ); + f.run(&mut app, vec![egui::Event::ModifiersChanged(egui::Modifiers::NONE)]); + f.button(&mut app, "Cancel"); + confirm(&mut app).unwrap(); + let o = app.session.tool_options_of("flare"); + assert_eq!( + (o["diameter"].as_f64(), o["rays"].as_u64(), o["ringsOn"].as_bool(), o["growth"].as_f64()), + (Some(100.0), Some(15), Some(true), Some(20.0)) + ); +} + /// The slider that screen readers name `label` in `out`'s tree: its node id, number and text. fn slider_node(out: &egui::FullOutput, label: &str) -> (egui::accesskit::NodeId, Option, Option) { let nodes = &out.platform_output.accesskit_update.as_ref().expect("an accessibility tree").nodes; diff --git a/crates/ui-egui/src/i18n/bg.tsv b/crates/ui-egui/src/i18n/bg.tsv index 0a5ef474b..aee83cf1f 100644 --- a/crates/ui-egui/src/i18n/bg.tsv +++ b/crates/ui-egui/src/i18n/bg.tsv @@ -4014,6 +4014,7 @@ axis Both И двете @msg no current layer няма текущ слой @msg no data няма данни @msg no dialog open няма отворен диалогов прозорец +@msg the open dialog has no Reset отвореният диалогов прозорец няма бутон „Нулиране“ @msg no document няма документ @msg no document open няма отворен документ @msg no effect applied yet все още няма приложен ефект diff --git a/crates/ui-egui/src/i18n/cs.tsv b/crates/ui-egui/src/i18n/cs.tsv index 839d7d307..cfc6c9f3d 100644 --- a/crates/ui-egui/src/i18n/cs.tsv +++ b/crates/ui-egui/src/i18n/cs.tsv @@ -4415,6 +4415,7 @@ imageTrace Outline Obrys @msg no current layer žádná aktuální vrstva @msg no data žádná data @msg no dialog open není otevřeno žádné dialogové okno +@msg the open dialog has no Reset otevřené dialogové okno nemá tlačítko Obnovit @msg no document žádný dokument @msg no document open není otevřen žádný dokument @msg no effect applied yet zatím nebyl použit žádný efekt diff --git a/crates/ui-egui/src/i18n/da.tsv b/crates/ui-egui/src/i18n/da.tsv index ba9fe08e8..65588a764 100644 --- a/crates/ui-egui/src/i18n/da.tsv +++ b/crates/ui-egui/src/i18n/da.tsv @@ -4124,6 +4124,7 @@ imageTrace Outline Kontur @msg no current layer intet aktuelt lag @msg no data ingen data @msg no dialog open ingen åben dialogboks +@msg the open dialog has no Reset den åbne dialogboks har ingen Nulstil-knap @msg no document intet dokument @msg no document open intet åbent dokument @msg no effect applied yet ingen effekt er anvendt endnu diff --git a/crates/ui-egui/src/i18n/de.tsv b/crates/ui-egui/src/i18n/de.tsv index e48dddd3e..3c9b3b0fc 100644 --- a/crates/ui-egui/src/i18n/de.tsv +++ b/crates/ui-egui/src/i18n/de.tsv @@ -4033,6 +4033,7 @@ theme Appearance Erscheinungsbild @msg no current layer keine aktuelle Ebene @msg no data keine Daten @msg no dialog open kein Dialogfeld geöffnet +@msg the open dialog has no Reset das geöffnete Dialogfeld hat keine Schaltfläche „Zurücksetzen“ @msg no document kein Dokument @msg no document open kein Dokument geöffnet @msg no effect applied yet noch kein Effekt angewendet diff --git a/crates/ui-egui/src/i18n/el.tsv b/crates/ui-egui/src/i18n/el.tsv index b3d1f1f02..c2b69e353 100644 --- a/crates/ui-egui/src/i18n/el.tsv +++ b/crates/ui-egui/src/i18n/el.tsv @@ -4075,6 +4075,7 @@ theme Appearance Εμφάνιση @msg no current layer δεν υπάρχει τρέχον επίπεδο @msg no data δεν υπάρχουν δεδομένα @msg no dialog open δεν υπάρχει ανοιχτό παράθυρο διαλόγου +@msg the open dialog has no Reset το ανοιχτό παράθυρο διαλόγου δεν έχει κουμπί Επαναφορά @msg no document δεν υπάρχει έγγραφο @msg no document open δεν υπάρχει ανοιχτό έγγραφο @msg no effect applied yet δεν έχει εφαρμοστεί ακόμη εφέ diff --git a/crates/ui-egui/src/i18n/es.tsv b/crates/ui-egui/src/i18n/es.tsv index bc0a24fde..76c6128ce 100644 --- a/crates/ui-egui/src/i18n/es.tsv +++ b/crates/ui-egui/src/i18n/es.tsv @@ -4112,6 +4112,7 @@ axis Both Ambos @msg no current layer no hay capa actual @msg no data no hay datos @msg no dialog open no hay ningún cuadro de diálogo abierto +@msg the open dialog has no Reset el cuadro de diálogo abierto no tiene el botón Restablecer @msg no document no hay documento @msg no document open no hay ningún documento abierto @msg no effect applied yet todavía no se aplicó ningún efecto diff --git a/crates/ui-egui/src/i18n/fi.tsv b/crates/ui-egui/src/i18n/fi.tsv index f965864e7..a9c6099c4 100644 --- a/crates/ui-egui/src/i18n/fi.tsv +++ b/crates/ui-egui/src/i18n/fi.tsv @@ -4327,6 +4327,7 @@ imageTrace Outline Ääriviiva @msg no current layer ei nykyistä tasoa @msg no data ei dataa @msg no dialog open valintaikkunaa ei ole auki +@msg the open dialog has no Reset avoimessa valintaikkunassa ei ole Palauta-painiketta @msg no document ei asiakirjaa @msg no document open asiakirjaa ei ole auki @msg no effect applied yet tehostetta ei ole vielä käytetty diff --git a/crates/ui-egui/src/i18n/fr.tsv b/crates/ui-egui/src/i18n/fr.tsv index e626ed451..6c6d46a6c 100644 --- a/crates/ui-egui/src/i18n/fr.tsv +++ b/crates/ui-egui/src/i18n/fr.tsv @@ -4109,6 +4109,7 @@ axis Both Les deux @msg no current layer aucun calque actif @msg no data aucune donnée @msg no dialog open aucune boîte de dialogue ouverte +@msg the open dialog has no Reset la boîte de dialogue ouverte n’a pas de bouton Réinitialiser @msg no document aucun document @msg no document open aucun document ouvert @msg no effect applied yet aucun effet appliqué pour l’instant diff --git a/crates/ui-egui/src/i18n/hu.tsv b/crates/ui-egui/src/i18n/hu.tsv index 9c5e71352..c3457639e 100644 --- a/crates/ui-egui/src/i18n/hu.tsv +++ b/crates/ui-egui/src/i18n/hu.tsv @@ -4772,6 +4772,7 @@ imageTrace Outline Körvonal @msg no current layer nincs aktuális réteg @msg no data nincs adat @msg no dialog open nincs nyitott párbeszédablak +@msg the open dialog has no Reset a nyitott párbeszédablakban nincs Visszaállít gomb @msg no document nincs dokumentum @msg no document open nincs megnyitott dokumentum @msg no effect applied yet még nincs alkalmazott effektus diff --git a/crates/ui-egui/src/i18n/id.tsv b/crates/ui-egui/src/i18n/id.tsv index c2895a7af..d021360d9 100644 --- a/crates/ui-egui/src/i18n/id.tsv +++ b/crates/ui-egui/src/i18n/id.tsv @@ -4124,6 +4124,7 @@ imageTrace Outline Kontur @msg no current layer tidak ada lapisan saat ini @msg no data tidak ada data @msg no dialog open tidak ada dialog yang terbuka +@msg the open dialog has no Reset dialog yang terbuka tidak memiliki tombol Atur ulang @msg no document tidak ada dokumen @msg no document open tidak ada dokumen yang terbuka @msg no effect applied yet belum ada efek yang diterapkan diff --git a/crates/ui-egui/src/i18n/it.tsv b/crates/ui-egui/src/i18n/it.tsv index 8dadd7942..efdffe2ca 100644 --- a/crates/ui-egui/src/i18n/it.tsv +++ b/crates/ui-egui/src/i18n/it.tsv @@ -4152,6 +4152,7 @@ axis Both Entrambi @msg no current layer nessun livello corrente @msg no data nessun dato @msg no dialog open nessuna finestra di dialogo aperta +@msg the open dialog has no Reset la finestra di dialogo aperta non ha il pulsante Reimposta @msg no document nessun documento @msg no document open nessun documento aperto @msg no effect applied yet nessun effetto ancora applicato diff --git a/crates/ui-egui/src/i18n/ja.tsv b/crates/ui-egui/src/i18n/ja.tsv index 8b7cead38..0049abc21 100644 --- a/crates/ui-egui/src/i18n/ja.tsv +++ b/crates/ui-egui/src/i18n/ja.tsv @@ -4552,6 +4552,7 @@ swatch Bright Violet ビビッドバイオレット @msg can't parse shortcut `{c}` ショートカット `{c}` を解釈できません @msg can't parse shortcut `{s}` for `{k}` `{k}` のショートカット `{s}` を解釈できません @msg no dialog open ダイアログが開かれていません +@msg the open dialog has no Reset 開いているダイアログにはリセットボタンがありません @msg no file reader ファイルの読み込み機能がありません @msg no file writer ファイルの書き込み機能がありません @msg not a VectorCraft shortcut set (missing `overrides`) VectorCraft のショートカットセットではありません (`overrides` がありません) diff --git a/crates/ui-egui/src/i18n/ka.tsv b/crates/ui-egui/src/i18n/ka.tsv index 1900ce09b..36f36f976 100644 --- a/crates/ui-egui/src/i18n/ka.tsv +++ b/crates/ui-egui/src/i18n/ka.tsv @@ -3889,6 +3889,7 @@ font-technology Variable ცვლადი @msg no current layer მიმდინარე შრე არ არის @msg no data მონაცემები არ არის @msg no dialog open დიალოგი გახსნილი არ არის +@msg the open dialog has no Reset გახსნილ დიალოგში ღილაკი ჩამოყრა არ არის @msg no document დოკუმენტი არ არის @msg no document open გახსნილი დოკუმენტი არ არის @msg no effect applied yet ეფექტი ჯერ არ გამოყენებულა diff --git a/crates/ui-egui/src/i18n/ko.tsv b/crates/ui-egui/src/i18n/ko.tsv index bbc033718..89386b853 100644 --- a/crates/ui-egui/src/i18n/ko.tsv +++ b/crates/ui-egui/src/i18n/ko.tsv @@ -4483,6 +4483,7 @@ theme Appearance 외관 @msg can't parse shortcut `{c}` 단축키 `{c}`을(를) 해석할 수 없습니다 @msg can't parse shortcut `{s}` for `{k}` `{k}`의 단축키 `{s}`을(를) 해석할 수 없습니다 @msg no dialog open 열린 대화상자가 없습니다 +@msg the open dialog has no Reset 열린 대화상자에 재설정 단추가 없습니다 @msg no file reader 파일 판독기가 없습니다 @msg no file writer 파일 기록기가 없습니다 @msg not a VectorCraft shortcut set (missing `overrides`) VectorCraft 단축키 세트가 아닙니다(`overrides`가 없음) diff --git a/crates/ui-egui/src/i18n/nl.tsv b/crates/ui-egui/src/i18n/nl.tsv index d4e13eefb..f7267de0b 100644 --- a/crates/ui-egui/src/i18n/nl.tsv +++ b/crates/ui-egui/src/i18n/nl.tsv @@ -4136,6 +4136,7 @@ imageTrace Outline Contour @msg no current layer geen huidige laag @msg no data geen gegevens @msg no dialog open geen dialoogvenster geopend +@msg the open dialog has no Reset het geopende dialoogvenster heeft geen knop Opnieuw instellen @msg no document geen document @msg no document open geen document geopend @msg no effect applied yet nog geen effect toegepast diff --git a/crates/ui-egui/src/i18n/pl.tsv b/crates/ui-egui/src/i18n/pl.tsv index 76b13f0bb..adeb0daa8 100644 --- a/crates/ui-egui/src/i18n/pl.tsv +++ b/crates/ui-egui/src/i18n/pl.tsv @@ -4239,6 +4239,7 @@ imageTrace Outline Kontur @msg no current layer brak bieżącej warstwy @msg no data brak danych @msg no dialog open brak otwartego okna dialogowego +@msg the open dialog has no Reset otwarte okno dialogowe nie ma przycisku Resetuj @msg no document brak dokumentu @msg no document open brak otwartego dokumentu @msg no effect applied yet nie zastosowano jeszcze żadnego efektu diff --git a/crates/ui-egui/src/i18n/pt-br.tsv b/crates/ui-egui/src/i18n/pt-br.tsv index cf3f77b98..0f05cf886 100644 --- a/crates/ui-egui/src/i18n/pt-br.tsv +++ b/crates/ui-egui/src/i18n/pt-br.tsv @@ -3685,6 +3685,7 @@ axis Both Ambos @msg no current layer nenhuma camada atual @msg no data sem dados @msg no dialog open nenhuma caixa de diálogo aberta +@msg the open dialog has no Reset a caixa de diálogo aberta não tem o botão Redefinir @msg no document nenhum documento @msg no document open nenhum documento aberto @msg no effect applied yet nenhum efeito aplicado ainda diff --git a/crates/ui-egui/src/i18n/ru.tsv b/crates/ui-egui/src/i18n/ru.tsv index 7fe6eba9c..76cb3386b 100644 --- a/crates/ui-egui/src/i18n/ru.tsv +++ b/crates/ui-egui/src/i18n/ru.tsv @@ -4148,6 +4148,7 @@ axis Both Оба @msg no current layer нет текущего слоя @msg no data нет данных @msg no dialog open нет открытого диалогового окна +@msg the open dialog has no Reset в открытом диалоговом окне нет кнопки «Сбросить» @msg no document нет документа @msg no document open нет открытого документа @msg no effect applied yet эффект ещё не применён diff --git a/crates/ui-egui/src/i18n/sv.tsv b/crates/ui-egui/src/i18n/sv.tsv index fccace32a..9e75c299a 100644 --- a/crates/ui-egui/src/i18n/sv.tsv +++ b/crates/ui-egui/src/i18n/sv.tsv @@ -4026,6 +4026,7 @@ axis Both Båda @msg no current layer inget aktuellt lager @msg no data inga data @msg no dialog open ingen dialogruta är öppen +@msg the open dialog has no Reset den öppna dialogrutan har ingen Återställ-knapp @msg no document inget dokument @msg no document open inget dokument är öppet @msg no effect applied yet ingen effekt har använts än diff --git a/crates/ui-egui/src/i18n/tr.tsv b/crates/ui-egui/src/i18n/tr.tsv index 8b1b4af04..4d9591404 100644 --- a/crates/ui-egui/src/i18n/tr.tsv +++ b/crates/ui-egui/src/i18n/tr.tsv @@ -3886,6 +3886,7 @@ axis Both Her İkisi @msg no current layer geçerli katman yok @msg no data veri yok @msg no dialog open iletişim kutusu açık değil +@msg the open dialog has no Reset açık iletişim kutusunda Sıfırla düğmesi yok @msg no document belge yok @msg no document open hiçbir belge açık değil @msg no effect applied yet henüz hiçbir efekt uygulanmadı diff --git a/crates/ui-egui/src/i18n/uk.tsv b/crates/ui-egui/src/i18n/uk.tsv index c000a7ecd..c0cb01543 100644 --- a/crates/ui-egui/src/i18n/uk.tsv +++ b/crates/ui-egui/src/i18n/uk.tsv @@ -4136,6 +4136,7 @@ axis Both Обидві @msg no current layer немає поточного шару @msg no data немає даних @msg no dialog open немає відкритого діалогового вікна +@msg the open dialog has no Reset у відкритому діалоговому вікні немає кнопки «Скинути» @msg no document немає документа @msg no document open немає відкритого документа @msg no effect applied yet ефект ще не застосований diff --git a/crates/ui-egui/src/i18n/vi.tsv b/crates/ui-egui/src/i18n/vi.tsv index de50f9393..966582fc2 100644 --- a/crates/ui-egui/src/i18n/vi.tsv +++ b/crates/ui-egui/src/i18n/vi.tsv @@ -4420,6 +4420,7 @@ theme Appearance Giao diện @msg no current layer không có lớp hiện tại @msg no data không có dữ liệu @msg no dialog open không có hộp thoại đang mở +@msg the open dialog has no Reset hộp thoại đang mở không có nút Đặt lại @msg no document không có tài liệu @msg no document open không có tài liệu nào đang mở @msg no effect applied yet chưa áp dụng hiệu ứng diff --git a/crates/ui-egui/src/i18n/zh-hans.tsv b/crates/ui-egui/src/i18n/zh-hans.tsv index 14ad041f7..14e60be8b 100644 --- a/crates/ui-egui/src/i18n/zh-hans.tsv +++ b/crates/ui-egui/src/i18n/zh-hans.tsv @@ -4277,6 +4277,7 @@ imageTrace Outline 轮廓 @msg can't parse shortcut `{c}` 无法解析快捷键 `{c}` @msg can't parse shortcut `{s}` for `{k}` 无法解析 `{k}` 的快捷键 `{s}` @msg no dialog open 没有打开的对话框 +@msg the open dialog has no Reset 打开的对话框没有重置按钮 @msg no file reader 没有文件读取器 @msg no file writer 没有文件写入器 @msg not a VectorCraft shortcut set (missing `overrides`) 不是 VectorCraft 快捷键组 (缺少 `overrides`) diff --git a/crates/ui-egui/src/i18n/zh-hant.tsv b/crates/ui-egui/src/i18n/zh-hant.tsv index 64a91b6ab..805ee2343 100644 --- a/crates/ui-egui/src/i18n/zh-hant.tsv +++ b/crates/ui-egui/src/i18n/zh-hant.tsv @@ -2232,6 +2232,7 @@ file-filter Templates 範本 @msg can't parse shortcut `{c}` 無法剖析快速鍵 `{c}` @msg can't parse shortcut `{s}` for `{k}` 無法剖析 `{k}` 的快速鍵 `{s}` @msg no dialog open 沒有開啟的對話框 +@msg the open dialog has no Reset 開啟的對話框沒有「重設」按鈕 @msg no file reader 沒有檔案讀取器 @msg no file writer 沒有檔案寫入器 @msg not a VectorCraft shortcut set (missing `overrides`) 不是 VectorCraft 快速鍵組 (沒有 `overrides`) diff --git a/crates/ui-egui/src/menus/run.rs b/crates/ui-egui/src/menus/run.rs index 943a700d4..2bb267b90 100644 --- a/crates/ui-egui/src/menus/run.rs +++ b/crates/ui-egui/src/menus/run.rs @@ -696,6 +696,7 @@ fn run_ui_part10(app: &mut VectorcraftApp, id: &str, p: &Value) -> Option crate::dialogs::simplify_slider::auto(app), "ui.simplifyMoreOptions" => crate::dialogs::simplify_slider::more_options(app), "ui.smoothAuto" => crate::dialogs::smooth_slider::auto(app), + "ui.dialogReset" => crate::dialogs::reset(app), "attributes.openUrl" => crate::panels::attributes::open_url(app, p), "ui.javascriptFilesDialog" => crate::panels::svg_interactivity::files_dialog(app, p), "ui.spotColors" => crate::dialogs::spot_colors::open(app), diff --git a/crates/ui-egui/src/menus/state.rs b/crates/ui-egui/src/menus/state.rs index 6a6d9aef6..e81ddc879 100644 --- a/crates/ui-egui/src/menus/state.rs +++ b/crates/ui-egui/src/menus/state.rs @@ -238,6 +238,7 @@ pub fn enabled(app: &VectorcraftApp, id: &str) -> bool { "ui.menuDialog" => app.session.active().is_some_and(|d| !d.selection.is_empty()), "ui.simplifyAuto" | "ui.simplifyMoreOptions" => crate::dialogs::simplify_slider::showing(app), "ui.smoothAuto" => crate::dialogs::smooth_slider::showing(app), + "ui.dialogReset" => crate::dialogs::can_reset(app), "ui.dxfOptionsDialog" => app.session.active().is_some(), "links.editOriginal" | "links.reveal" => selected_image(app, |im| im.link.is_some()) || selected_placed(app), "ui.placementOptionsDialog" => selected_image(app, |_| true) || selected_placed(app), diff --git a/crates/ui-egui/src/menus/ui_commands.rs b/crates/ui-egui/src/menus/ui_commands.rs index 83aadabec..33b184f26 100644 --- a/crates/ui-egui/src/menus/ui_commands.rs +++ b/crates/ui-egui/src/menus/ui_commands.rs @@ -595,7 +595,7 @@ pub const UI_COMMANDS: &[(&str, &str, &str, &str)] = &[ "tool.options", "Tool Options…", "", - "{tool: id} what double-clicking a tool button opens: hand → fits the artboard in the window (view.fitArtboard), zoom → 100% (view.actualSize), rotate|scale|reflect|shear → that Object › Transform dialog (dialog `rotate`, `scale`, `reflect` or `shear`; error `nothing selected` without a selection), selection|directSelection|groupSelection → the Move dialog (dialog `move`; the same error), gradient|magicWand → the Gradient or Magic Wand panel (window.panel), artboard → Artboard Options of the active artboard (dialog `artboardOptions`, fields index, name, x, y, width, height, showCenterMark, showCrossHairs; OK runs artboard.setProps, and with other artboards selected with the Artboard tool a new width or height goes to each of them too, in its `artboards` list, each resized about the reference point the form used for that size, or about its top-left corner when the size was set in the fields directly), flare → Flare Tool Options (dialog `flareOptions`, fields diameter and pathLength (pt), opacity, brightness, growth, fuzziness, longest, rayFuzziness, largest (%), rays, rings, direction (°), raysOn, ringsOn; OK runs tool.setOption {tool: \"flare\", values}: the next flare dragged out uses them, and a Flare click's dialog, which also has x and y, draws one there with them), lineSegment|arc|rectangularGrid|polarGrid → that tool's Tool Options, its click dialog without x and y (dialog kind = the tool id, `__toolOptions: true`; lineSegment: length (pt), angle (°), fillLine; arc: lengthX, lengthY (pt), reference (0–8), arcType: open|closed, baseAlong: x|y, slope (−100…100), fillArc; rectangularGrid: width, height (pt, the Default Size), reference (0–8), rows, columns, rowSkew, columnSkew (%), frame, fill; polarGrid: the same with concentric, radial, concentricSkew, radialSkew and compound for rows, columns, the skews and frame; OK runs tool.setOption {tool, values} and draws nothing: the next drag uses them (Fill Line, the arc's type, base, slope and fill, the grids' dividers, skews and switches) and a click's dialog opens at them), columnGraph|stackedColumnGraph|barGraph|stackedBarGraph|lineGraph|areaGraph|scatterGraph|pieGraph|radarGraph → Graph Type for the selected graph (dialog `command` running graph.setType; an error without one), typeOnPath|verticalTypeOnPath → Type on a Path Options for the selected type on a path (dialog `command` running type.pathOptions; error `nothing selected` without a selection, and the command's error when no type on a path is selected),symbolSprayer|symbolShifter|symbolScruncher|symbolSizer|symbolSpinner|symbolStainer|symbolScreener|symbolStyler → Symbolism Tools Options (dialog `symbolismOptions`, fields tool, diameter (pt), intensity and density (1–10), shared by the eight tools; OK runs tool.setOption {tool, values}), blend → Blend Options, perspectiveGrid → Perspective Grid Options, eyedropper → Eyedropper Options (dialog `eyedropperOptions`, fields sampleSize, pickUp, apply; OK runs eyedropper.setOptions), printTiling → resets the print tiling (print.tiling.set {reset: true}), warp|twirl|pucker|bloat|scallop|crystallize|wrinkle → that tool's Tool Options (dialog `liquifyOptions`, fields tool, width, height, angle, intensity %, usePressure, detail, simplify, simplifyOn, rate, complexity, horizontal %, vertical %, affectAnchors, affectIn, affectOut, showBrush; OK runs tool.setOption {tool, values}), pencil|paintbrush|smooth|blobBrush|eraser → that tool's Tool Options (dialog `freehandOptions`, fields tool and the options the tool keeps: fidelity (pt), fill, keepSelected (on for pencil and paintbrush, off for blobBrush), mergeOnlySelection (off), closeWithin and editWithin (px, 0 is off), livePreview (pencil, on: off draws a thin line while the stroke is drawn, and the path's fill and stroke on release), size (pt), angle (°, −180–180; 0) and roundness (%, 1–100; 100) of the eraser's tip; OK runs tool.setOption {tool, values}), livePaintSelection → Live Paint Selection Tool Options (dialog `livePaintSelectionOptions`, fields selectFills and selectStrokes (both on), color (the highlight color, #rrggbb or a layer color's name; #ff2a2a), width (the highlight's width, 1–20 px; 4); OK runs tool.setOption {tool: \"livePaintSelection\", values}), shapeBuilder → Shape Builder Tool Options (dialog `shapeBuilderOptions`, fields gapDetection (off), gapLength (pt, 0–72; 3), openFilledAsClosed (on), clickStrokeSplitsPath (off), pickColorFrom: artwork|swatches (artwork), cursorSwatchPreview (off), selection: freeform|straightLine (freeform), highlightFill (on), highlightStroke (on), highlightColor (#rrggbb or a layer color's name; #ff4f4f); OK runs tool.setOption {tool: \"shapeBuilder\", values})", + "{tool: id} what double-clicking a tool button opens: hand → fits the artboard in the window (view.fitArtboard), zoom → 100% (view.actualSize), rotate|scale|reflect|shear → that Object › Transform dialog (dialog `rotate`, `scale`, `reflect` or `shear`; error `nothing selected` without a selection), selection|directSelection|groupSelection → the Move dialog (dialog `move`; the same error), gradient|magicWand → the Gradient or Magic Wand panel (window.panel), artboard → Artboard Options of the active artboard (dialog `artboardOptions`, fields index, name, x, y, width, height, showCenterMark, showCrossHairs; OK runs artboard.setProps, and with other artboards selected with the Artboard tool a new width or height goes to each of them too, in its `artboards` list, each resized about the reference point the form used for that size, or about its top-left corner when the size was set in the fields directly), flare → Flare Tool Options (dialog `flareOptions`, fields diameter and pathLength (pt), opacity, brightness, growth, fuzziness, longest, rayFuzziness, largest (%), rays, rings, direction (°), raysOn, ringsOn; OK runs tool.setOption {tool: \"flare\", values}: the next flare dragged out uses them, and a Flare click's dialog, which also has x, y and preview (on initially), previews one there and accepts it as one Undo step; Cancel rolls back the preview), lineSegment|arc|rectangularGrid|polarGrid → that tool's Tool Options, its click dialog without x and y (dialog kind = the tool id, `__toolOptions: true`; lineSegment: length (pt), angle (°), fillLine; arc: lengthX, lengthY (pt), reference (0–8), arcType: open|closed, baseAlong: x|y, slope (−100…100), fillArc; rectangularGrid: width, height (pt, the Default Size), reference (0–8), rows, columns, rowSkew, columnSkew (%), frame, fill; polarGrid: the same with concentric, radial, concentricSkew, radialSkew and compound for rows, columns, the skews and frame; OK runs tool.setOption {tool, values} and draws nothing: the next drag uses them (Fill Line, the arc's type, base, slope and fill, the grids' dividers, skews and switches) and a click's dialog opens at them), columnGraph|stackedColumnGraph|barGraph|stackedBarGraph|lineGraph|areaGraph|scatterGraph|pieGraph|radarGraph → Graph Type for the selected graph (dialog `command` running graph.setType; an error without one), typeOnPath|verticalTypeOnPath → Type on a Path Options for the selected type on a path (dialog `command` running type.pathOptions; error `nothing selected` without a selection, and the command's error when no type on a path is selected),symbolSprayer|symbolShifter|symbolScruncher|symbolSizer|symbolSpinner|symbolStainer|symbolScreener|symbolStyler → Symbolism Tools Options (dialog `symbolismOptions`, fields tool, diameter (pt), intensity and density (1–10), shared by the eight tools; OK runs tool.setOption {tool, values}), blend → Blend Options, perspectiveGrid → Perspective Grid Options, eyedropper → Eyedropper Options (dialog `eyedropperOptions`, fields sampleSize, pickUp, apply; OK runs eyedropper.setOptions), printTiling → resets the print tiling (print.tiling.set {reset: true}), warp|twirl|pucker|bloat|scallop|crystallize|wrinkle → that tool's Tool Options (dialog `liquifyOptions`, fields tool, width, height, angle, intensity %, usePressure, detail, simplify, simplifyOn, rate, complexity, horizontal %, vertical %, affectAnchors, affectIn, affectOut, showBrush; OK runs tool.setOption {tool, values}), pencil|paintbrush|smooth|blobBrush|eraser → that tool's Tool Options (dialog `freehandOptions`, fields tool and the options the tool keeps: fidelity (pt), fill, keepSelected (on for pencil and paintbrush, off for blobBrush), mergeOnlySelection (off), closeWithin and editWithin (px, 0 is off), livePreview (pencil, on: off draws a thin line while the stroke is drawn, and the path's fill and stroke on release), size (pt), angle (°, −180–180; 0) and roundness (%, 1–100; 100) of the eraser's tip; OK runs tool.setOption {tool, values}), livePaintSelection → Live Paint Selection Tool Options (dialog `livePaintSelectionOptions`, fields selectFills and selectStrokes (both on), color (the highlight color, #rrggbb or a layer color's name; #ff2a2a), width (the highlight's width, 1–20 px; 4); OK runs tool.setOption {tool: \"livePaintSelection\", values}), shapeBuilder → Shape Builder Tool Options (dialog `shapeBuilderOptions`, fields gapDetection (off), gapLength (pt, 0–72; 3), openFilledAsClosed (on), clickStrokeSplitsPath (off), pickColorFrom: artwork|swatches (artwork), cursorSwatchPreview (off), selection: freeform|straightLine (freeform), highlightFill (on), highlightStroke (on), highlightColor (#rrggbb or a layer color's name; #ff4f4f); OK runs tool.setOption {tool: \"shapeBuilder\", values})", ), ( "ui.colorGuideOptions", @@ -870,6 +870,12 @@ pub const UI_COMMANDS: &[(&str, &str, &str, &str)] = &[ "", "{} the Simplify dialog (dialog `simplify`: tolerance (pt), angleThreshold, straightLines, showOriginal, retain: ticked, OK makes Object › Path › Simplify open this dialog with these fields next time) takes the open Simplify slider's place, at the slider's tolerance → {tolerance}; an error when the slider isn't open", ), + ( + "ui.dialogReset", + "Reset", + "", + "{} the open dialog's Reset, which its Cancel button reads while Alt (Option on macOS) is held (Flare Tool Options, dialog `flareOptions`): its fields go back to their defaults and the dialog stays open, so OK applies them → the dialog; an error when no dialog is open or the open one has no Reset", + ), ( "ui.justification", "Justification…", diff --git a/docs/gaps.md b/docs/gaps.md index 50e7ebdbf..d5b98bd65 100644 --- a/docs/gaps.md +++ b/docs/gaps.md @@ -645,8 +645,8 @@ trap, and the defaults (0.25 pt, 100%, 40%) are VectorCraft's own, the pages giv | Date | Change | Summary | |---|---|---| -| 2026-10-26 | minor | G9: EPS save-back: an opened EPS saves back to its own path as EPS, keeping the chosen artboard's page frame and transparent margins and the complete editable VectorCraft document; Save's TIFF preview is capped at 1024 px (Export keeps 2048); partly read, preview-only or damaged-editing-data sources still need confirmation before they are overwritten. This narrows G9's save-back workflow only; its import-fidelity items (layer and group structure, guides, open speed, live objects) and estimate are unchanged, and writing Illustrator's own editing data stays out of scope (#868) | | 2026-10-29 | minor | G8: a blend makes at most 100,000 steps in all, the steps of blends nested in its keys and steps included; past it each pair of keys keeps the same share of its steps (#3579). No entry closed, estimates unchanged. | +| 2026-10-26 | minor | G9: EPS save-back: an opened EPS saves back to its own path as EPS, keeping the chosen artboard's page frame and transparent margins and the complete editable VectorCraft document; Save's TIFF preview is capped at 1024 px (Export keeps 2048); partly read, preview-only or damaged-editing-data sources still need confirmation before they are overwritten. This narrows G9's save-back workflow only; its import-fidelity items (layer and group structure, guides, open speed, live objects) and estimate are unchanged, and writing Illustrator's own editing data stays out of scope (#868) | | 2026-10-26 | minor | G7: View › New View… / Edit Views… ([public source](https://helpx.adobe.com/illustrator/using/viewing-artwork.html)): the View menu lists every one of a document's 25 saved views (it listed 10), Edit Views… lists them to rename or delete in one undo step (`view.saved.edit {edits}`), and a file's views are checked when it opens; New View/Edit Views leave G7's missing list; estimate unchanged | | 2026-10-25 | minor | G4: a double-click on a threaded port with the Selection tool breaks the thread there (`text.thread.break {id, port}`): the story flows into the frames before the break, the frames after it are left empty and stay threaded with each other when two or more; a double-click on a port with no thread does nothing; estimate unchanged | | 2026-10-25 | minor | G1: a selected Grid Repeat shows handles: the one below the grid adds or removes rows, the one right of it columns, the one past its bottom-right corner both, and the sliders between the first two columns and rows set the horizontal and vertical spacing; each drag is one undo step and Escape cancels it (#2691); bounding-box handles keep priority where they meet; Radial Repeat handles remain; estimates unchanged. | @@ -829,6 +829,7 @@ trap, and the defaults (0.25 pt, 100%, 40%) are VectorCraft's own, the pages giv | 2026-10-10 | minor | G9 evidence counted from the tracker (28 `.ai`/EPS issues, 20 fixed); impact narrowed to handing files back | | 2026-10-10 | minor | Alpha blockers checked against the core-workflow gate: none | | 2026-10-10 | major | Moved from the ROADMAP's "Where we're lacking"; kept ids G1–G8, added G9–G19 (file formats, stability, bugs, preferences, 30.x additions, pen hardware, performance, localization, ecosystem, AI, accessibility) and re-ranked | +| 2026-10-28 | minor | Flare Tool Options opened by a canvas click previews its settings at that click. Reset refreshes the enabled preview while keeping the dialog open. Cancel discards preview art and tentative options; OK accepts one flare in one Undo step. Editing existing flare artwork remains outside this dialog scope. Scores and estimates unchanged. | > **Tab-drag status (2026-10-22):** updated from upstream, including the Turkish catalog and all three tab-drag translations requested in #3479; Selection-tool reset regression-checked and clipboard evidence scoped to internal state; drag lifecycle, insertion and regression contracts documented; behavior, scores and estimates unchanged. diff --git a/docs/mcp.md b/docs/mcp.md index 5ef220019..ade15572a 100644 --- a/docs/mcp.md +++ b/docs/mcp.md @@ -5051,7 +5051,9 @@ active the active artboard (the navigator's and the Artboards panel's). `tool.options {tool}` opens what double-clicking the tool's button opens (its params doc lists every tool), in the desktop app. The Flare tool's are its Flare Tool Options (dialog `flareOptions`): `diameter` and `pathLength` (pt), `opacity`, `brightness`, `growth`, `fuzziness`, `longest`, `rayFuzziness` and `largest` (%), `rays`, `rings`, -`direction` (°), and `raysOn` and `ringsOn` (the Rays and Rings checkboxes; off, the flare has none). OK keeps them +`direction` (°), and `raysOn` and `ringsOn` (the Rays and Rings checkboxes; off, the flare has none). While Alt +(Option on macOS) is held, the dialog's Cancel button reads Reset. Reset puts every option back to the tool's default, +leaves a click's `x` and `y` unchanged and keeps the dialog open; `ui.dialogReset` does the same. OK keeps the options (`tool.setOption {tool: "flare", values}`) and the next flare dragged out uses them; a click with the tool opens the same dialog, and its OK also draws a flare there. The Artboard tool's are the active artboard's Artboard Options (dialog `artboardOptions`; the Artboard tool's active artboard while it is in use, else the window's; its `x` and `y` @@ -5064,6 +5066,7 @@ for a new artboard, with `new: true` and the name, position and size that `artbo `artboard.new` with the fields and makes the new artboard the active one, and Cancel adds no artboard. `artboard.new` and `artboard.setProps` trim the white space around `name`, and a blank name gives the artboard its default name, "Artboard N" for the Nth artboard. +A canvas-click dialog also has `preview` (initially on): tentative settings draw at the remembered click, Reset refreshes that preview, and Cancel discards it without persisting settings. OK accepts one flare as one Undo step. Toolbar-only options draw no artwork. ```json {"name":"run_command","arguments":{"command":"tool.setOption","params":{"tool":"flare","values":{"rays":24,"ringsOn":false}}}} diff --git a/docs/roadmap.md b/docs/roadmap.md index c9dd1ce83..4e66928f6 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -278,6 +278,7 @@ separate. Scores and hours unchanged. [Behavior and command details](development | 2026-10-10 | minor | M9 row from main: initial Revolve | | 2026-10-10 | minor | Added the Alpha gate table (core-workflow gate): all six workflows work end to end, `.ai` exchange partial but not blocking; stage stays alpha | | 2026-10-10 | major | Created from ROADMAP.md's milestone table and "Where we're going"; added Current focus and the beta list | +| 2026-10-28 | minor | Flare Tool Options opened by a canvas click previews its settings at that click. Reset refreshes the enabled preview while keeping the dialog open. Cancel discards preview art and tentative options; OK accepts one flare in one Undo step. Editing existing flare artwork remains outside this dialog scope. Scores and estimates unchanged. | > **Tab-drag status (2026-10-22):** updated from upstream, including the Turkish catalog and all three tab-drag translations requested in #3479; Selection-tool reset regression-checked and clipboard evidence scoped to internal state; drag lifecycle, insertion and regression contracts documented; behavior, scores and estimates unchanged. diff --git a/docs/target-app-parity.md b/docs/target-app-parity.md index e52e76612..bca4b8bf9 100644 --- a/docs/target-app-parity.md +++ b/docs/target-app-parity.md @@ -598,6 +598,7 @@ Moved from the ROADMAP's "Shipped so far" on 2026-10-10. Update it when a featur - Preferences › Type › Highlight Substituted Fonts (on by default) paints pink behind text drawn in a substitute for a missing font in every document, and turning it off removes that highlight everywhere (`prefs.set highlightSubstitutedFonts`); Document Setup keeps Highlight Substituted Glyphs ([help](https://helpx.adobe.com/illustrator/desktop/design-with-text/fonts-and-scripts/edit-text-without-replacing-missing-fonts.html)). - Dialogs move by dragging their heading (the band down from the top edge, as a title bar), stay on screen and keep where they were moved for the session; the form dialogs' choices are dropdowns (Offset Path's Joins, Average's and Shear's and Reflect's axis), and Offset Path lists Offset, Joins, Miter Limit and previews (#423). - Dialogs open with their first field focused and its value selected: type a value and press Enter (Move, Rotate, Scale…). A dialog opened from a menu takes the keyboard focus every time it opens, not only the first (#1367), and one whose first field starts greyed out (Blend Options on Smooth Color, Layers Panel Options) gives the focus to that field once it is enabled (#1395). Number fields in panels, the Control bar and dialogs (preferences too) step with Up/Down, or with the mouse wheel over the focused field (#485: a notch a step; the panel under it then stays put, and an unfocused field leaves the wheel to scrolling) (Shift: ten, Ctrl/Cmd: a tenth of their unit), applied at once. + - While Alt (Option on macOS) is held, the Flare Tool Options' Cancel button reads Reset, which puts every option back to the Flare tool's default and leaves the dialog open (`ui.dialogReset`). - A plain step of a number field (Up/Down or a wheel notch) goes to the next whole unit in its direction and a Ctrl/Cmd step goes to the next tenth, so 5.1 mm steps up to 6 mm and down to 5 mm (#2881). A Shift step adds or takes ten and keeps the fraction. - In the number, text and color fields of the panels and the Control bar, Shift+Enter (Shift+Return) applies the value and keeps the field active with its value selected; a text box of several lines takes it as a line break. In a dialog, Shift+Enter applies the value and confirms the dialog, as Enter does. - The Pattern Options panel's Name field and the name fields that a double-click opens in the Layers, Artboards and Asset Export panels take Shift+Enter (Shift+Return) the same way: it applies the name and keeps the field active with the name selected. @@ -1426,6 +1427,7 @@ applies to fills). Tests: `color::gradient::tests` (perceptual midpoint, expansi | 2026-10-10 | major | Full re-measure against Illustrator 2026 30.x from code counts, open issues and public docs; added breadth/depth/ready-for-real-work numbers, generative-AI row, calibration from PR timestamps; merged the ROADMAP's parity estimate, honest assessment and "Shipped so far" into this file | | 2026-10-05 | major | (in ROADMAP.md) M3 and M4 rows re-derived after the paint and files milestones | | 2026-10-02 | major | (in ROADMAP.md) First 22-area weighted estimate | +| 2026-10-28 | minor | Flare Tool Options opened by a canvas click previews its settings at that click. Reset refreshes the enabled preview while keeping the dialog open. Cancel discards preview art and tentative options; OK accepts one flare in one Undo step. Editing existing flare artwork remains outside this dialog scope. Scores and estimates unchanged. | > **Tab-drag status (2026-10-22):** updated from upstream, including the Turkish catalog and all three tab-drag translations requested in #3479; Selection-tool reset regression-checked and clipboard evidence scoped to internal state; drag lifecycle, insertion and regression contracts documented; behavior, scores and estimates unchanged. diff --git a/docs/ui-parity.md b/docs/ui-parity.md index 135986b62..f86001db8 100644 --- a/docs/ui-parity.md +++ b/docs/ui-parity.md @@ -485,6 +485,7 @@ separate. Scores and hours unchanged. [Behavior and command details](development | 2026-10-11 | minor | Edit Toolbar opens the All Tools drawer beside the toolbar instead of a centred dialog, dims the tools the toolbar holds, and edits the toolbar by drag and drop while it is open (#1018); score unchanged (estimated) | | 2026-10-11 | minor | Direct Selection: dragging a path selected whole by an anchor moves it whole; Alt-drag copies by an anchor too, toggles during the drag and snaps onto the original (#1104); score unchanged (estimated) | | 2026-10-10 | major | First checklist, built from the tool sources and tests against Illustrator 2026's public documentation | +| 2026-10-28 | minor | Flare Tool Options opened by a canvas click previews its settings at that click. Reset refreshes the enabled preview while keeping the dialog open. Cancel discards preview art and tentative options; OK accepts one flare in one Undo step. Editing existing flare artwork remains outside this dialog scope. Scores and estimates unchanged. | > **Tab-drag status (2026-10-22):** updated from upstream, including the Turkish catalog and all three tab-drag translations requested in #3479; Selection-tool reset regression-checked and clipboard evidence scoped to internal state; drag lifecycle, insertion and regression contracts documented; behavior, scores and estimates unchanged.