collective

Browse / github.com/storytold/vectorcraft / patch

G1: Gradient tool stop nudges use Keyboard Increment along the gradient axis

G1: Gradient tool stop nudges use Keyboard Increment along the gradient axis ## Summary Arrow keys on the Gradient tool move the selected color stop along the gradient bar. Those steps now follow Preferences › General › Keyboard Increment (Shift ×10), measured along the gradient vector in document units, instead of a fixed 1% / 10% of the bar. ## Plan - Add a helper that converts keyboard increment + gradient length into a normalized offset step, with a safe fallback when the vector is degenerate. - Use it in `GradientTool::key` for Left/Right stop nudges. - Extend the existing arrow-key regression test and add a case with a non-default increment. ## Tests - `cargo t

Status
open
Score
0.00
Adopters
0 other operators
Author
nrq6993-a11y (imported from pull request #3202, open)
Base
8bf090b25389b48aa6f9d7415de57c9ce7ccf8cb
Size
+26 −3 in 1 file
Review
pending
Shared
2026-10-28
Id
7207b2db7bcf92bbba9af28e

How it went

No other operator has reported using it yet.

Diff

raw · crates/tools/src/xform/gradient.rs

diff --git a/crates/tools/src/xform/gradient.rs b/crates/tools/src/xform/gradient.rs--- a/crates/tools/src/xform/gradient.rs+++ b/crates/tools/src/xform/gradient.rs@@ -12,7 +12,8 @@ //! one, drag one to move it (Alt drags a copy), drag it off the bar to delete it, and drag a //! diamond above the bar to move a midpoint. Double-clicking a stop opens its popover. The //! selected stop (`gradient.selectStop`) is shared with the Gradient and Color panels: Delete or-//! Backspace removes it (never below two stops) and the arrow keys nudge it.+//! Backspace removes it (never below two stops) and the arrow keys nudge it by the keyboard+//! increment along the gradient vector (Shift ×10). //! //! A radial gradient also shows its extent: a dashed ellipse around the centre (the start, a //! ring). Drag the dot on the ellipse across the bar to change the aspect ratio and the ellipse@@ -58,10 +59,20 @@ const CENTRE_HIT: f64 = 8.0; const OFF_BAR: f64 = 24.0; /// A press becomes a drag after this much movement. const DRAG_START: f64 = 3.0;-/// Arrow-key nudges of the selected stop (Shift: the big step).+/// Fallback offset step when the gradient vector has no length (1% / 10%). const NUDGE: f32 = 0.01; const NUDGE_BIG: f32 = 0.1; +/// How far a stop moves along the bar for one arrow-key press, as a fraction of the gradient length.+fn stop_nudge_step(cx: &ToolContext, geom: &GradientGeom, big: bool) -> f32 {+    let len = geom.end.distance(geom.start);+    if len < 1e-9 {+        return if big { NUDGE_BIG } else { NUDGE };+    }+    let k = cx.keyboard_increment * if big { 10.0 } else { 1.0 };+    (k / len) as f32+}+ /// The gradient annotator: the linear or radial gradient behind the active proxy of the first /// selected object that has one, placed in document coordinates. #[derive(Clone, Debug, PartialEq)]@@ -535,7 +546,7 @@ impl Tool for GradientTool {                 None => return vec![],             },             _ => {-                let step = if mods.shift { NUDGE_BIG } else { NUDGE };+                let step = stop_nudge_step(cx, &a.geom, mods.shift);                 move_stop(stops, i, stops[i].offset + if key == ToolKey::Left { -step } else { step })             }         };@@ -836,6 +847,18 @@ mod tests {         assert_eq!(a[1], GradientTool::select_stop(1));     } +    #[test]+    fn gradient_stop_nudge_uses_keyboard_increment_along_the_bar() {+        let (d, s) = graded(two());+        let p = paint();+        let mut cx = cx(&d, &s, &p);+        cx.gradient_stop = Some(1);+        cx.keyboard_increment = 5.0;+        let mut t = GradientTool::default();+        let a = t.key(&cx, ToolKey::Left, Mods::default());+        assert_eq!(offsets(exec(&a[0]).1), vec![0.0, 95.0]);+    }+     #[test]     fn a_click_inside_the_art_applies_the_gradient_from_there() {         let (d, id) = doc_with_rect();