diff --git a/crates/ui-egui/src/grid/interact.rs b/crates/ui-egui/src/grid/interact.rs index a7bbede7e..4b7adf587 100644 --- a/crates/ui-egui/src/grid/interact.rs +++ b/crates/ui-egui/src/grid/interact.rs @@ -124,16 +124,18 @@ pub(super) fn interact(app: &mut SheetApp, ui: &mut egui::Ui, resp: &egui::Respo // A drag is recognised only after the pointer has moved, so grab the object where the press began. let at = if primary_drag { pointer.press_origin().map(|p| geo.mirror_pos(p)).or(pos) } else { pos }; // The selected object's handles reach a little outside it, so they win over hit-testing. - let on_handle = at.and_then(|p| crate::chartview::selected_handle(app, geo, sh, p)).map(|(o, r, _)| (o, r)); + // Only they resize: a press anywhere on another object selects and moves it, as the + // hover cursor shows. + let on_handle = at.and_then(|p| crate::chartview::selected_handle(app, geo, sh, p)); + let handle = on_handle.map(|(.., h)| h); if let Some(p) = at - && let Some((obj, rect)) = on_handle.or_else(|| crate::chartview::hit(app, geo, sh, p)) + && let Some((obj, _)) = on_handle.map(|(o, r, _)| (o, r)).or_else(|| crate::chartview::hit(app, geo, sh, p)) { app.selected_object = Some(obj); if resp.double_clicked() && app.open_object(obj) != crate::objects::OpenAction::Select { return; } if primary_drag && let Some(a) = sh.object_anchor(obj) { - let handle = crate::objects::handle_at(rect, p); app.grid.drag = Drag::Object { obj, start: p, orig: (a.cell, a.dx, a.dy, a.width, a.height), handle, stepped: false }; // The first recognised drag frame already holds movement away from the press. if let Some(now) = pos { diff --git a/crates/ui-egui/tests/it/objects.rs b/crates/ui-egui/tests/it/objects.rs index 521a2f44c..e3382352d 100644 --- a/crates/ui-egui/tests/it/objects.rs +++ b/crates/ui-egui/tests/it/objects.rs @@ -344,3 +344,21 @@ fn each_drag_of_an_object_is_its_own_undo_step() { h.run_steps(2); assert_eq!(rect(&h, o.image), start, "a second undo takes back the move"); } + +#[test] +fn dragging_an_unselected_object_by_its_edge_moves_it() { + let (mut h, o) = fixture(); + assert_eq!(h.state().selected_object, None); + let before = rect(&h, o.shape); + // On the bottom-right corner, where the handle would be if the shape were selected; the + // pointer shows Move there, and the press selects and moves the shape. + let grab = Handle::BottomRight.pos(before) - vec2(2.0, 2.0); + h.input_mut().events.push(Event::PointerMoved(grab)); + h.run_steps(2); + assert_eq!(h.output().platform_output.cursor_icon, egui::CursorIcon::Move); + drag(&mut h, grab, grab + vec2(30.0, 20.0)); + let after = rect(&h, o.shape); + assert_eq!(h.state().selected_object, Some(o.shape)); + assert!((after.size() - before.size()).length() < 0.5, "not resized: {before:?} {after:?}"); + assert!((after.min - before.min - vec2(30.0, 20.0)).length() < 1.0, "moved with the pointer: {before:?} {after:?}"); +}