From 3d14ffd722a0ab46df5603c2741fb9818e15d7c7 Mon Sep 17 00:00:00 2001 From: alehel Date: Thu, 29 Oct 2026 14:27:40 +0100 Subject: [PATCH] fix(ui): Add text places a box on a picture and beside a paragraph again With Add text, the page router's hits included Edit text's pictures and paragraph edges, which nothing acts on with Add text, and Add text starts a box only where nobody owns the press: on a scanned page (a picture filling it) no click placed a box, a click within a paragraph's edge grip beside it did nothing, and the cursor over a picture was the hand. Add text now has only the paragraphs' bodies, over their text, where it finishes the box being typed (over_source). New test add_text_places_a_box_on_a_picture_and_beside_a_paragraph, seen failing on the previous commit. From CodeRabbit's review of #5300. Co-Authored-By: Claude Opus 5.5 --- crates/ui-egui/src/canvas.rs | 15 +++++++++---- crates/ui-egui/tests/it/editing.rs | 36 ++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 4 deletions(-) diff --git a/crates/ui-egui/src/canvas.rs b/crates/ui-egui/src/canvas.rs index f843a2ca6c..6bdf5660c6 100644 --- a/crates/ui-egui/src/canvas.rs +++ b/crates/ui-egui/src/canvas.rs @@ -1433,11 +1433,18 @@ impl PageHits<'_> { .filter(|e| !e.has_changes()) .and_then(|e| lines.get(e.block)) .map(|l| xf.user_rect(info, page, l.rect.map(|v| v as f32)).expand(2.0)); + // Add text acts on the page's paragraphs only over their text (it finishes the box + // being typed there): not on pictures, nor beside a paragraph, where a click starts + // a new box. + let edit_text = tool == QuickTool::EditText; + let body = |h: &crate::page_router::Hit| { + matches!(h.owner, crate::page_router::Owner::Paragraph { part: crate::page_router::ParagraphPart::Body, .. }) + }; ( - crate::edit_text_ui::picture_hit(xf, page, info, images, view, p), - crate::edit_text_ui::hit(xf, info, page, lines, open.map(|e| e.block), p), - (tool == QuickTool::EditText).then(|| crate::object_ui::hit(view, xf, info, page, frame, p)).flatten(), - crate::edit_text_ui::picture_handle_hit(clip, xf, page, info, images, view, p), + edit_text.then(|| crate::edit_text_ui::picture_hit(xf, page, info, images, view, p)).flatten(), + crate::edit_text_ui::hit(xf, info, page, lines, open.map(|e| e.block), p).filter(|h| edit_text || body(h)), + edit_text.then(|| crate::object_ui::hit(view, xf, info, page, frame, p)).flatten(), + edit_text.then(|| crate::edit_text_ui::picture_handle_hit(clip, xf, page, info, images, view, p)).flatten(), ) } else { (None, None, None, None) diff --git a/crates/ui-egui/tests/it/editing.rs b/crates/ui-egui/tests/it/editing.rs index be5413b49c..96020a67fd 100644 --- a/crates/ui-egui/tests/it/editing.rs +++ b/crates/ui-egui/tests/it/editing.rs @@ -3935,6 +3935,42 @@ fn editing_existing_images_on_the_page() { check_existing_artwork("picture.png", png); } +/// Add text places a box with a click anywhere off its own boxes: on a scanned page (one picture +/// filling it) too, and just beside a paragraph, where Edit text would rewrap it. +#[test] +fn add_text_places_a_box_on_a_picture_and_beside_a_paragraph() { + let mut png = Vec::new(); + image::RgbImage::from_pixel(80, 40, image::Rgb([200, 40, 40])).write_to(&mut std::io::Cursor::new(&mut png), image::ImageFormat::Png).unwrap(); + let mut h = Harness::builder().with_size(egui::vec2(1400.0, 900.0)).build_eframe(move |_cc| { + let mut app = PdfCraftApp::new(); + app.set_option("language", "en").unwrap(); + app.open_bytes("picture.png", None, png.clone()).expect("opens"); + app + }); + h.run_steps(4); + h.state_mut().quick_tool = pdfcraft_ui_egui::QuickTool::AddText; + h.run_steps(2); + let c = h.state().views[0].page_screen_rect(0).expect("on screen").center(); + h.hover_at(c); + h.run_steps(2); + assert_eq!(h.output().platform_output.cursor_icon, egui::CursorIcon::Text, "the I-beam over the picture"); + click_at(&mut h, c); + assert!(h.state().views[0].content.draft.is_some(), "a click on the picture starts a text box"); + + let mut h = harness(2, |_| {}); + h.state_mut().quick_tool = pdfcraft_ui_egui::QuickTool::AddText; + h.run_steps(2); + let id = h.state().views[0].id; + let block = h.state().session.get(id).unwrap().text_blocks(0)[0].clone(); + let r = h.state().views[0].page_screen_rect(0).expect("on screen"); + let k = r.width() / 200.0; + // 6 px left of the text: 4 px past its box, within a closed paragraph's edge grip in Edit text. + let beside = egui::pos2(r.left() + block.rect[0] as f32 * k, r.top() + (300.0 - ((block.rect[1] + block.rect[3]) / 2.0) as f32) * k) + - egui::vec2(6.0, 0.0); + click_at(&mut h, beside); + assert!(h.state().views[0].content.draft.is_some(), "a click beside the paragraph starts a text box"); +} + #[test] fn dragging_the_rotate_knob_turns_a_page_image() { let mut png = Vec::new();