KEY-TOGGLEZOOM: a click down and up within one frame keeps its zoom on Space's release

A real mouse can deliver the press and the release in the same egui
frame: no button is down then, so the hand was not marked used and a
quick release of Space ran the tap fallback, zooming straight back.
tick() now also counts a press seen this frame. New headless test sends
both button events in one frame (the synthetic pointer queue sends one
per frame, which is why the existing tests missed it).

Reported by AlexChambers in review.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
helgehelge123
2026-10-24 16:08:51 +02:00
co-authored by Claude Opus 5.5
parent abf0caf201
commit 9e305d642e
2 changed files with 23 additions and 2 deletions
+3 -2
View File
@@ -53,8 +53,9 @@ pub(crate) fn begin(app: &mut LightcraftApp, ctx: &egui::Context) -> bool {
/// zoom as it ends.
pub(crate) fn tick(app: &mut LightcraftApp, ctx: &egui::Context) {
let Some(mut hand) = app.space_hand else { return };
let (held, pointer, now) = ctx.input(|i| (i.key_down(Key::Space), i.pointer.any_down(), i.time));
hand.used |= pointer;
let (held, pointer, pressed, now) = ctx.input(|i| (i.key_down(Key::Space), i.pointer.any_down(), i.pointer.any_pressed(), i.time));
// a quick click can go down and up within one frame: no button is down then, but it pressed
hand.used |= pointer || pressed;
let tool = tool_owns_pointer(app) && app.ui.dialog.is_none();
// held, or let go in the middle of a pan: the hand stays until the button is up
if tool && (held || pointer) {
+20
View File
@@ -158,6 +158,26 @@ fn space_held_click_zooms_to_the_point_clicked_and_back() {
assert_eq!(develop(&h).spots.len(), spots, "a click painted a spot");
}
#[test]
fn a_click_down_and_up_within_one_frame_is_not_a_tap() {
// a real mouse can deliver the press and the release in the same frame: no button is down
// then, yet the click zoomed, and letting go of Space quickly must not zoom back
let mut h = detail(Some("panel.remove"));
space(&mut h, "down");
pointer(&mut h, json!([{"kind": "move", "x": 0.25, "y": 0.3}]));
let img = h.app.image_rect.unwrap();
let pos = egui::pos2(img.left() + 0.25 * img.width(), img.top() + 0.3 * img.height());
for pressed in [true, false] {
h.events.push(egui::Event::PointerButton { pos, button: egui::PointerButton::Primary, pressed, modifiers: egui::Modifiers::NONE });
}
h.step();
let zoomed = Zoom::Percent(h.app.ui.click_zoom as f32);
assert_eq!(h.app.ui.zoom, zoomed, "the click did not zoom");
space(&mut h, "up");
assert!(h.app.space_hand.is_none());
assert_eq!(h.app.ui.zoom, zoomed, "the release toggled the zoom back");
}
#[test]
fn a_tap_over_a_tool_toggles_on_release_and_a_long_hold_does_not() {
let mut h = detail(Some("panel.remove"));