diff --git a/ROADMAP.md b/ROADMAP.md index 4115c31c2..0088ac5a0 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -1,6 +1,7 @@ # VectorCraft Roadmap - Contour add-on (beyond Illustrator): drag a selected shape's edge outward or inward for a live, editable offset copy, with a floating bar for distance and Sharp, Round or Square corners; Bake turns it into paths. Scores and estimates unchanged. +- Compound Shapes add-on (beyond Illustrator): a menu for Make, Release and Expand Compound Shape and a setting, off by default, that makes the Pathfinder panel's Shape Mode buttons create compound shapes on a click. Scores and estimates unchanged. - Paint: new gradients use the document's color model for default stops, including Gradient tool creation. Scores and estimates unchanged. @@ -13,7 +14,7 @@ **Stage: alpha** · next: beta, ~13 points (ready for real work ~62% → ~75%, and reliable `.ai` exchange) and ~170–270 h away -> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-11-05 · **Change:** minor (Contour add-on, beyond Illustrator; scores and estimates unchanged; new gradients follow document color mode; scores and estimates unchanged) · **Target:** Adobe Illustrator 2026 (30.x) +> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-11-05 · **Change:** minor (Compound Shapes add-on, beyond Illustrator; scores and estimates unchanged; Contour add-on, beyond Illustrator; scores and estimates unchanged; new gradients follow document color mode; scores and estimates unchanged) · **Target:** Adobe Illustrator 2026 (30.x) VectorCraft is a clean-room, open-source, pure-Rust reimplementation of the Adobe Illustrator workflow. It runs on macOS, Windows, Linux, FreeBSD and the web (WASM), and agents can drive all of it over MCP, the CLI and a JSON diff --git a/crates/ui-egui/src/addons.rs b/crates/ui-egui/src/addons.rs index f0238aee2..3f0909842 100644 --- a/crates/ui-egui/src/addons.rs +++ b/crates/ui-egui/src/addons.rs @@ -3,6 +3,7 @@ pub mod arrange; pub mod cleanup; pub mod color; +pub mod compounds; pub mod contour; pub mod document; pub mod enclosing_lasso; @@ -19,6 +20,7 @@ pub fn plugin_menu() -> Vec { Item::Sub("Arrange Tools", arrange::menu()), Item::Sub("Artwork Cleanup", cleanup::menu()), Item::Sub("Color Effects", color::menu()), + Item::Sub("Compound Shapes", compounds::menu()), Item::Sub("Contour", contour::menu()), Item::Sub("Document Tools", document::menu()), Item::Sub("Enclosing Lasso", enclosing_lasso::menu()), diff --git a/crates/ui-egui/src/addons/compounds.rs b/crates/ui-egui/src/addons/compounds.rs new file mode 100644 index 000000000..00336013a --- /dev/null +++ b/crates/ui-egui/src/addons/compounds.rs @@ -0,0 +1,19 @@ +//! Compound Shapes in the interface: its submenu (Object › Plug-ins › Compound Shapes) puts Make, +//! Release and Expand Compound Shape (also in the Pathfinder panel's menu) in the menus, and holds the +//! setting that makes the Pathfinder panel's Shape Mode buttons make compound shapes on a click. It +//! acts through `object.compoundShape.*` and `window.pathfinder.compoundShapes`; nothing else +//! about the Pathfinder panel changes. + +use serde_json::{Value, json}; + +use crate::menus::Item; + +pub fn menu() -> Vec { + vec![ + Item::Cmd("Make Compound Shape", "object.compoundShape.make", json!({})), + Item::Cmd("Release Compound Shape", "object.compoundShape.release", json!({})), + Item::Cmd("Expand Compound Shape", "object.compoundShape.expand", json!({})), + Item::Sep, + Item::Cmd("Shape Mode Buttons Make Compound Shapes", "window.pathfinder.compoundShapes", Value::Null), + ] +} diff --git a/crates/ui-egui/src/i18n/bg.tsv b/crates/ui-egui/src/i18n/bg.tsv index 96735ce20..07c4f90d9 100644 --- a/crates/ui-egui/src/i18n/bg.tsv +++ b/crates/ui-egui/src/i18n/bg.tsv @@ -6214,3 +6214,7 @@ breakText Glyphs Глифи Even-Numbered Anchors Четни опорни точки Minimum angle Минимален ъгъл Maximum angle Максимален ъгъл + +# Compound Shapes add-on + Compound Shapes Съставни фигури + Shape Mode Buttons Make Compound Shapes Бутоните за режими на фигури създават съставни фигури diff --git a/crates/ui-egui/src/i18n/bs.tsv b/crates/ui-egui/src/i18n/bs.tsv index ad78ee84e..d007b6829 100644 --- a/crates/ui-egui/src/i18n/bs.tsv +++ b/crates/ui-egui/src/i18n/bs.tsv @@ -6249,3 +6249,7 @@ shape Open Otvoren Even-Numbered Anchors Parna sidra Minimum angle Najmanji ugao Maximum angle Najveći ugao + +# Compound Shapes add-on + Compound Shapes Složeni oblici + Shape Mode Buttons Make Compound Shapes Tasteri načina oblika prave složene oblike diff --git a/crates/ui-egui/src/i18n/ca.tsv b/crates/ui-egui/src/i18n/ca.tsv index 8ad31d6d0..34988b565 100644 --- a/crates/ui-egui/src/i18n/ca.tsv +++ b/crates/ui-egui/src/i18n/ca.tsv @@ -6350,3 +6350,7 @@ breakText Glyphs Glifs Even-Numbered Anchors Ancoratges parells Minimum angle Angle mínim Maximum angle Angle màxim + +# Compound Shapes add-on + Compound Shapes Formes compostes + Shape Mode Buttons Make Compound Shapes Els botons de mode de forma creen formes compostes diff --git a/crates/ui-egui/src/i18n/cs.tsv b/crates/ui-egui/src/i18n/cs.tsv index d801c39fd..57c3092b0 100644 --- a/crates/ui-egui/src/i18n/cs.tsv +++ b/crates/ui-egui/src/i18n/cs.tsv @@ -6364,3 +6364,7 @@ breakText Glyphs Glyfy Even-Numbered Anchors Sudé kotevní body Minimum angle Minimální úhel Maximum angle Maximální úhel + +# Compound Shapes add-on + Compound Shapes Složené tvary + Shape Mode Buttons Make Compound Shapes Tlačítka režimů tvarů vytvářejí složené tvary diff --git a/crates/ui-egui/src/i18n/da.tsv b/crates/ui-egui/src/i18n/da.tsv index e410c8e4a..b5980d572 100644 --- a/crates/ui-egui/src/i18n/da.tsv +++ b/crates/ui-egui/src/i18n/da.tsv @@ -6230,3 +6230,7 @@ breakText Glyphs Glyffer Even-Numbered Anchors Lige ankre Minimum angle Mindste vinkel Maximum angle Største vinkel + +# Compound Shapes add-on + Compound Shapes Sammensatte figurer + Shape Mode Buttons Make Compound Shapes Knapper til formtilstande opretter sammensatte figurer diff --git a/crates/ui-egui/src/i18n/de.tsv b/crates/ui-egui/src/i18n/de.tsv index e11cf1bac..5e38f90f5 100644 --- a/crates/ui-egui/src/i18n/de.tsv +++ b/crates/ui-egui/src/i18n/de.tsv @@ -5950,3 +5950,7 @@ breakText Glyphs Glyphen Even-Numbered Anchors Gerade Ankerpunkte Minimum angle Minimaler Winkel Maximum angle Maximaler Winkel + +# Compound Shapes add-on + Compound Shapes Zusammengesetzte Formen + Shape Mode Buttons Make Compound Shapes Formmodus-Schaltflächen erstellen zusammengesetzte Formen diff --git a/crates/ui-egui/src/i18n/el.tsv b/crates/ui-egui/src/i18n/el.tsv index 9f3d0c18e..84232bda2 100644 --- a/crates/ui-egui/src/i18n/el.tsv +++ b/crates/ui-egui/src/i18n/el.tsv @@ -6316,3 +6316,7 @@ breakText Glyphs Γλύφοι Even-Numbered Anchors Ζυγά σημεία αγκύρωσης Minimum angle Ελάχιστη γωνία Maximum angle Μέγιστη γωνία + +# Compound Shapes add-on + Compound Shapes Σύνθετα σχήματα + Shape Mode Buttons Make Compound Shapes Τα κουμπιά λειτουργιών σχημάτων δημιουργούν σύνθετα σχήματα diff --git a/crates/ui-egui/src/i18n/es.tsv b/crates/ui-egui/src/i18n/es.tsv index b02abb8f1..c09b51167 100644 --- a/crates/ui-egui/src/i18n/es.tsv +++ b/crates/ui-egui/src/i18n/es.tsv @@ -6306,3 +6306,7 @@ breakText Glyphs Glifos Even-Numbered Anchors Anclas pares Minimum angle Ángulo mínimo Maximum angle Ángulo máximo + +# Compound Shapes add-on + Compound Shapes Formas compuestas + Shape Mode Buttons Make Compound Shapes Los botones de modo de forma crean formas compuestas diff --git a/crates/ui-egui/src/i18n/fi.tsv b/crates/ui-egui/src/i18n/fi.tsv index eebd34d89..909240b3d 100644 --- a/crates/ui-egui/src/i18n/fi.tsv +++ b/crates/ui-egui/src/i18n/fi.tsv @@ -6399,3 +6399,7 @@ breakText Glyphs Merkit Even-Numbered Anchors Parilliset ankkurit Minimum angle Pienin kulma Maximum angle Suurin kulma + +# Compound Shapes add-on + Compound Shapes Yhdistelmämuodot + Shape Mode Buttons Make Compound Shapes Muototilapainikkeet luovat yhdistelmämuotoja diff --git a/crates/ui-egui/src/i18n/fr.tsv b/crates/ui-egui/src/i18n/fr.tsv index a5fbb1ab0..6738ec8df 100644 --- a/crates/ui-egui/src/i18n/fr.tsv +++ b/crates/ui-egui/src/i18n/fr.tsv @@ -6359,3 +6359,7 @@ breakText Glyphs Glyphes Even-Numbered Anchors Points d’ancrage pairs Minimum angle Angle minimal Maximum angle Angle maximal + +# Compound Shapes add-on + Compound Shapes Formes composées + Shape Mode Buttons Make Compound Shapes Les boutons de mode de forme créent des formes composées diff --git a/crates/ui-egui/src/i18n/hu.tsv b/crates/ui-egui/src/i18n/hu.tsv index 3959b3fee..491c89fae 100644 --- a/crates/ui-egui/src/i18n/hu.tsv +++ b/crates/ui-egui/src/i18n/hu.tsv @@ -6348,3 +6348,7 @@ breakText Glyphs Glifák Even-Numbered Anchors Páros horgonypontok Minimum angle Legkisebb szög Maximum angle Legnagyobb szög + +# Compound Shapes add-on + Compound Shapes Összetett alakzatok + Shape Mode Buttons Make Compound Shapes Az alakzatmód-gombok összetett alakzatokat hoznak létre diff --git a/crates/ui-egui/src/i18n/id.tsv b/crates/ui-egui/src/i18n/id.tsv index fd72bc7e6..ffb0cbf56 100644 --- a/crates/ui-egui/src/i18n/id.tsv +++ b/crates/ui-egui/src/i18n/id.tsv @@ -6230,3 +6230,7 @@ breakText Glyphs Glif Even-Numbered Anchors Jangkar bernomor genap Minimum angle Sudut minimum Maximum angle Sudut maksimum + +# Compound Shapes add-on + Compound Shapes Bentuk majemuk + Shape Mode Buttons Make Compound Shapes Tombol mode bentuk membuat bentuk majemuk diff --git a/crates/ui-egui/src/i18n/it.tsv b/crates/ui-egui/src/i18n/it.tsv index 4f2035969..cfd99e62b 100644 --- a/crates/ui-egui/src/i18n/it.tsv +++ b/crates/ui-egui/src/i18n/it.tsv @@ -5984,3 +5984,7 @@ breakText Glyphs Glifi Even-Numbered Anchors Ancoraggi pari Minimum angle Angolo minimo Maximum angle Angolo massimo + +# Compound Shapes add-on + Compound Shapes Forme composte + Shape Mode Buttons Make Compound Shapes I pulsanti dei metodi forma creano forme composte diff --git a/crates/ui-egui/src/i18n/ja.tsv b/crates/ui-egui/src/i18n/ja.tsv index 9f089ecf4..5da2097f2 100644 --- a/crates/ui-egui/src/i18n/ja.tsv +++ b/crates/ui-egui/src/i18n/ja.tsv @@ -6049,3 +6049,7 @@ breakText Glyphs 字形 Even-Numbered Anchors 偶数番目のアンカー Minimum angle 最小角度 Maximum angle 最大角度 + +# Compound Shapes add-on + Compound Shapes 複合シェイプ + Shape Mode Buttons Make Compound Shapes シェイプモードボタンで複合シェイプを作成 diff --git a/crates/ui-egui/src/i18n/ka.tsv b/crates/ui-egui/src/i18n/ka.tsv index 78da64abc..b9f4a70a0 100644 --- a/crates/ui-egui/src/i18n/ka.tsv +++ b/crates/ui-egui/src/i18n/ka.tsv @@ -6375,3 +6375,7 @@ font-script Japanese იაპონური Even-Numbered Anchors ლუწი საყრდენი წერტილები Minimum angle მინიმალური კუთხე Maximum angle მაქსიმალური კუთხე + +# Compound Shapes add-on + Compound Shapes შედგენილი ფიგურები + Shape Mode Buttons Make Compound Shapes ფიგურის რეჟიმის ღილაკები ქმნის შედგენილ ფიგურებს diff --git a/crates/ui-egui/src/i18n/ko.tsv b/crates/ui-egui/src/i18n/ko.tsv index 3e99b509b..ac5d1193a 100644 --- a/crates/ui-egui/src/i18n/ko.tsv +++ b/crates/ui-egui/src/i18n/ko.tsv @@ -5945,3 +5945,7 @@ breakText Glyphs 글리프 Even-Numbered Anchors 짝수 번째 앵커 Minimum angle 최소 각도 Maximum angle 최대 각도 + +# Compound Shapes add-on + Compound Shapes 컴파운드 모양 + Shape Mode Buttons Make Compound Shapes 모양 모드 버튼으로 컴파운드 모양 만들기 diff --git a/crates/ui-egui/src/i18n/nl.tsv b/crates/ui-egui/src/i18n/nl.tsv index 7f7818c54..62385d6c9 100644 --- a/crates/ui-egui/src/i18n/nl.tsv +++ b/crates/ui-egui/src/i18n/nl.tsv @@ -6274,3 +6274,7 @@ breakText Glyphs Glyphs Even-Numbered Anchors Even ankerpunten Minimum angle Minimale hoek Maximum angle Maximale hoek + +# Compound Shapes add-on + Compound Shapes Samengestelde vormen + Shape Mode Buttons Make Compound Shapes Vormmodus-knoppen maken samengestelde vormen diff --git a/crates/ui-egui/src/i18n/pl.tsv b/crates/ui-egui/src/i18n/pl.tsv index 56127f052..908f36c94 100644 --- a/crates/ui-egui/src/i18n/pl.tsv +++ b/crates/ui-egui/src/i18n/pl.tsv @@ -6219,3 +6219,7 @@ breakText Glyphs Glify Even-Numbered Anchors Punkty parzyste Minimum angle Kąt minimalny Maximum angle Kąt maksymalny + +# Compound Shapes add-on + Compound Shapes Kształty złożone + Shape Mode Buttons Make Compound Shapes Przyciski trybów kształtu tworzą kształty złożone diff --git a/crates/ui-egui/src/i18n/pt-br.tsv b/crates/ui-egui/src/i18n/pt-br.tsv index 7f68c5c7f..eb376906c 100644 --- a/crates/ui-egui/src/i18n/pt-br.tsv +++ b/crates/ui-egui/src/i18n/pt-br.tsv @@ -6437,3 +6437,7 @@ swatch Yellow Green Verde-amarelado Even-Numbered Anchors Âncoras Pares Minimum angle Ângulo Mínimo Maximum angle Ângulo Máximo + +# Compound Shapes add-on + Compound Shapes Formas Compostas + Shape Mode Buttons Make Compound Shapes Os Botões de Modo de Forma Criam Formas Compostas diff --git a/crates/ui-egui/src/i18n/ru.tsv b/crates/ui-egui/src/i18n/ru.tsv index 10426b2ef..d700736c6 100644 --- a/crates/ui-egui/src/i18n/ru.tsv +++ b/crates/ui-egui/src/i18n/ru.tsv @@ -6453,3 +6453,7 @@ shape Open Открытый Even-Numbered Anchors Чётные опорные точки Minimum angle Минимальный угол Maximum angle Максимальный угол + +# Compound Shapes add-on + Compound Shapes Составные фигуры + Shape Mode Buttons Make Compound Shapes Кнопки режимов фигур создают составные фигуры diff --git a/crates/ui-egui/src/i18n/sv.tsv b/crates/ui-egui/src/i18n/sv.tsv index 1d2d9b03e..85f4812d1 100644 --- a/crates/ui-egui/src/i18n/sv.tsv +++ b/crates/ui-egui/src/i18n/sv.tsv @@ -6420,3 +6420,7 @@ digits Hindi Hindi Even-Numbered Anchors Jämna ankare Minimum angle Minsta vinkel Maximum angle Största vinkel + +# Compound Shapes add-on + Compound Shapes Sammansatta former + Shape Mode Buttons Make Compound Shapes Formlägesknapparna skapar sammansatta former diff --git a/crates/ui-egui/src/i18n/tr.tsv b/crates/ui-egui/src/i18n/tr.tsv index 133538fe9..5c6446de7 100644 --- a/crates/ui-egui/src/i18n/tr.tsv +++ b/crates/ui-egui/src/i18n/tr.tsv @@ -6321,3 +6321,7 @@ breakText Glyphs Glifler Even-Numbered Anchors Çift Numaralı Çapalar Minimum angle En Küçük Açı Maximum angle En Büyük Açı + +# Compound Shapes add-on + Compound Shapes Bileşik Şekiller + Shape Mode Buttons Make Compound Shapes Şekil Modu Düğmeleri Bileşik Şekiller Yapar diff --git a/crates/ui-egui/src/i18n/uk.tsv b/crates/ui-egui/src/i18n/uk.tsv index 95724a3d7..4bb708340 100644 --- a/crates/ui-egui/src/i18n/uk.tsv +++ b/crates/ui-egui/src/i18n/uk.tsv @@ -5964,3 +5964,7 @@ breakText Glyphs Гліфи Even-Numbered Anchors Парні опорні точки Minimum angle Мінімальний кут Maximum angle Максимальний кут + +# Compound Shapes add-on + Compound Shapes Складені фігури + Shape Mode Buttons Make Compound Shapes Кнопки режимів фігур створюють складені фігури diff --git a/crates/ui-egui/src/i18n/vi.tsv b/crates/ui-egui/src/i18n/vi.tsv index 93113bc39..330792405 100644 --- a/crates/ui-egui/src/i18n/vi.tsv +++ b/crates/ui-egui/src/i18n/vi.tsv @@ -5965,3 +5965,7 @@ breakText Glyphs Glyph Even-Numbered Anchors Điểm neo số chẵn Minimum angle Góc tối thiểu Maximum angle Góc tối đa + +# Compound Shapes add-on + Compound Shapes Hình phức hợp + Shape Mode Buttons Make Compound Shapes Nút chế độ hình dạng tạo hình phức hợp diff --git a/crates/ui-egui/src/i18n/zh-hans.tsv b/crates/ui-egui/src/i18n/zh-hans.tsv index 20ec64796..48f040a9c 100644 --- a/crates/ui-egui/src/i18n/zh-hans.tsv +++ b/crates/ui-egui/src/i18n/zh-hans.tsv @@ -6205,3 +6205,7 @@ breakText Glyphs 字形 Even-Numbered Anchors 偶数锚点 Minimum angle 最小角度 Maximum angle 最大角度 + +# Compound Shapes add-on + Compound Shapes 复合形状 + Shape Mode Buttons Make Compound Shapes 形状模式按钮创建复合形状 diff --git a/crates/ui-egui/src/i18n/zh-hant.tsv b/crates/ui-egui/src/i18n/zh-hant.tsv index 7dbb11507..f0c659b50 100644 --- a/crates/ui-egui/src/i18n/zh-hant.tsv +++ b/crates/ui-egui/src/i18n/zh-hant.tsv @@ -6002,3 +6002,7 @@ breakText Glyphs 字符 Even-Numbered Anchors 偶數錨點 Minimum angle 最小角度 Maximum angle 最大角度 + +# Compound Shapes add-on + Compound Shapes 複合形狀 + Shape Mode Buttons Make Compound Shapes 形狀模式按鈕製作複合形狀 diff --git a/crates/ui-egui/src/menus/run.rs b/crates/ui-egui/src/menus/run.rs index 2d134f76f..e9776e78f 100644 --- a/crates/ui-egui/src/menus/run.rs +++ b/crates/ui-egui/src/menus/run.rs @@ -494,6 +494,7 @@ fn run_ui_part6(app: &mut VectorcraftApp, id: &str, p: &Value) -> Option flag(&mut app.ui.task_bar), + "window.pathfinder.compoundShapes" => flag(&mut app.ui.shape_modes_compound), "window.taskBar.pin" => { let place = &mut app.ui.task_bar_place; opt_bool(p, "pinned").map(|pinned| { diff --git a/crates/ui-egui/src/menus/state.rs b/crates/ui-egui/src/menus/state.rs index 2dd1051b1..673ceb81f 100644 --- a/crates/ui-egui/src/menus/state.rs +++ b/crates/ui-egui/src/menus/state.rs @@ -79,6 +79,7 @@ pub fn checked(app: &VectorcraftApp, id: &str, p: &Value) -> Option { crate::toolbar::strips(&app.ui, toolbar).iter().any(|f| f.tools.iter().any(|id| id == tool)) } "window.taskBar" => app.ui.task_bar, + "window.pathfinder.compoundShapes" => app.ui.shape_modes_compound, "window.taskBar.pin" => app.ui.task_bar_place.pinned, "window.panel" => { let panel = p.get("panel").and_then(Value::as_str).unwrap_or(""); diff --git a/crates/ui-egui/src/menus/ui_commands.rs b/crates/ui-egui/src/menus/ui_commands.rs index 02fd4ba5f..44627725d 100644 --- a/crates/ui-egui/src/menus/ui_commands.rs +++ b/crates/ui-egui/src/menus/ui_commands.rs @@ -523,6 +523,12 @@ pub const UI_COMMANDS: &[(&str, &str, &str, &str)] = &[ ), ("window.toolbar.list", "List Toolbars", "", "{} the toolbars made with New Toolbar in the current workspace: [{name, shown, double, slots}]"), ("window.taskBar", "Contextual Task Bar", "", "{}"), + ( + "window.pathfinder.compoundShapes", + "Shape Mode Buttons Make Compound Shapes", + "", + "{} toggles the Compound Shapes add-on's setting: on, the Pathfinder panel's Shape Mode buttons make a compound shape and Alt-click gives the permanent Pathfinder result; off (the default), the other way round. Members of a compound shape selected always take the mode", + ), ( "window.taskBar.pin", "Pin Bar Position", diff --git a/crates/ui-egui/src/panels/pathfinder.rs b/crates/ui-egui/src/panels/pathfinder.rs index 4d08938c5..97959ed4a 100644 --- a/crates/ui-egui/src/panels/pathfinder.rs +++ b/crates/ui-egui/src/panels/pathfinder.rs @@ -77,12 +77,19 @@ fn button(ui: &mut Ui, icon: &str, tip: &str, selected: bool, n: usize, min: usi } /// A Shape Mode button clicked: Alt makes a compound shape of the selection in `mode`; with -/// members of compound shapes selected they take `mode`; otherwise operation `op` runs. +/// members of compound shapes selected they take `mode`; otherwise operation `op` runs. With the +/// Compound Shapes add-on's setting on, a click on the selection (not on members) makes the +/// compound shape and Alt gives the permanent result. fn shape_mode(app: &mut VectorcraftApp, ui: &Ui, op: &str, mode: ShapeMode, members: bool) { - if ui.input(|i| i.modifiers.alt) { + let alt = ui.input(|i| i.modifiers.alt); + if members { + if alt { + crate::menus::invoke(app, "object.compoundShape.make", json!({"mode": mode.name()})); + } else { + crate::menus::invoke(app, "object.compoundShape.setMode", json!({"mode": mode.name()})); + } + } else if alt != app.ui.shape_modes_compound { crate::menus::invoke(app, "object.compoundShape.make", json!({"mode": mode.name()})); - } else if members { - crate::menus::invoke(app, "object.compoundShape.setMode", json!({"mode": mode.name()})); } else { run(app, op); } @@ -588,4 +595,68 @@ mod tests { assert_eq!(app.last_pathfinder, None); assert!(!crate::menus::enabled(&app, "pathfinder.repeat")); } + + /// How many compound shapes the active document holds. + fn compound_shapes(app: &VectorcraftApp) -> usize { + let mut n = 0; + app.session.active().unwrap().doc.walk(|node| n += usize::from(node.is_compound_shape())); + n + } + + /// Off (the default) a Shape Mode click is the permanent Pathfinder result and Alt-click makes a + /// compound shape; with the Compound Shapes add-on's setting on it is the other way round. + #[test] + fn the_compound_shapes_setting_swaps_click_and_alt_on_the_shape_modes() { + // Off: unchanged. + let mut app = two_squares(); + assert!(!app.ui.shape_modes_compound); + click_button(&mut app, "Unite"); + assert_eq!((objects(&app).len(), compound_shapes(&app)), (1, 0), "a click is permanent"); + let mut app = two_squares(); + click_button_with_modifiers(&mut app, "Unite", egui::Modifiers::ALT); + assert_eq!(compound_shapes(&app), 1, "Alt makes a compound shape"); + + // On: a click makes the compound shape, Alt the permanent result. + let mut app = two_squares(); + app.run("window.pathfinder.compoundShapes", json!({})).unwrap(); + assert!(app.ui.shape_modes_compound); + assert_eq!(crate::menus::checked(&app, "window.pathfinder.compoundShapes", &serde_json::Value::Null), Some(true)); + click_button(&mut app, "Unite"); + assert_eq!(compound_shapes(&app), 1, "a click makes a compound shape"); + let mut app = two_squares(); + app.run("window.pathfinder.compoundShapes", json!({})).unwrap(); + click_button_with_modifiers(&mut app, "Unite", egui::Modifiers::ALT); + assert_eq!((objects(&app).len(), compound_shapes(&app)), (1, 0), "Alt is permanent"); + + // Toggled off again, and the check mark follows. + app.run("window.pathfinder.compoundShapes", json!({})).unwrap(); + assert!(!app.ui.shape_modes_compound); + assert_eq!(crate::menus::checked(&app, "window.pathfinder.compoundShapes", &serde_json::Value::Null), Some(false)); + } + + /// Members of a compound shape that are selected take the clicked mode whatever the setting says. + #[test] + fn selected_members_take_the_mode_with_the_setting_on() { + let mut app = two_squares(); + app.run("window.pathfinder.compoundShapes", json!({})).unwrap(); + click_button(&mut app, "Unite"); + let shape = app.session.active().unwrap().selection.objects[0]; + let front = app.session.active().unwrap().doc.node(shape).unwrap().children().unwrap().last().unwrap().id; + app.run("select.set", json!({"ids": [front.0]})).unwrap(); + click_button(&mut app, "Minus Front"); + assert_eq!(compound_shapes(&app), 1, "no second compound shape"); + assert_eq!(vectorcraft_engine::cmd::selected_member_modes(&app.session), [ShapeMode::Subtract]); + } + + /// The setting is kept with the preferences; preferences saved before it read as off. + #[test] + fn the_compound_shapes_setting_is_saved_and_older_preferences_read_as_off() { + let mut app = two_squares(); + app.run("window.pathfinder.compoundShapes", json!({})).unwrap(); + let mut saved = serde_json::to_value(&app.ui).unwrap(); + assert_eq!(saved["shape_modes_compound"], json!(true)); + assert!(serde_json::from_value::(saved.clone()).unwrap().shape_modes_compound); + saved.as_object_mut().unwrap().remove("shape_modes_compound"); + assert!(!serde_json::from_value::(saved).unwrap().shape_modes_compound); + } } diff --git a/crates/ui-egui/src/state.rs b/crates/ui-egui/src/state.rs index 77c19753f..2baf6f6ee 100644 --- a/crates/ui-egui/src/state.rs +++ b/crates/ui-egui/src/state.rs @@ -366,6 +366,10 @@ pub struct UiState { /// starts under the selection at every launch. #[serde(skip)] pub task_bar_place: TaskBarPlace, + /// The Pathfinder panel's Shape Mode buttons make a compound shape on a click, and give the + /// permanent Pathfinder result on Alt-click (off, the default: the other way round). + #[serde(default)] + pub shape_modes_compound: bool, /// The locked objects under the pointer at the last right-click on the canvas, with the /// document's `uid`: the context menu's Unlock submenu lists them while the menu is open. Not /// saved. @@ -935,6 +939,7 @@ impl Default for UiState { toolbar_advanced: false, task_bar: true, task_bar_place: TaskBarPlace::default(), + shape_modes_compound: false, context_locked: None, context_intertwine: None, slot_tool: Default::default(), diff --git a/docs/control-protocol.md b/docs/control-protocol.md index 191be7975..a0e392cd6 100644 --- a/docs/control-protocol.md +++ b/docs/control-protocol.md @@ -402,6 +402,12 @@ Bar Position (`window.taskBar.reset`), which unpins it and puts it back under th Panel. As in Illustrator, neither the position nor the pin is saved: each launch starts with the bar under the selection. +The Compound Shapes add-on's setting, `window.pathfinder.compoundShapes` (omitted params toggle; checked while on; kept with the +preferences; off by default), swaps what a click and an Alt-click do on the Pathfinder panel's Shape Mode buttons: on, a click makes a +compound shape (`object.compoundShape.make`) and Alt-click gives the permanent Pathfinder result. Selected members of a compound +shape always take the clicked mode (`object.compoundShape.setMode`). Its submenu, Object › Plug-ins › Compound Shapes, also lists +Make, Release and Expand Compound Shape. + The Free Transform widget: while the Free Transform tool (E) is active, a small box at the canvas's top left holds Constrain over the tool's three modes, Free Transform, Perspective Distort and Free Distort. The buttons set the tool's options, as `tool.setOption {key: "mode", value: "free"|"perspective"|"distort"}` and `{key: "constrain", value}` do: diff --git a/docs/gaps.md b/docs/gaps.md index 68d08df0b..7b458a347 100644 --- a/docs/gaps.md +++ b/docs/gaps.md @@ -1,6 +1,6 @@ # Gaps -> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-11-05 · **Change:** minor (Contour add-on, beyond Illustrator; scores and estimates unchanged; a slow first frame is waited for instead of restarting without the graphics adapter, and the menu bar no longer waits for the installed fonts' scan; scores and estimates unchanged) · **Target:** Adobe Illustrator 2026 (30.x) +> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-11-05 · **Change:** minor (Compound Shapes add-on, beyond Illustrator; scores and estimates unchanged; Contour add-on, beyond Illustrator; scores and estimates unchanged; a slow first frame is waited for instead of restarting without the graphics adapter, and the menu bar no longer waits for the installed fonts' scan; scores and estimates unchanged) · **Target:** Adobe Illustrator 2026 (30.x) ## Feature submission evidence @@ -31,6 +31,7 @@ Artboard Options forwards the active Artboard tool's Scale Artwork with Artboard | 2026-11-04 | minor | Contour add-on (beyond Illustrator): drag away from a selected shape's edge to grow a live copy of it, or toward the inside to shrink it; the copy carries a live Offset Path effect, so it stays editable until Bake (Expand Appearance), a second drag changes the same Contour instead of nesting one, and a floating bar sets the distance and the Sharp, Round or Square corners. `addon.contour.set` is the command behind it. It is a built-in add-on: Object › Plug-ins › Contour, and its own heading in All Tools, with no default shortcut or toolbar slot. A VectorCraft design built on Offset Path; no other application was inspected. Scores and estimates unchanged. | | 2026-11-04 | minor | Contour tool (beyond Illustrator): drag away from a selected shape's edge to grow a live copy of it, or toward the inside to shrink it; the copy carries a live Offset Path effect, so it stays editable until Bake (Expand Appearance), a second drag changes the same Contour instead of nesting one, and a floating bar sets the distance and the Sharp, Round or Square corners. `object.contour` is the command behind it. A VectorCraft design built on Offset Path; no other application was inspected. Scores and estimates unchanged. | | 2026-11-05 | minor | G12: Hyphenation › Default Language sets the language of new type unless Document Setup chose one, stored as a tag; each run hyphenates in its own language, English only so far, so 2 Preferences options stay unused (#394) | +| 2026-11-05 | minor | Compound Shapes add-on (beyond Illustrator): Object › Plug-ins › Compound Shapes lists Make, Release and Expand Compound Shape, and holds a setting, off by default, that makes the Pathfinder panel's Shape Mode buttons make a compound shape on a click and give the permanent result on Alt-click (the default is the reverse). Selected members of a compound shape always take the clicked mode. The setting is `window.pathfinder.compoundShapes`; no existing behavior changes while it is off. Scores and estimates unchanged. | | 2026-11-03 | minor | New gradients use CMYK default stops in CMYK documents, including Gradient tool creation. Scores and estimates unchanged. | | 2026-11-02 | minor | Font-family fields step selected text with the mouse wheel (#5253); no scored gap or estimate reassessed. | | 2026-10-24 | minor | G12: General › Corner Radius is the Rounded Rectangle tool's radius, a change while the tool is active reaches it, and the radius ↑/↓ set while drawing (or a Tool Options value) becomes the preference, within 0–1296 pt (#394, `crates/engine/src/tests/constrain_tools.rs`); no entry closed, estimate unchanged. | diff --git a/docs/target-app-parity.md b/docs/target-app-parity.md index 53c26cd35..50e1b0cf2 100644 --- a/docs/target-app-parity.md +++ b/docs/target-app-parity.md @@ -1,6 +1,6 @@ # Parity with Adobe Illustrator -> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-11-05 · **Change:** minor (Contour add-on, beyond Illustrator; scores and estimates unchanged; Optical kerning spaces pairs by the font's own stem spacing instead of a fixed tight gap; scores and estimates unchanged) · **Target:** Adobe Illustrator 2026 (30.x; public release notes through 30.7, August 2026) +> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-11-05 · **Change:** minor (Compound Shapes add-on, beyond Illustrator; scores and estimates unchanged; Contour add-on, beyond Illustrator; scores and estimates unchanged; Optical kerning spaces pairs by the font's own stem spacing instead of a fixed tight gap; scores and estimates unchanged) · **Target:** Adobe Illustrator 2026 (30.x; public release notes through 30.7, August 2026) ## Feature submission evidence @@ -483,6 +483,7 @@ since 2026-10-01. | **Scrubby numeric fields** | beyond Illustrator | As in Photoshop, dragging a numeric field's label (`W:`, `Opacity:`, the Character panel's icons) left or right steps its value live; one undo step per drag, Escape cancels (#400) | | **Align Stroke on live type** | beyond Illustrator | The Stroke panel's Align Stroke works on type's character stroke: inside or outside the glyphs without Create Outlines, the type staying editable (as InDesign does; users have asked Illustrator for it since 2010, e.g. [redd.it/1dwhos6](https://redd.it/1dwhos6)). Canvas, PDF and EPS clip it to its side of the glyphs; SVG keeps the text live and draws the stroke on the glyph outlines (#2294) | | **Contour add-on** | beyond Illustrator | Drag away from a selected shape's edge to grow a live copy of it, or toward the inside to shrink it (Shift: whole points); the copy carries a live Offset Path effect so it stays editable, with its own fill and stroke, until Bake (Expand Appearance). A second drag on a selected Contour changes it instead of nesting another; Escape cancels. A floating bar above the selection sets the distance and the corners (Sharp, Round, Square); `addon.contour.set` makes or changes one over MCP and the control channel. The tool is in Object › Plug-ins › Contour and under its own heading in All Tools, with no default shortcut or toolbar slot. Two Contours baked and combined with Minus Front give a border with a gap. Paths, shapes and compound paths only; type isn't offset. Tests: `crates/engine/src/cmd/addons/contour/tests.rs`, `crates/ui-egui/src/canvas/tests.rs` | +| **Compound Shapes add-on** | beyond Illustrator | Object › Plug-ins › Compound Shapes puts Make, Release and Expand Compound Shape in the menus, and holds a setting (off by default) that swaps the Pathfinder panel's Shape Mode buttons: a click makes a compound shape and Alt-click gives the permanent result. Selected members of a compound shape always take the clicked mode; the setting is kept with the preferences. Tests: `panels::pathfinder::tests` in `crates/ui-egui/src/panels/pathfinder.rs` | ## Evidence: what ships today, by area @@ -1655,6 +1656,7 @@ Edit › Copy and Cut put the selected ruler guides on the clipboard, with the s | 2026-11-04 | minor | Contour tool (beyond Illustrator): drag away from a selected shape's edge to grow a live copy of it, or toward the inside to shrink it; the copy carries a live Offset Path effect, so it stays editable until Bake (Expand Appearance), a second drag changes the same Contour instead of nesting one, and a floating bar sets the distance and the Sharp, Round or Square corners. `object.contour` is the command behind it. A VectorCraft design built on Offset Path; no other application was inspected. Scores and estimates unchanged. | | 2026-11-05 | minor | View & navigation: document tabs are reordered by dragging them along the tab strip (`document.move`, #5663); evidence added; scores unchanged. | | 2026-10-30 | minor | Effects: Color Halftone's Max Radius is 4–127 px of the Document Raster Effects resolution, shown in px whatever the units; older documents open converted, and files saved for older app versions hold points (#3260); scores unchanged. | +| 2026-11-05 | minor | Compound Shapes add-on (beyond Illustrator): Object › Plug-ins › Compound Shapes lists Make, Release and Expand Compound Shape, and holds a setting, off by default, that makes the Pathfinder panel's Shape Mode buttons make a compound shape on a click and give the permanent result on Alt-click (the default is the reverse). Selected members of a compound shape always take the clicked mode. The setting is `window.pathfinder.compoundShapes`; no existing behavior changes while it is off. Scores and estimates unchanged. | | 2026-11-01 | minor | Batch Trace Folder (`imageTrace.batchFolder`, #4921); evidence added; scores unchanged. | | 2026-11-01 | minor | Copy and paste ruler guides (#3226); evidence added; scores unchanged. | | 2026-11-04 | minor | Area type vertical alignment buttons in the Properties panel's Paragraph section and the Control panel, off for columns, rows and threaded frames (#3759); evidence added; scores unchanged. | diff --git a/docs/ui-parity.md b/docs/ui-parity.md index ac9cf181b..fca5458f0 100644 --- a/docs/ui-parity.md +++ b/docs/ui-parity.md @@ -1,6 +1,6 @@ # UI and interaction parity -> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-11-05 · **Change:** minor (Contour add-on, beyond Illustrator; scores and estimates unchanged; Select by Artboards add-on selects by overlap, inside or outside several artboards; Cmd+Space keeps the active drawing cursor during its drag; scores and estimates unchanged) · **Target:** Adobe Illustrator 2026 (30.x; Units › East Asian Type acts, with Q and Ha units; scores unchanged) +> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-11-05 · **Change:** minor (Compound Shapes add-on, beyond Illustrator; scores and estimates unchanged; Contour add-on, beyond Illustrator; scores and estimates unchanged; Select by Artboards add-on selects by overlap, inside or outside several artboards; Cmd+Space keeps the active drawing cursor during its drag; scores and estimates unchanged) · **Target:** Adobe Illustrator 2026 (30.x; Units › East Asian Type acts, with Q and Ha units; scores unchanged) ## Feature submission evidence @@ -442,6 +442,7 @@ separate. Scores and hours unchanged. [Behavior and command details](development | 2026-11-05 | minor | Document tabs are reordered by dragging them along the tab strip (`document.move`, #5663). | | 2026-11-04 | minor | Path Precision Tools add-on (a VectorCraft addition): Set Corners… rounds only the corners in an angle range (#5545); scores and estimates unchanged | | 2026-11-04 | minor | Path Precision Tools add-on (a VectorCraft addition): Set Corners… rounds all, the odd-numbered or the even-numbered anchors (#5546); scores and estimates unchanged | +| 2026-11-05 | minor | Compound Shapes add-on (beyond Illustrator): Object › Plug-ins › Compound Shapes lists Make, Release and Expand Compound Shape, and holds a setting, off by default, that makes the Pathfinder panel's Shape Mode buttons make a compound shape on a click and give the permanent result on Alt-click (the default is the reverse). Selected members of a compound shape always take the clicked mode. The setting is `window.pathfinder.compoundShapes`; no existing behavior changes while it is off. Scores and estimates unchanged. | | 2026-11-04 | minor | New Document: the units chosen in Preset Details belong to the chosen document, as the pane's options are listed "for the selected preset" ([public source](https://helpx.adobe.com/illustrator/desktop/add-and-import-files/start-a-new-file/create-and-save-custom-document-presets.html)); the chosen card shows them, every other Recent and Saved card keeps the units its document or preset was made in, and the built-in tabs still follow the chosen units (#2078); scores and estimates unchanged | | 2026-11-01 | minor | Object › Image Trace › Batch Trace Folder asks for a source and a destination folder and traces each image into it (#4921); scores and estimates unchanged | | 2026-11-01 | minor | Edit › Copy and Cut take the selected ruler guides, with the objects or alone; pasting puts them on the layer new art goes to, moved as the objects are (alone: where they were), Paste in Place onto the active artboard and Paste on All Artboards onto each (#3226); scores and estimates unchanged |