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]