From 21c86ddcb7dc9c152d915ac2775de618bec83b1a Mon Sep 17 00:00:00 2001 From: moppeeer Date: Tue, 20 Oct 2026 20:48:43 +0200 Subject: [PATCH 1/2] Layout: Create Guides puts its guides on both pages of the spread in view, as InDesign does Co-Authored-By: Claude Opus 5.5 --- ROADMAP.md | 1 + crates/ui-egui/src/dialogs.rs | 29 ++++++++++++++++------------- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index 0128924c0..5f8ccdf11 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** · Layout › Create Guides puts its guides on both pages of the spread in view, as InDesign does; "This page" in Apply to narrows them to one page. 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/dialogs.rs b/crates/ui-egui/src/dialogs.rs index 8b4043787..407e05775 100644 --- a/crates/ui-egui/src/dialogs.rs +++ b/crates/ui-egui/src/dialogs.rs @@ -869,19 +869,20 @@ fn doc_unit(app: &DesignApp) -> Unit { app.session.active().map(|s| s.doc.settings.horizontal_units).unwrap_or(Unit::Picas) } -/// Layout › Create Guides…: guides go on the page in view (or the parent page being edited), not -/// on the first page, and the gutters are typed in the document's ruler unit. +/// Layout › Create Guides…: guides go on every page of the spread in view (or of the parent +/// spread being edited), as InDesign's do; "This page" narrows them to +/// the page in view. The gutters are typed in the document's ruler unit. pub fn open_create_guides(app: &mut DesignApp) { let unit = doc_unit(app); let Some((spread, page)) = crate::canvas::current_spread_page(app) else { return }; - let editing_parents = matches!(spread, SpreadRef::Parent(_)); let gutter = json!(format_measure(12.0, unit)); let mut d = Dialog::new( "createGuides", json!({"rows": 0, "columns": 0, "rowGutter": gutter, "columnGutter": gutter, "fitTo": "margins", "removeExisting": false, "spread": serde_json::to_value(spread).unwrap_or(json!(0)), "page": page, - // A parent spread is edited as a whole (both pages of a facing spread), so the guides show on every page that uses it. - "target": if editing_parents { "spread" } else { "page" }, + // InDesign puts the guides on both pages of a facing spread (and a parent spread is + // edited as a whole, so they show on every page that uses it). + "target": "spread", "where": target_description(app, spread, page)}), ); d.unit = unit; @@ -9875,18 +9876,20 @@ mod tests { } #[test] - fn create_guides_dialog_targets_the_page_in_view() { + fn create_guides_dialog_covers_the_spread_in_view() { let mut app = facing_app(6); + // As in InDesign, both pages of the facing spread in view get the guides. + crate::canvas::go_to_page(&mut app, 1); + crate::menus::activate(&mut app, "layout.createGuides", &Value::Null); + assert_eq!(app.ui.dialog.as_ref().unwrap().s("target"), "spread"); + ctl(&mut app, "ui.dialog.set", json!({"field": "columns", "value": "2"})); + assert_eq!(ctl(&mut app, "ui.dialog.confirm", json!({}))["ok"], true); + assert_eq!(guide_counts(&app), vec![0, 2, 2, 0, 0, 0]); + // "This page" narrows them to the page in view. crate::canvas::go_to_page(&mut app, 4); crate::menus::activate(&mut app, "layout.createGuides", &Value::Null); ctl(&mut app, "ui.dialog.set", json!({"field": "columns", "value": "3"})); - assert_eq!(ctl(&mut app, "ui.dialog.confirm", json!({}))["ok"], true); - assert_eq!(guide_counts(&app), vec![0, 0, 0, 0, 4, 0]); - // "Both pages of the spread" covers the facing pair. - crate::canvas::go_to_page(&mut app, 1); - crate::menus::activate(&mut app, "layout.createGuides", &Value::Null); - ctl(&mut app, "ui.dialog.set", json!({"field": "columns", "value": "2"})); - ctl(&mut app, "ui.dialog.set", json!({"field": "target", "value": "spread"})); + ctl(&mut app, "ui.dialog.set", json!({"field": "target", "value": "page"})); assert_eq!(ctl(&mut app, "ui.dialog.confirm", json!({}))["ok"], true); assert_eq!(guide_counts(&app), vec![0, 2, 2, 0, 4, 0]); } From e7a29a8ad5968f873b5bbbdb9fa5b26cf0413b6a Mon Sep 17 00:00:00 2001 From: moppeeer Date: Thu, 29 Oct 2026 13:55:33 +0100 Subject: [PATCH 2/2] rustfmt Co-Authored-By: Claude Opus 5.5 --- crates/ui-egui/src/dialogs/tests.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/crates/ui-egui/src/dialogs/tests.rs b/crates/ui-egui/src/dialogs/tests.rs index 900407f5e..7d1f217b7 100644 --- a/crates/ui-egui/src/dialogs/tests.rs +++ b/crates/ui-egui/src/dialogs/tests.rs @@ -3469,20 +3469,20 @@ fn guide_counts(app: &DesignApp) -> Vec { } #[test] - fn create_guides_dialog_covers_the_spread_in_view() { +fn create_guides_dialog_covers_the_spread_in_view() { let mut app = facing_app(6); - // As in InDesign, both pages of the facing spread in view get the guides. + // As in InDesign, both pages of the facing spread in view get the guides. crate::canvas::go_to_page(&mut app, 1); crate::menus::activate(&mut app, "layout.createGuides", &Value::Null); - assert_eq!(app.ui.dialog.as_ref().unwrap().s("target"), "spread"); + assert_eq!(app.ui.dialog.as_ref().unwrap().s("target"), "spread"); ctl(&mut app, "ui.dialog.set", json!({"field": "columns", "value": "2"})); - assert_eq!(ctl(&mut app, "ui.dialog.confirm", json!({}))["ok"], true); - assert_eq!(guide_counts(&app), vec![0, 2, 2, 0, 0, 0]); - // "This page" narrows them to the page in view. - crate::canvas::go_to_page(&mut app, 4); - crate::menus::activate(&mut app, "layout.createGuides", &Value::Null); - ctl(&mut app, "ui.dialog.set", json!({"field": "columns", "value": "3"})); - ctl(&mut app, "ui.dialog.set", json!({"field": "target", "value": "page"})); + assert_eq!(ctl(&mut app, "ui.dialog.confirm", json!({}))["ok"], true); + assert_eq!(guide_counts(&app), vec![0, 2, 2, 0, 0, 0]); + // "This page" narrows them to the page in view. + crate::canvas::go_to_page(&mut app, 4); + crate::menus::activate(&mut app, "layout.createGuides", &Value::Null); + ctl(&mut app, "ui.dialog.set", json!({"field": "columns", "value": "3"})); + ctl(&mut app, "ui.dialog.set", json!({"field": "target", "value": "page"})); assert_eq!(ctl(&mut app, "ui.dialog.confirm", json!({}))["ok"], true); assert_eq!(guide_counts(&app), vec![0, 2, 2, 0, 4, 0]); }