Touch: a two-finger tap switches between selection and drawing modes

In the Touch workspace, a two-finger tap on the canvas now switches
between the Selection tool and the drawing tool chosen last, as the
help page describes. It no longer undoes there; outside Touch a
two-finger tap still undoes, and a three-finger tap still redoes in
every workspace.

- New UI command tool.toggleTouchMode (Switch Selection and Drawing
  Modes, {} -> {tool}). From the Selection, Direct Selection, Group
  Selection, Magic Wand, Lasso or Perspective Selection tool it chooses
  the drawing tool chosen last in the window, or the Pencil tool when
  none has been chosen; from any other tool it chooses the Selection
  tool. The Hand, Rotate View, Zoom and Print Tiling tools never become
  the drawing tool. It adds no undo step.
- These tool lists and Pencil as the first drawing tool are
  VectorCraft's own rules.
- The label is in every catalog. Docs: docs/mcp.md, the touch row of
  docs/hardware-parity.md and docs/target-app-parity.md.
This commit is contained in:
dotCooCoo
2026-11-12 21:21:52 -08:00
parent f062dd7ed2
commit cc19dc1db2
38 changed files with 201 additions and 8 deletions
+6
View File
@@ -731,6 +731,12 @@ pub const UI_COMMANDS: &[(&str, &str, &str, &str)] = &[
"",
"{key, value} | {values: {key: value…}}, tool?: id (default: the active tool) → the tool's options (`{}` reads them). The options a tool keeps (Liquify brush and tool options, Mirror & Cut, Puppet Warp, drawing tools…) last across tool switches and are saved with the preferences; another tool's are stored for when it is chosen",
),
(
"tool.toggleTouchMode",
"Switch Selection and Drawing Modes",
"",
"{} from the Selection, Direct Selection, Group Selection, Magic Wand, Lasso or Perspective Selection tool, choose the drawing tool chosen last in this window (none yet: the Pencil tool); from any other tool, choose the Selection tool, remembering the tool left as the drawing tool unless it is the Hand, Rotate View, Zoom or Print Tiling tool → {tool}. A two-finger tap on the canvas runs it in the Touch workspace (Enable Touch Gestures on)",
),
(
"effect.dialog",
"Effect…",
+4
View File
@@ -416,6 +416,10 @@ impl VectorcraftApp {
self.pen_end.forget_tool();
self.held_tool.clear();
self.activate_tool(id, true);
let now = self.session.tool_id();
if crate::touch::is_drawing_tool(now) {
self.ui.touch_drawing_tool = Some(now.to_string());
}
}
/// Go back to tool `id` after a tool that stood in for it (the pen's eraser end, [`stylus`]):
+82
View File
@@ -966,6 +966,88 @@ fn two_finger_tap_undoes_and_three_finger_tap_redoes() {
assert_eq!(count(&app), 2, "off: the first finger draws as the pointer, and nothing is undone");
}
/// In the Touch workspace a two-finger tap switches between the Selection tool and the drawing tool
/// chosen last, and undoes nothing; three fingers still redo. Outside it, two fingers undo again.
#[test]
fn two_finger_tap_in_touch_switches_selection_and_drawing_modes() {
let mut app = VectorcraftApp::new(Session::new(), Default::default());
app.session.execute("file.new", &json!({"width": 400, "height": 300})).unwrap();
app.session.execute("shape.rectangle", &json!({"x": 50, "y": 50, "width": 40, "height": 40})).unwrap();
crate::workspaces::switch(&mut app.ui, crate::workspaces::TOUCH).unwrap();
app.select_tool("rectangle");
let ctx = egui::Context::default();
frame(&mut app, &ctx, vec![]);
let count = |app: &VectorcraftApp| app.session.active().unwrap().doc.layers[0].children().unwrap().len();
let c = app.canvas_rect.unwrap().center();
let touch = |n: u64, phase, pos| egui::Event::Touch { device_id: egui::TouchDeviceId(1), id: egui::TouchId(n), phase, pos, force: None };
let button = |pos, pressed| egui::Event::PointerButton { pos, button: egui::PointerButton::Primary, pressed, modifiers: Default::default() };
let tap = |app: &mut VectorcraftApp, fingers: u64| {
let at = |n: u64| c + vec2(n as f32 * 50.0, 0.0);
frame(app, &ctx, vec![touch(0, egui::TouchPhase::Start, at(0)), egui::Event::PointerMoved(at(0)), button(at(0), true)]);
frame(app, &ctx, vec![touch(0, egui::TouchPhase::Move, at(0) + vec2(6.0, 6.0)), egui::Event::PointerMoved(at(0) + vec2(6.0, 6.0))]);
frame(app, &ctx, (1..fingers).map(|n| touch(n, egui::TouchPhase::Start, at(n))).collect());
frame(app, &ctx, vec![touch(0, egui::TouchPhase::End, at(0)), button(at(0) + vec2(6.0, 6.0), false), egui::Event::PointerGone]);
frame(app, &ctx, (1..fingers).map(|n| touch(n, egui::TouchPhase::End, at(n))).collect());
frame(app, &ctx, vec![]);
};
tap(&mut app, 2);
assert_eq!((app.session.tool_id(), count(&app)), ("selection", 1), "selection mode, nothing undone or drawn");
tap(&mut app, 2);
assert_eq!((app.session.tool_id(), count(&app)), ("rectangle", 1), "back to the drawing tool");
// A tool chosen by hand becomes the drawing tool a switch returns to.
app.select_tool("ellipse");
tap(&mut app, 2);
tap(&mut app, 2);
assert_eq!((app.session.tool_id(), count(&app)), ("ellipse", 1));
// The switches added no undo step: undo still takes the rectangle away, and three fingers redo it.
app.run("edit.undo", json!({})).unwrap();
assert_eq!(count(&app), 0);
tap(&mut app, 3);
assert_eq!(count(&app), 1, "three fingers redo in Touch too");
// Presentation Mode runs neither.
app.ui.screen_mode = 3;
frame(&mut app, &ctx, vec![]);
tap(&mut app, 2);
assert_eq!(app.session.tool_id(), "ellipse", "Presentation Mode: no switch");
app.ui.screen_mode = 0;
// Enable Touch Gestures off: no switch.
app.session.prefs.touch_gestures = false;
app.select_tool("selection");
frame(&mut app, &ctx, vec![]);
tap(&mut app, 2);
assert_eq!(app.session.tool_id(), "selection", "off: no switch");
app.session.prefs.touch_gestures = true;
// Another workspace: two fingers undo again and switch no tool.
crate::workspaces::switch(&mut app.ui, crate::workspaces::ESSENTIALS).unwrap();
app.select_tool("rectangle");
frame(&mut app, &ctx, vec![]);
let before = count(&app);
tap(&mut app, 2);
assert_eq!(app.session.tool_id(), "rectangle");
assert_eq!(count(&app), before - 1, "Essentials: undone");
}
/// Switch Selection and Drawing Modes from the command: Pencil when no drawing tool was chosen yet,
/// a view tool is left for Selection without becoming the drawing tool, and every selection tool
/// switches to drawing mode.
#[test]
fn switch_selection_and_drawing_modes_command() {
let mut app = VectorcraftApp::new(Session::new(), Default::default());
app.session.execute("file.new", &json!({"width": 400, "height": 300})).unwrap();
assert!(app.ui.touch_drawing_tool.is_none());
app.select_tool("selection");
let r = app.run(crate::touch::TOGGLE_MODE, json!({})).unwrap();
assert_eq!((r, app.session.tool_id()), (json!({"tool": "pencil"}), "pencil"), "no drawing tool chosen yet: Pencil");
app.select_tool("hand");
assert_eq!(app.run(crate::touch::TOGGLE_MODE, json!({})).unwrap(), json!({"tool": "selection"}));
assert_eq!(app.run(crate::touch::TOGGLE_MODE, json!({})).unwrap(), json!({"tool": "pencil"}), "the Hand tool is no drawing tool");
app.select_tool("pen");
for id in ["directSelection", "groupSelection", "magicWand", "lasso"] {
app.select_tool(id);
assert_eq!(app.run(crate::touch::TOGGLE_MODE, json!({})).unwrap(), json!({"tool": "pen"}), "{id}");
}
}
/// The Artboard tool's label holds the artboard's name (never translated); the tools' own
/// labels are interface text.
#[test]
+4 -3
View File
@@ -532,7 +532,8 @@ pub(super) fn wheel(
/// Enable Touch Gestures: this frame's finger contacts on the canvas ([`crate::touch`]). A second
/// finger drops the press the first one began (its tool interaction rolled back; the rest of the
/// gesture presses nothing), and a tap of two fingers undoes, one of three redoes.
/// gesture presses nothing), and a tap of two fingers undoes, one of three redoes. In the Touch
/// workspace a tap of two fingers switches between selection and drawing modes instead.
pub(super) fn touch_gestures(app: &mut VectorcraftApp, ui: &Ui, rect: egui::Rect, view: vectorcraft_engine::ViewInfo) {
if !app.session.prefs.touch_gestures {
return;
@@ -564,12 +565,12 @@ pub(super) fn touch_gestures(app: &mut VectorcraftApp, ui: &Ui, rect: egui::Rect
drop_press(app, ui, view);
ui.data_mut(|d| d.insert_temp(drag_id(), Drag::Gesture));
}
Some(crate::touch::Touch::Tap(n)) => tap = crate::touch::tap_command(n),
Some(crate::touch::Touch::Tap(n)) => tap = crate::touch::tap_command(n, app.ui.workspace == crate::workspaces::TOUCH),
None => {}
}
}
ui.data_mut(|d| d.insert_temp(key, taps));
// In Presentation Mode a tap of two or three fingers undoes or redoes nothing.
// In Presentation Mode a tap of two or three fingers runs nothing.
if let Some(cmd) = tap
&& app.ui.screen_mode < 3
{
+1
View File
@@ -1015,6 +1015,7 @@ font-technology Variable Променливи
Enable Rubber Band for Разрешаване на ластик за
Enable text access for screen readers Разрешаване на достъп до текст за екранни четци
Enable Touch Gestures Разрешаване на докосващи жестове
Switch Selection and Drawing Modes Превключване между режим на селекция и рисуване
Enable Touch Workspace Разрешаване на работно пространство за докосване
Encoding Кодиране
Encoding: Кодиране:
Can't render this file because it contains an unexpected character in line 2 and column 73.
+1
View File
@@ -3732,6 +3732,7 @@ theme Appearance Izgled
Enable Missing Glyph Protection Omogući zaštitu od nedostajućih glifova
Enable Rubber Band for Omogući gumenu traku za
Enable Touch Gestures Omogući pokrete dodirom
Switch Selection and Drawing Modes Prebaci između načina odabira i crtanja
Enable Touch Workspace Omogući radni prostor za dodir
English: UK Engleski: UK
Every (minutes) Svakih (minuta)
Can't render this file because it contains an unexpected character in line 2 and column 73.
+1
View File
@@ -1478,6 +1478,7 @@ antiAlias Sharp Nítid
Enable Rubber Band for Activa la goma elàstica per a
Enable text access for screen readers Activa l’accés al text per als lectors de pantalla
Enable Touch Gestures Activa els gestos tàctils
Switch Selection and Drawing Modes Canvia entre els modes de selecció i de dibuix
Enable Touch Workspace Activa l’espai de treball tàctil
Encoding Codificació
Encoding and writing the file… S’està codificant i escrivint el fitxer…
Can't render this file because it contains an unexpected character in line 2 and column 73.
+1
View File
@@ -3786,6 +3786,7 @@ theme Appearance Motiv
Enable Missing Glyph Protection Povolit ochranu chybějících glyfů
Enable Rubber Band for Povolit gumovou čáru pro
Enable Touch Gestures Povolit dotyková gesta
Switch Selection and Drawing Modes Přepnout mezi režimem výběru a kreslení
Enable Touch Workspace Povolit dotykový pracovní prostor
English: UK Angličtina: Spojené království
Every (minutes) Každých (minut)
Can't render this file because it contains an unexpected character in line 2 and column 73.
+1
View File
@@ -3519,6 +3519,7 @@ theme Appearance Udseende
Enable Missing Glyph Protection Aktivér beskyttelse mod manglende glyffer
Enable Rubber Band for Aktivér gummibånd for
Enable Touch Gestures Aktivér berøringsbevægelser
Switch Selection and Drawing Modes Skift mellem markerings- og tegnetilstand
Enable Touch Workspace Aktivér touch-arbejdsområde
English: UK Engelsk: UK
Every (minutes) Hvert (minut)
Can't render this file because it contains an unexpected character in line 2 and column 73.
+1
View File
@@ -1017,6 +1017,7 @@ font-technology Variable Variabel
Enable Rubber Band for Gummiband aktivieren für
Enable text access for screen readers Textzugriff für Bildschirmlesegeräte zulassen
Enable Touch Gestures Touch-Gesten aktivieren
Switch Selection and Drawing Modes Zwischen Auswahl- und Zeichenmodus wechseln
Enable Touch Workspace Touch-Arbeitsbereich aktivieren
Encoding Kodierung
Encoding: Kodierung:
Can't render this file because it contains an unexpected character in line 2 and column 73.
+1
View File
@@ -985,6 +985,7 @@ font-technology Variable Μεταβλητές
Enable Rubber Band for Ενεργοποίηση δυναμικής προεπισκόπησης γραμμής για
Enable text access for screen readers Ενεργοποίηση πρόσβασης κειμένου για αναγνώστες οθόνης
Enable Touch Gestures Ενεργοποίηση χειρονομιών αφής
Switch Selection and Drawing Modes Εναλλαγή λειτουργιών επιλογής και σχεδίασης
Enable Touch Workspace Ενεργοποίηση χώρου εργασίας αφής
Encoding Κωδικοποίηση
Encoding: Κωδικοποίηση:
Can't render this file because it is too large.
+1
View File
@@ -1038,6 +1038,7 @@ font-technology Variable Variables
Enable Rubber Band for Activar banda elástica para
Enable text access for screen readers Permitir el acceso al texto para lectores de pantalla
Enable Touch Gestures Activar gestos táctiles
Switch Selection and Drawing Modes Cambiar entre modos de selección y dibujo
Enable Touch Workspace Activar espacio de trabajo táctil
Encoding Codificación
Encoding: Codificación:
Can't render this file because it contains an unexpected character in line 2 and column 73.
+1
View File
@@ -3724,6 +3724,7 @@ theme Appearance Ulkoasu
Enable Missing Glyph Protection Ota puuttuvien merkkien suojaus käyttöön
Enable Rubber Band for Ota kumilankavalinta käyttöön kohteelle
Enable Touch Gestures Ota kosketuseleet käyttöön
Switch Selection and Drawing Modes Vaihda valinta- ja piirtotilan välillä
Enable Touch Workspace Ota kosketustyötila käyttöön
English: UK Englanti: UK
Every (minutes) Välein (minuuttia)
Can't render this file because it contains an unexpected character in line 2 and column 73.
+1
View File
@@ -1033,6 +1033,7 @@ font-technology Variable Variables
Enable Rubber Band for Activer l’élastique pour
Enable text access for screen readers Autoriser l’accès au texte pour les lecteurs d’écran
Enable Touch Gestures Activer les gestes tactiles
Switch Selection and Drawing Modes Basculer entre les modes sélection et dessin
Enable Touch Workspace Activer l’espace de travail tactile
Encoding Codage
Encoding: Codage :
Can't render this file because it contains an unexpected character in line 2 and column 73.
+1
View File
@@ -1629,6 +1629,7 @@ antiAlias Sharp शार्प
Enable Rubber Band for के लिए रबर बैंड सक्षम करें
Enable text access for screen readers स्क्रीन रीडर के लिए टेक्स्ट एक्सेस सक्षम करें
Enable Touch Gestures टच जेस्चर ऑन करें
Switch Selection and Drawing Modes चयन और ड्रॉइंग मोड के बीच बदलें
Enable Touch Workspace टच वर्कस्पेस सक्षम करें
Enclosing Lasso लासो संलग्न करना
Enclosing Lasso Tool लासो टूल संलग्न करना
Can't render this file because it is too large.
+1
View File
@@ -1314,6 +1314,7 @@ font-technology Variable Változó
Enable Rubber Band for Gumiszalag-előnézet ehhez:
Enable text access for screen readers Szöveghozzáférés engedélyezése képernyőolvasóknak
Enable Touch Gestures Érintési kézmozdulatok
Switch Selection and Drawing Modes Váltás a kijelölési és a rajzolási mód között
Enable Touch Workspace Érintőképernyős munkaterület
Encoding Kódolás
Encoding: Kódolás:
Can't render this file because it contains an unexpected character in line 2 and column 73.
+1
View File
@@ -3519,6 +3519,7 @@ theme Appearance Tampilan
Enable Missing Glyph Protection Aktifkan perlindungan glyph yang hilang
Enable Rubber Band for Aktifkan rubber band untuk
Enable Touch Gestures Aktifkan gestur sentuh
Switch Selection and Drawing Modes Beralih antara mode seleksi dan menggambar
Enable Touch Workspace Aktifkan ruang kerja sentuh
English: UK Inggris: UK
Every (minutes) Setiap (menit)
Can't render this file because it contains an unexpected character in line 2412 and column 5.
+1
View File
@@ -1047,6 +1047,7 @@ font-technology Variable Variabili
Enable Rubber Band for Attiva elastico per
Enable text access for screen readers Consenti l'accesso al testo per le utilità di lettura dello schermo
Enable Touch Gestures Attiva gesti touch
Switch Selection and Drawing Modes Passa tra modalità selezione e disegno
Enable Touch Workspace Attiva area di lavoro touch
Encoding Codifica
Encoding: Codifica:
Can't render this file because it contains an unexpected character in line 2 and column 73.
+1
View File
@@ -1635,6 +1635,7 @@ antiAlias Sharp シャープ
Enable Opacity Mask 不透明マスクを有効にする
Enable Rubber Band for ラバーバンドを有効にする対象
Enable Touch Gestures タッチジェスチャーを有効にする
Switch Selection and Drawing Modes 選択モードと描画モードを切り替え
Enable Touch Workspace タッチワークスペースを有効にする
Enable copying of text, images and other content テキスト、イメージ、その他のコンテンツのコピーを許可
Enable in-menu font previews メニュー内でフォントプレビューを有効にする
Can't render this file because it contains an unexpected character in line 2 and column 73.
+1
View File
@@ -3363,6 +3363,7 @@ theme Appearance იერსახე
Enable Missing Glyph Protection გამოტოვებული გლიფებისგან დაცვის ჩართვა
Enable Rubber Band for რეზინის ზოლის ჩართვა:
Enable Touch Gestures შეხების ჟესტების ჩართვა
Switch Selection and Drawing Modes მონიშვნისა და ხატვის რეჟიმების გადართვა
Enable Touch Workspace სენსორული სამუშაო სივრცის ჩართვა
English: UK ინგლისური: ბრიტანეთი
Every (minutes) ყოველ (წუთში)
Can't render this file because it is too large.
+1
View File
@@ -1625,6 +1625,7 @@ antiAlias Sharp 날카롭게
Enable Opacity Mask 불투명 마스크 사용
Enable Rubber Band for 러버 밴드 사용 대상
Enable Touch Gestures 터치 제스처 사용
Switch Selection and Drawing Modes 선택 모드와 그리기 모드 전환
Enable Touch Workspace 터치 작업 영역 사용
Enable copying of text, images and other content 텍스트, 이미지 및 기타 콘텐츠 복사 허용
Enable in-menu font previews 메뉴에서 글꼴 미리 보기 사용
Can't render this file because it contains an unexpected character in line 2 and column 73.
+1
View File
@@ -3533,6 +3533,7 @@ theme Appearance Vormgeving
Enable Missing Glyph Protection Beveiliging tegen ontbrekende glyphs inschakelen
Enable Rubber Band for Rubberband inschakelen voor
Enable Touch Gestures Touchgebaren inschakelen
Switch Selection and Drawing Modes Wisselen tussen selectie- en tekenmodus
Enable Touch Workspace Touch-werkruimte inschakelen
English: UK Engels: VK
Every (minutes) Elke (minuten)
Can't render this file because it contains an unexpected character in line 2 and column 73.
+1
View File
@@ -3663,6 +3663,7 @@ theme Appearance Wygląd
Enable Missing Glyph Protection Włącz ochronę przed brakującymi glifami
Enable Rubber Band for Włącz gumkę podglądu dla
Enable Touch Gestures Włącz gesty dotykowe
Switch Selection and Drawing Modes Przełącz tryby zaznaczania i rysowania
Enable Touch Workspace Włącz dotykowy obszar roboczy
English: UK Angielski: Wielka Brytania
Every (minutes) Co (minuty)
Can't render this file because it contains an unexpected character in line 2 and column 73.
+1
View File
@@ -929,6 +929,7 @@ antiAlias Sharp Nítido
Enable Opacity Mask Habilitar Máscara de Opacidade
Enable Rubber Band for Habilitar Elástico para
Enable Touch Gestures Habilitar Gestos de Toque
Switch Selection and Drawing Modes Alternar Modos de Seleção e Desenho
Enable Touch Workspace Habilitar Espaço de Trabalho de Toque
Enable copying of text, images and other content Habilitar cópia de texto, imagens e outro conteúdo
Enable in-menu font previews Habilitar visualizações de fonte no menu
Can't render this file because it contains an unexpected character in line 6 and column 47.
+1
View File
@@ -1036,6 +1036,7 @@ font-technology Variable Вариативные
Enable Rubber Band for Включить «резиновую полосу» для
Enable text access for screen readers Разрешить доступ к тексту для программ чтения с экрана
Enable Touch Gestures Включить сенсорные жесты
Switch Selection and Drawing Modes Переключить режимы выделения и рисования
Enable Touch Workspace Включить сенсорную рабочую среду
Encoding Кодировка
Encoding: Кодировка:
Can't render this file because it is too large.
+1
View File
@@ -1017,6 +1017,7 @@ font-technology Variable Variabla
Enable Rubber Band for Aktivera gummiband för
Enable text access for screen readers Ge skärmläsare åtkomst till text
Enable Touch Gestures Aktivera pekgester
Switch Selection and Drawing Modes Växla mellan markerings- och ritläge
Enable Touch Workspace Aktivera arbetslayout för pekskärm
Encoding Kodning
Encoding: Kodning:
Can't render this file because it contains an unexpected character in line 5 and column 25.
+1
View File
@@ -1009,6 +1009,7 @@ font-technology Variable Değişken
Enable Rubber Band for Lastik Bandı Etkinleştir
Enable text access for screen readers Ekran okuyucular için metin erişimini etkinleştirin
Enable Touch Gestures Dokunma Hareketlerini Etkinleştir
Switch Selection and Drawing Modes Seçim ve Çizim Modları Arasında Geçiş Yap
Enable Touch Workspace Dokunmatik Çalışma Alanını Etkinleştir
Encoding Kodlama
Encoding: Kodlama:
Can't render this file because it contains an unexpected character in line 5 and column 25.
+1
View File
@@ -1041,6 +1041,7 @@ font-technology Variable Варіативні
Enable Rubber Band for Включити «гумову смугу» для
Enable text access for screen readers Дозволити доступ до тексту для програм читання з екрану
Enable Touch Gestures Увімкнути сенсорні жести
Switch Selection and Drawing Modes Перемкнути режими виділення та малювання
Enable Touch Workspace Включити сенсорне робоче середовище
Encoding Кодування
Encoding: Кодування:
Can't render this file because it is too large.
+1
View File
@@ -1204,6 +1204,7 @@ font-technology Variable Biến thiên
Enable Rubber Band for Bật vùng chọn kéo cho
Enable text access for screen readers Bật truy cập văn bản cho trình đọc màn hình
Enable Touch Gestures Bật cử chỉ cảm ứng
Switch Selection and Drawing Modes Chuyển giữa chế độ chọn và vẽ
Enable Touch Workspace Bật không gian làm việc cảm ứng
Encoding Mã hóa
Encoding: Mã hóa:
Can't render this file because it contains an unexpected character in line 204 and column 5.
+1
View File
@@ -979,6 +979,7 @@ antiAlias Sharp 锐利
Enable Rubber Band for 为这些工具启用橡皮筋预览
Enable text access for screen readers 启用屏幕阅读器的文字访问
Enable Touch Gestures 启用触控手势
Switch Selection and Drawing Modes 切换选择与绘图模式
Enable Touch Workspace 启用触控工作区
Encoding 编码
Encoding: 编码:
Can't render this file because it contains an unexpected character in line 2 and column 73.
+1
View File
@@ -1009,6 +1009,7 @@ font-technology Variable 可變
Enable Rubber Band for 啟用橡皮筋預覽,適用於
Enable text access for screen readers 啟用螢幕閱讀器的文字存取
Enable Touch Gestures 啟用觸控手勢
Switch Selection and Drawing Modes 切換選取與繪圖模式
Enable Touch Workspace 啟用觸控工作區
Encoding 編碼
Encoding: 編碼:
Can't render this file because it contains an unexpected character in line 6 and column 47.
+1
View File
@@ -684,6 +684,7 @@ fn run_ui_part6(app: &mut VectorcraftApp, id: &str, p: &Value) -> Option<Result<
Some(t) => Err(format!("unknown tool `{t}`")),
None => Err("missing `tool`".into()),
},
crate::touch::TOGGLE_MODE => Ok(crate::touch::toggle_mode(app)),
crate::addons::pathtools::corner::COMMAND => crate::addons::pathtools::corner::open(app),
crate::addons::pathtools::shared_edge::COMMAND => crate::addons::pathtools::shared_edge::open(app),
crate::addons::arrange::ZOOM => crate::addons::arrange::zoom(app),
+6
View File
@@ -732,6 +732,12 @@ pub const UI_COMMANDS: &[(&str, &str, &str, &str)] = &[
"",
"{key, value} | {values: {key: value…}}, tool?: id (default: the active tool) → the tool's options (`{}` reads them). The options a tool keeps (Liquify brush and tool options, Mirror & Cut, Puppet Warp, drawing tools…) last across tool switches and are saved with the preferences; another tool's are stored for when it is chosen",
),
(
crate::touch::TOGGLE_MODE,
"Switch Selection and Drawing Modes",
"",
"{} from the Selection, Direct Selection, Group Selection, Magic Wand, Lasso or Perspective Selection tool, choose the drawing tool chosen last in this window (none yet: the Pencil tool); from any other tool, choose the Selection tool, remembering the tool left as the drawing tool unless it is the Hand, Rotate View, Zoom or Print Tiling tool → {tool}. A two-finger tap on the canvas runs it in the Touch workspace (Enable Touch Gestures on)",
),
(
"effect.dialog",
"Effect…",
+5
View File
@@ -565,6 +565,10 @@ pub struct UiState {
pub flyout: Option<usize>,
/// Last tool shown for each toolbar group (flyout selection sticks).
pub group_tool: Vec<String>,
/// The drawing tool last chosen in this window, which a two-finger tap in the Touch workspace
/// returns to from the Selection tool ([`crate::touch::toggle_mode`]). Not saved.
#[serde(skip)]
pub touch_drawing_tool: Option<String>,
pub status: String,
/// The Replace Font request behind the status bar's warning ([`ReplaceFontWarning`]). Not saved.
#[serde(skip)]
@@ -1129,6 +1133,7 @@ impl Default for UiState {
answering_control: false,
flyout: None,
group_tool: vectorcraft_tools::TOOL_GROUPS.iter().map(|g| g[0].id.to_string()).collect(),
touch_drawing_tool: None,
status: String::new(),
replace_font_warning: None,
status_notes: None,
+55 -4
View File
@@ -1,5 +1,6 @@
//! Touch gestures on the canvas (Preferences › Devices › Enable Touch Gestures, #585): a tap with
//! two fingers undoes, one with three redoes.
//! two fingers undoes, one with three redoes. In the Touch workspace a tap with two fingers
//! switches between selection and drawing modes instead ([`TOGGLE_MODE`]).
//!
//! egui hands every finger's contact over as [`egui::Event::Touch`] (winit reads them from the
//! system: `WM_POINTER` on Windows), and makes the first finger the mouse pointer too. So the first
@@ -121,15 +122,52 @@ impl Taps {
}
}
/// The command a tap of `fingers` runs: two undo, three redo.
pub(crate) fn tap_command(fingers: usize) -> Option<&'static str> {
/// The command a tap of `fingers` runs: two undo, three redo. In the Touch workspace (`touch_workspace`)
/// two switch between the Selection tool and the last drawing tool ([`TOGGLE_MODE`]).
pub(crate) fn tap_command(fingers: usize, touch_workspace: bool) -> Option<&'static str> {
match fingers {
2 if touch_workspace => Some(TOGGLE_MODE),
2 => Some("edit.undo"),
3 => Some("edit.redo"),
_ => None,
}
}
/// Switch between selection and drawing modes: the Selection tool, and back to the drawing tool
/// chosen last.
pub const TOGGLE_MODE: &str = "tool.toggleTouchMode";
/// The drawing tool a switch out of selection mode chooses when none has been chosen in this window.
pub const FIRST_DRAWING_TOOL: &str = "pencil";
/// A tool of selection mode: one that selects objects or parts of them.
fn selects(id: &str) -> bool {
vectorcraft_tools::catalog::is_selection_tool(id) || matches!(id, "magicWand" | "lasso" | "perspectiveSelection")
}
/// A tool of drawing mode: any tool but those of selection mode and those that only move, turn or
/// zoom the view.
pub(crate) fn is_drawing_tool(id: &str) -> bool {
!selects(id) && !matches!(id, "hand" | "rotateView" | "zoom" | "printTiling")
}
/// [`TOGGLE_MODE`]: from a tool of selection mode, choose the drawing tool chosen last (none yet:
/// [`FIRST_DRAWING_TOOL`]); from any other tool, keep it as the drawing tool and choose the
/// Selection tool. → `{tool}`, the tool now active.
pub(crate) fn toggle_mode(app: &mut crate::VectorcraftApp) -> serde_json::Value {
let now = app.session.tool_id().to_string();
let next = if selects(&now) {
app.ui.touch_drawing_tool.clone().unwrap_or_else(|| FIRST_DRAWING_TOOL.to_string())
} else {
if is_drawing_tool(&now) {
app.ui.touch_drawing_tool = Some(now);
}
"selection".to_string()
};
app.select_tool(&next);
serde_json::json!({"tool": app.session.tool_id()})
}
#[cfg(test)]
mod tests {
use super::*;
@@ -155,7 +193,20 @@ mod tests {
}
let ends: Vec<_> = [4, 5, 6].into_iter().map(|n| t.feed(id(n), TouchPhase::End, p, 1.2)).collect();
assert_eq!(ends, [None, None, Some(Touch::Tap(3))]);
assert_eq!((tap_command(2), tap_command(3), tap_command(1)), (Some("edit.undo"), Some("edit.redo"), None));
assert_eq!((tap_command(2, false), tap_command(3, false), tap_command(1, false)), (Some("edit.undo"), Some("edit.redo"), None));
assert_eq!((tap_command(2, true), tap_command(3, true), tap_command(1, true)), (Some(TOGGLE_MODE), Some("edit.redo"), None));
}
#[test]
fn drawing_tools_are_neither_selection_nor_view_tools() {
for id in ["pencil", "pen", "rectangle", "paintbrush", "type", "eraser", "shapeBuilder"] {
assert!(is_drawing_tool(id), "{id}");
}
let selecting = ["selection", "directSelection", "groupSelection", "magicWand", "lasso", "perspectiveSelection"];
for id in selecting.into_iter().chain(["hand", "rotateView", "zoom", "printTiling"]) {
assert!(!is_drawing_tool(id), "{id}");
}
assert!(vectorcraft_tools::tool_info(FIRST_DRAWING_TOOL).is_some_and(|t| is_drawing_tool(t.id)));
}
#[test]
+1 -1
View File
@@ -24,7 +24,7 @@ It reads the pen's tilt and barrel rotation on macOS and on Linux under X11 and
| Pen pressure | yes (Wacom, Windows Ink, macOS tablet events) | yes, read from AppKit's tablet events before the window gets them (winit reports none), each move of a stroke with its own pressure, mouse event coalescing off (#852; not yet tried on a Mac) | yes (pointer force via `WM_POINTER`) | under X11 and XWayland (Preferences › Performance › Linux Display Server, #1151, #2028; Automatic uses XWayland when a pen is attached on a Wayland session, #4967), read from XInput2 raw events (#764); **no** on native Wayland, where winit reports none and the pen may not reach the window (#491) | browser pointer events, with coalesced events; Apple Pencil on iPad (hover, palm rejection: fingers navigate after a pen contact until reload) | partial: 2–4 h for Wayland (winit 0.31), plus a check on a Mac |
| Pen tilt, bearing, barrel rotation (6D Art Pen) | yes, drives brushes | read from AppKit's tablet events (tilt, and the barrel rotation of a pen that reports one); Calligraphic and Scatter brushes vary with them (#764; not yet tried on a Mac) | with Windows Ink, read from the pen's `POINTER_PEN_INFO` (tilt and barrel rotation where its pen mask says the pen reports them); Calligraphic and Scatter brushes vary with them (#372; not yet tried with a pen) | under X11 and XWayland, read from XInput2 raw events; Calligraphic and Scatter brushes vary with them (#764); **no** on native Wayland | no | partial: native Wayland and the web read none, and Pattern and Bristle brushes do not use them (an Art brush's Width follows them); 3–6 h (#372) |
| Pen eraser end | yes | the eraser end (AppKit's tablet proximity events) selects the Eraser tool and the tip brings back the tool used before, as on Linux (#852; not yet tried on a Mac) | with Windows Ink, an inverted pen or its eraser button (`PEN_FLAG_INVERTED`, `PEN_FLAG_ERASER` in the pen's pointer messages) selects the Eraser tool and the tip brings back the tool used before, as on Linux (not yet tried with a pen) | under X11 and XWayland, the eraser end selects the Eraser tool and the tip brings back the tool used before (#764); **no** on native Wayland | a press of the eraser end (Pointer Events eraser button, `button` 5) selects the Eraser tool, and that press erases; a press of the tip brings back the tool used before; Pointer Events report no end while the pen hovers | partial |
| Touch gestures (pinch zoom, two-finger pan, rotate view, Touch workspace) | yes (Windows touch, Surface) | trackpad pinch, scroll and rotate | pinch, pan (a second finger cancels the first finger's tool press, #4198); two-finger tap undo, three-finger redo (#585) | same where winit reports touch | eframe until the first pen contact, then Pointer Events (pen and fingers told apart); long press opens the context menu | partial: touch workspace and touch-screen rotation missing, 3–5 h |
| Touch gestures (pinch zoom, two-finger pan, rotate view, Touch workspace) | yes (Windows touch, Surface) | trackpad pinch, scroll and rotate | pinch, pan (a second finger cancels the first finger's tool press, #4198); two-finger tap undo, three-finger redo (#585); in the Touch workspace a two-finger tap switches between the Selection tool and the last drawing tool | same where winit reports touch | eframe until the first pen contact, then Pointer Events (pen and fingers told apart); long press opens the context menu | partial: touch workspace and touch-screen rotation missing, 3–5 h |
| Trackpad (smooth scroll, pinch) | yes | yes | precision touchpads | yes | yes | done |
| HiDPI / Retina, per-monitor scale | yes | yes | yes | yes | yes | done; a window dragged between monitors of different scale can still grow on Windows (#1459, open); the custom title bar's window on Windows stays truly borderless so the pointer lines up with what is drawn (#1791, #1758; awaiting the reporter's confirmation) ; macOS cursors use aligned 1×/2× native image representations (#2292), covered by headless construction tests; mixed-display transitions and physical cursor sizing remain unverified, no additional hardware validated |
| Multiple monitors: panels and document windows on another screen | yes | no (one OS window) | no | no | — | missing: 6–10 h (with multiple windows, gap G7) |
+9
View File
@@ -5459,6 +5459,15 @@ point deltas from an unnamed source in the desktop app, or line deltas that are
trackpad gesture holds Alt, it zooms until it ends, also after Alt is let go. The control channel's
`ui.wheel` with `cmd: true` turns the wheel with Cmd/Ctrl held.
With Preferences › Devices › Enable Touch Gestures on, a two-finger tap on the canvas undoes and a three-finger tap
redoes. In the Touch workspace a two-finger tap runs `tool.toggleTouchMode` (Switch Selection and Drawing Modes, `{}`,
desktop app) instead and undoes nothing ([the help page](https://helpx.adobe.com/illustrator/desktop/get-started/learn-the-basics/touch-workspace-in-illustrator.html)).
From the Selection, Direct Selection, Group Selection, Magic Wand, Lasso or Perspective Selection tool it chooses the
drawing tool chosen last in the window, or the Pencil tool when none has been chosen yet; from any other tool it
chooses the Selection tool, and the tool left becomes the drawing tool unless it is the Hand, Rotate View, Zoom or Print
Tiling tool. It returns `{tool}` and adds no undo step. Pencil as the first drawing tool and the list of selection tools
are VectorCraft's own rules. A tap in Presentation Mode runs nothing.
`gridlineEvery` (72 pt by default) and `gridSubdivisions` (8 by default) set the document grid that View › Show Grid
draws, and View › Snap to Grid snaps to its subdivisions. Changing either sets the grid of every open document.
`file.new` gives a new document that grid, and `document.open`, `file.newFromTemplate` and `file.revert` give it to
+1
View File
@@ -1149,6 +1149,7 @@ Moved from the ROADMAP's "Shipped so far" on 2026-10-10. Update it when a featur
With the view rotated, an Escape that has nothing else to end resets the rotation, as Reset Rotate View does, with or without a selection, which stays selected. An Escape that ends something else ends only that, and the next Escape resets the view: to reset the view while another tool or feature is in use, Escape is pressed twice ([Rotate canvas view](https://helpx.adobe.com/illustrator/desktop/add-and-import-files/start-a-new-file/rotate-canvas-view.html)). Under VectorCraft's own rule, the things an Escape ends first are isolation mode, pattern editing, Global Edit, a tool flyout, a full screen mode, Presentation Mode, a path being drawn with the Pen, Smart Pen or Curvature tool, the Blend tool's first pick, the Artboard tool, a tool's drag, a menu, a dialog, a text field and a drag of the ruler origin, and the second press may come any time later, after clicks or other keys. With the Rotate View tool, the view resets before a full screen mode ends; with another tool, Escape leaves a full screen mode first, and Shift+Escape, which does not leave it, resets the view. An Escape does not reset the view while About, a progress window or an Appearance row's popup is open, while a pointer button is held, or in the frame a button is let go. It used to reset the view only as the second of two Escape presses less than a second apart.
A two-finger rotation on a Mac trackpad turns the view about the pointer once it reaches 5° (Preferences › General › Trackpad Gesture to Rotate View, on by default).
On a touch screen a second finger cancels the tool press the first finger began, in the frame it lands or later: the Pencil's stroke or a Selection move is rolled back with no undo entry, and a finger that lands while another is down presses nothing, so a pinch or two-finger pan only zooms and pans (#4198; canvas test `a_second_finger_cancels_the_tool_gesture_the_first_began`).
In the Touch workspace a two-finger tap switches between the Selection tool and the drawing tool chosen last (the Pencil tool when none has been chosen yet) and undoes nothing; outside Touch it still undoes, and a three-finger tap still redoes ([the help page](https://helpx.adobe.com/illustrator/desktop/get-started/learn-the-basics/touch-workspace-in-illustrator.html); `tool.toggleTouchMode`; canvas test `two_finger_tap_in_touch_switches_selection_and_drawing_modes`).
A tool press dropped by a second finger, a long touch or a canceled touch cancels the tool's drag as Escape does: the tool gets back the options it had when the press began (the Polygon tool's sides, set with ↑ and ↓) and they are not stored, a press held still opens no size dialog, a Selection or Artboard tool marquee selects nothing, and the Pen goes on drawing its path without the dropped anchor (canvas tests `a_canceled_touch_drops_the_drag_without_keeping_its_options` and `long_touch_drops_a_tool_press_without_committing_art`; engine tests in `tests::toolsettings`).
The status bar navigator's field shows the active artboard's number and name, and its drop-down lists every artboard by number and name, as the Artboards panel does. Choosing an artboard in the list makes it the active artboard and fits it in the window (`view.goToArtboard`). The list opens on the active artboard's row and lays out only the rows in view and at most one more.
- **Geometry and effects:**