diff --git a/crates/ui-egui/src/control.rs b/crates/ui-egui/src/control.rs index 91a7b0bb4..3a5648e79 100644 --- a/crates/ui-egui/src/control.rs +++ b/crates/ui-egui/src/control.rs @@ -399,7 +399,7 @@ pub fn handle(app: &mut VectorcraftApp, ctx: &egui::Context, req: &ControlReques app.ui.control_bar = v; } if let Some(v) = p.get("imageTracePreview").and_then(Value::as_bool) { - app.ui.image_trace_preview = v; + r = app.run("imageTrace.preview", json!({"on": v})); } if p.get("closePanel").is_some() { app.ui.open_panel = None; @@ -602,6 +602,22 @@ mod tests { } } + #[test] + fn the_image_trace_preview_is_a_command() { + let mut app = VectorcraftApp::new(Session::new(), Services::default()); + assert!(crate::menus::UI_COMMANDS.iter().any(|c| c.0 == "imageTrace.preview")); + assert_eq!(app.run("imageTrace.preview", json!({})), Ok(json!(false)), "toggles"); + assert!(!app.ui.image_trace_preview); + assert_eq!(app.run("imageTrace.preview", json!({"on": false})), Ok(json!(false)), "stays off"); + assert_eq!(app.run("imageTrace.preview", json!({"on": true})), Ok(json!(true))); + assert!(app.ui.image_trace_preview); + assert!(app.run("imageTrace.preview", json!({"on": "yes"})).is_err()); + assert!(app.ui.image_trace_preview, "a bad value leaves it"); + let r = input_request(&mut app, "engine.execute", json!({"command": "imageTrace.preview", "params": {"on": false}})); + assert_eq!(r["ok"], true, "{r}"); + assert!(!app.ui.image_trace_preview, "the control channel reaches it"); + } + #[test] fn control_input_rejects_excessive_counts_before_mutation() { // Only modest over-limit values on the baseline: never exercise an unbounded loop. diff --git a/crates/ui-egui/src/i18n/bg.tsv b/crates/ui-egui/src/i18n/bg.tsv index 8db5c9c4a..a39605ff1 100644 --- a/crates/ui-egui/src/i18n/bg.tsv +++ b/crates/ui-egui/src/i18n/bg.tsv @@ -3022,6 +3022,7 @@ font-technology Variable Променливи Snap to Grid Прилепване към мрежа Snap to Pixel Прилепване към пиксел Precise Cursors Прецизни курсори + Image Trace Preview Преглед на трасирането на изображение Snap to Point Прилепване към точка Snap to Unit Прилепване към мерна единица Snapping Tolerance Толеранс на прилепване diff --git a/crates/ui-egui/src/i18n/cs.tsv b/crates/ui-egui/src/i18n/cs.tsv index 905991ddb..ded761f51 100644 --- a/crates/ui-egui/src/i18n/cs.tsv +++ b/crates/ui-egui/src/i18n/cs.tsv @@ -583,6 +583,7 @@ Save Grid as Preset… Uložit mřížku jako přednastavení… Snap to Pixel Přichytávat k obrazovým bodům Precise Cursors Přesné kurzory + Image Trace Preview Náhled vektorizace obrazu Snap to Point Přichytávat k bodům Snap to Glyph Přichytávat ke glyfům New View… Nové zobrazení… diff --git a/crates/ui-egui/src/i18n/da.tsv b/crates/ui-egui/src/i18n/da.tsv index c0f2ac983..64e77487e 100644 --- a/crates/ui-egui/src/i18n/da.tsv +++ b/crates/ui-egui/src/i18n/da.tsv @@ -536,6 +536,7 @@ Save Grid as Preset… Gem gitter som forudindstilling… Snap to Pixel Fastgør til pixel Precise Cursors Præcise markører + Image Trace Preview Forhåndsvisning af billedsporing Snap to Point Fastgør til punkt Snap to Glyph Fastgør til tegn New View… Ny visning… diff --git a/crates/ui-egui/src/i18n/de.tsv b/crates/ui-egui/src/i18n/de.tsv index c4ea20835..a036d1022 100644 --- a/crates/ui-egui/src/i18n/de.tsv +++ b/crates/ui-egui/src/i18n/de.tsv @@ -3060,6 +3060,7 @@ effect Points Punkte Snap to Grid Am Raster ausrichten Snap to Pixel An Pixel ausrichten Precise Cursors Präzise Cursor + Image Trace Preview Bildnachzeichner-Vorschau Snap to Point An Punkt ausrichten Snap to Unit An Einheit ausrichten Snapping Tolerance Einrasttoleranz diff --git a/crates/ui-egui/src/i18n/el.tsv b/crates/ui-egui/src/i18n/el.tsv index 8ea627a28..c7a68ee82 100644 --- a/crates/ui-egui/src/i18n/el.tsv +++ b/crates/ui-egui/src/i18n/el.tsv @@ -3483,6 +3483,7 @@ theme Appearance Εμφάνιση Snap Options Επιλογές προσκόλλησης Snap to Glyph Προσκόλληση σε γλυφή Precise Cursors Δείκτες ακριβείας + Image Trace Preview Προεπισκόπηση ανίχνευσης περιγραμμάτων εικόνας Snapping Tolerance Ανοχή προσκόλλησης Social Square Post 1080×1080 Τετράγωνη δημοσίευση κοινωνικών δικτύων 1080×1080 Sort by Kind Ταξινόμηση κατά είδος diff --git a/crates/ui-egui/src/i18n/es.tsv b/crates/ui-egui/src/i18n/es.tsv index 376080274..4e4704949 100644 --- a/crates/ui-egui/src/i18n/es.tsv +++ b/crates/ui-egui/src/i18n/es.tsv @@ -3090,6 +3090,7 @@ font-technology Variable Variables Snap to Grid Ajustar a cuadrícula Snap to Pixel Ajustar a píxel Precise Cursors Cursores precisos + Image Trace Preview Vista previa de Calco de imagen Snap to Point Ajustar a punto Snap to Unit Ajustar a unidad Snapping Tolerance Tolerancia de ajuste diff --git a/crates/ui-egui/src/i18n/fi.tsv b/crates/ui-egui/src/i18n/fi.tsv index 849bbbaf2..016b8a7b5 100644 --- a/crates/ui-egui/src/i18n/fi.tsv +++ b/crates/ui-egui/src/i18n/fi.tsv @@ -574,6 +574,7 @@ Save Grid as Preset… Tallenna ruudukko esiasetukseksi… Snap to Pixel Kohdista pikseliin Precise Cursors Tarkat osoittimet + Image Trace Preview Kuvan jäljityksen esikatselu Snap to Point Kohdista pisteeseen Snap to Glyph Kohdista merkkiin New View… Uusi näkymä… diff --git a/crates/ui-egui/src/i18n/fr.tsv b/crates/ui-egui/src/i18n/fr.tsv index 54048e7f3..4d99c7e07 100644 --- a/crates/ui-egui/src/i18n/fr.tsv +++ b/crates/ui-egui/src/i18n/fr.tsv @@ -3087,6 +3087,7 @@ font-technology Variable Variables Snap to Grid Magnétisme de la grille Snap to Pixel Magnétisme du pixel Precise Cursors Pointeurs précis + Image Trace Preview Aperçu de la vectorisation de l’image Snap to Point Magnétisme du point Snap to Unit Magnétisme de l’unité Snapping Tolerance Tolérance du magnétisme diff --git a/crates/ui-egui/src/i18n/hu.tsv b/crates/ui-egui/src/i18n/hu.tsv index 0013f0fe0..3473988cc 100644 --- a/crates/ui-egui/src/i18n/hu.tsv +++ b/crates/ui-egui/src/i18n/hu.tsv @@ -3715,6 +3715,7 @@ mark-style Japanese Japán Snap to Grid Illesztés a rácshoz Snap to Pixel Illesztés pixelhez Precise Cursors Pontos kurzorok + Image Trace Preview Képvektorizálás előnézete Snap to Point Illesztés pontra Snap to Unit Illesztés mértékegységhez Snapping Tolerance Illesztési tűrés diff --git a/crates/ui-egui/src/i18n/id.tsv b/crates/ui-egui/src/i18n/id.tsv index 64f84668a..500fd22e3 100644 --- a/crates/ui-egui/src/i18n/id.tsv +++ b/crates/ui-egui/src/i18n/id.tsv @@ -536,6 +536,7 @@ Save Grid as Preset… Simpan kisi sebagai preset… Snap to Pixel Snap ke piksel Precise Cursors Kursor presisi + Image Trace Preview Pratinjau Image Trace Snap to Point Snap ke titik Snap to Glyph Snap ke glif New View… Tampilan baru… diff --git a/crates/ui-egui/src/i18n/it.tsv b/crates/ui-egui/src/i18n/it.tsv index 56ef85e6a..35482e90d 100644 --- a/crates/ui-egui/src/i18n/it.tsv +++ b/crates/ui-egui/src/i18n/it.tsv @@ -3124,6 +3124,7 @@ mark-style Japanese Giapponese Snap to Grid Aggancia alla griglia Snap to Pixel Aggancia ai pixel Precise Cursors Cursori di precisione + Image Trace Preview Anteprima di Ricalco immagine Snap to Point Aggancia al punto Snap to Unit Aggancia all'unità Snapping Tolerance Tolleranza di aggancio diff --git a/crates/ui-egui/src/i18n/ja.tsv b/crates/ui-egui/src/i18n/ja.tsv index 38da5a882..acd2b776b 100644 --- a/crates/ui-egui/src/i18n/ja.tsv +++ b/crates/ui-egui/src/i18n/ja.tsv @@ -566,6 +566,7 @@ font-technology Variable バリアブル Save Grid as Preset… グリッドをプリセットとして保存… Snap to Pixel ピクセルにスナップ Precise Cursors 精密カーソル + Image Trace Preview 画像トレースのプレビュー Snap to Point ポイントにスナップ Snap to Glyph グリフにスナップ New View… 新規表示… diff --git a/crates/ui-egui/src/i18n/ka.tsv b/crates/ui-egui/src/i18n/ka.tsv index 9b8ead253..fcf12d546 100644 --- a/crates/ui-egui/src/i18n/ka.tsv +++ b/crates/ui-egui/src/i18n/ka.tsv @@ -4815,6 +4815,7 @@ imageTrace Outline კონტური Needs a key საჭიროა კლავიში No equivalent შესატყვისი არ არის Precise Cursors ზუსტი კურსორები + Image Trace Preview გამოსახულების ვექტორიზაციის წინასწარი ნახვა Press a key… დააჭირეთ კლავიშს… Read Shortcut Set File მალსახმობების ნაკრების ფაილის წაკითხვა Ready მზადაა diff --git a/crates/ui-egui/src/i18n/ko.tsv b/crates/ui-egui/src/i18n/ko.tsv index dd059b45b..465a7eff7 100644 --- a/crates/ui-egui/src/i18n/ko.tsv +++ b/crates/ui-egui/src/i18n/ko.tsv @@ -564,6 +564,7 @@ font-technology Variable 가변 Save Grid as Preset… 격자를 프리셋으로 저장… Snap to Pixel 픽셀에 스냅 Precise Cursors 정밀 커서 + Image Trace Preview 이미지 추적 미리 보기 Snap to Point 포인트에 스냅 Snap to Glyph 글리프에 스냅 New View… 새 보기… diff --git a/crates/ui-egui/src/i18n/nl.tsv b/crates/ui-egui/src/i18n/nl.tsv index 57c4f9ed2..5e60c58fa 100644 --- a/crates/ui-egui/src/i18n/nl.tsv +++ b/crates/ui-egui/src/i18n/nl.tsv @@ -550,6 +550,7 @@ Save Grid as Preset… Raster opslaan als voorinstelling… Snap to Pixel Uitlijnen op pixel Precise Cursors Nauwkeurige cursors + Image Trace Preview Voorbeeld van Afbeelding traceren Snap to Point Uitlijnen op punt Snap to Glyph Uitlijnen op glyph New View… Nieuwe weergave… diff --git a/crates/ui-egui/src/i18n/pl.tsv b/crates/ui-egui/src/i18n/pl.tsv index b9fd725dd..078c6eb0d 100644 --- a/crates/ui-egui/src/i18n/pl.tsv +++ b/crates/ui-egui/src/i18n/pl.tsv @@ -541,6 +541,7 @@ Save Grid as Preset… Zapisz siatkę jako ustawienie… Snap to Pixel Przyciągaj do pikseli Precise Cursors Precyzyjne kursory + Image Trace Preview Podgląd obrysu obrazu Snap to Point Przyciągaj do punktów Snap to Glyph Przyciągaj do glifów New View… Nowy widok… diff --git a/crates/ui-egui/src/i18n/pt-br.tsv b/crates/ui-egui/src/i18n/pt-br.tsv index 3649bff31..8415173b4 100644 --- a/crates/ui-egui/src/i18n/pt-br.tsv +++ b/crates/ui-egui/src/i18n/pt-br.tsv @@ -2560,6 +2560,7 @@ Snap to Grid Ajustar à Grade Snap to Pixel Ajustar ao Pixel Precise Cursors Cursores Precisos + Image Trace Preview Visualização do Rastreamento de Imagem Snap to Point Ajustar ao Ponto Snap to Unit Ajustar à Unidade Snapping Tolerance Tolerância de Ajuste diff --git a/crates/ui-egui/src/i18n/ru.tsv b/crates/ui-egui/src/i18n/ru.tsv index d971aab6d..136fc6868 100644 --- a/crates/ui-egui/src/i18n/ru.tsv +++ b/crates/ui-egui/src/i18n/ru.tsv @@ -3120,6 +3120,7 @@ mark-style Japanese Японский Snap to Grid Привязать к сетке Snap to Pixel Привязать к пикселю Precise Cursors Точные курсоры + Image Trace Preview Просмотр трассировки изображения Snap to Point Привязать к точке Snap to Unit Привязать к единицам Snapping Tolerance Допуск привязки diff --git a/crates/ui-egui/src/i18n/sv.tsv b/crates/ui-egui/src/i18n/sv.tsv index 89cf00ec4..3e10de425 100644 --- a/crates/ui-egui/src/i18n/sv.tsv +++ b/crates/ui-egui/src/i18n/sv.tsv @@ -3022,6 +3022,7 @@ font-technology Variable Variabla Snap to Grid Fäst mot rutnät Snap to Pixel Fäst mot pixel Precise Cursors Exakta markörer + Image Trace Preview Förhandsgranskning av bildkalkering Snap to Point Fäst mot punkt Snap to Unit Fäst mot enhet Snapping Tolerance Fästtolerans diff --git a/crates/ui-egui/src/i18n/tr.tsv b/crates/ui-egui/src/i18n/tr.tsv index 3c0d4b722..6384ae068 100644 --- a/crates/ui-egui/src/i18n/tr.tsv +++ b/crates/ui-egui/src/i18n/tr.tsv @@ -2930,6 +2930,7 @@ font-technology Variable Değişken Snap to Grid Izgaraya Yasla Snap to Pixel Piksel'e Yapış Precise Cursors Hassas İmleçler + Image Trace Preview Görüntü İzleme Önizlemesi Snap to Point Noktaya Yasla Snapping Tolerance Yapışma Toleransı Social Square Post 1080×1080 Sosyal Meydan Gönderisi 1080×1080 diff --git a/crates/ui-egui/src/i18n/uk.tsv b/crates/ui-egui/src/i18n/uk.tsv index c9c09442d..3b61d4e17 100644 --- a/crates/ui-egui/src/i18n/uk.tsv +++ b/crates/ui-egui/src/i18n/uk.tsv @@ -3117,6 +3117,7 @@ effect Points Точки Snap to Grid Прив’язати до сітки Snap to Pixel Прив’язати до пікселя Precise Cursors Точні курсори + Image Trace Preview Перегляд трасування зображення Snap to Point Прив’язати до точки Snap to Unit Прив’язати до одиниць Snapping Tolerance Допуск прив’язки diff --git a/crates/ui-egui/src/i18n/vi.tsv b/crates/ui-egui/src/i18n/vi.tsv index f6f231ef6..4a6ae2137 100644 --- a/crates/ui-egui/src/i18n/vi.tsv +++ b/crates/ui-egui/src/i18n/vi.tsv @@ -3449,6 +3449,7 @@ mark-style Japanese Kiểu Nhật Snap to Grid Hút vào lưới Snap to Pixel Hút vào pixel Precise Cursors Con trỏ chính xác + Image Trace Preview Xem trước Vector hóa ảnh Snap to Point Hút vào điểm Snap to Unit Hút vào đơn vị Snapping Tolerance Dung sai hút diff --git a/crates/ui-egui/src/i18n/zh-hans.tsv b/crates/ui-egui/src/i18n/zh-hans.tsv index a3b7ee35f..ed0f434aa 100644 --- a/crates/ui-egui/src/i18n/zh-hans.tsv +++ b/crates/ui-egui/src/i18n/zh-hans.tsv @@ -2956,6 +2956,7 @@ font-script Japanese 汉字 Snap to Grid 对齐网格 Snap to Pixel 对齐像素 Precise Cursors 精确光标 + Image Trace Preview 图像描摹预览 Snap to Point 对齐点 Snap to Unit 对齐单位 Snapping Tolerance 吸附容差 diff --git a/crates/ui-egui/src/i18n/zh-hant.tsv b/crates/ui-egui/src/i18n/zh-hant.tsv index 78d01aa71..d64dc9029 100644 --- a/crates/ui-egui/src/i18n/zh-hant.tsv +++ b/crates/ui-egui/src/i18n/zh-hant.tsv @@ -3892,6 +3892,7 @@ font-script Japanese 漢字 Snap to Grid 靠齊格點 Snap to Pixel 靠齊像素 Precise Cursors 精確游標 + Image Trace Preview 影像描圖預覽 Snap to Point 靠齊控制點 Snap to Unit 靠齊單位 Snapping Tolerance 靠齊容許度 diff --git a/crates/ui-egui/src/menus.rs b/crates/ui-egui/src/menus.rs index cf8bb4ac9..aa2269e00 100644 --- a/crates/ui-egui/src/menus.rs +++ b/crates/ui-egui/src/menus.rs @@ -205,6 +205,12 @@ pub const UI_COMMANDS: &[(&str, &str, &str, &str)] = &[ "", "{} toggle General › Use Precise Cursors: the drawing tools' pointers become a crosshair → true when on", ), + ( + "imageTrace.preview", + "Image Trace Preview", + "", + "{on?: bool} turn the Image Trace panel's Preview on (true), off (false) or toggle it (omitted), as its checkbox does: on, setting changes trace the selected Image Trace object at once; off, they wait for Trace; returns the new state", + ), ("view.textThreads", "Hide Text Threads", "Cmd+Shift+Y", "{} toggle the thread lines between threaded text frames"), ("view.gradientAnnotator", "Hide Gradient Annotator", "Cmd+Alt+G", "{} toggle the Gradient tool's annotator"), ( @@ -1576,6 +1582,11 @@ pub fn run_ui_command(app: &mut VectorcraftApp, id: &str, p: &Value) -> Option flag(&mut app.ui.toolbar_advanced), + "imageTrace.preview" => opt_bool(p, "on").map(|on| { + let on = on.unwrap_or(!app.ui.image_trace_preview); + app.ui.image_trace_preview = on; + json!(on) + }), "window.floatTools" => { let floating = match opt_bool(p, "floating") { Ok(on) => on, diff --git a/crates/ui-egui/src/panels/image_trace.rs b/crates/ui-egui/src/panels/image_trace.rs index c477a877b..83ca93893 100644 --- a/crates/ui-egui/src/panels/image_trace.rs +++ b/crates/ui-egui/src/panels/image_trace.rs @@ -3,8 +3,9 @@ //! Strokes with the widest line stroked. With an Image Trace object selected and Preview on (the //! default, kept with the UI preferences), changing a setting re-traces it (one undo step per //! change; sliders apply when released); with Preview off, the changes wait in the panel until -//! Trace applies them, or until Preview is turned on again. Changing the view redraws the object -//! without tracing again. With an image selected, Trace makes a new Image Trace object. +//! Trace applies them, or until Preview is turned on again; they stay with their object while +//! another one is selected. `imageTrace.preview` turns Preview on or off. Changing the view redraws +//! the object without tracing again. With an image selected, Trace makes a new Image Trace object. //! The public documentation of the panel describes Preview as showing the result of the current //! settings (). @@ -74,6 +75,9 @@ struct TraceUi { object: Option<(u64, NodeId)>, /// Preview was off at the panel's last frame. preview_off: bool, + /// The settings that wait for objects no longer selected, by document and object: the preset, + /// the parameters, and the object's stored settings they were changed from. + drafts: std::collections::HashMap<(u64, NodeId), (String, Value, Value)>, } /// Each preset: its name, its parameters, and those of its enhanced version (null if it has none). @@ -296,13 +300,39 @@ pub fn show(app: &mut VectorcraftApp, ui: &mut Ui) { let (is_trace, is_image, stored) = target(app); let any_trace = any_trace(app); let object = target_key(app); + let same = |a: &Value, b: &Value| a["preset"] == b["preset"] && a["params"] == b["params"]; + let mut restored = false; + // Another object: the settings that wait for the one left are kept until it is selected again, + // also when a plain image or nothing is selected next. + if object != st.object + && let Some(left) = st.object + && !st.synced.is_null() + && st.params != st.synced["params"] + { + st.drafts.insert(left, (st.preset.clone(), st.params.clone(), st.synced.clone())); + } + // A plain image (or nothing) keeps the panel's settings, which no longer wait for the object left. + if stored.is_none() && object != st.object { + st.synced = Value::Null; + st.object = object; + } if let Some(t) = stored.filter(|t| *t != st.synced || object != st.object) { // A change of the object's view alone (here or in the Control bar) keeps the settings that // wait in the panel with Preview off. - if object != st.object || t["preset"] != st.synced["preset"] || t["params"] != st.synced["params"] { + if object != st.object || !same(&t, &st.synced) { st.preset = t["preset"].as_str().unwrap_or("Custom").to_string(); st.params = t["params"].clone(); } + // The object selected again shows the settings that wait for it, unless its own settings + // changed since (Undo, or a trace from elsewhere). + if object != st.object + && let Some((preset, params, from)) = object.and_then(|k| st.drafts.remove(&k)) + && same(&from, &t) + { + st.preset = preset; + st.params = params; + restored = true; + } st.view = TraceView::of(&t); st.synced = t; st.object = object; @@ -508,8 +538,10 @@ pub fn show(app: &mut VectorcraftApp, ui: &mut Ui) { } ui.horizontal(|ui| { let preview = app.ui.image_trace_preview; - if widgets::check(ui, tl!("Preview"), preview, true) { - app.ui.image_trace_preview = !preview; + if widgets::check(ui, tl!("Preview"), preview, true) + && let Err(e) = app.run("imageTrace.preview", json!({})) + { + app.ui.status = e; } let r = ui.add_enabled_ui(is_trace || is_image, |ui| widgets::flat_button(ui, tl!("Trace"), 80.0)).inner; if r.on_disabled_hover_text(tl!("Select an image to trace")).clicked() { @@ -519,10 +551,12 @@ pub fn show(app: &mut VectorcraftApp, ui: &mut Ui) { app.run("imageTrace.expand", json!({})).ok(); } }); - // Preview turned on (the checkbox, or `ui.set`): the selected object shows the settings that - // waited in the panel. With no Image Trace object selected, they wait until it is selected again. + // Preview turned on (the checkbox, `imageTrace.preview` or `ui.set`): the selected object is + // traced with the settings that waited in the panel. With no Image Trace object selected, it is + // traced when it is selected again. An object whose settings waited while another object was + // selected is traced when it is selected again with Preview on. let preview = app.ui.image_trace_preview; - retrace |= preview && st.preview_off && is_trace && st.params != st.synced["params"]; + retrace |= preview && (st.preview_off || restored) && is_trace && st.params != st.synced["params"]; if is_trace || !preview { st.preview_off = !preview; } @@ -825,6 +859,95 @@ mod tests { assert_eq!(target(&app).2.unwrap()["params"]["strokes"], json!(false), "B is traced with its own settings"); } + #[test] + fn settings_that_wait_come_back_when_their_object_is_selected_again() { + let mut app = traced_app(); + let ctx = egui::Context::default(); + crate::theme::install_fonts(&ctx); + let a = first_selected(&app).unwrap().id; + app.run("edit.duplicate", json!({})).unwrap(); + let b = first_selected(&app).unwrap().id; + let shown = |ctx: &egui::Context| pstate::(ctx, "image-trace").params["strokes"].clone(); + let undo = |app: &VectorcraftApp| app.session.active().unwrap().history.undo.len(); + app.run("select.set", json!({"ids": [a.0]})).unwrap(); + click(&mut app, &ctx, "Preview"); + click(&mut app, &ctx, "Strokes"); + app.run("select.set", json!({"ids": [b.0]})).unwrap(); + frame(&mut app, &ctx, vec![]); + assert_eq!(shown(&ctx), json!(false), "B's own settings"); + app.run("select.set", json!({"ids": [a.0]})).unwrap(); + frame(&mut app, &ctx, vec![]); + assert_eq!(shown(&ctx), json!(true), "A's change still waits"); + let steps = undo(&app); + click(&mut app, &ctx, "Trace"); + assert_eq!(target(&app).2.unwrap()["params"]["strokes"], json!(true), "A is traced with its change"); + assert_eq!(undo(&app), steps + 1); + // Preview turned on while B is selected: A is traced with its change when it is selected again. + let a = first_selected(&app).unwrap().id; + click(&mut app, &ctx, "Strokes"); + app.run("select.set", json!({"ids": [b.0]})).unwrap(); + frame(&mut app, &ctx, vec![]); + click(&mut app, &ctx, "Preview"); + assert!(app.ui.image_trace_preview); + let steps = undo(&app); + app.run("select.set", json!({"ids": [a.0]})).unwrap(); + frame(&mut app, &ctx, vec![]); + assert_eq!(target(&app).2.unwrap()["params"]["strokes"], json!(false), "traced with the change that waited"); + assert_eq!(undo(&app), steps + 1); + frame(&mut app, &ctx, vec![]); + assert_eq!(undo(&app), steps + 1, "traced once"); + } + + #[test] + fn settings_that_wait_are_kept_when_a_plain_image_is_traced_in_between() { + let mut app = traced_app(); + let ctx = egui::Context::default(); + crate::theme::install_fonts(&ctx); + let a = first_selected(&app).unwrap().id; + click(&mut app, &ctx, "Preview"); + click(&mut app, &ctx, "Strokes"); + let img = image::RgbaImage::from_fn(20, 20, |_, y| image::Rgba(if y < 10 { [0, 0, 0, 255] } else { [255, 255, 255, 255] })); + let mut png = vec![]; + img.write_to(&mut std::io::Cursor::new(&mut png), image::ImageFormat::Png).unwrap(); + let data = vectorcraft_format::base64_encode(&png); + app.run("file.place", json!({"name": "plain.png", "dataBase64": data, "link": false})).unwrap(); + assert!(target(&app).1, "a plain image is selected"); + frame(&mut app, &ctx, vec![]); + click(&mut app, &ctx, "Strokes"); + click(&mut app, &ctx, "Trace"); + assert_eq!(target(&app).2.unwrap()["params"]["strokes"], json!(false), "the image is traced with the panel's settings"); + app.run("select.set", json!({"ids": [a.0]})).unwrap(); + frame(&mut app, &ctx, vec![]); + assert_eq!(pstate::(&ctx, "image-trace").params["strokes"], json!(true), "A's change still waits"); + } + + #[test] + fn settings_that_wait_are_dropped_when_their_object_changed_since() { + let mut app = traced_app(); + let ctx = egui::Context::default(); + crate::theme::install_fonts(&ctx); + let a = first_selected(&app).unwrap().id; + app.run("edit.duplicate", json!({})).unwrap(); + let b = first_selected(&app).unwrap().id; + app.run("select.set", json!({"ids": [a.0]})).unwrap(); + click(&mut app, &ctx, "Preview"); + click(&mut app, &ctx, "Strokes"); + app.run("select.set", json!({"ids": [b.0]})).unwrap(); + frame(&mut app, &ctx, vec![]); + // A's settings as they were when the change was made, other than its settings now. + let mut st: TraceUi = pstate(&ctx, "image-trace"); + let key = (app.session.active().unwrap().uid, a); + let draft = st.drafts.get_mut(&key).expect("the change waits for A"); + assert_eq!(draft.1["strokes"], json!(true)); + draft.2["params"]["threshold"] = json!(1); + set_pstate(&ctx, "image-trace", st); + app.run("select.set", json!({"ids": [a.0]})).unwrap(); + frame(&mut app, &ctx, vec![]); + let shown = pstate::(&ctx, "image-trace"); + assert_eq!(shown.params, target(&app).2.unwrap()["params"], "the panel shows A's settings as they are now"); + assert!(shown.drafts.is_empty(), "the change is dropped"); + } + #[test] fn preview_is_kept_with_the_preferences_and_reset_to_default_leaves_it() { let mut app = traced_app(); diff --git a/docs/target-app-parity.md b/docs/target-app-parity.md index 83a049191..b4ae5561e 100644 --- a/docs/target-app-parity.md +++ b/docs/target-app-parity.md @@ -793,7 +793,7 @@ Moved from the ROADMAP's "Shipped so far" on 2026-10-10. Update it when a featur - **Image Trace, large images:** images over 1500 px on a side trace with a warning in the result and the status bar; the anchor limit is 8,000,000 (2,000,000 on the web), measured at about 90 bytes an anchor (see [quality notes](image-trace-quality.md#large-images)). - **Image Trace, Flat Logo working size:** Flat Logo traces at most 1024 px on a side; a larger decoded raster (the 64-megapixel copy for a bigger image) is averaged down in whole-number blocks first, and the trace's `warnings` name the size it was traced at and the image's own size, in place of the slower-trace and 64-megapixel notes; code-drawn 1024 and 1025 px tests in `crates/trace` and `crates/engine`. - **Image Trace, Flat Logo working size:** Flat Logo traces at most 1024 px on a side; a larger image is averaged down by a whole factor first, and the trace's `warnings` name the size it was traced at and the image's own size, in place of the slower-trace and 64-megapixel notes; code-drawn 1024 and 1025 px tests in `crates/trace` and `crates/engine`. -- **Image Trace, Preview:** the Image Trace panel's Preview checkbox, before Trace, is on by default, and a setting change traces the selected Image Trace object again at once. Off, changes wait in the panel until Trace applies them as one undo step, or until Preview is turned on again. Preview is kept with the UI preferences, and Reset to Default leaves it. +- **Image Trace, Preview:** the Image Trace panel's Preview checkbox, before Trace, is on by default, and a setting change traces the selected Image Trace object again at once. Off, changes wait in the panel until Trace applies them as one undo step, or until Preview is turned on again. Changes stay with the object they were made for while another object is selected. When Preview is turned on with that object not selected, the object is traced with its changes when it is selected again. Preview is kept with the UI preferences, and Reset to Default leaves it. The `imageTrace.preview` command turns it on or off. - **Image Trace small contours:** closed fits too small to form an editable subpath retain their positioned outline, including holes. Source-generated island, hole/winding and stepped-region regressions cover Corners and Noise; defaults, parity scores and estimates are unchanged. - **Create Strokes baseline (2026-10-17, measured):** the ignored centre-lines class covers 23 exact code-drawn scenes in aa and hard variants, including junctions, crossings, fills meeting strokes and varying widths. [Baseline and metric definitions](image-trace-quality.md#centre-lines). Topology is recovered from emitted geometry; width-profile metrics remain unavailable. No behaviour change or score increase. - **Image Trace, collapsed loops keep few segments:** a loop whose fit collapses to one cubic keeps the fewest segments that hold its area and course, so a higher Paths gives no fewer segments; a code-drawn Paths sweep in `crates/trace` (see [quality notes](image-trace-quality.md#collapsed-loops-keep-few-segments)). diff --git a/docs/ui-parity.md b/docs/ui-parity.md index af3ec3574..dfdb19811 100644 --- a/docs/ui-parity.md +++ b/docs/ui-parity.md @@ -273,7 +273,7 @@ empty), without opening the dialog. | Quick Image Trace presets trace at once and leave the panel as it was; the Image Trace button (Control bar, Properties) opens the editable controls | done | Per the public documentation, choosing a preset traces the image with it straight away, and the panel is opened with the Image Trace button in the Control panel or in Properties' Image Trace section (). The controls show Threshold, Paths, Corners and Noise with Advanced open; `panels/image_trace.rs` headless tests (`a_quick_trace_leaves_the_panel_as_it_was`, `sketch_quick_trace_reveals_all_adjustments_and_keeps_the_source` for the button's route). No algorithm parity claim. | | Image Trace panel: holding the eye button next to View down shows the selected Image Trace objects' source image on the canvas | done | Per the public documentation, the control next to View is pressed and held to compare the trace result with the source image (). On release the objects show their View again; the document, its View and the undo history are unchanged. `RenderOptions::trace_source`; `panels/image_trace.rs` headless test `holding_the_eye_button_shows_the_source_image_until_released`, render test `trace_source_draws_the_source_image_of_the_listed_objects`. The Control bar and Properties have no such button | | Live trace result bounds and selection highlights exclude the retained bitmap; source-image views retain it | done | All TraceView modes and rotated result bounds regression-covered; ordinary hidden group behavior retained | -| Image Trace panel: the Preview checkbox before Trace chooses whether a setting change traces the selected Image Trace object again at once | done | Per the public documentation, Preview shows the result of the current settings and Trace traces with them (). Preview is on by default and kept with the UI preferences; Reset to Default leaves it. Off, changes wait in the panel until Trace applies them as one undo step, or until Preview is turned on again. `ui.set {imageTracePreview}`; `panels/image_trace.rs` headless tests (`with_preview_off_a_slider_change_waits_for_trace`, `turning_preview_on_traces_the_changes_that_waited`, `preview_turned_on_with_nothing_selected_traces_when_the_object_is_selected_again`, `settings_that_wait_stay_with_their_object`, `preview_is_kept_with_the_preferences_and_reset_to_default_leaves_it`) | +| Image Trace panel: the Preview checkbox before Trace chooses whether a setting change traces the selected Image Trace object again at once | done | Per the public documentation, Preview shows the result of the current settings and Trace traces with them (). Preview is on by default and kept with the UI preferences; Reset to Default leaves it. Off, changes wait in the panel until Trace applies them as one undo step, or until Preview is turned on again. Changes stay with the object they were made for while another object is selected, and come back when it is selected again. `imageTrace.preview {on?}`, `ui.set {imageTracePreview}`; `panels/image_trace.rs` headless tests (`with_preview_off_a_slider_change_waits_for_trace`, `turning_preview_on_traces_the_changes_that_waited`, `preview_turned_on_with_nothing_selected_traces_when_the_object_is_selected_again`, `settings_that_wait_stay_with_their_object`, `settings_that_wait_come_back_when_their_object_is_selected_again`, `settings_that_wait_are_dropped_when_their_object_changed_since`, `preview_is_kept_with_the_preferences_and_reset_to_default_leaves_it`) | | Toolbar without group labels by default, one or two columns; All Tools drawer by flyout group with shortcuts, its menu (Reset, Basic, Advanced) and Show section | done | #1751; a preference brings the labels back; `toolbar.show` sets the Fill/Stroke, Coloring, Draw Mode and Screen Mode controls | | Actions panel: a clicked action stays selected for Play Current Selection and Delete Selection | partial | #1853 (part of #1629); editing actions and action shortcuts remain | | Actions panel: Create New Set (bottom bar, ≡ › New Set…) names a new set and Set Options… renames the current one; a click on a set's name makes it current and a recording goes into the current set ([helpx: Automation with actions](https://helpx.adobe.com/illustrator/using/automation-actions.html)) | partial | #3712; the New Action dialog (name, set menu, shortcut, colour), dragging actions between sets and deleting a set remain |