Merge pull request #7397 from dotCooCoo/fix/dimension-first-preview

Dimension tool: the first preview of a drag-out is drawn at the pointer
This commit is contained in:
BFlat
2026-11-14 13:43:03 +07:00
committed by GitHub
+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.