Merge pull request #4376 from dotCooCoo/fix/pencil-alt-smooth-radius

Pencil: Alt smooths as far from the drag as the Smooth tool does
This commit is contained in:
BFlat
2026-10-29 10:53:40 +07:00
committed by GitHub
2 changed files with 38 additions and 2 deletions
+10 -2
View File
@@ -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}))],
+28
View File
@@ -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<Action>]| 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]