From 663368b38d9713aa5340019f4810abc3d2fa0151 Mon Sep 17 00:00:00 2001 From: RiceDee <345114586+RiceDee@users.noreply.github.com> Date: Fri, 23 Oct 2026 10:38:46 +1100 Subject: [PATCH 1/3] fix(ui): the added-text editor keeps the box's alignment Opening a centred or right-aligned Add text box drew its text at the left edge, a layout the box never had, and Ctrl+Z inside the box (which goes to the text, not the document) left it showing that way. The editor now lays the text out with the box's alignment. Justified text is still shown left-aligned while editing (TextEdit can't justify). --- crates/ui-egui/src/content_ui.rs | 8 ++++++++ crates/ui-egui/tests/it/content.rs | 22 ++++++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/crates/ui-egui/src/content_ui.rs b/crates/ui-egui/src/content_ui.rs index 674210529..f8db4c8ca 100644 --- a/crates/ui-egui/src/content_ui.rs +++ b/crates/ui-egui/src/content_ui.rs @@ -560,6 +560,13 @@ pub(crate) fn editor(ctx: &egui::Context, view: &mut DocView, info: &DocInfo, ad // The box is white in every theme, so the caret must not follow the theme (pale in dark mode) (#655). ui.visuals_mut().text_cursor.stroke.color = crate::edit_text_ui::caret_color_on(Color32::WHITE); let [cr, cg, cb] = t.style.color.map(|v| (v.clamp(0.0, 1.0) * 255.0) as u8); + // Laid out as the page draws it, so opening the box doesn't show it realigned. + // shortcut: justified text is shown left-aligned here (TextEdit can't justify), until the editor gets its own layouter. + let halign = match t.style.align { + pdfcraft_engine::TextAlign::Center => egui::Align::Center, + pdfcraft_engine::TextAlign::Right => egui::Align::Max, + pdfcraft_engine::TextAlign::Left | pdfcraft_engine::TextAlign::Justify => egui::Align::Min, + }; ui.horizontal_top(|ui| { ui.spacing_mut().item_spacing.x = 4.0; let resp = ui.add( @@ -567,6 +574,7 @@ pub(crate) fn editor(ctx: &egui::Context, view: &mut DocView, info: &DocInfo, ad .font(font) .desired_width(r.width().max(60.0)) .desired_rows(1) + .horizontal_align(halign) .background_color(if background_ready { Color32::TRANSPARENT } else { Color32::WHITE }) .text_color(Color32::from_rgb(cr, cg, cb)) .hint_text(tl!("Type text")) diff --git a/crates/ui-egui/tests/it/content.rs b/crates/ui-egui/tests/it/content.rs index 515e3e04f..de06d44b1 100644 --- a/crates/ui-egui/tests/it/content.rs +++ b/crates/ui-egui/tests/it/content.rs @@ -715,6 +715,28 @@ fn format_text_panel_sets_alignment_and_lists_planned_controls_disabled() { } /// Where a mode bar tab is, by its label. +/// Opening right-aligned added text to edit it shows it right-aligned, as the page does, not at +/// the box's left edge, where it never was. +#[test] +fn the_text_editor_keeps_the_boxs_alignment() { + let _gpu = gpu(); + let mut h = harness(); + let rect = [40.0, 195.0, 240.0, 210.0]; + let text = pdfcraft_engine::AddedText { rect, text: "Hi".into(), align: pdfcraft_engine::TextAlign::Right, ..Default::default() }; + assert!(h.state_mut().apply_edit(pdfcraft_engine::Edit::AddText { page: 0, text })); + assert!(h.state_mut().execute("edit.text")); + h.run_steps(3); + let point = at(&h, 200.0, 195.0); + click(&mut h, point); + assert_eq!(h.state().views[0].content.draft.as_ref().and_then(|d| d.index), Some(0), "the editor opened on the text"); + h.run_steps(3); + let r = item_on_screen(&h, rect); + let pixels = h.render().unwrap(); + let left = ink(&pixels, egui::Rect::from_min_max(r.min, pos2(r.center().x, r.max.y))); + let right = ink(&pixels, egui::Rect::from_min_max(pos2(r.center().x, r.min.y), r.max)); + assert!(left == 0 && right > 20, "the text is drawn at the right ({left} dark pixels left, {right} right)"); +} + fn mode_tab(h: &Harness<'static, PdfCraftApp>, label: &str) -> egui::Rect { h.get_all_by_role_and_label(egui::accesskit::Role::Button, label).map(|n| n.rect()).find(|r| r.bottom() < 120.0).expect("a mode tab") } From b1795b9d7b8ea818ec192d1b2478af06d378b70f Mon Sep 17 00:00:00 2001 From: RiceDee <345114586+RiceDee@users.noreply.github.com> Date: Fri, 23 Oct 2026 15:23:58 +1100 Subject: [PATCH 2/3] fix(ui): a narrow added-text box keeps its text at its own edge The editor is at least 60 points wide on screen, so a short box can be clicked into. With the box's alignment applied, right-aligned or centred text in a box narrower than that was placed against the wider editor's edge, past the box's right edge. The editor now reaches past a narrow box away from the edge its text keeps, so the text stays where the page draws it. --- crates/ui-egui/src/content_ui.rs | 14 ++++++++++++-- crates/ui-egui/tests/it/content.rs | 23 +++++++++++++++++++++++ 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/crates/ui-egui/src/content_ui.rs b/crates/ui-egui/src/content_ui.rs index f8db4c8ca..1622273e3 100644 --- a/crates/ui-egui/src/content_ui.rs +++ b/crates/ui-egui/src/content_ui.rs @@ -537,6 +537,16 @@ pub(crate) fn editor(ctx: &egui::Context, view: &mut DocView, info: &DocInfo, ad } let r = screen_rect(&xf, info, page, draft.rect); let source_rect = draft.index.map(|_| screen_rect(&xf, info, page, draft.style.rect)); + // At least 60 points wide, so a short box can still be clicked into. Where that is wider than + // the box, the editor reaches past it away from the edge its text keeps (the right edge for + // right-aligned text, both halves for centred), so the text stays where the page draws it. + let width = r.width().max(60.0); + let anchor = match draft.style.align { + pdfcraft_engine::TextAlign::Center => 0.5, + pdfcraft_engine::TextAlign::Right => 1.0, + pdfcraft_engine::TextAlign::Left | pdfcraft_engine::TextAlign::Justify => 0.0, + }; + let at = r.min - egui::vec2((width - r.width()) * anchor, 0.0); let background_ready = draft.index.is_some_and(|index| view.text_background.ready_added(page, index)); let tokens = Tokens::get(ctx); let (mut commit, mut cancel, mut done) = (false, false, false); @@ -548,7 +558,7 @@ pub(crate) fn editor(ctx: &egui::Context, view: &mut DocView, info: &DocInfo, ad egui::Area::new(egui::Id::new(("added-text", view.id.0))) .fade_in(false) .order(egui::Order::Foreground) - .fixed_pos(r.min) + .fixed_pos(at) .constrain_to(view.viewport_rect()) .constrain(false) .show(ctx, |ui| { @@ -572,7 +582,7 @@ pub(crate) fn editor(ctx: &egui::Context, view: &mut DocView, info: &DocInfo, ad let resp = ui.add( egui::TextEdit::multiline(&mut t.text) .font(font) - .desired_width(r.width().max(60.0)) + .desired_width(width) .desired_rows(1) .horizontal_align(halign) .background_color(if background_ready { Color32::TRANSPARENT } else { Color32::WHITE }) diff --git a/crates/ui-egui/tests/it/content.rs b/crates/ui-egui/tests/it/content.rs index de06d44b1..add686846 100644 --- a/crates/ui-egui/tests/it/content.rs +++ b/crates/ui-egui/tests/it/content.rs @@ -737,6 +737,29 @@ fn the_text_editor_keeps_the_boxs_alignment() { assert!(left == 0 && right > 20, "the text is drawn at the right ({left} dark pixels left, {right} right)"); } +/// A box narrower than the editor's least width (60 points on screen): right-aligned text stays +/// at the box's right edge, not the wider editor's, which lies past it. +#[test] +fn the_text_editor_aligns_a_narrow_box_to_its_own_edge() { + let _gpu = gpu(); + let mut h = harness(); + let rect = [40.0, 195.0, 60.0, 210.0]; + let text = pdfcraft_engine::AddedText { rect, text: "Hi".into(), align: pdfcraft_engine::TextAlign::Right, ..Default::default() }; + assert!(h.state_mut().apply_edit(pdfcraft_engine::Edit::AddText { page: 0, text })); + assert!(h.state_mut().execute("edit.text")); + h.run_steps(3); + let point = at(&h, 50.0, 195.0); + click(&mut h, point); + assert_eq!(h.state().views[0].content.draft.as_ref().and_then(|d| d.index), Some(0), "the editor opened on the text"); + h.run_steps(3); + let r = item_on_screen(&h, rect); + assert!(r.width() < 60.0, "the box is narrower than the editor: {}", r.width()); + let pixels = h.render().unwrap(); + let inside = ink(&pixels, r); + let past = ink(&pixels, egui::Rect::from_min_max(pos2(r.right() + 2.0, r.min.y), pos2(r.right() + 40.0, r.max.y))); + assert!(inside > 20 && past == 0, "the text is drawn in its box ({inside} dark pixels in it, {past} past its right edge)"); +} + fn mode_tab(h: &Harness<'static, PdfCraftApp>, label: &str) -> egui::Rect { h.get_all_by_role_and_label(egui::accesskit::Role::Button, label).map(|n| n.rect()).find(|r| r.bottom() < 120.0).expect("a mode tab") } From 950715da0dd311148c849e67194622dbf5a8537d Mon Sep 17 00:00:00 2001 From: RiceDee <345114586+RiceDee@users.noreply.github.com> Date: Fri, 23 Oct 2026 16:23:53 +1100 Subject: [PATCH 3/3] test(ui): the narrow-box tests check the text reaches the box's right edge --- crates/ui-egui/tests/it/content.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/crates/ui-egui/tests/it/content.rs b/crates/ui-egui/tests/it/content.rs index add686846..619352b8f 100644 --- a/crates/ui-egui/tests/it/content.rs +++ b/crates/ui-egui/tests/it/content.rs @@ -756,8 +756,12 @@ fn the_text_editor_aligns_a_narrow_box_to_its_own_edge() { assert!(r.width() < 60.0, "the box is narrower than the editor: {}", r.width()); let pixels = h.render().unwrap(); let inside = ink(&pixels, r); + let edge = ink(&pixels, egui::Rect::from_min_max(pos2(r.right() - r.width() * 0.25, r.min.y), r.max)); let past = ink(&pixels, egui::Rect::from_min_max(pos2(r.right() + 2.0, r.min.y), pos2(r.right() + 40.0, r.max.y))); - assert!(inside > 20 && past == 0, "the text is drawn in its box ({inside} dark pixels in it, {past} past its right edge)"); + assert!( + inside > 20 && edge > 0 && past == 0, + "the text is drawn in its box, up to its right edge ({inside} dark pixels in it, {edge} in its last quarter, {past} past it)" + ); } fn mode_tab(h: &Harness<'static, PdfCraftApp>, label: &str) -> egui::Rect {