From 6bb53981195c673d25de95c4d658d7d323885513 Mon Sep 17 00:00:00 2001 From: dotCooCoo Date: Tue, 27 Oct 2026 17:01:53 -0700 Subject: [PATCH] Pencil: Alt smooths as far from the drag as the Smooth tool does With "Alt key toggles to Smooth Tool" on, an Alt drag with the Pencil smoothed within the Pencil's "Edit selected paths" Within distance. At 0, which turns editing off, it smoothed nothing. It now smooths within the Smooth tool's 12 px radius at every Within value. --- crates/tools/src/draw2/gesture.rs | 12 +++++++++-- crates/tools/src/draw2/gesture/tests.rs | 28 +++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/crates/tools/src/draw2/gesture.rs b/crates/tools/src/draw2/gesture.rs index bdb8e4d84..d4a351e4f 100644 --- a/crates/tools/src/draw2/gesture.rs +++ b/crates/tools/src/draw2/gesture.rs @@ -22,6 +22,10 @@ use super::{FEEDBACK, eraser_area, points_json, polyline}; use crate::guides::DrawSnap; use crate::{Action, Cursor, Mods, Overlay, PointerEvent, PointerKind, Tool, ToolContext, ToolKey}; +/// How far from its drag the Smooth tool smooths, in screen pixels. The Pencil uses the same +/// radius while Alt switches it to the Smooth tool. +const SMOOTH_RADIUS: f64 = 12.0; + pub struct GestureTool { /// How many points the last preview of the stroke had ([`crate::previews_at`]). previewed: usize, @@ -339,9 +343,13 @@ impl GestureTool { let pts = &self.points; let has_sel = !cx.selection.is_empty(); let tol = cx.tol(self.edit_within); + let radius = cx.tol(SMOOTH_RADIUS); if self.smoothing { if has_sel && pts.len() >= 2 { - return vec![Action::Exec("path.smoothRegion".into(), json!({"points": points_json(pts), "radius": tol, "fidelity": self.fidelity}))]; + return vec![Action::Exec( + "path.smoothRegion".into(), + json!({"points": points_json(pts), "radius": radius, "fidelity": self.fidelity}), + )]; } return vec![]; } @@ -378,7 +386,7 @@ impl GestureTool { )], "knife" if pts.len() >= 2 => vec![Action::Exec("path.knife".into(), json!({"points": points_json(pts)}))], "smooth" if has_sel && pts.len() >= 2 => { - vec![Action::Exec("path.smoothRegion".into(), json!({"points": points_json(pts), "radius": tol, "fidelity": self.fidelity}))] + vec![Action::Exec("path.smoothRegion".into(), json!({"points": points_json(pts), "radius": radius, "fidelity": self.fidelity}))] } "pathEraser" if has_sel => vec![Action::Exec("path.eraseSegments".into(), json!({"points": points_json(pts), "width": cx.tol(8.0)}))], "join" if pts.len() >= 2 => vec![Action::Exec("path.joinScrub".into(), json!({"points": points_json(pts), "tolerance": tol}))], diff --git a/crates/tools/src/draw2/gesture/tests.rs b/crates/tools/src/draw2/gesture/tests.rs index 2daac5705..d1e07d13b 100644 --- a/crates/tools/src/draw2/gesture/tests.rs +++ b/crates/tools/src/draw2/gesture/tests.rs @@ -703,6 +703,34 @@ fn pencil_alt_with_alt_to_smooth_on_smooths_instead_of_drawing_a_line() { assert!(matches!(&acts.last().unwrap()[0], Action::Exec(c, v) if c == "path.smoothRegion" && v["points"].as_array().unwrap().len() == 3)); } +/// While Alt switches the Pencil to the Smooth tool, the Pencil smooths within the Smooth tool's +/// radius at any Edit selected paths Within value, 0 included. +#[test] +fn pencil_alt_smooths_within_the_smooth_tools_radius() { + let (d, id) = doc_with_rect(); + let mut s = Selection::default(); + s.set([id]); + let p = paint(); + let mut cx = cx(&d, &s, &p); + cx.smart_guides = false; + let pts = [(50.0, 150.0), (150.0, 150.0), (250.0, 160.0)]; + let radius = |acts: &[Vec]| match acts.last().and_then(|a| a.first()) { + Some(Action::Exec(c, v)) if c == "path.smoothRegion" => v["radius"].as_f64().unwrap(), + a => panic!("expected path.smoothRegion, got: {a:?}"), + }; + let alt = Mods { alt: true, ..Default::default() }; + for zoom in [1.0, 2.0] { + cx.zoom = zoom; + let want = radius(&drag(&mut GestureTool::new("smooth"), &cx, &pts, Mods::default())); + for within in [0.0, 5.0, 40.0] { + let mut t = GestureTool::new("pencil"); + t.set_option("altSmooth", &json!(true)); + t.set_option("editWithin", &json!(within)); + assert_eq!(radius(&drag_held(&mut t, &cx, &pts, alt)), want, "zoom {zoom}, editWithin {within}"); + } + } +} + /// #3799: Alt's line starts and ends on Smart Guides as a stroke does, and pressed on an end of /// a selected open path it continues the path from that end to the pointer. #[test]