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 <noreply@anthropic.com>
This commit is contained in:
alehel
2026-10-29 14:27:40 +01:00
co-authored by Claude Opus 5.5
parent 4b3033c869
commit 3d14ffd722
2 changed files with 47 additions and 4 deletions
+11 -4
View File
@@ -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)
+36
View File
@@ -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();