Merge #1023: fix(engine): show the Pen's Shift 45° step in its preview line (#970) (@vxMacDev)

This commit is contained in:
bflatastic
2026-10-24 09:17:11 +07:00
2 changed files with 31 additions and 3 deletions
+21
View File
@@ -63,3 +63,24 @@ fn finishing_the_path_clears_its_handles_and_band() {
let ov = &s.tool.overlay;
assert!(ov.pen.is_empty() && ov.pen_handles.is_empty() && ov.rubber.is_none() && ov.rubber_handle.is_none());
}
#[test]
fn shift_keeps_the_band_and_the_next_point_at_45_degree_steps() {
// #970: with Shift the band shows where the point will land, at a 45° step from the last
// anchor (the same length as the pointer is away), not under the pointer.
let mut s = Session::new();
s.set_tool(ToolId::Pen);
at(&mut s, PointerKind::Down, 100.0, 100.0);
at(&mut s, PointerKind::Up, 100.0, 100.0);
let shifted = |kind, x, y| PointerEvent { shift: true, ..PointerEvent::at(kind, x, y, 1.0) };
s.pointer(&shifted(PointerKind::Hover, 300.0, 120.0)).unwrap();
let [x0, y0, x1, y1] = s.tool.overlay.rubber.unwrap();
assert_eq!([x0, y0, y1], [100.0, 100.0, 100.0], "level with the last anchor");
assert!((x1 - (100.0 + 200f64.hypot(20.0))).abs() < 1e-9, "{x1}");
s.pointer(&shifted(PointerKind::Down, 300.0, 120.0)).unwrap();
s.pointer(&shifted(PointerKind::Up, 300.0, 120.0)).unwrap();
s.pointer(&shifted(PointerKind::Hover, 400.0, 230.0)).unwrap();
let [x0, y0, x1, y1] = s.tool.overlay.rubber.unwrap();
assert_eq!(y0, 100.0, "the point landed on the band");
assert!((x1 - x0 - (y1 - y0)).abs() < 1e-9, "45° down to the right: {:?}", [x0, y0, x1, y1]);
}
+10 -3
View File
@@ -459,6 +459,13 @@ pub(crate) enum Gesture {
},
}
/// Where Shift puts the Pen's next point: as far from `last` as `p` is, at the nearest 45° step.
fn at_45_degrees(last: Point, p: Point) -> Point {
let v = p - last;
let ang = (v.atan2() / (std::f64::consts::PI / 4.0)).round() * std::f64::consts::PI / 4.0;
last + Vec2::from_angle(ang) * v.hypot()
}
/// The handles a pen path shows while it is drawn ([`Overlay::pen_handles`]): the last anchor's in
/// and out handles and the one before's out handle, those that aren't zero.
fn pen_handles(points: &[(Point, Vec2, Vec2)]) -> Vec<[f64; 4]> {
@@ -1158,6 +1165,8 @@ impl Session {
guides = g;
self.tool.overlay.cursor = Cursor::Pen(self.pen_cursor(&doc, &sel, to, ev.zoom));
if let Some((last, _, out)) = self.tool.pen.as_ref().and_then(|pen| pen.points.last()) {
// With Shift the band ends where a click puts the point (#970).
let to = if ev.shift { at_45_degrees(*last, to) } else { to };
self.tool.overlay.rubber = Some([last.x, last.y, to.x, to.y]);
self.tool.overlay.rubber_handle = (out.hypot() > 0.0).then_some([last.x + out.x, last.y + out.y]);
}
@@ -2214,9 +2223,7 @@ impl Session {
if ev.shift
&& let Some((last, _, _)) = pen.points.last()
{
let v = p - *last;
let ang = (v.atan2() / (std::f64::consts::PI / 4.0)).round() * std::f64::consts::PI / 4.0;
p = *last + Vec2::from_angle(ang) * v.hypot();
p = at_45_degrees(*last, p);
}
pen.points.push((p, Vec2::ZERO, Vec2::ZERO));
self.tool.gesture = Gesture::PenDrag { anchor: p };