M1, #1758: a primary drag let go during a pan still ends

This commit is contained in:
ashokram-si committed 2026-11-06 09:50:15 +05:30
1 parent 30a1db7363
commit 971c82b8f1
2 files changed
+48 -14

No files matched your search

+26 -14
View File
@@ -148,6 +148,31 @@ fn import_dropped(app: &mut FigApp, ctx: &egui::Context, hover_pos: Option<egui:
}
}
/// One frame of a pan (the middle or a side button held, or Space + drag): the view follows the
/// pointer from where the pan began, and the pan ends once no button that pans is held.
fn pan_view(app: &mut FigApp, ctx: &egui::Context, pos: Pos2, mods: &egui::Modifiers, middle_down: bool) {
if let Ok(ds) = app.session.ds_mut() {
match app.canvas.middle_pan {
None => app.canvas.middle_pan = Some((pos, ds.view.cx, ds.view.cy)),
Some((p0, cx, cy)) => {
let z = ds.view.zoom.max(1e-6);
ds.view.cx = cx - f64::from(pos.x - p0.x) / z;
ds.view.cy = cy - f64::from(pos.y - p0.y) / z;
ds.revision += 1;
}
}
}
// A primary drag under way when the pan began ends when its button is let go, pan or
// not: the engine gets its release here, as it does over the canvas or off it.
if app.canvas.dragging && !ctx.input(|i| i.pointer.primary_down()) {
app.canvas.dragging = false;
send(app, PointerKind::Up, pos, mods);
}
if !middle_down && !ctx.input(|i| i.pointer.primary_down()) {
app.canvas.middle_pan = None;
}
}
/// The pointer and keys on the canvas. False when something on it with a cursor of its own has
/// the pointer (a comment pin, a ruler guide, a gradient or padding handle): the tool's cursor
/// then doesn't show.
@@ -224,20 +249,7 @@ pub(super) fn input(app: &mut FigApp, ui: &mut Ui, resp: &egui::Response) -> boo
// Middle-button (or side-button) / space panning.
let middle_down = ctx.input(pan_button_down);
if (middle_down || (app.canvas.space_pan && ctx.input(|i| i.pointer.primary_down()))) && resp.hovered() || app.canvas.middle_pan.is_some() {
if let Ok(ds) = app.session.ds_mut() {
match app.canvas.middle_pan {
None => app.canvas.middle_pan = Some((pos, ds.view.cx, ds.view.cy)),
Some((p0, cx, cy)) => {
let z = ds.view.zoom.max(1e-6);
ds.view.cx = cx - f64::from(pos.x - p0.x) / z;
ds.view.cy = cy - f64::from(pos.y - p0.y) / z;
ds.revision += 1;
}
}
}
if !middle_down && !ctx.input(|i| i.pointer.primary_down()) {
app.canvas.middle_pan = None;
}
pan_view(app, &ctx, pos, &mods, middle_down);
return true;
}
// A handle drag whose button went up ends first, wherever on the canvas the pointer is: over a
@@ -109,3 +109,25 @@ fn side_buttons_pan_like_the_middle_button() {
check_button(b, false, true);
}
}
/// A primary drag under way when a pan starts (a side or the middle button pressed mid-drag) ends
/// when the primary button is let go during the pan: the engine gets the release, so its gesture
/// isn't left open once the pan is over.
#[test]
fn a_primary_drag_released_during_a_pan_ends() {
for pan in [PointerButton::Middle, PointerButton::Extra1] {
let mut u = Frames::new();
let rect = u.app.canvas.rect;
let start = Pos2::new(rect.min.x + 200.0, rect.center().y);
let moved = Pos2::new(rect.min.x + 400.0, rect.center().y);
u.frame(vec![Event::PointerMoved(start)]);
u.frame(vec![button(start, PointerButton::Primary, true)]);
u.frame(vec![Event::PointerMoved(moved)]);
assert!(u.app.session.tool.busy(), "{pan:?}: a primary drag is under way");
u.frame(vec![button(moved, pan, true)]);
u.frame(vec![button(moved, PointerButton::Primary, false)]);
u.frame(vec![button(moved, pan, false)]);
u.frame(vec![]);
assert!(!u.app.session.tool.busy(), "{pan:?}: the primary release reached the engine");
}
}