From d7d9c4230ac26fb0f2416a65bff068134e319def Mon Sep 17 00:00:00 2001 From: moppeeer Date: Tue, 20 Oct 2026 23:38:48 +0200 Subject: [PATCH 1/5] Object menu: InDesign's order and groups, Join/Open/Close Path under Paths, Convert Point Co-Authored-By: Claude Opus 5.5 --- ROADMAP.md | 1 + crates/ui-egui/src/i18n.rs | 2 + crates/ui-egui/src/i18n/ar.rs | 2 + crates/ui-egui/src/i18n/cs.rs | 4 + crates/ui-egui/src/i18n/de.rs | 4 + crates/ui-egui/src/i18n/it.rs | 2 + crates/ui-egui/src/i18n/ja.rs | 2 + crates/ui-egui/src/i18n/ka.rs | 4 + crates/ui-egui/src/i18n/pl.rs | 4 + crates/ui-egui/src/i18n/pt_br.rs | 2 + crates/ui-egui/src/i18n/ru.rs | 4 + crates/ui-egui/src/i18n/uk.rs | 2 + crates/ui-egui/src/menus.rs | 220 +++++++++++++++++++++---------- 13 files changed, 186 insertions(+), 67 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index 0128924c0..57285e793 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -348,6 +348,7 @@ list) · [roadmap.md](docs/roadmap.md) (milestones, plan) · [parity-checklist.m Newest first. +- **2026-10-20** · The Object menu is in InDesign's order and groups; Paths has Join, Open Path and Close Path (Convert Shape lists only shapes, as InDesign's does) and a Convert Point submenu (Plain, Corner, Smooth, Symmetrical) is added. No readiness percentage change. - **2026-10-16** · Type › Reload Fonts (`font.reload`): fonts installed, edited or removed while DesignCraft runs are read again without a restart, and the open documents recompose with them (#328, #547). An edited font file is noticed by its length and modification time; bundled, added and document fonts stay as they are. InDesign does this by itself, so noticing changes automatically is still open (gap 6). No readiness percentage change. - **2026-10-16** · Parents can be deleted from their Pages-panel context menu or `layout.parents.delete {id}`. Applied-page and based-on references are cleared, local override copies survive, and Undo restores the parent. Addresses the deletion portion of #956; no readiness percentage change. - **2026-10-17** · File › Package writes the document's and the IDML's links relative to the package (`Links/logo.png`, `file:Links/logo.png`), so a package holds no path from the machine that made it; opening a document resolves them to the files beside it. Links › Copy Link(s) To still links by full path. (#340). No readiness percentage change. diff --git a/crates/ui-egui/src/i18n.rs b/crates/ui-egui/src/i18n.rs index efe089ef9..22e8a0a87 100644 --- a/crates/ui-egui/src/i18n.rs +++ b/crates/ui-egui/src/i18n.rs @@ -89,6 +89,8 @@ const TABLE: &[(&str, [&str; 5])] = &[ ("Cut", ["Ausschneiden", "Couper", "Cortar", "カット", "剪切"]), ("Copy", ["Kopieren", "Copier", "Copiar", "コピー", "复制"]), ("Paste", ["Einfügen", "Coller", "Pegar", "ペースト", "粘贴"]), + ("Join", ["Join", "Joindre", "Join", "Join", "连接"]), + ("Convert Point", ["Convert Point", "Convertir le point", "Convert Point", "Convert Point", "转换点"]), ("Hide Rulers", ["Lineale ausblenden", "Masquer les règles", "Ocultar reglas", "定規を隠す", "隐藏标尺"]), ("Inches Decimal", ["Zoll dezimal", "Pouces décimaux", "Pulgadas decimales", "インチ(10 進)", "十进制英寸"]), ( diff --git a/crates/ui-egui/src/i18n/ar.rs b/crates/ui-egui/src/i18n/ar.rs index b050de38b..c9e6f463e 100644 --- a/crates/ui-egui/src/i18n/ar.rs +++ b/crates/ui-egui/src/i18n/ar.rs @@ -30,6 +30,8 @@ pub(super) const TABLE: &[(&str, &str)] = &[ ("Cut", "قص"), ("Copy", "نسخ"), ("Paste", "لصق"), + ("Join", "وصل"), + ("Convert Point", "تحويل النقطة"), ("Paste Vector Art", "لصق رسم متجه"), ("Baseline Options", "خيارات خط الأساس"), ("Fixed Number", "عدد ثابت"), diff --git a/crates/ui-egui/src/i18n/cs.rs b/crates/ui-egui/src/i18n/cs.rs index e77e72a1c..dcebc1180 100644 --- a/crates/ui-egui/src/i18n/cs.rs +++ b/crates/ui-egui/src/i18n/cs.rs @@ -31,6 +31,10 @@ pub(super) const TABLE: &[(&str, &str)] = &[ ("Cut", "Vyjmout"), ("Copy", "Kopírovat"), ("Paste", "Vložit"), + ("Join", "Spojit"), + ("Convert Point", "Převést bod"), + ("Plain", "Obyčejný"), + ("Symmetrical", "Symetrický"), ("Reverse Path", "Obrátit cestu"), ("Set Anchor", "Nastavit kotvu"), ("Clear", "Vymazat"), diff --git a/crates/ui-egui/src/i18n/de.rs b/crates/ui-egui/src/i18n/de.rs index efc128858..778f028ae 100644 --- a/crates/ui-egui/src/i18n/de.rs +++ b/crates/ui-egui/src/i18n/de.rs @@ -31,6 +31,10 @@ pub(super) const TABLE: &[(&str, &str)] = &[ ("Cut", "Ausschneiden"), ("Copy", "Kopieren"), ("Paste", "Einfügen"), + ("Join", "Verbinden"), + ("Convert Point", "Punkt konvertieren"), + ("Plain", "Einfach"), + ("Symmetrical", "Symmetrisch"), ("Inches Decimal", "Zoll dezimal"), ("Back", "Zurück"), ("Warning", "Warnung"), diff --git a/crates/ui-egui/src/i18n/it.rs b/crates/ui-egui/src/i18n/it.rs index a918a9829..818eafcf3 100644 --- a/crates/ui-egui/src/i18n/it.rs +++ b/crates/ui-egui/src/i18n/it.rs @@ -28,6 +28,8 @@ pub(super) const TABLE: &[(&str, &str)] = &[ ("Cut", "Taglia"), ("Copy", "Copia"), ("Paste", "Incolla"), + ("Join", "Unisci"), + ("Convert Point", "Converti punto"), ("Paste Vector Art", "Incolla grafica vettoriale"), ("Baseline Options", "Opzioni linea di base"), ("Fixed Number", "Numero fisso"), diff --git a/crates/ui-egui/src/i18n/ja.rs b/crates/ui-egui/src/i18n/ja.rs index 5647ca940..9f98222dd 100644 --- a/crates/ui-egui/src/i18n/ja.rs +++ b/crates/ui-egui/src/i18n/ja.rs @@ -30,6 +30,8 @@ pub(super) const TABLE: &[(&str, &str)] = &[ ("Cut", "カット"), ("Copy", "コピー"), ("Paste", "ペースト"), + ("Join", "連結"), + ("Convert Point", "ポイントを切り換え"), ("Paste Vector Art", "ベクトルアートをペースト"), ("Baseline Options", "ベースラインオプション"), ("Column Rules", "段落境界線"), diff --git a/crates/ui-egui/src/i18n/ka.rs b/crates/ui-egui/src/i18n/ka.rs index d938c2dc7..d0c67ae3c 100644 --- a/crates/ui-egui/src/i18n/ka.rs +++ b/crates/ui-egui/src/i18n/ka.rs @@ -31,6 +31,10 @@ pub(super) const TABLE: &[(&str, &str)] = &[ ("Cut", "ამოჭრა"), ("Copy", "კოპირება"), ("Paste", "ჩასმა"), + ("Join", "შეერთება"), + ("Convert Point", "წერტილის გარდაქმნა"), + ("Plain", "მარტივი"), + ("Symmetrical", "სიმეტრიული"), ("Inches Decimal", "ინჩები (ათობითი)"), ("Back", "უკან"), ("Warning", "გაფრთხილება"), diff --git a/crates/ui-egui/src/i18n/pl.rs b/crates/ui-egui/src/i18n/pl.rs index 68d685d99..4b5763383 100644 --- a/crates/ui-egui/src/i18n/pl.rs +++ b/crates/ui-egui/src/i18n/pl.rs @@ -29,6 +29,10 @@ pub(super) const TABLE: &[(&str, &str)] = &[ ("Cut", "Wytnij"), ("Copy", "Kopiuj"), ("Paste", "Wklej"), + ("Join", "Połącz"), + ("Convert Point", "Konwertuj punkt"), + ("Plain", "Zwykły"), + ("Symmetrical", "Symetryczny"), ("Clear", "Wyczyść"), ("Duplicate", "Powiel"), ("Select All", "Zaznacz wszystko"), diff --git a/crates/ui-egui/src/i18n/pt_br.rs b/crates/ui-egui/src/i18n/pt_br.rs index 8521de594..4042fe559 100644 --- a/crates/ui-egui/src/i18n/pt_br.rs +++ b/crates/ui-egui/src/i18n/pt_br.rs @@ -31,6 +31,8 @@ pub(super) const TABLE: &[(&str, &str)] = &[ ("Cut", "Recortar"), ("Copy", "Copiar"), ("Paste", "Colar"), + ("Join", "Unir"), + ("Convert Point", "Converter ponto"), ("Paste Vector Art", "Colar arte vetorial"), ("Baseline Options", "Opções de linha de base"), ("Fixed Number", "Número fixo"), diff --git a/crates/ui-egui/src/i18n/ru.rs b/crates/ui-egui/src/i18n/ru.rs index 251555ca5..0503aa350 100644 --- a/crates/ui-egui/src/i18n/ru.rs +++ b/crates/ui-egui/src/i18n/ru.rs @@ -33,6 +33,10 @@ pub(super) const TABLE: &[(&str, &str)] = &[ ("Cut", "Вырезать"), ("Copy", "Копировать"), ("Paste", "Вставить"), + ("Join", "Соединить"), + ("Convert Point", "Преобразовать точку"), + ("Plain", "Простая"), + ("Symmetrical", "Симметричная"), ("Clear", "Очистить"), ("Duplicate", "Дублировать"), ("Select All", "Выделить все"), diff --git a/crates/ui-egui/src/i18n/uk.rs b/crates/ui-egui/src/i18n/uk.rs index dd4a1434d..e21385496 100644 --- a/crates/ui-egui/src/i18n/uk.rs +++ b/crates/ui-egui/src/i18n/uk.rs @@ -29,6 +29,8 @@ pub(super) const TABLE: &[(&str, &str)] = &[ ("Cut", "Вирізати"), ("Copy", "Копіювати"), ("Paste", "Вставити"), + ("Join", "Зʼєднати"), + ("Convert Point", "Перетворити точку"), ("Paste Vector Art", "Вставити векторну графіку"), ("Baseline Options", "Параметри базової лінії"), ("Fixed Number", "Фіксована кількість"), diff --git a/crates/ui-egui/src/menus.rs b/crates/ui-egui/src/menus.rs index 79b8b2c4e..667593746 100644 --- a/crates/ui-egui/src/menus.rs +++ b/crates/ui-egui/src/menus.rs @@ -597,57 +597,12 @@ pub const MENUS: &[(&str, &[&str])] = &[ "cmd:transform.again|Transform Sequence Again|{\"sequence\": true}", "cmd:transform.again|Transform Sequence Again Individually|{\"sequence\": true, \"individually\": true}", "<", - ">Flex Layout", - "cmd:flex.add", - "cmd:flex.convert", - "cmd:flex.remove", - "-", - "ui:window.panel|Show Flex Controls|{\"panel\": \"flexLayout\"}", - "<", - ">Paths", - "cmd:object.makeCompoundPath", - "cmd:object.releaseCompoundPath", - "-", - "cmd:path.reverse", - "<", - ">Pathfinder", - "cmd:object.pathfinder|Add|{\"op\": \"add\"}", - "cmd:object.pathfinder|Subtract|{\"op\": \"subtract\"}", - "cmd:object.pathfinder|Intersect|{\"op\": \"intersect\"}", - "cmd:object.pathfinder|Exclude Overlap|{\"op\": \"exclude\"}", - "cmd:object.pathfinder|Minus Back|{\"op\": \"minusBack\"}", - "<", ">Arrange", "cmd:object.bringToFront", "cmd:object.bringForward", "cmd:object.sendBackward", "cmd:object.sendToBack", "<", - "-", - "cmd:object.group", - "cmd:object.ungroup", - "cmd:object.lock", - "cmd:object.unlockAll", - "cmd:object.hide", - "cmd:object.showAll", - "-", - "cmd:object.textFrameOptions", - "ui:app.layerOptions", - "cmd:object.exportOptions", - "cmd:object.primaryTextFrame", - "cmd:object.cornerOptions", - "-", - ">Effects", - "ui:effects.dialog|Transparency…|{\"page\": \"transparency\"}", - "cmd:object.dropShadow", - "cmd:object.innerShadow", - "cmd:object.outerGlow", - "cmd:object.innerGlow", - "cmd:object.bevel", - "cmd:object.satin", - "cmd:object.feather", - "cmd:object.directionalFeather", - "<", ">Select", "cmd:select.firstAbove", "cmd:select.nextAbove", @@ -660,34 +615,23 @@ pub const MENUS: &[(&str, &[&str])] = &[ "cmd:select.previousInGroup", "cmd:select.nextInGroup", "<", - ">Convert Shape", - "cmd:object.convertShape|Rectangle|{\"to\": \"rectangle\"}", - "cmd:object.convertShape|Rounded Rectangle|{\"to\": \"roundedRectangle\"}", - "cmd:object.convertShape|Beveled Rectangle|{\"to\": \"beveledRectangle\"}", - "cmd:object.convertShape|Inverse Rounded Rectangle|{\"to\": \"inverseRoundedRectangle\"}", - "cmd:object.convertShape|Ellipse|{\"to\": \"ellipse\"}", - "cmd:object.convertShape|Triangle|{\"to\": \"triangle\"}", - "cmd:object.convertShape|Polygon|{\"to\": \"polygon\"}", - "cmd:object.convertShape|Line|{\"to\": \"line\"}", - "cmd:object.convertShape|Orthogonal Line|{\"to\": \"orthogonalLine\"}", "-", - "cmd:object.convertShape|Open Path|{\"to\": \"openPath\"}", - "cmd:object.convertShape|Closed Path|{\"to\": \"closedPath\"}", - "<", + "cmd:object.group", + "cmd:object.ungroup", + "cmd:object.lock", + "cmd:object.unlockAll", + "cmd:object.hide", + "cmd:object.showAll", + "-", "ui:app.qrCode", - ">Clipping Path", - "cmd:object.clippingPathOptions|None|{\"type\": \"none\"}", - "cmd:object.clippingPath|Alpha Channel|{\"type\": \"alpha\"}", - "cmd:object.clippingPath|Detect Edges|{\"type\": \"edges\"}", - "<", - ">Captions", - "cmd:object.caption", - "cmd:object.caption|Generate Live Caption|{\"live\": true}", - "<", + "-", + "cmd:object.textFrameOptions", + "cmd:object.primaryTextFrame", ">Anchored Object", "cmd:anchored.options", "cmd:anchored.release", "<", + "-", ">Fitting", "ui:fit.fillFrameProportionally", "ui:fit.contentProportionally", @@ -702,6 +646,73 @@ pub const MENUS: &[(&str, &[&str])] = &[ "cmd:object.content|Text|{\"type\":\"text\"}", "cmd:object.content|Unassigned|{\"type\":\"unassigned\"}", "<", + "-", + ">Effects", + "ui:effects.dialog|Transparency…|{\"page\": \"transparency\"}", + "cmd:object.dropShadow", + "cmd:object.innerShadow", + "cmd:object.outerGlow", + "cmd:object.innerGlow", + "cmd:object.bevel", + "cmd:object.satin", + "cmd:object.feather", + "cmd:object.directionalFeather", + "<", + "cmd:object.cornerOptions", + "-", + "ui:app.layerOptions", + "cmd:object.exportOptions", + ">Captions", + "cmd:object.caption", + "cmd:object.caption|Generate Live Caption|{\"live\": true}", + "<", + ">Clipping Path", + "cmd:object.clippingPathOptions|None|{\"type\": \"none\"}", + "cmd:object.clippingPath|Alpha Channel|{\"type\": \"alpha\"}", + "cmd:object.clippingPath|Detect Edges|{\"type\": \"edges\"}", + "<", + "-", + ">Flex Layout", + "cmd:flex.add", + "cmd:flex.convert", + "cmd:flex.remove", + "-", + "ui:window.panel|Show Flex Controls|{\"panel\": \"flexLayout\"}", + "<", + "-", + ">Paths", + "cmd:path.join", + "cmd:object.convertShape|Open Path|{\"to\": \"openPath\"}", + "cmd:object.convertShape|Close Path|{\"to\": \"closedPath\"}", + "cmd:path.reverse", + "-", + "cmd:object.makeCompoundPath", + "cmd:object.releaseCompoundPath", + "<", + ">Pathfinder", + "cmd:object.pathfinder|Add|{\"op\": \"add\"}", + "cmd:object.pathfinder|Subtract|{\"op\": \"subtract\"}", + "cmd:object.pathfinder|Intersect|{\"op\": \"intersect\"}", + "cmd:object.pathfinder|Exclude Overlap|{\"op\": \"exclude\"}", + "cmd:object.pathfinder|Minus Back|{\"op\": \"minusBack\"}", + "<", + ">Convert Shape", + "cmd:object.convertShape|Rectangle|{\"to\": \"rectangle\"}", + "cmd:object.convertShape|Rounded Rectangle|{\"to\": \"roundedRectangle\"}", + "cmd:object.convertShape|Beveled Rectangle|{\"to\": \"beveledRectangle\"}", + "cmd:object.convertShape|Inverse Rounded Rectangle|{\"to\": \"inverseRoundedRectangle\"}", + "cmd:object.convertShape|Ellipse|{\"to\": \"ellipse\"}", + "cmd:object.convertShape|Triangle|{\"to\": \"triangle\"}", + "cmd:object.convertShape|Polygon|{\"to\": \"polygon\"}", + "cmd:object.convertShape|Line|{\"to\": \"line\"}", + "cmd:object.convertShape|Orthogonal Line|{\"to\": \"orthogonalLine\"}", + "<", + ">Convert Point", + "cmd:path.convertPoints|Plain|{\"kind\": \"plain\"}", + "cmd:path.convertPoints|Corner|{\"kind\": \"corner\"}", + "cmd:path.convertPoints|Smooth|{\"kind\": \"smooth\"}", + "cmd:path.convertPoints|Symmetrical|{\"kind\": \"symmetrical\"}", + "<", ], ), ( @@ -3254,6 +3265,81 @@ mod tests { items.iter().filter_map(|e| e.split_once(':').map(|(_, rest)| rest.split('|').next().unwrap_or(rest))).collect() } + /// The Object menu's top level in InDesign's order and groups (as InDesign 2023 shows it in + /// Learn Skills Daily's course), with Paths holding Join, Open and Close Path, Convert Shape + /// only shapes, and a Convert Point submenu. + #[test] + fn the_object_menu_is_in_indesigns_order() { + let items = MENUS.iter().find(|(t, _)| *t == "Object").map(|(_, items)| *items).unwrap(); + // The top-level entries: submenus by name, separators as "-", items by command id. + let mut top = Vec::new(); + let mut depth = 0; + for e in items { + match *e { + "<" => depth -= 1, + e if e.starts_with('>') => { + if depth == 0 { + top.push(e.trim_start_matches('>')); + } + depth += 1; + } + e if depth == 0 => top.push(e.split_once(':').map_or(e, |(_, r)| r.split('|').next().unwrap_or(r))), + _ => {} + } + } + assert_eq!( + top, + [ + "Transform", + "Transform Again", + "Arrange", + "Select", + "-", + "object.group", + "object.ungroup", + "object.lock", + "object.unlockAll", + "object.hide", + "object.showAll", + "-", + "app.qrCode", + "-", + "object.textFrameOptions", + "object.primaryTextFrame", + "Anchored Object", + "-", + "Fitting", + "Content", + "-", + "Effects", + "object.cornerOptions", + "-", + "app.layerOptions", + "object.exportOptions", + "Captions", + "Clipping Path", + "-", + "Flex Layout", + "-", + "Paths", + "Pathfinder", + "Convert Shape", + "Convert Point", + ] + ); + let ids = menu_ids("Object"); + for id in ["path.join", "path.reverse", "path.convertPoints"] { + assert!(ids.contains(&id), "{id}"); + } + let sub = |name: &str| { + let i = items.iter().position(|e| *e == format!(">{name}")).unwrap(); + items[i + 1..].iter().take_while(|e| **e != "<").copied().collect::>() + }; + assert!(sub("Paths").iter().any(|e| e.contains("|Open Path|")) && sub("Paths").iter().any(|e| e.contains("|Close Path|"))); + assert!(!sub("Convert Shape").iter().any(|e| e.contains("openPath") || e.contains("closedPath")), "shapes only"); + assert_eq!(sub("Convert Point").len(), 4); + } + #[test] fn view_items_are_in_the_view_menu_as_in_indesign() { let (view, typ) = (menu_ids("View"), menu_ids("Type")); From aa66d3455790710109185fb2eb1875c6f40f758e Mon Sep 17 00:00:00 2001 From: moppeeer Date: Wed, 21 Oct 2026 00:29:58 +0200 Subject: [PATCH 2/5] i18n: Spanish for the new labels Co-Authored-By: Claude Opus 5.5 --- crates/ui-egui/src/i18n.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/ui-egui/src/i18n.rs b/crates/ui-egui/src/i18n.rs index 22e8a0a87..1b04cd89c 100644 --- a/crates/ui-egui/src/i18n.rs +++ b/crates/ui-egui/src/i18n.rs @@ -89,8 +89,8 @@ const TABLE: &[(&str, [&str; 5])] = &[ ("Cut", ["Ausschneiden", "Couper", "Cortar", "カット", "剪切"]), ("Copy", ["Kopieren", "Copier", "Copiar", "コピー", "复制"]), ("Paste", ["Einfügen", "Coller", "Pegar", "ペースト", "粘贴"]), - ("Join", ["Join", "Joindre", "Join", "Join", "连接"]), - ("Convert Point", ["Convert Point", "Convertir le point", "Convert Point", "Convert Point", "转换点"]), + ("Join", ["Join", "Joindre", "Unir", "Join", "连接"]), + ("Convert Point", ["Convert Point", "Convertir le point", "Convertir punto", "Convert Point", "转换点"]), ("Hide Rulers", ["Lineale ausblenden", "Masquer les règles", "Ocultar reglas", "定規を隠す", "隐藏标尺"]), ("Inches Decimal", ["Zoll dezimal", "Pouces décimaux", "Pulgadas decimales", "インチ(10 進)", "十进制英寸"]), ( From 7c07c883b0838f1ea41763740308d3a88a5ddc19 Mon Sep 17 00:00:00 2001 From: paaspaas00 <151774837+paaspaas00@users.noreply.github.com> Date: Wed, 21 Oct 2026 12:02:29 +0200 Subject: [PATCH 3/5] =?UTF-8?q?i18n:=20Object/Convert=20Point=20for=20Edit?= =?UTF-8?q?=20=E2=80=BA=20Menus?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 --- crates/ui-egui/src/i18n/ar.rs | 1 + crates/ui-egui/src/i18n/cs.rs | 1 + crates/ui-egui/src/i18n/de.rs | 1 + crates/ui-egui/src/i18n/fr.rs | 1 + crates/ui-egui/src/i18n/ja.rs | 1 + crates/ui-egui/src/i18n/ka.rs | 1 + crates/ui-egui/src/i18n/pl.rs | 1 + crates/ui-egui/src/i18n/ru.rs | 1 + 8 files changed, 8 insertions(+) diff --git a/crates/ui-egui/src/i18n/ar.rs b/crates/ui-egui/src/i18n/ar.rs index c9e6f463e..ff86a04a4 100644 --- a/crates/ui-egui/src/i18n/ar.rs +++ b/crates/ui-egui/src/i18n/ar.rs @@ -1925,6 +1925,7 @@ pub(super) const TABLE: &[(&str, &str)] = &[ ("Object/Fitting", "كائن/ملاءمة"), ("Object/Pathfinder", "كائن/باحث المسارات"), ("Object/Paths", "كائن/مسارات"), + ("Object/Convert Point", "كائن/تحويل النقطة"), ("Object/Select", "كائن/تحديد"), ("Object/Transform", "كائن/تحويل"), ("Object/Transform Again", "كائن/تحويل مجدداً"), diff --git a/crates/ui-egui/src/i18n/cs.rs b/crates/ui-egui/src/i18n/cs.rs index dcebc1180..98cdfe317 100644 --- a/crates/ui-egui/src/i18n/cs.rs +++ b/crates/ui-egui/src/i18n/cs.rs @@ -1609,6 +1609,7 @@ pub(super) const TABLE: &[(&str, &str)] = &[ ("Object/Fitting", "Objekt/Přizpůsobení"), ("Object/Pathfinder", "Objekt/Operace s cestami"), ("Object/Paths", "Objekt/Cesty"), + ("Object/Convert Point", "Objekt/Převést bod"), ("Object/Select", "Objekt/Vybrat"), ("Object/Transform", "Objekt/Transformace"), ("Object/Transform Again", "Objekt/Transformovat znovu"), diff --git a/crates/ui-egui/src/i18n/de.rs b/crates/ui-egui/src/i18n/de.rs index 778f028ae..a12a70295 100644 --- a/crates/ui-egui/src/i18n/de.rs +++ b/crates/ui-egui/src/i18n/de.rs @@ -1639,6 +1639,7 @@ pub(super) const TABLE: &[(&str, &str)] = &[ ("Object/Fitting", "Objekt/Anpassen"), ("Object/Pathfinder", "Objekt/Pathfinder"), ("Object/Paths", "Objekt/Pfade"), + ("Object/Convert Point", "Objekt/Punkt konvertieren"), ("Object/Select", "Objekt/Auswählen"), ("Object/Transform", "Objekt/Transformieren"), ("Object/Transform Again", "Objekt/Erneut transformieren"), diff --git a/crates/ui-egui/src/i18n/fr.rs b/crates/ui-egui/src/i18n/fr.rs index 78c5d5948..d9985411a 100644 --- a/crates/ui-egui/src/i18n/fr.rs +++ b/crates/ui-egui/src/i18n/fr.rs @@ -128,6 +128,7 @@ pub(super) const TABLE: &[(&str, &str)] = &[ ("Object/Fitting", "Objet/Ajustement"), ("Object/Pathfinder", "Objet/Pathfinder"), ("Object/Paths", "Objet/Tracés"), + ("Object/Convert Point", "Objet/Convertir le point"), ("Object/Select", "Objet/Sélectionner"), ("Object/Transform", "Objet/Transformation"), ("Object/Transform Again", "Objet/Répéter la transformation"), diff --git a/crates/ui-egui/src/i18n/ja.rs b/crates/ui-egui/src/i18n/ja.rs index 9f98222dd..0fd41bd4a 100644 --- a/crates/ui-egui/src/i18n/ja.rs +++ b/crates/ui-egui/src/i18n/ja.rs @@ -1841,6 +1841,7 @@ pub(super) const TABLE: &[(&str, &str)] = &[ ("Object/Fitting", "オブジェクト/オブジェクトサイズの調整"), ("Object/Pathfinder", "オブジェクト/パスファインダー"), ("Object/Paths", "オブジェクト/パス"), + ("Object/Convert Point", "オブジェクト/ポイントを切り換え"), ("Object/Select", "オブジェクト/選択"), ("Object/Transform", "オブジェクト/変形"), ("Object/Transform Again", "オブジェクト/変形を再適用"), diff --git a/crates/ui-egui/src/i18n/ka.rs b/crates/ui-egui/src/i18n/ka.rs index d0c67ae3c..6d25d5d72 100644 --- a/crates/ui-egui/src/i18n/ka.rs +++ b/crates/ui-egui/src/i18n/ka.rs @@ -1656,6 +1656,7 @@ pub(super) const TABLE: &[(&str, &str)] = &[ ("Object/Fitting", "ობიექტი/ზომაზე მორგება"), ("Object/Pathfinder", "ობიექტი/ტრაექტორიების ოპერაციები"), ("Object/Paths", "ობიექტი/ტრაექტორიები"), + ("Object/Convert Point", "ობიექტი/წერტილის გარდაქმნა"), ("Object/Select", "ობიექტი/მონიშვნა"), ("Object/Transform", "ობიექტი/გარდაქმნა"), ("Object/Transform Again", "ობიექტი/გარდაქმნის გამეორება"), diff --git a/crates/ui-egui/src/i18n/pl.rs b/crates/ui-egui/src/i18n/pl.rs index 4b5763383..b3e0eb79f 100644 --- a/crates/ui-egui/src/i18n/pl.rs +++ b/crates/ui-egui/src/i18n/pl.rs @@ -1587,6 +1587,7 @@ pub(super) const TABLE: &[(&str, &str)] = &[ ("Object/Fitting", "Obiekt/Dopasowanie"), ("Object/Pathfinder", "Obiekt/Kształtowanie ścieżek"), ("Object/Paths", "Obiekt/Ścieżki"), + ("Object/Convert Point", "Obiekt/Konwertuj punkt"), ("Object/Select", "Obiekt/Zaznacz"), ("Object/Transform", "Obiekt/Przekształć"), ("Object/Transform Again", "Obiekt/Przekształć ponownie"), diff --git a/crates/ui-egui/src/i18n/ru.rs b/crates/ui-egui/src/i18n/ru.rs index 0503aa350..4a1e3d41f 100644 --- a/crates/ui-egui/src/i18n/ru.rs +++ b/crates/ui-egui/src/i18n/ru.rs @@ -1591,6 +1591,7 @@ pub(super) const TABLE: &[(&str, &str)] = &[ ("Object/Fitting", "Объект/Подгонка"), ("Object/Pathfinder", "Объект/Обработка контуров"), ("Object/Paths", "Объект/Контуры"), + ("Object/Convert Point", "Объект/Преобразовать точку"), ("Object/Select", "Объект/Выбрать"), ("Object/Transform", "Объект/Трансформирование"), ("Object/Transform Again", "Объект/Повторить трансформирование"), From 35e2f8e66c8dfcee1c45516fc6ea95e2553c3488 Mon Sep 17 00:00:00 2001 From: moppeeer Date: Thu, 29 Oct 2026 13:51:04 +0100 Subject: [PATCH 4/5] rustfmt Co-Authored-By: Claude Opus 5.5 --- crates/ui-egui/src/menus/tests.rs | 140 +++++++++++++++--------------- 1 file changed, 70 insertions(+), 70 deletions(-) diff --git a/crates/ui-egui/src/menus/tests.rs b/crates/ui-egui/src/menus/tests.rs index 60455a4fc..5f7f5b93d 100644 --- a/crates/ui-egui/src/menus/tests.rs +++ b/crates/ui-egui/src/menus/tests.rs @@ -6,80 +6,80 @@ fn menu_ids(title: &str) -> Vec<&'static str> { items.iter().filter_map(|e| e.split_once(':').map(|(_, rest)| rest.split('|').next().unwrap_or(rest))).collect() } - /// The Object menu's top level in InDesign's order and groups (as InDesign 2023 shows it in - /// Learn Skills Daily's course), with Paths holding Join, Open and Close Path, Convert Shape - /// only shapes, and a Convert Point submenu. - #[test] - fn the_object_menu_is_in_indesigns_order() { - let items = MENUS.iter().find(|(t, _)| *t == "Object").map(|(_, items)| *items).unwrap(); - // The top-level entries: submenus by name, separators as "-", items by command id. - let mut top = Vec::new(); - let mut depth = 0; - for e in items { - match *e { - "<" => depth -= 1, - e if e.starts_with('>') => { - if depth == 0 { - top.push(e.trim_start_matches('>')); - } - depth += 1; +/// The Object menu's top level in InDesign's order and groups (as InDesign 2023 shows it in +/// Learn Skills Daily's course), with Paths holding Join, Open and Close Path, Convert Shape +/// only shapes, and a Convert Point submenu. +#[test] +fn the_object_menu_is_in_indesigns_order() { + let items = MENUS.iter().find(|(t, _)| *t == "Object").map(|(_, items)| *items).unwrap(); + // The top-level entries: submenus by name, separators as "-", items by command id. + let mut top = Vec::new(); + let mut depth = 0; + for e in items { + match *e { + "<" => depth -= 1, + e if e.starts_with('>') => { + if depth == 0 { + top.push(e.trim_start_matches('>')); } - e if depth == 0 => top.push(e.split_once(':').map_or(e, |(_, r)| r.split('|').next().unwrap_or(r))), - _ => {} + depth += 1; } + e if depth == 0 => top.push(e.split_once(':').map_or(e, |(_, r)| r.split('|').next().unwrap_or(r))), + _ => {} } - assert_eq!( - top, - [ - "Transform", - "Transform Again", - "Arrange", - "Select", - "-", - "object.group", - "object.ungroup", - "object.lock", - "object.unlockAll", - "object.hide", - "object.showAll", - "-", - "app.qrCode", - "-", - "object.textFrameOptions", - "object.primaryTextFrame", - "Anchored Object", - "-", - "Fitting", - "Content", - "-", - "Effects", - "object.cornerOptions", - "-", - "app.layerOptions", - "object.exportOptions", - "Captions", - "Clipping Path", - "-", - "Flex Layout", - "-", - "Paths", - "Pathfinder", - "Convert Shape", - "Convert Point", - ] - ); - let ids = menu_ids("Object"); - for id in ["path.join", "path.reverse", "path.convertPoints"] { - assert!(ids.contains(&id), "{id}"); - } - let sub = |name: &str| { - let i = items.iter().position(|e| *e == format!(">{name}")).unwrap(); - items[i + 1..].iter().take_while(|e| **e != "<").copied().collect::>() - }; - assert!(sub("Paths").iter().any(|e| e.contains("|Open Path|")) && sub("Paths").iter().any(|e| e.contains("|Close Path|"))); - assert!(!sub("Convert Shape").iter().any(|e| e.contains("openPath") || e.contains("closedPath")), "shapes only"); - assert_eq!(sub("Convert Point").len(), 4); } + assert_eq!( + top, + [ + "Transform", + "Transform Again", + "Arrange", + "Select", + "-", + "object.group", + "object.ungroup", + "object.lock", + "object.unlockAll", + "object.hide", + "object.showAll", + "-", + "app.qrCode", + "-", + "object.textFrameOptions", + "object.primaryTextFrame", + "Anchored Object", + "-", + "Fitting", + "Content", + "-", + "Effects", + "object.cornerOptions", + "-", + "app.layerOptions", + "object.exportOptions", + "Captions", + "Clipping Path", + "-", + "Flex Layout", + "-", + "Paths", + "Pathfinder", + "Convert Shape", + "Convert Point", + ] + ); + let ids = menu_ids("Object"); + for id in ["path.join", "path.reverse", "path.convertPoints"] { + assert!(ids.contains(&id), "{id}"); + } + let sub = |name: &str| { + let i = items.iter().position(|e| *e == format!(">{name}")).unwrap(); + items[i + 1..].iter().take_while(|e| **e != "<").copied().collect::>() + }; + assert!(sub("Paths").iter().any(|e| e.contains("|Open Path|")) && sub("Paths").iter().any(|e| e.contains("|Close Path|"))); + assert!(!sub("Convert Shape").iter().any(|e| e.contains("openPath") || e.contains("closedPath")), "shapes only"); + assert_eq!(sub("Convert Point").len(), 4); +} #[test] fn view_items_are_in_the_view_menu_as_in_indesign() { From a04852c8cd4fa756cb9895766f4bef679306f417 Mon Sep 17 00:00:00 2001 From: moppeeer Date: Thu, 29 Oct 2026 15:31:57 +0100 Subject: [PATCH 5/5] Georgian: main's rows for the Object menu's point words, once each Co-Authored-By: Claude Opus 5.5 --- crates/ui-egui/src/i18n/ka.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/crates/ui-egui/src/i18n/ka.rs b/crates/ui-egui/src/i18n/ka.rs index b973aaba1..812b8d9a6 100644 --- a/crates/ui-egui/src/i18n/ka.rs +++ b/crates/ui-egui/src/i18n/ka.rs @@ -32,10 +32,6 @@ pub(super) const TABLE: &[(&str, &str)] = &[ ("Cut", "ამოჭრა"), ("Copy", "კოპირება"), ("Paste", "ჩასმა"), - ("Join", "შეერთება"), - ("Convert Point", "წერტილის გარდაქმნა"), - ("Plain", "მარტივი"), - ("Symmetrical", "სიმეტრიული"), ("Restart Numbering", "ნუმერაციის თავიდან დაწყება"), ("Continue Numbering", "ნუმერაციის გაგრძელება"), ("Keep Options…", "შენარჩუნების პარამეტრები…"),