Spiral tool: Alt-drag adds or removes whole winds of four segments

Alt in a spiral drag now rounds the fitted segment count to whole winds
of four segments, counted from the segment count when Alt went down.
Ctrl/Cmd takes precedence when both keys are held, and switching back to
Alt starts from the current count with the held inner end kept. Arrow
keys, Escape, release and a new drag clear the held Alt count.

Tests cover both keys together, a switch mid-drag, Escape, the 2 to 1000
bounds and the committed path's anchor count. docs/mcp.md and
docs/target-app-parity.md describe the rule.
This commit is contained in:
dotCooCoo
2026-10-30 23:17:01 +07:00
committed by bflatastic
parent 856c602310
commit 88e2177fec
4 changed files with 136 additions and 41 deletions
+9 -9
View File
@@ -1275,9 +1275,9 @@ fn shape_arc_closed_along_y_closes_through_the_top_left_corner() {
assert!((area - std::f64::consts::FRAC_PI_4).abs() < 0.01, "{area}");
}
/// A spiral dragged out with Alt pressed part way gets more segments as its outer end moves out,
/// and one dragged with Ctrl/Cmd pressed part way gets the decay that keeps its inner end's
/// distance from the center; the Spiral tool keeps both for the next spiral.
/// A spiral dragged out with Alt pressed part way gets four more segments per wind as its outer end
/// moves out. Ctrl/Cmd pressed part way fits the decay so the inner end keeps its distance from the
/// center. The Spiral tool keeps both values for the next spiral.
#[test]
fn spiral_drags_with_alt_and_ctrl_change_its_segments_and_decay() {
let mut s = session();
@@ -1293,17 +1293,17 @@ fn spiral_drags_with_alt_and_ctrl_change_its_segments_and_decay() {
};
s.select_tool("spiral", v).unwrap();
let undo = undo_steps(&s);
// Alt from a radius of 100 to 200: 10 segments become 13, the outer end at the pointer.
// Alt from a radius of 100 to 200: 10 segments become 14, one full wind of four quarter turns.
let (anchors, outer) = spiral(&mut s, Mods { alt: true, ..Mods::default() }, (300.0, 100.0));
assert_eq!(anchors, 14);
assert_eq!(anchors, 15);
assert!(near(outer, Point::new(300.0, 100.0)), "{outer:?}");
assert_eq!(s.tool_options()["segments"], json!(13));
// Ctrl/Cmd from 100 to 50: the decay rises from 80 % to 80 × 2^(1/13) %.
assert_eq!(s.tool_options()["segments"], json!(14));
// Ctrl/Cmd from 100 to 50: the decay rises from 80 % to 80 × 2^(1/14) %.
let (anchors, outer) = spiral(&mut s, Mods { cmd: true, ..Mods::default() }, (150.0, 100.0));
assert_eq!(anchors, 14);
assert_eq!(anchors, 15);
assert!(near(outer, Point::new(150.0, 100.0)), "{outer:?}");
let decay = s.tool_options()["decay"].as_f64().unwrap();
assert!((decay - 80.0 * 2f64.powf(1.0 / 13.0)).abs() < 1e-9, "{decay}");
assert!((decay - 80.0 * 2f64.powf(1.0 / 14.0)).abs() < 1e-9, "{decay}");
assert_eq!(undo_steps(&s) - undo, 2, "one undo step a spiral");
}