From 472aeccffd2f894ecb5456c1e5ba64e591ca7d11 Mon Sep 17 00:00:00 2001 From: David Mann Date: Thu, 29 Oct 2026 14:51:25 +0100 Subject: [PATCH] Integration: a shared transform box keeps the held handle's cursor (#8623) Main's handle_at (#5405) read only the one-layer preview's gesture, so with several layers framed the corner being dragged lost its resize pointer once the pointer left the handle (it showed the commit pointer instead). It now reads the shared box's gesture too, through live_gesture. Co-authored-by: ekedal <71788463+ekedal@users.noreply.github.com> Co-Authored-By: Claude Opus 5.5 --- .../src/tools/transform_tool/pointer.rs | 2 +- .../ui-egui/src/tools/transform_tool/tests.rs | 23 +++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/crates/ui-egui/src/tools/transform_tool/pointer.rs b/crates/ui-egui/src/tools/transform_tool/pointer.rs index d8cf0f81eb..6d1553f70d 100644 --- a/crates/ui-egui/src/tools/transform_tool/pointer.rs +++ b/crates/ui-egui/src/tools/transform_tool/pointer.rs @@ -316,7 +316,7 @@ pub(super) fn rotate_dir(t: &TransformSession, gesture: Option, p: [f64 /// The handle a drag in progress holds, else the one under document point `p`. pub(super) fn handle_at(app: &PhotocraftApp, t: &TransformSession, p: [f64; 2], tol: f64) -> Hit { - app.transform_preview.as_ref().and_then(|pv| pv.gesture.map(|g| g.hit)).unwrap_or_else(|| hit(t, p, tol)) + live_gesture(app).map(|g| g.hit).unwrap_or_else(|| hit(t, p, tol)) } /// Cursor for hovering a document point while transforming. `xf` is the canvas's view; diff --git a/crates/ui-egui/src/tools/transform_tool/tests.rs b/crates/ui-egui/src/tools/transform_tool/tests.rs index 3b71dc5a31..b934605b2f 100644 --- a/crates/ui-egui/src/tools/transform_tool/tests.rs +++ b/crates/ui-egui/src/tools/transform_tool/tests.rs @@ -1132,6 +1132,29 @@ fn shared_transform_detects_a_changed_layer_selection() { assert!(multi_selection_changed(&app, app.multi_transform.as_ref().unwrap())); } +/// A shared box keeps the held handle's pointer for the whole drag, as a one-layer box does +/// (#5405): dragged off its corner, the resize pointer doesn't turn into the commit one. +#[test] +fn a_shared_box_keeps_the_held_handles_cursor_during_a_drag() { + let mut app = app_with_square(64, photocraft_geom::Rect::new(8, 8, 24, 24)); + app.ui.extras.snap = false; + let first = app.session.active().unwrap().active_layer.unwrap(); + app.session.execute("layer.new.layer", json!({})).unwrap(); + let second = app.session.active().unwrap().active_layer.unwrap(); + app.session.execute("layer.select", json!({"layer": first.0, "mode": "add"})).unwrap(); + begin_layers(&mut app, vec![first, second], [8.0, 8.0, 48.0, 24.0]).unwrap(); + let xf = ViewXform::active(&app).unwrap(); + let none = egui::Modifiers::NONE; + let corner = cursor(&app, &xf, [48.0, 24.0], none); + let far = cursor(&app, &xf, [48.0, 60.0], none); + assert_ne!(corner, far, "away from the box the pointer differs"); + crate::canvas::tool_event(&mut app, ToolEvent::Down { x: 48.0, y: 24.0, pressure: 1.0 }, none); + crate::canvas::tool_event(&mut app, ToolEvent::Move { x: 48.0, y: 60.0, pressure: 1.0 }, none); + assert!(app.multi_transform.as_ref().is_some_and(|m| m.gesture.is_some()), "the shared box holds the corner"); + assert_eq!(cursor(&app, &xf, [48.0, 60.0], none), corner, "the dragged corner keeps its pointer"); + crate::canvas::tool_event(&mut app, ToolEvent::Up { x: 48.0, y: 60.0 }, none); +} + /// Transform Selection cannot replace a shared transform that is already open. #[test] fn transform_selection_rejects_an_open_multi_transform_without_replacing_it() {