feat(iced): add transform handle hit-testing
This commit is contained in:
@@ -66,6 +66,8 @@ struct OverlayState {
|
|||||||
cursor_pos: Option<Point>,
|
cursor_pos: Option<Point>,
|
||||||
/// Whether the mouse is over the overlay.
|
/// Whether the mouse is over the overlay.
|
||||||
is_hovered: bool,
|
is_hovered: bool,
|
||||||
|
/// Current handle being hovered (for cursor changes).
|
||||||
|
hovered_handle: TransformHandle,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OverlayProgram {
|
impl OverlayProgram {
|
||||||
@@ -84,6 +86,69 @@ impl OverlayProgram {
|
|||||||
(ox, oy, display_w, display_h)
|
(ox, oy, display_w, display_h)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Test which transform handle is at the given viewport position.
|
||||||
|
pub fn hit_test_handle(
|
||||||
|
&self,
|
||||||
|
viewport_x: f32,
|
||||||
|
viewport_y: f32,
|
||||||
|
) -> TransformHandle {
|
||||||
|
let Some(ref tr) = self.selection_transform else {
|
||||||
|
return TransformHandle::None;
|
||||||
|
};
|
||||||
|
if tr.is_empty() {
|
||||||
|
return TransformHandle::None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let (origin_x, origin_y, _, _) = self.canvas_origin(iced::Size::new(0.0, 0.0));
|
||||||
|
|
||||||
|
// Convert viewport to canvas coordinates
|
||||||
|
let canvas_x = (viewport_x - origin_x) / self.zoom;
|
||||||
|
let canvas_y = (viewport_y - origin_y) / self.zoom;
|
||||||
|
|
||||||
|
let handle_size = TransformHandle::HANDLE_SIZE / self.zoom;
|
||||||
|
let half = handle_size / 2.0;
|
||||||
|
|
||||||
|
let x = tr.pos.x;
|
||||||
|
let y = tr.pos.y;
|
||||||
|
let w = tr.size.x;
|
||||||
|
let h = tr.size.y;
|
||||||
|
|
||||||
|
// Check rotation handle first (it's outside the box)
|
||||||
|
let rotate_y = y - TransformHandle::ROTATE_OFFSET / self.zoom;
|
||||||
|
let rotate_x = x + w / 2.0;
|
||||||
|
let rotate_radius = 4.0 / self.zoom;
|
||||||
|
let dx = canvas_x - rotate_x;
|
||||||
|
let dy = canvas_y - rotate_y;
|
||||||
|
if dx * dx + dy * dy <= rotate_radius * rotate_radius {
|
||||||
|
return TransformHandle::Rotate;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check corner and edge handles
|
||||||
|
let handles = [
|
||||||
|
(TransformHandle::TopLeft, x, y),
|
||||||
|
(TransformHandle::TopRight, x + w, y),
|
||||||
|
(TransformHandle::BottomLeft, x, y + h),
|
||||||
|
(TransformHandle::BottomRight, x + w, y + h),
|
||||||
|
(TransformHandle::Top, x + w / 2.0, y),
|
||||||
|
(TransformHandle::Bottom, x + w / 2.0, y + h),
|
||||||
|
(TransformHandle::Left, x, y + h / 2.0),
|
||||||
|
(TransformHandle::Right, x + w, y + h / 2.0),
|
||||||
|
];
|
||||||
|
|
||||||
|
for (handle, hx, hy) in &handles {
|
||||||
|
if (canvas_x - hx).abs() <= half && (canvas_y - hy).abs() <= half {
|
||||||
|
return *handle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if inside the selection box (for move)
|
||||||
|
if canvas_x >= x && canvas_x <= x + w && canvas_y >= y && canvas_y <= y + h {
|
||||||
|
return TransformHandle::Move;
|
||||||
|
}
|
||||||
|
|
||||||
|
TransformHandle::None
|
||||||
|
}
|
||||||
|
|
||||||
/// Draw transform handles for selection.
|
/// Draw transform handles for selection.
|
||||||
fn draw_transform_handles(
|
fn draw_transform_handles(
|
||||||
&self,
|
&self,
|
||||||
@@ -291,11 +356,19 @@ impl canvas::Program<Message> for OverlayProgram {
|
|||||||
);
|
);
|
||||||
state.cursor_pos = Some(local_pos);
|
state.cursor_pos = Some(local_pos);
|
||||||
state.is_hovered = bounds.contains(position);
|
state.is_hovered = bounds.contains(position);
|
||||||
|
|
||||||
|
// Update hovered handle
|
||||||
|
if self.selection_transform.is_some() {
|
||||||
|
state.hovered_handle = self.hit_test_handle(position.x, position.y);
|
||||||
|
} else {
|
||||||
|
state.hovered_handle = TransformHandle::None;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
if state.is_hovered && !cursor.is_over(bounds) {
|
if state.is_hovered && !cursor.is_over(bounds) {
|
||||||
state.is_hovered = false;
|
state.is_hovered = false;
|
||||||
state.cursor_pos = None;
|
state.cursor_pos = None;
|
||||||
|
state.hovered_handle = TransformHandle::None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user