Merge branch 'pr/527' into batch1

This commit is contained in:
Brandon Thomas committed 2026-10-13 02:23:11 -04:00
commit 160ae04b8b
5 files changed
+124 -35

No files matched your search

+1
View File
@@ -143,6 +143,7 @@ Newest first.
- **2026-10-12** · The Tools panel's Fill/Stroke keys work: D (default fill and stroke), X (fill or stroke in front), Shift+X (swap per object, tints included) and / (Apply None), as `color.*` commands; swap and default are one undo step (`object.swapFillStroke`, `object.defaultFillStroke`); the Color panel follows the proxy's fill/stroke choice. No readiness percentage change.
- **2026-10-11** · Corner Options keep curved sides curved and round every corner point, including where an arc meets a line (a Pathfinder quarter circle with rounded corners stayed a triangle). No readiness percentage change.
- **2026-10-11** · `story.replaceRange`, `story.setText`, notes, footnotes, endnotes, type on a path and table cells read `\r` and `\r\n` as paragraph returns, as `frame.create` and `text.insert` already did. No readiness percentage change.
- **2026-10-11** · The View menu follows InDesign's: proofing first, then zoom, Rotate Spread, Screen Mode, Display Performance, rulers, Extras, Grids & Guides and Structure; the view items that sat at the end of the Type menu moved there. No readiness percentage change.
- **2026-10-12** · Words in capitals hyphenate like capitalized words (FERRUM COM-MODI), as in InDesign; Hyphenate Capitalized Words off keeps them whole. No readiness percentage change.
- **2026-10-11** · `transform.move {copy}`, Edit › Duplicate and Step and Repeat return the copies' ids, so a script can go on with them. No readiness percentage change.
- **2026-10-11** · `object.fill` and `object.stroke` refuse a swatch name the document doesn't have (it painted nothing) and suggest the name meant (`Paper` → `[Paper]`). No readiness percentage change.
+3
View File
@@ -2822,6 +2822,9 @@ const TABLE: &[(&str, [&str; 5])] = &[
("Paragraph Rules", ["Absatzlinien", "Filets de paragraphe", "Filetes de párrafo", "段落境界線", "段落线"]),
("Rule Below", ["Linie unterhalb", "Filet après", "Filete después", "後境界線", "下方横线"]),
("Tint:", ["Farbton:", "Teinte:", "Matiz:", "濃淡:", "色调:"]),
("Slug", ["Infobereich", "Ligne-bloc", "Indicaciones", "印刷可能領域", "辅助信息区"]),
("Presentation", ["Präsentation", "Présentation", "Presentación", "プレゼンテーション", "演示文稿"]),
("Extras", ["Extras", "Options supplémentaires", "Extras", "エクストラ", "附加"]),
("Column", ["Spalte", "Colonne", "Columna", "段", "栏"]),
];
+1
View File
@@ -1498,4 +1498,5 @@ pub(super) const TABLE: &[(&str, &str)] = &[
("Paragraph Rules", "Filetti paragrafo"),
("Rule Below", "Filetto sotto"),
("Tint:", "Tinta:"),
("Presentation", "Presentazione"),
];
+6 -3
View File
@@ -1555,15 +1555,18 @@ pub(super) const TABLE: &[(&str, &str)] = &[
("Type/Insert Special Character/Quotation Marks", "書式/特殊文字を挿入/引用符"),
("Type/Insert Special Character/Symbols", "書式/特殊文字を挿入/記号"),
("Type/Insert White Space", "書式/空白文字を挿入"),
("Type/Proof Setup", "書式/カラー校正設定"),
("Type/Rotate Spread", "書式/スプレッドを回転"),
("Type/Separations Preview", "書式/分版プレビュー"),
("Type/Story Direction", "書式/組み方向"),
("Type/Text Variables", "書式/テキスト変数"),
("Type/Track Changes", "書式/変更を記録"),
("Type/Type on a Path", "書式/パス上のテキスト"),
("View/Display Performance", "表示/表示品質"),
("View/Extras", "表示/表示補助"),
("View/Grids & Guides", "表示/グリッドとガイド"),
("View/Proof Setup", "表示/カラー校正設定"),
("View/Rotate Spread", "表示/スプレッドを回転"),
("View/Screen Mode", "表示/スクリーンモード"),
("View/Separations Preview", "表示/分版プレビュー"),
("View/Structure", "表示/構造"),
("Window/Arrange", "ウィンドウ/配置"),
("Window/Interactive", "ウィンドウ/インタラクティブ"),
("Window/Interface Color Theme", "ウィンドウ/インターフェイスのカラーテーマ"),
+113 -32
View File
@@ -417,34 +417,6 @@ pub const MENUS: &[(&str, &[&str])] = &[
"cmd:type.sizeDown",
"-",
"ui:view.hiddenCharacters",
"ui:view.taggedFrames",
">Rotate Spread",
"ui:view.rotateSpread|90° CW|{\"angle\": 90}",
"ui:view.rotateSpread|90° CCW|{\"angle\": -90}",
"ui:view.rotateSpread|180°|{\"angle\": 180}",
"ui:view.rotateSpread|Clear Rotation|{\"angle\": 0}",
"<",
">Proof Setup",
"ui:view.proofSetup|Working CMYK|{\"target\": \"workingCmyk\"}",
"ui:view.proofSetup|Internet Standard RGB (sRGB)|{\"target\": \"srgb\"}",
"ui:view.proofSetup|Legacy Macintosh RGB|{\"target\": \"legacyMacRgb\"}",
"ui:view.proofSetup|Monitor RGB|{\"target\": \"monitorRgb\"}",
"ui:view.proofSetup|Color Blindness – Protanopia|{\"target\": \"protanopia\"}",
"ui:view.proofSetup|Color Blindness – Deuteranopia|{\"target\": \"deuteranopia\"}",
"-",
"ui:view.proofSetup|Simulate Paper Color|{\"simulatePaper\": \"toggle\"}",
"<",
"ui:view.proofColors",
"ui:view.flattenerPreview",
"ui:view.tagMarkers",
">Separations Preview",
"ui:view.separations|Off|{\"plate\": null, \"inkLimit\": null}",
"ui:view.separations|Cyan|{\"plate\": \"cyan\"}",
"ui:view.separations|Magenta|{\"plate\": \"magenta\"}",
"ui:view.separations|Yellow|{\"plate\": \"yellow\"}",
"ui:view.separations|Black|{\"plate\": \"black\"}",
"ui:view.separations|Ink Limit 300%|{\"inkLimit\": 300}",
"<",
"-",
">Hyperlinks & Cross-References",
"cmd:hyperlink.create",
@@ -636,6 +608,28 @@ pub const MENUS: &[(&str, &[&str])] = &[
(
"View",
&[
"ui:view.overprintPreview",
">Proof Setup",
"ui:view.proofSetup|Working CMYK|{\"target\": \"workingCmyk\"}",
"ui:view.proofSetup|Internet Standard RGB (sRGB)|{\"target\": \"srgb\"}",
"ui:view.proofSetup|Legacy Macintosh RGB|{\"target\": \"legacyMacRgb\"}",
"ui:view.proofSetup|Monitor RGB|{\"target\": \"monitorRgb\"}",
"ui:view.proofSetup|Color Blindness – Protanopia|{\"target\": \"protanopia\"}",
"ui:view.proofSetup|Color Blindness – Deuteranopia|{\"target\": \"deuteranopia\"}",
"-",
"ui:view.proofSetup|Simulate Paper Color|{\"simulatePaper\": \"toggle\"}",
"<",
"ui:view.proofColors",
">Separations Preview",
"ui:view.separations|Off|{\"plate\": null, \"inkLimit\": null}",
"ui:view.separations|Cyan|{\"plate\": \"cyan\"}",
"ui:view.separations|Magenta|{\"plate\": \"magenta\"}",
"ui:view.separations|Yellow|{\"plate\": \"yellow\"}",
"ui:view.separations|Black|{\"plate\": \"black\"}",
"ui:view.separations|Ink Limit 300%|{\"inkLimit\": 300}",
"<",
"ui:view.flattenerPreview",
"-",
"ui:view.zoomIn",
"ui:view.zoomOut",
"ui:view.fitPage",
@@ -644,8 +638,20 @@ pub const MENUS: &[(&str, &[&str])] = &[
"ui:view.actualSize",
"ui:view.entirePasteboard",
"-",
"ui:view.overprintPreview",
"ui:view.togglePreview",
">Rotate Spread",
"ui:view.rotateSpread|90° CW|{\"angle\": 90}",
"ui:view.rotateSpread|90° CCW|{\"angle\": -90}",
"ui:view.rotateSpread|180°|{\"angle\": 180}",
"ui:view.rotateSpread|Clear Rotation|{\"angle\": 0}",
"<",
"-",
">Screen Mode",
"ui:view.screenMode|Normal|{\"mode\": \"normal\"}",
"ui:view.screenMode|Preview|{\"mode\": \"preview\"}",
"ui:view.screenMode|Bleed|{\"mode\": \"bleed\"}",
"ui:view.screenMode|Slug|{\"mode\": \"slug\"}",
"ui:view.screenMode|Presentation|{\"mode\": \"presentation\"}",
"<",
">Display Performance",
"ui:view.fastDisplay",
"ui:view.typicalDisplay",
@@ -653,10 +659,11 @@ pub const MENUS: &[(&str, &[&str])] = &[
"<",
"-",
"ui:view.rulers",
"-",
">Extras",
"ui:view.frameEdges",
"ui:view.textThreads",
"ui:view.hiddenCharacters",
"-",
"<",
">Grids & Guides",
"ui:view.guides",
"ui:view.snapToGuides",
@@ -666,6 +673,11 @@ pub const MENUS: &[(&str, &[&str])] = &[
"-",
"ui:app.deleteAllGuides",
"<",
"-",
">Structure",
"ui:view.taggedFrames",
"ui:view.tagMarkers",
"<",
],
),
(
@@ -1801,6 +1813,17 @@ pub fn checked(app: &DesignApp, id: &str, params: &Value) -> Option<bool> {
"view.proofColors" => app.ui.proof_colors,
"view.flattenerPreview" => app.ui.flattener_preview,
"view.tagMarkers" => app.ui.tag_markers,
"view.screenMode" => {
let mode = match params.get("mode").and_then(Value::as_str) {
Some("normal") => crate::ScreenMode::Normal,
Some("preview") => crate::ScreenMode::Preview,
Some("bleed") => crate::ScreenMode::Bleed,
Some("slug") => crate::ScreenMode::Slug,
Some("presentation") => crate::ScreenMode::Presentation,
_ => return None,
};
app.ui.screen_mode == mode
}
"view.rotateSpread" => match params.get("angle").and_then(Value::as_i64) {
Some(0) => app.session.active().is_some_and(|st| st.doc.spreads.iter().all(|sp| sp.pages.first().is_none_or(|p| p.view_rotation == 0))),
_ => return None,
@@ -2300,6 +2323,64 @@ pub fn quick_apply_items(session: &designcraft_engine::Session, query: &str) ->
mod tests {
use super::*;
/// The entries (command ids) of a menu bar menu, submenus included.
fn menu_ids(title: &str) -> Vec<&'static str> {
let items = MENUS.iter().find(|(t, _)| *t == title).map(|(_, items)| *items).unwrap_or_default();
items.iter().filter_map(|e| e.split_once(':').map(|(_, rest)| rest.split('|').next().unwrap_or(rest))).collect()
}
#[test]
fn view_items_are_in_the_view_menu_as_in_indesign() {
let (view, typ) = (menu_ids("View"), menu_ids("Type"));
for id in [
"view.rotateSpread",
"view.proofSetup",
"view.proofColors",
"view.flattenerPreview",
"view.separations",
"view.taggedFrames",
"view.tagMarkers",
] {
assert!(view.contains(&id), "{id} is in View");
assert!(!typ.contains(&id), "{id} isn't in Type");
}
// Screen Mode and Extras are View submenus; Show Hidden Characters stays in Type.
assert!(view.contains(&"view.screenMode") && view.contains(&"view.frameEdges"));
assert!(typ.contains(&"view.hiddenCharacters") && !view.contains(&"view.hiddenCharacters"));
// W still toggles Normal / Preview without a menu entry.
assert_eq!(ui_label("view.togglePreview").and_then(|c| c.1), Some("W"));
}
/// The submenu paths of a menu bar menu ("View/Screen Mode"), as Edit › Menus keys them.
fn submenu_paths(title: &str) -> Vec<String> {
let items = MENUS.iter().find(|(t, _)| *t == title).map(|(_, items)| *items).unwrap_or_default();
let mut stack = vec![title.to_string()];
let mut out = Vec::new();
for e in items {
if let Some(name) = e.strip_prefix('>') {
let path = format!("{}/{name}", stack.last().map_or("", String::as_str));
out.push(path.clone());
stack.push(path);
} else if *e == "<" {
stack.pop();
}
}
out
}
#[test]
fn screen_mode_shows_the_current_mode_and_view_submenus_are_translated() {
let mut app = DesignApp::new(designcraft_engine::Session::new(), crate::Services::default());
let mode = |app: &DesignApp, m: &str| checked(app, "view.screenMode", &json!({ "mode": m }));
assert_eq!((mode(&app, "normal"), mode(&app, "preview")), (Some(true), Some(false)));
app.ui.screen_mode = crate::ScreenMode::Preview;
assert_eq!((mode(&app, "normal"), mode(&app, "preview")), (Some(false), Some(true)));
// Every View submenu has its Japanese path (Edit › Menus shows them).
for path in submenu_paths("View") {
assert_ne!(crate::i18n::tr("ja", &path), path, "{path} has no Japanese row");
}
}
fn walk(items: &[Item], out: &mut Vec<(String, String, Value)>) {
for it in items {
match it {