LR-CROP-STRAIGHTEN: a crop drag cut short leaves nothing behind

Closing the crop tool in the middle of a rotation (Return, Esc) left the
rotate gesture set, as only the canvas's drag-stopped cleared it. Once
the rotation pointer and angle readout were derived from it, reopening
Crop showed both everywhere, over the side panels too, until the next
drag. A crop gesture with no button held is now over.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Nathaniel Ledford
2026-10-09 12:10:50 -04:00
co-authored by Claude Opus 5.5
parent b83ba84a79
commit f34c967900
2 changed files with 37 additions and 0 deletions
+8
View File
@@ -1248,6 +1248,14 @@ fn crop_overlay(app: &mut LightcraftApp, ui: &mut egui::Ui, resp: &egui::Respons
let s = to_straight(n, d.crop.geometry.angle, frame);
d.crop.geometry.rect.contains(Point::new(s.x.clamp(-1.0, 2.0), s.y))
};
// a crop drag cut short (the tool closed before the release) leaves its gesture behind: with no
// button held it is over
if matches!(app.gesture, Some(Gesture::CropRotate { .. } | Gesture::CropHandle { .. }))
&& !resp.drag_stopped()
&& !ui.input(|i| i.pointer.any_down())
{
app.gesture = None;
}
// while rotating, the pointer may leave the canvas: it still shows rotation and the angle
let rotating = matches!(app.gesture, Some(Gesture::CropRotate { .. }));
let pointer = resp.hover_pos().or_else(|| if rotating { ui.input(|i| i.pointer.latest_pos()) } else { None });
+29
View File
@@ -300,3 +300,32 @@ fn moving_the_box_never_shows_rotation() {
assert!(!has(&h, "cropRotateCursor"));
assert_eq!(angle(&h), 0.0, "nothing rotated");
}
/// Closing the crop tool in the middle of a rotation (Return) leaves nothing behind: reopened,
/// the box shows the move pointer and no angle.
#[test]
fn a_rotation_cut_short_leaves_nothing_behind() {
let mut h = crop_tool();
let r = h.request(
"ui.pointer",
json!({"events": [{"kind": "down", "x": -0.05, "y": 0.2}, {"kind": "drag", "x": -0.05, "y": 0.25}, {"kind": "drag", "x": -0.05, "y": 0.3}]}),
T,
);
assert_eq!(r["ok"], true, "{r}");
h.settle(SETTLE);
assert!(has(&h, "cropAngleReadout"), "rotating");
for (method, params) in [
("engine.execute", json!({"command": "tool.done"})),
("ui.pointer", json!({"events": [{"kind": "up", "x": -0.05, "y": 0.3}]})),
("engine.execute", json!({"command": "panel.crop"})),
] {
let r = h.request(method, params, T);
assert_eq!(r["ok"], true, "{r}");
h.settle(SETTLE);
}
let img = h.app.image_rect.expect("the photo on screen");
hover(&mut h, img.center());
assert_eq!(h.last_cursor, egui::CursorIcon::Move);
assert!(!has(&h, "cropAngleReadout"), "no angle");
assert!(!has(&h, "cropRotateCursor"), "no rotation glyph");
}