M5: a callout's leader line follows its text box while the box is resized (#1152)

Review on #4094: resizing a callout's text box moved its frame, but
changing_points had no Resize branch, so no leader line was drawn to the box
until the page was redrawn. A Resize gesture, and the ResizeAnnotation edit
just released, now count as changing the callout: its points stay and its
line is drawn to where the box is going. A box moved alone and released keeps
its knee beside it, as while it was dragged.

Test: a_callout_being_resized_draws_its_leader_line, which fails with the fix
reverted.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pq7HyCfwzyRXj4VfQAVVdv
This commit is contained in:
mtlcl410andClaude Opus 5.5 committed 2026-10-31 08:01:02 +08:00
1 parent adc0b91b1e
commit a36dcbb3bc
2 files changed
+31

No files matched your search

@@ -100,6 +100,10 @@ pub(super) fn changing_points(
}),
(_, Some(Edit::ReshapeAnnotation { page: p, index: i, points: to })) if (*p, *i) == (page, index) => Some(to.clone()),
(_, Some(Edit::MoveAnnotation { page: p, index: i, dx, dy })) if (*p, *i) == (page, index) => Some(shifted(*dx, *dy)),
// A callout's text box resized (or moved alone): its points stay, and its line is drawn to
// the box where it is going (see `paint_points`).
(Some(Gesture::Resize { page: p, index: i, .. }), _) if (*p, *i) == (page, index) => pointer.map(|_| points.to_vec()),
(_, Some(Edit::ResizeAnnotation { page: p, index: i, .. })) if (*p, *i) == (page, index) => Some(points.to_vec()),
_ => None,
}
}
@@ -119,6 +123,19 @@ fn paint_points(painter: &egui::Painter, cx: &PageCx<'_>, view: &DocView, a: &An
{
*p = [f64::from(first[0]), f64::from(first[1])];
}
// A callout's box moved alone and released: its knee came along, as while it was dragged.
if let (Some(Edit::ResizeAnnotation { page, index, rect }), Some(tb)) = (view.pending_edit.as_ref(), a.text_box.filter(|_| is_callout(a)))
&& (*page, *index) == (cx.page, a.index)
{
let tb = tb.map(f64::from);
let same = |a: f64, b: f64| (a - b).abs() < 0.01;
if same(rect[2] - rect[0], tb[2] - tb[0]) && same(rect[3] - rect[1], tb[3] - tb[1]) {
let (dx, dy) = (rect[0] - tb[0], rect[1] - tb[1]);
for q in points.iter_mut().skip(1) {
*q = [q[0] + dx, q[1] + dy];
}
}
}
let screen: Vec<Pos2> = points.iter().map(|q| cx.to_screen(*q)).collect();
if changed {
let stroke = Stroke::new(1.5, SELECT_BLUE);
@@ -24,6 +24,20 @@ fn a_moved_or_reshaped_line_is_drawn_at_its_new_points() {
assert_eq!(changing_points(None, None, (0, 3), &line, to_user, to, straight), None, "not changing");
}
/// Review on #4094: a callout's text box being resized, and the resize just released, draw its
/// leader line too (to the box where it is going): its points are changing, though they stay.
#[test]
fn a_callout_being_resized_draws_its_leader_line() {
let lead = [[10.0, 10.0], [40.0, 30.0]];
let to_user = |p: Pos2| [f64::from(p.x), f64::from(p.y)];
let resizing = Gesture::Resize { page: 0, index: 3, handle: (1, 1), from: pos2(80.0, 60.0), aspect_ratio: None };
let at = Some(pos2(95.0, 70.0));
assert_eq!(changing_points(Some(&resizing), None, (0, 3), &lead, to_user, at, straight), Some(lead.to_vec()));
assert_eq!(changing_points(Some(&resizing), None, (0, 4), &lead, to_user, at, straight), None, "another comment's resize");
let released = Edit::ResizeAnnotation { page: 0, index: 3, rect: [50.0, 20.0, 110.0, 70.0] };
assert_eq!(changing_points(None, Some(&released), (0, 3), &lead, to_user, None, straight), Some(lead.to_vec()));
}
/// A sticky note on a page turned a quarter is drawn upright beside its `/Rect`: an edit
/// composer stays open while the drawn note is partly in view, even with `/Rect` out of it.
#[test]