diff --git a/crates/tools/src/select.rs b/crates/tools/src/select.rs index 17bf7eeaef..d0d624bbeb 100644 --- a/crates/tools/src/select.rs +++ b/crates/tools/src/select.rs @@ -239,7 +239,8 @@ pub(crate) struct MoveSnap { copy_targets: Option, copy_points: Option, /// With Smart Guides on, the ruler guides View › Snap to Point still pulls the grabbed point - /// onto (#1534), and lines the bounds up with (#5746); `points` holds them with Smart Guides off. + /// onto (#1534), and lines the bounds up with (#5746), within the Snapping Tolerance as drawing + /// does; `points` holds them with Smart Guides off. rulers: Option, } @@ -303,7 +304,7 @@ impl MoveSnap { // axis without one that Smart Guides left free, the bounds line up with the ruler guides // (#5746), alongside the Smart Guides. if let Some(t) = &self.rulers { - let (adj, ov, held) = t.snap_moved_to_rulers(start + d, self.bounds.map(|b| b + d), cx.tol(cx.snap_tolerance), taken); + let (adj, ov, held) = t.snap_moved_to_rulers(start + d, self.bounds.map(|b| b + d), cx.snap_tol(), taken); if adj != Vec2::ZERO { d += adj; if held { @@ -373,7 +374,7 @@ impl MoveSnap { } } if let Some(t) = &self.rulers { - let (q, ov) = t.snap_point_along(start + d, u, cx.tol(cx.snap_tolerance)); + let (q, ov) = t.snap_point_along(start + d, u, cx.snap_tol()); if q != start + d { d = q - start; guides = ov; @@ -382,7 +383,7 @@ impl MoveSnap { { // Nothing else lined up: the bounds slide along the line onto a ruler guide, as // they do without Shift (#4312). - let (adj, ov) = t.snap_moved_along_to_rulers(start + d, b + d, u, cx.tol(cx.snap_tolerance)); + let (adj, ov) = t.snap_moved_along_to_rulers(start + d, b + d, u, cx.snap_tol()); d += adj; guides = ov; } diff --git a/crates/tools/src/select/tests.rs b/crates/tools/src/select/tests.rs index 659e50a6a5..c41056b7aa 100644 --- a/crates/tools/src/select/tests.rs +++ b/crates/tools/src/select/tests.rs @@ -751,7 +751,7 @@ fn escape_cancels_a_move_or_an_alt_drag_copy() { } /// #1534: with Smart Guides on (the default), the point a selection is dragged by still snaps -/// to a ruler guide within the Snap to Point distance; not with Snap to Point off. +/// to a ruler guide within the Snapping Tolerance; not with Snap to Point off. #[test] fn a_move_snaps_the_grabbed_point_to_a_ruler_guide_with_smart_guides_on() { let (mut d, id) = doc_with_rect(); @@ -797,6 +797,39 @@ fn a_shift_move_lands_the_edges_on_a_ruler_guide() { assert!(moved_by(m, (231.0, 0.0)), "{m:?}"); } +/// With Smart Guides on, a moved selection reaches a ruler guide within the Snapping Tolerance +/// (4 px), as drawing and handle drags do; with Smart Guides off, Snap to Point reaches it within +/// its own distance (2 px). +#[test] +fn a_move_reaches_ruler_guides_within_the_snapping_tolerance() { + let (mut d, id) = doc_with_rect(); + d.add_ruler_guide(&vectorcraft_doc::Guide::new(true, 340.0)); + let mut s = Selection::default(); + s.add(id); + let p = paint(); + let dx = |c: &ToolContext, to: f64| { + let mut t = SelectionTool::default(); + t.pointer(c, &ev(PointerKind::Down, 150.0, 150.0)); + let a = t.pointer(c, &ev(PointerKind::Drag, to, 150.0)); + let Some(Action::Preview(_, v)) = a.last() else { panic!("{a:?}") }; + v["matrix"][4].as_f64().unwrap() + }; + let c = cx(&d, &s, &p); + assert!(c.smart_guides && c.snap_to_point && c.guides); + // The right edge, 3 px short of the guide, lands on it, with or without Shift. + assert_eq!(dx(&c, 150.0 + 137.0), 140.0); + let (m, _) = shift_moved(&c, (150.0 + 137.0, 150.0)); + assert!(moved_by(m, (140.0, 0.0)), "{m:?}"); + // The grabbed point, 3 px from the guide, lands on it. + assert_eq!(dx(&c, 337.0), 190.0); + // 5 px away is out of reach. + assert_eq!(dx(&c, 150.0 + 135.0), 135.0); + // Smart Guides off: the grabbed point lands on the guide from 1.5 px, not from 3 px. + let off = ToolContext { smart_guides: false, ..cx(&d, &s, &p) }; + assert_eq!(dx(&off, 338.5), 190.0); + assert_eq!(dx(&off, 337.0), 187.0); +} + /// Alt pressed during a move makes a copy, which snaps to the original it leaves behind (as /// gathered before the previews moved it); released, the move doesn't. #[test]