refactor(ui): crop mode's hit is a hit test of its own

Crop mode owns every press on its page, the controls beside its frame included (0595d4d39).
`PageHits::at` made that hit itself. A `Hit` comes from a module's hit test, named `hit` or
`…_hit`, so the cursor, the tip and the press agree, and the Page presses guard holds the page
modules to it. The picture module's `crop_hit` makes it now, and `PageHits::at` asks it first,
as before. No change in behaviour.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
alehelandClaude Opus 5.5 committed 2026-11-02 20:38:09 +01:00
1 parent 168a3cb91e
commit 12e17a1f64
3 files changed
+13 -10

No files matched your search

+3 -9
View File
@@ -1804,18 +1804,12 @@ impl PageHits<'_> {
images,
clip,
} = *self;
// Crop mode owns presses on its page, including the controls beside its
// frame. Underlying paragraphs and the empty-page marquee must not take
// a crop button's press before the image module receives it.
// Crop mode owns every press on its page (`edit_text_ui::crop_hit`).
if tool == QuickTool::EditText
&& can_modify
&& let Some(selection) = view.image_selection.as_ref().filter(|s| s.page == page && s.crop.is_some())
&& let Some(crop) = crate::edit_text_ui::crop_hit(view, page)
{
return vec![crate::page_router::Hit::new(
crate::page_router::Owner::Picture { index: selection.index, part: crate::page_router::PicturePart::Body },
crate::page_cursor::Layer::Handle,
egui::CursorIcon::Default,
)];
return vec![crop];
}
let fields = if preparing {
crate::prepare::hit(xf, info, page, form, field_tool, prepare_allowed, &view.prepare, p)
+2 -1
View File
@@ -23,7 +23,8 @@ mod layout;
pub(crate) use background::TextBackground;
pub use image::{CropMode, DragTarget, ImageAction, ImageDrag, ImageHandle, ImageSelection, image_menu_id};
pub(crate) use image::{
ImageCx, Matrix, body_hit as picture_hit, handle_hit as picture_handle_hit, image_context_menu, image_input, quad_contains, user_to_screen,
ImageCx, Matrix, body_hit as picture_hit, crop_hit, handle_hit as picture_handle_hit, image_context_menu, image_input, quad_contains,
user_to_screen,
};
#[cfg(test)]
use image::{rotate_knob, turn_degrees, turn_degrees_delta};
@@ -519,6 +519,14 @@ pub(crate) fn handle_hit(
Some(Hit::new(picture(PicturePart::Corner(grip)), Layer::Handle, obb.handle_cursor(handle)))
}
/// The picture being cropped on `page`: crop mode owns every press there, the controls beside its
/// frame included, so the paragraphs under it and the empty page's marquee never take a crop
/// button's press before the picture does. `None` when no picture on `page` is being cropped.
pub(crate) fn crop_hit(view: &DocView, page: usize) -> Option<Hit> {
let selection = view.image_selection.as_ref().filter(|s| s.page == page && s.crop.is_some())?;
Some(Hit::new(Owner::Picture { index: selection.index, part: PicturePart::Body }, Layer::Handle, egui::CursorIcon::Default))
}
/// The picture under `p` (its shape, not only its box): a click selects it, a drag moves the
/// selected one. On the text layer, asked before the paragraphs: editable text on top of a
/// picture takes the press.