Dimension tool: the first preview of a drag-out is drawn at the pointer

Dragging out a dimension from a segment (Linear) or a corner (Angular)
drew its first preview frame at the wrong distance. The preview placed
the dimension at the pointer before reading the segment's end points or
the corner from the art, and measured the offset from the placeholder
points the dimension starts with. A drag from the top edge of a
rectangle to 40 pt above it showed an offset of 60 instead of -40.

The preview now clears the offset, reads the art's points, places the
dimension at the pointer and checks the result. Clearing the offset
keeps an out-of-range offset from the last pointer position from
failing the read.

Tests: the segment and corner drag-out tests fail without the change.
placement_recovers_after_a_position_out_of_range also passes on main;
it fails when only the offset clear is removed.
This commit is contained in:
dotCooCoo
2026-11-13 19:08:02 -08:00
parent 446bf59bc2
commit dea57b348b
+57 -1
View File
@@ -344,10 +344,19 @@ impl DimensionTool {
_ => Orientation::Aligned,
};
}
d.place(p);
// A dimension dragged out from art starts with placeholder points. Read the art's points
// before placing the dimension at the pointer. Clear the offset first: an out-of-range
// offset from the last pointer position fails the read.
if !matches!(d.mode, DimensionMode::Radius | DimensionMode::Diameter) {
d.offset = 0.0;
}
if d.resolve(cx.doc).is_err() {
return vec![];
}
d.place(p);
if d.validate().is_err() {
return vec![];
}
let mut actions = vec![];
if !self.began {
actions.push(Action::Begin("Create Dimension".into()));
@@ -675,6 +684,53 @@ mod tests {
assert!(matches!(placed.last(), Some(Action::Commit)), "{placed:?}");
}
/// A pointer position too far away to place the dimension shows no preview, and the preview
/// comes back where the pointer returns.
#[test]
fn placement_recovers_after_a_position_out_of_range() {
let (d, _) = doc_with_rect();
let (s, p) = (Selection::default(), paint());
let c = cx(&d, &s, &p);
let mut t = DimensionTool::default();
for (x, y) in [(400.0, 400.0), (450.0, 400.0)] {
t.pointer(&c, &PointerEvent::new(PointerKind::Down, x, y));
t.pointer(&c, &PointerEvent::new(PointerKind::Up, x, y));
}
assert!(t.pointer(&c, &PointerEvent::new(PointerKind::Move, 420.0, 3.0e6)).is_empty());
let acts = t.pointer(&c, &PointerEvent::new(PointerKind::Move, 420.0, 450.0));
let Some(Action::Preview(_, params)) = acts.last() else { panic!("{acts:?}") };
assert_eq!(params["offset"], json!(50.0));
}
/// Dragging out from a segment previews the dimension at the pointer from the first drag on.
#[test]
fn the_first_preview_of_a_segment_drag_is_at_the_pointer() {
let (d, _) = doc_with_rect();
let (s, p) = (Selection::default(), paint());
let c = cx(&d, &s, &p);
let mut t = DimensionTool::default();
t.pointer(&c, &PointerEvent::new(PointerKind::Down, 150.0, 100.0));
let acts = t.pointer(&c, &PointerEvent::new(PointerKind::Drag, 150.0, 60.0));
let Some(Action::Preview(_, params)) = acts.last() else { panic!("{acts:?}") };
assert_eq!(params["offset"], json!(-40.0), "40 pt above the top edge");
}
/// Dragging out from a corner previews the angle at the pointer's distance from the corner
/// from the first drag on.
#[test]
fn the_first_preview_of_a_corner_drag_is_at_the_pointer() {
let (d, _) = doc_with_rect();
let (s, p) = (Selection::default(), paint());
let c = cx(&d, &s, &p);
let mut t = DimensionTool::default();
t.set_option("mode", &json!("angular"));
t.pointer(&c, &PointerEvent::new(PointerKind::Down, 100.0, 100.0));
let acts = t.pointer(&c, &PointerEvent::new(PointerKind::Drag, 130.0, 140.0));
let Some(Action::Preview(_, params)) = acts.last() else { panic!("{acts:?}") };
assert_eq!(params["vertex"], json!([100.0, 100.0]));
assert_eq!(params["offset"], json!(50.0), "50 pt from the corner");
}
/// A Linear press on an anchor picks that anchor even when the pointer moves a few pixels
/// before the release: it does not drag out the dimension of a segment that ends there. Both
/// picks keep their links to the path, so the dimension measures between the two anchors.