From a44b850dac96fb4a375e9c54f693123fafed54f4 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] 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 | 17 +++++++++++++++-- crates/ui-egui/tests/it/content.rs | 23 +++++++++++++++++++++++ 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/crates/ui-egui/src/content_ui.rs b/crates/ui-egui/src/content_ui.rs index c9d2c33aba..58f954a895 100644 --- a/crates/ui-egui/src/content_ui.rs +++ b/crates/ui-egui/src/content_ui.rs @@ -559,6 +559,19 @@ 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. + // shortcut: lines aligned differently from each other in a box under 60 points keep the + // editor's left edge; anchor each line on its own if such boxes turn out to matter. + let width = r.width().max(60.0); + let uniform = (0..pdfcraft_engine::paragraph_align::count(&draft.text)).all(|i| draft.style.paragraph_align(i) == draft.style.align); + let anchor = match draft.style.align { + pdfcraft_engine::TextAlign::Center if uniform => 0.5, + pdfcraft_engine::TextAlign::Right if uniform => 1.0, + _ => 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); @@ -575,7 +588,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| { @@ -601,7 +614,7 @@ pub(crate) fn editor(ctx: &egui::Context, view: &mut DocView, info: &DocInfo, ad ui.spacing_mut().item_spacing.x = 4.0; let output = egui::TextEdit::multiline(&mut t.text) .font(font) - .desired_width(r.width().max(60.0)) + .desired_width(width) .desired_rows(1) .layouter(&mut layouter) .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 7edb13ef6a..a4024e513e 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") }