diff --git a/crates/tools/src/blendwidget.rs b/crates/tools/src/blendwidget.rs index 634e2639a1..af1194d78b 100644 --- a/crates/tools/src/blendwidget.rs +++ b/crates/tools/src/blendwidget.rs @@ -239,11 +239,11 @@ impl BlendWidgetDrag { /// An arrow key during the drag: one point more (`more`) or less, ten with Shift. pub fn step(&mut self, cx: &ToolContext, more: bool, big: bool) -> Vec { let by = if big { 10.0 } else { 1.0 }; - self.keys += if more { by } else { -by }; - // Past either end, the keys stop adding: the way back starts at once. + // The step goes from the value shown, so past either end (by keys or by the drag) the way + // back starts at once. let (lo, hi) = self.widget.control.range(); - let free = self.dragged(cx); - self.keys = self.keys.clamp(lo - free, hi - free); + let stepped = (self.value_now(cx) + if more { by } else { -by }).clamp(lo, hi); + self.keys = stepped - self.dragged(cx); self.preview(cx) } @@ -533,4 +533,36 @@ mod tests { assert!(!t.busy() && !t.transforming()); assert!(t.pointer(&c, &ev(PointerKind::Up, at)).is_empty(), "the release commits nothing"); } + + /// A double-click on a widget with the Selection tool does nothing to the artwork under it. + #[test] + fn a_double_click_on_a_widget_leaves_the_artwork_under_it_alone() { + let (mut d, _, s) = blend_doc(&[(100.0, 200.0), (300.0, 200.0)], eased()); + cover(&mut d, 190.0, 206.0, 210.0, 226.0); + let p = paint(); + let c = cx(&d, &s, &p); + let at = Point::new(200.0, 216.0); + assert!(over_widget(&c, at)); + let mut t = SelectionTool::default(); + assert!(t.pointer(&c, &ev(PointerKind::DoubleClick, at)).is_empty()); + // Beside the widget, the double-click reaches the artwork. + assert!(!t.pointer(&c, &ev(PointerKind::DoubleClick, Point::new(192.0, 224.0))).is_empty()); + } + + /// After a drag past either end, the first arrow key steps back from the value shown. + #[test] + fn an_arrow_key_after_a_drag_past_an_end_steps_from_the_value_shown() { + let (d, id, s) = blend_doc(&[(100.0, 200.0), (300.0, 200.0)], eased()); + let p = paint(); + let c = cx(&d, &s, &p); + let at = Point::new(200.0, 216.0); + let ramp = |v: f64| vec![Action::Preview("object.blend.setEasing".into(), json!({"id": id.0, "ramp": v}))]; + for (moved, back, shown) in [(200.0, ToolKey::Left, 99.0), (-200.0, ToolKey::Right, 1.0)] { + let mut t = SelectionTool::default(); + t.pointer(&c, &ev(PointerKind::Down, at)); + t.pointer(&c, &ev(PointerKind::Drag, at + Vec2::new(moved, 0.0))); + assert_eq!(t.key(&c, back, Mods::default()), ramp(shown), "{moved}"); + assert_eq!(t.pointer(&c, &ev(PointerKind::Up, at + Vec2::new(moved, 0.0))), vec![Action::Commit]); + } + } } diff --git a/crates/tools/src/select.rs b/crates/tools/src/select.rs index 84a10d350f..a0c7e43d48 100644 --- a/crates/tools/src/select.rs +++ b/crates/tools/src/select.rs @@ -1531,6 +1531,11 @@ impl SelectionTool { if let Some(a) = release_guide_at(cx, p, m) { return vec![a]; } + // A selected blend's widget takes a plain double-click: the artwork under it is neither + // edited nor isolated. + if blendwidget::over_widget(cx, p) { + return vec![]; + } if crate::rulerguide::guide_at(cx, p).is_some() { return vec![]; } diff --git a/docs/gaps.md b/docs/gaps.md index 4186fa64dd..1c3b39a664 100644 --- a/docs/gaps.md +++ b/docs/gaps.md @@ -534,8 +534,9 @@ macOS cursor delivery (#2292) is narrowed to a native host adapter using the exi (#1676). A linked image is refused, as the public documentation has it. - **Partial:** blend easing (#1124, 30.7): Window › Blend has Type (Ease In, Ease Out, Ease In Out, Ease Out In), Ramp 0–100% and independent color Shift; easing is disabled without a spine. - The original polynomial distributions approximate the public description. On-canvas easing handles - and their synchronization remain missing. [Public source](https://helpx.adobe.com/illustrator/desktop/manage-colors/apply-transparency-and-blending/blend-panel-overview.html). + The original polynomial distributions approximate the public description. With the Selection or + Blend tool, on-canvas widgets set the color Shift and, when the steps follow a spine, the Ramp; the + Blend panel shows the values they set. [Public source](https://helpx.adobe.com/illustrator/desktop/manage-colors/apply-transparency-and-blending/blend-panel-overview.html). - **Done:** gradient Dither (30.0): the Gradient panel's Dither box (`paint.editGradient` `dither`, also in `paint.setFill`'s `gradient`, swatches and the native file) draws a linear or radial gradient fill as pixels with seeded noise of up to a diff --git a/docs/mcp.md b/docs/mcp.md index 7053f0ede9..80fd96edc6 100644 --- a/docs/mcp.md +++ b/docs/mcp.md @@ -8632,10 +8632,10 @@ first selected blend without `id`) and returns `{id, easingType, ramp, colorShif replaced or edited spine, or `orientation: "path"`) and not made without one (`createSpine: "never"`), as the Blend panel's Type and Ramp do. A value out of range, a hidden or locked blend and a target that is not a blend are errors, and a call that changes nothing records no undo step (`changed: false`). With one blend selected that has a spine, -the Selection and Blend tools show the same two values as widgets +the Selection and Blend tools show the same values as widgets 16 px above and below the spine's halfway point (where the boxes of three or more other visible objects hold that spot, a widget moves out in 16 px steps, up to 144 px, joined to the halfway point by a line): the upper one sets -`colorShift` and the lower one `ramp`, by one per screen pixel dragged along the spine and by one per arrow key +`colorShift` and the lower one, shown only when the steps follow the spine as `ramp` needs, sets `ramp`, by one per screen pixel dragged along the spine and by one per arrow key during the drag (ten with Shift). Each drag is one undo step, and `press_key` Escape or a switch to another tool during it puts the value back: