diff --git a/crates/tools/src/select.rs b/crates/tools/src/select.rs index f2f4229de..cac9e6adf 100644 --- a/crates/tools/src/select.rs +++ b/crates/tools/src/select.rs @@ -1315,15 +1315,17 @@ impl SelectionTool { return out; } // A Shift-drag from a highlighted object of the Global Edit selects it and moves it - // with the selection. `cx` still holds the selection without it, so the snap targets - // are gathered at the next drag event. - if let Some((_, top)) = exclude { - out.push(Action::Exec("select.toggle".into(), json!({ "id": top.0 }))); - } + // with the selection: its snap targets are gathered for the selection with it. + self.moving = Some(match exclude { + Some((_, top)) => { + out.push(Action::Exec("select.toggle".into(), json!({ "id": top.0 }))); + let mut selection = cx.selection.clone(); + selection.add(top); + MoveSnap::new(&ToolContext { selection: &selection, ..*cx }) + } + None => MoveSnap::new(cx), + }); out.push(Action::Begin(if m.alt { "Copy".into() } else { "Move".into() })); - self.moving = exclude.is_none().then(|| MoveSnap::new(cx)); - } else if self.moving.is_none() { - self.moving = Some(MoveSnap::new(cx)); } let mut d = move_delta(start, p, m.shift, cx.constrain_angle); let unsnapped = d; diff --git a/crates/tools/src/select/tests.rs b/crates/tools/src/select/tests.rs index 4555eee7a..8f6299f06 100644 --- a/crates/tools/src/select/tests.rs +++ b/crates/tools/src/select/tests.rs @@ -1032,6 +1032,25 @@ fn shift_drag_on_a_global_edit_match_selects_and_moves_it() { assert_eq!(t.pointer(&cx, &shift(PointerKind::Up, 350.0, 150.0)), vec![Action::Exec("select.globalEditExclude".into(), json!({"id": b.0}))]); } +/// The first preview of a Shift-drag from a Global Edit match snaps, the match's bounds taken in +/// with the selection's: with Snap to Grid, a move of 13 right brings the right edge (413) onto +/// the gridline 414. +#[test] +fn shift_drag_on_a_global_edit_match_snaps_from_its_first_event() { + let (d, a, b) = two_rects(Rect::new(300.0, 100.0, 400.0, 200.0)); + let p = paint(); + let s = Selection::default(); + let members = [(a, Affine::IDENTITY), (b, Affine::IDENTITY)]; + let cx = ToolContext { global_edit: &members, snap_to_grid: true, ..cx(&d, &s, &p) }; + let shift = |kind, x, y| ev(kind, x, y).with_mods(Mods { shift: true, ..Mods::default() }); + let mut t = SelectionTool::default(); + assert!(t.pointer(&cx, &shift(PointerKind::Down, 350.0, 150.0)).is_empty()); + let actions = t.pointer(&cx, &shift(PointerKind::Drag, 363.0, 150.0)); + let Some(Action::Preview(_, v)) = actions.get(2) else { panic!("{actions:?}") }; + let m = Vec2::new(v["matrix"][4].as_f64().unwrap(), v["matrix"][5].as_f64().unwrap()); + assert!(moved_by(m, (14.0, 0.0)), "{m:?}"); +} + /// #541: a click on one object of a selection of several makes it the key object; a click on /// the key again lets it go. A drag moves them all, a lone object has no key unless ruler /// guides are selected with it.