Keep corner resize cursors diagonal on wide and tall layers

Fixes #370

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
NetterSilver
2026-10-15 03:50:00 +02:00
co-authored by Claude Haiku 5.5
parent 833f0d2c27
commit fc6f52e852
2 changed files with 36 additions and 1 deletions
+12 -1
View File
@@ -685,7 +685,18 @@ pub(crate) fn handle_cursor(c: &[Point; 4], h: Handle) -> Cursor {
Handle::Corner(i) => {
let a = c.get(i as usize).copied().unwrap_or_default();
let b = c.get((i as usize + 2) % 4).copied().unwrap_or_default();
Cursor::Resize(angle(a, b))
// Along the box's own axes at 45°, not the diagonal, so wide or tall boxes still get a
// diagonal cursor. A box with no width or height falls back to the diagonal.
let unit = |v: figcraft_geom::kurbo::Vec2| {
let len = v.hypot();
(len.is_finite() && len > 1e-9).then(|| v / len)
};
let next = c.get((i as usize + 1) % 4).copied().unwrap_or_default();
let prev = c.get((i as usize + 3) % 4).copied().unwrap_or_default();
match (unit(next - a), unit(prev - a)) {
(Some(u), Some(v)) => Cursor::Resize((u + v).atan2().to_degrees()),
_ => Cursor::Resize(angle(a, b)),
}
}
Handle::Edge(i) => {
let a = c.get(i as usize).copied().unwrap_or_default();
@@ -378,6 +378,30 @@ fn smart_guides_snap_to_edges_centres_and_equal_spacing() {
assert_eq!(bounds(&s, b).origin(), Point::new(198.0, 2.0));
}
#[test]
fn corner_cursors_stay_diagonal_whatever_the_proportions() {
let mut s = session();
let mod180 = |a: f64, b: f64| near((a - b).rem_euclid(180.0).min((b - a).rem_euclid(180.0)), 0.0);
for (w, h) in [(65.0, 15.0), (100.0, 100.0), (60.0, 200.0), (200.0, 50.0)] {
let r = rect(&mut s, 0.0, 0.0, w, h, None);
let doc = s.doc().unwrap().clone();
let q = selection_box(&doc, &[r]).unwrap();
for (i, want) in [(0u8, 45.0), (1, 135.0), (2, 45.0), (3, 135.0)] {
let Cursor::Resize(a) = handle_cursor(&q, Handle::Corner(i)) else { panic!() };
assert!(mod180(a, want), "{w}x{h} corner {i}: {a}, want {want}");
}
// Turned, the corner cursors turn with the layer's own axes.
set(&mut s, &[r], json!({"rotation": 30}));
let doc = s.doc().unwrap().clone();
let q = selection_box(&doc, &[r]).unwrap();
let axis = (q[1] - q[0]).atan2().to_degrees();
for (i, off) in [(0u8, 45.0), (1, 135.0), (2, 45.0), (3, 135.0)] {
let Cursor::Resize(a) = handle_cursor(&q, Handle::Corner(i)) else { panic!() };
assert!(mod180(a, axis + off), "{w}x{h} turned corner {i}: {a}, want {}", axis + off);
}
}
}
#[test]
fn the_transform_box_and_its_handles() {
let mut s = session();