From 1c7b02a6fefa3c431f1c2fce8ec32859701ee42a Mon Sep 17 00:00:00 2001 From: nrq6993-a11y Date: Mon, 19 Oct 2026 20:18:29 +0300 Subject: [PATCH 1/2] G12: honor Enable Touch Workspace preference Switch to the Touch built-in workspace when the preference is on and a touch screen is present; restore the prior workspace when it is turned off. Co-authored-by: Cursor --- crates/engine/src/tests_prefs.rs | 11 ++++++ crates/ui-egui/src/lib.rs | 3 ++ crates/ui-egui/src/prefs_dialog.rs | 9 +++++ crates/ui-egui/src/state.rs | 4 +++ crates/ui-egui/src/workspaces.rs | 58 +++++++++++++++++++++++++++++- 5 files changed, 84 insertions(+), 1 deletion(-) diff --git a/crates/engine/src/tests_prefs.rs b/crates/engine/src/tests_prefs.rs index b069105e5..68b9987d0 100644 --- a/crates/engine/src/tests_prefs.rs +++ b/crates/engine/src/tests_prefs.rs @@ -1370,6 +1370,17 @@ fn show_font_names_in_english_preference_is_stored() { assert!(s.prefs.font_names_in_english); } +/// Preferences › Devices › Enable Touch Workspace (#394): stored and restored through `prefs.set`. +#[test] +fn touch_workspace_preference_is_stored() { + let mut s = Session::new(); + assert!(s.prefs.touch_workspace, "on by default"); + set_pref(&mut s, "touchWorkspace", json!(false)); + assert!(!s.prefs.touch_workspace); + set_pref(&mut s, "touchWorkspace", json!(true)); + assert!(s.prefs.touch_workspace); +} + /// Preferences › Type › Highlight Alternate Glyphs (#394): off by default so OpenType /// substitutions are not pink on every canvas until the user turns the preference on. #[test] diff --git a/crates/ui-egui/src/lib.rs b/crates/ui-egui/src/lib.rs index 7d6eb2a4c..c4a376e75 100644 --- a/crates/ui-egui/src/lib.rs +++ b/crates/ui-egui/src/lib.rs @@ -514,6 +514,8 @@ pub struct VectorcraftApp { pub(crate) ime_discard: bool, /// Preferences were confirmed (see [`Self::take_prefs_changed`]). pub(crate) prefs_changed: bool, + /// Whether the last frame's input reported a touch screen (Preferences › Devices › Touch Workspace). + pub touch_screen: bool, /// A numeric field is being scrubbed: the document's edits meanwhile are one undo step /// ([`scrub::begin_frame`]). scrub_group: bool, @@ -623,6 +625,7 @@ impl VectorcraftApp { ime_marked: None, ime_discard: false, prefs_changed: false, + touch_screen: false, scrub_group: false, scrub_scope: None, automation_roots: None, diff --git a/crates/ui-egui/src/prefs_dialog.rs b/crates/ui-egui/src/prefs_dialog.rs index 7d48e8994..e1ec90018 100644 --- a/crates/ui-egui/src/prefs_dialog.rs +++ b/crates/ui-egui/src/prefs_dialog.rs @@ -39,7 +39,11 @@ pub fn open(app: &mut VectorcraftApp, category: Option<&str>) { pub fn confirm(app: &mut VectorcraftApp) -> Result { let Some(d) = app.ui.dialog.clone() else { return Err("no dialog open".into()) }; let values: Map = d.fields.iter().filter(|(k, _)| !k.starts_with("__")).map(|(k, v)| (k.clone(), v.clone())).collect(); + let touch_ws = values.get("touchWorkspace").and_then(Value::as_bool); app.run("prefs.set", json!({ "values": values }))?; + if touch_ws.is_some() { + crate::workspaces::sync_touch_workspace(app, app.touch_screen); + } app.ui.view.smart_guides = d.fields.get("__smartGuides").and_then(Value::as_bool).unwrap_or(app.ui.view.smart_guides); app.ui.view.snap_to_grid = d.fields.get("__snapToGrid").and_then(Value::as_bool).unwrap_or(app.ui.view.snap_to_grid); app.ui.task_bar = d.fields.get("__taskBar").and_then(Value::as_bool).unwrap_or(app.ui.task_bar); @@ -149,6 +153,11 @@ pub fn apply_runtime(app: &mut VectorcraftApp, ctx: &egui::Context) { if (ctx.zoom_factor() - z).abs() > 1e-3 { ctx.set_zoom_factor(z); } + let touch = ctx.input(|i| i.has_touch_screen()); + if touch != app.touch_screen { + app.touch_screen = touch; + crate::workspaces::sync_touch_workspace(app, touch); + } } pub fn show(app: &mut VectorcraftApp, ctx: &egui::Context) { diff --git a/crates/ui-egui/src/state.rs b/crates/ui-egui/src/state.rs index bda4a23eb..f28a94388 100644 --- a/crates/ui-egui/src/state.rs +++ b/crates/ui-egui/src/state.rs @@ -422,6 +422,9 @@ pub struct UiState { /// Current workspace (Window → Workspace). #[serde(default = "default_workspace")] pub workspace: String, + /// Workspace before Preferences › Devices › Enable Touch Workspace switched to Touch (#394). + #[serde(default, skip_serializing_if = "Option::is_none")] + pub touch_workspace_restore: Option, /// User-saved workspaces (New Workspace…). #[serde(default)] pub custom_workspaces: Vec, @@ -824,6 +827,7 @@ impl Default for UiState { shortcut_overrides: Default::default(), shortcut_set: default_shortcut_set(), workspace: default_workspace(), + touch_workspace_restore: None, custom_workspaces: vec![], recent_files: vec![], recent_fonts: vec![], diff --git a/crates/ui-egui/src/workspaces.rs b/crates/ui-egui/src/workspaces.rs index 055860213..dfca5bb31 100644 --- a/crates/ui-egui/src/workspaces.rs +++ b/crates/ui-egui/src/workspaces.rs @@ -54,6 +54,8 @@ impl Default for Workspace { } pub const ESSENTIALS: &str = "Essentials"; +/// Touch workspace (Window → Workspace → Touch; Preferences › Devices › Enable Touch Workspace). +pub const TOUCH: &str = "Touch"; /// Built-in workspaces, in Illustrator's menu order (Essentials first). pub fn builtins() -> Vec { @@ -115,9 +117,45 @@ pub fn builtins() -> Vec { x.toolbar_advanced = true; x.open_panel = Some("symbols".into()); }), + w(TOUCH, &|x| { + x.control_bar = true; + x.toolbar = true; + x.toolbar_advanced = true; + x.task_bar = true; + x.open_panel = Some("align".into()); + }), ] } +/// Preferences › Devices › Enable Touch Workspace (#394): on, a touch screen switches to the Touch +/// workspace; off, or when no touch screen is reported, the workspace before that switch is +/// restored if Touch was entered automatically. +pub fn sync_touch_workspace(app: &mut VectorcraftApp, touch_screen: bool) { + let auto = app.session.prefs.touch_workspace && touch_screen; + if auto { + if app.ui.workspace != TOUCH { + if app.ui.touch_workspace_restore.is_none() { + app.ui.touch_workspace_restore = Some(app.ui.workspace.clone()); + } + if let Some(w) = find(&app.ui, TOUCH) { + apply(&mut app.ui, &w); + } + } + } else if app.ui.touch_workspace_restore.is_some() && app.ui.workspace == TOUCH { + let back = app + .ui + .touch_workspace_restore + .take() + .filter(|n| find(&app.ui, n).is_some()) + .unwrap_or_else(|| ESSENTIALS.to_string()); + if let Some(w) = find(&app.ui, &back) { + apply(&mut app.ui, &w); + } + } else if !auto { + app.ui.touch_workspace_restore = None; + } +} + pub fn is_builtin(name: &str) -> bool { builtins().iter().any(|w| w.name == name) } @@ -493,11 +531,29 @@ mod tests { #[test] fn all_requested_workspaces_exist() { let ui = UiState::default(); - for n in ["Essentials", "Essentials Classic", "Painting", "Typography", "Layout", "Tracing", "Web", "Automation"] { + for n in ["Essentials", "Essentials Classic", "Painting", "Typography", "Layout", "Tracing", "Web", "Automation", TOUCH] { assert!(find(&ui, n).is_some(), "{n}"); } } + #[test] + fn touch_workspace_preference_switches_and_restores() { + use crate::{Services, VectorcraftApp}; + use vectorcraft_engine::Session; + + let mut app = VectorcraftApp::new(Session::new(), Services::default()); + app.ui.workspace = "Typography".into(); + app.session.prefs.touch_workspace = true; + sync_touch_workspace(&mut app, true); + assert_eq!(app.ui.workspace, TOUCH); + assert_eq!(app.ui.touch_workspace_restore.as_deref(), Some("Typography")); + assert!(app.ui.control_bar && app.ui.open_panel.as_deref() == Some("align")); + app.session.prefs.touch_workspace = false; + sync_touch_workspace(&mut app, true); + assert_eq!(app.ui.workspace, "Typography"); + assert!(app.ui.touch_workspace_restore.is_none()); + } + #[test] fn saved_workspaces_restore_dock_width() { let mut ui = UiState { dock_width: Some(420.0), ..Default::default() }; From 4e5f5e608bcd3a0f9aff732887d6389abb4238c9 Mon Sep 17 00:00:00 2001 From: nrq6993-a11y Date: Tue, 20 Oct 2026 07:15:12 +0300 Subject: [PATCH 2/2] G12: translate Touch workspace for complete i18n catalogs Co-authored-by: Cursor --- crates/ui-egui/src/i18n/bg.tsv | 1 + crates/ui-egui/src/i18n/da.tsv | 1 + crates/ui-egui/src/i18n/id.tsv | 1 + crates/ui-egui/src/i18n/nl.tsv | 1 + crates/ui-egui/src/i18n/tests.rs | 1 + crates/ui-egui/src/i18n/zh-hans.tsv | 1 + crates/ui-egui/src/i18n/zh-hant.tsv | 1 + 7 files changed, 7 insertions(+) diff --git a/crates/ui-egui/src/i18n/bg.tsv b/crates/ui-egui/src/i18n/bg.tsv index ea0df0e42..af003046f 100644 --- a/crates/ui-egui/src/i18n/bg.tsv +++ b/crates/ui-egui/src/i18n/bg.tsv @@ -5077,6 +5077,7 @@ theme Appearance Външен вид Painting Живопис Printing and Proofing Печат и пробно отпечатване Tracing Трасиране + Touch Докосване Typography Типография VectorCraft VectorCraft Web Уеб diff --git a/crates/ui-egui/src/i18n/da.tsv b/crates/ui-egui/src/i18n/da.tsv index 349cd65f3..7776b605c 100644 --- a/crates/ui-egui/src/i18n/da.tsv +++ b/crates/ui-egui/src/i18n/da.tsv @@ -4871,6 +4871,7 @@ mark-style Japanese Japansk Painting Maling Printing and Proofing Udskrivning og prøvetrykning Tracing Sporing + Touch Touch Typography Typografi VectorCraft VectorCraft Web Web diff --git a/crates/ui-egui/src/i18n/id.tsv b/crates/ui-egui/src/i18n/id.tsv index 823700764..cbe5761d0 100644 --- a/crates/ui-egui/src/i18n/id.tsv +++ b/crates/ui-egui/src/i18n/id.tsv @@ -4871,6 +4871,7 @@ mark-style Japanese Jepang Painting Painting Printing and Proofing Printing and Proofing Tracing Tracing + Touch Touch Typography Typography VectorCraft VectorCraft Web Web diff --git a/crates/ui-egui/src/i18n/nl.tsv b/crates/ui-egui/src/i18n/nl.tsv index 102eaa407..4b8887f22 100644 --- a/crates/ui-egui/src/i18n/nl.tsv +++ b/crates/ui-egui/src/i18n/nl.tsv @@ -4883,6 +4883,7 @@ mark-style Japanese Japans Painting Schilderen Printing and Proofing Afdrukken en proefdrukken Tracing Tracering + Touch Touch Typography Typografie VectorCraft VectorCraft Web Web diff --git a/crates/ui-egui/src/i18n/tests.rs b/crates/ui-egui/src/i18n/tests.rs index cacdadb0f..eace05586 100644 --- a/crates/ui-egui/src/i18n/tests.rs +++ b/crates/ui-egui/src/i18n/tests.rs @@ -885,6 +885,7 @@ const MENU_KEEP_AS_IS: &[&str] = &[ "Painting", "Printing and Proofing", "Tracing", + "Touch", "Typography", "Web", "[1P-Normal View]", diff --git a/crates/ui-egui/src/i18n/zh-hans.tsv b/crates/ui-egui/src/i18n/zh-hans.tsv index 5f01f2fe9..5d9e16023 100644 --- a/crates/ui-egui/src/i18n/zh-hans.tsv +++ b/crates/ui-egui/src/i18n/zh-hans.tsv @@ -3180,6 +3180,7 @@ font-script Japanese 汉字 Top-to-Top Leading 上缘至上缘行距 Top: 上: Total Width: 总宽度: + Touch 触控 Touch Type Tool 修饰文字工具 Trace 描摹 Trace the image with the Default preset 使用“默认”预设描摹图像 diff --git a/crates/ui-egui/src/i18n/zh-hant.tsv b/crates/ui-egui/src/i18n/zh-hant.tsv index fb483e6ba..725ab8011 100644 --- a/crates/ui-egui/src/i18n/zh-hant.tsv +++ b/crates/ui-egui/src/i18n/zh-hant.tsv @@ -4087,6 +4087,7 @@ font-script Japanese 漢字 Top-to-Top Leading 上緣至上緣行距 Top: 上: Total Width: 總寬度: + Touch 觸控 Touch Type 觸控文字 Touch Type Tool 觸控文字工具 Trace 描圖