From 88e71d0777175ef52898389b1c7cd6732eb0fc5a Mon Sep 17 00:00:00 2001 From: ashokram-si <347905169+ashokram-si@users.noreply.github.com> Date: Wed, 28 Oct 2026 12:54:59 +0530 Subject: [PATCH] Canvas: the spine follows the shared edge of a right-to-left spread Review follow-up: bound right to left, a spread lists its right page first, so averaging the first page's right edge with the second page's left edge put the line halfway between the outer edges when the pages differ in width. Order the two pages by position and use the edges that meet. Test: a right-to-left spread whose right page is narrower. --- crates/ui-egui/src/canvas/page_decor.rs | 5 ++++- crates/ui-egui/src/canvas/tests.rs | 19 +++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/crates/ui-egui/src/canvas/page_decor.rs b/crates/ui-egui/src/canvas/page_decor.rs index 90119659b..0271b4bcd 100644 --- a/crates/ui-egui/src/canvas/page_decor.rs +++ b/crates/ui-egui/src/canvas/page_decor.rs @@ -82,8 +82,11 @@ fn draw_bleed_and_slug(painter: &egui::Painter, xf: &Xf, doc: &Document, slot: & fn draw_spine(painter: &egui::Painter, xf: &Xf, slot: &SpreadSlot, sp: &designcraft_doc::Spread, t: &Tokens) { let pt = |p: Point| xf.to_screen(slot.xf * p); for pair in sp.pages.windows(2) { + // Bound right to left, a spread lists its right page first: take the two edges that + // meet, whichever page comes first. let (a, b) = (pair[0].bounds(), pair[1].bounds()); - let x = (a.x1 + b.x0) / 2.0; + let (left, right) = if a.x0 <= b.x0 { (a, b) } else { (b, a) }; + let x = (left.x1 + right.x0) / 2.0; let (y0, y1) = (a.y0.min(b.y0), a.y1.max(b.y1)); painter.line_segment([pt(Point::new(x, y0)), pt(Point::new(x, y1))], Stroke::new(hair(painter), t.text_dim)); } diff --git a/crates/ui-egui/src/canvas/tests.rs b/crates/ui-egui/src/canvas/tests.rs index cdb73f3c2..584dd7ba5 100644 --- a/crates/ui-egui/src/canvas/tests.rs +++ b/crates/ui-egui/src/canvas/tests.rs @@ -78,6 +78,25 @@ fn a_spread_shows_a_spine_line_between_its_pages() { assert!(pairs > 0, "the document has a spread with two pages"); } +#[test] +fn the_spine_sits_where_the_pages_of_a_right_to_left_spread_meet() { + // Bound right to left, the spread lists its right page first. With pages of different + // widths, the line must be at their shared edge, not halfway between the outer ones. + let mut app = DesignApp::new(designcraft_engine::Session::new(), crate::Services::default()); + app.run("file.new", serde_json::json!({"pages": 3, "facingPages": true})).unwrap(); + app.run("layout.documentSetup", serde_json::json!({"binding": "rightToLeft"})).unwrap(); + let w = app.session.active().unwrap().doc.settings.page_width; + app.run("layout.pageSize", serde_json::json!({"pages": [2], "width": w * 0.6})).unwrap(); + let shapes = canvas_shapes(&mut app); + let st = app.session.active().unwrap(); + let layout = CanvasLayout::new(&st.doc, false); + let xf = Xf::new(app.canvas_rect.unwrap(), app.view().unwrap()); + let (right, left) = (xf.rect(layout.page_rect(&st.doc, 1).unwrap()), xf.rect(layout.page_rect(&st.doc, 2).unwrap())); + assert!((left.max.x - right.min.x).abs() < 0.01, "page 3 is the left page, page 2 the right"); + assert!((left.width() - right.width()).abs() > 1.0, "the pages differ in width"); + assert_eq!(vertical_lines_at(&shapes, left.max.x, left), 1); +} + #[test] fn the_spine_line_hides_with_the_other_guides() { for (guides, mode) in [(false, ScreenMode::Normal), (true, ScreenMode::Preview), (true, ScreenMode::Presentation)] {