From 6939a481a43b022263848a0cbe5aa88b1b5c2087 Mon Sep 17 00:00:00 2001 From: vangel76 Date: Fri, 16 Oct 2026 20:03:37 +0200 Subject: [PATCH] Dimension tool: Shift shows the constrained line while picking the second point (#2432) The Shift click already snapped the second point to 45-degree steps, but the dashed line from the first point followed the raw pointer, so the constraint looked absent until the click. Co-Authored-By: Claude Opus 5.5 --- crates/engine/tests/dimensions.rs | 18 ++++++++++++++++++ crates/tools/src/dimension.rs | 14 ++++++++++++-- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/crates/engine/tests/dimensions.rs b/crates/engine/tests/dimensions.rs index f65a292c7..83e7be165 100644 --- a/crates/engine/tests/dimensions.rs +++ b/crates/engine/tests/dimensions.rs @@ -389,3 +389,21 @@ fn unknown_dimension_options_are_refused_by_commands_but_a_newer_file_still_open let doc = vectorcraft_format::load(&serde_json::to_vec(&v).unwrap()).unwrap(); assert!(doc.node(NodeId(id)).unwrap().extras().dimension.is_some()); } + +/// With Shift down, the dashed line from the first picked point follows the 45-degree step the +/// second click will pick (#2432), not the raw pointer. +#[test] +fn shift_shows_the_constrained_line_while_picking_the_second_point() { + use vectorcraft_engine::tools::Overlay; + let mut s = session(); + s.select_tool("dimension", ViewInfo::default()).unwrap(); + ev(&mut s, PointerKind::Down, 300.0, 300.0); + ev(&mut s, PointerKind::Up, 300.0, 300.0); + let end = |s: &mut Session, shift: bool| { + let e = PointerEvent::new(PointerKind::Move, 372.0, 310.0).with_mods(Mods { shift, ..Mods::default() }); + s.pointer(&e, ViewInfo::default()).unwrap(); + s.overlays(ViewInfo::default()).into_iter().find_map(|o| if let Overlay::Line { b, .. } = o { Some(b) } else { None }).unwrap() + }; + assert_eq!(end(&mut s, false).y, 310.0); + assert!((end(&mut s, true).y - 300.0).abs() < 1e-9); +} diff --git a/crates/tools/src/dimension.rs b/crates/tools/src/dimension.rs index eb482a036..9fd871c70 100644 --- a/crates/tools/src/dimension.rs +++ b/crates/tools/src/dimension.rs @@ -60,9 +60,17 @@ pub struct DimensionTool { dragging: bool, hover: Option, at: Point, + /// Whether Shift was down at the last pointer event: the picked line shows constrained. + shift: bool, began: bool, } +/// `at` as a Shift click picks it: the direction from `last` snapped to 45° steps (from the +/// constrain angle), the distance kept. +fn constrained(cx: &ToolContext, last: Point, at: Point) -> Point { + last + vectorcraft_geom::constrain_angle_from(at - last, 45.0, cx.constrain_angle) +} + /// Nearest editable segment, with bounded work and no snapping to dimension artwork itself. pub fn pick(cx: &ToolContext, p: Point) -> Option { let mut best = None; @@ -217,7 +225,7 @@ impl DimensionTool { if mods.shift && let Some((last, _)) = self.points.last() { - at = *last + vectorcraft_geom::constrain_angle_from(at - *last, 45.0, cx.constrain_angle); + at = constrained(cx, *last, at); reference = reference.filter(|r| r.position(cx.doc) == Some(at)); } self.points.push((at, reference)); @@ -293,6 +301,7 @@ impl Tool for DimensionTool { } fn pointer(&mut self, cx: &ToolContext, ev: &PointerEvent) -> Vec { self.at = ev.pos; + self.shift = ev.mods.shift; match ev.kind { PointerKind::Move => { if self.pending.is_some() { @@ -393,7 +402,8 @@ impl Tool for DimensionTool { segment(edge, &mut out); } if let Some((p, _)) = self.points.last() { - out.push(Overlay::Line { a: *p, b: self.at, color, dashed: true }); + let b = if self.shift { constrained(cx, *p, self.at) } else { self.at }; + out.push(Overlay::Line { a: *p, b, color, dashed: true }); } out }