mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-31 21:27:00 -06:00
Merge pull request #4706 from dotCooCoo/fix/pencil-alt-smooth-fidelity
Pencil and Blob Brush: Alt smooths with the Smooth tool's Fidelity
This commit is contained in:
@@ -96,3 +96,38 @@ fn options_are_saved_with_the_preferences() {
|
||||
t.execute("prefs.reset", &json!({})).unwrap();
|
||||
assert_eq!(t.prefs.tool_settings["polygon"]["sides"], json!(9));
|
||||
}
|
||||
|
||||
/// The Fidelity an Alt smoothing drag uses on a selected path.
|
||||
fn alt_smooth_fidelity(s: &mut Session) -> Option<f64> {
|
||||
use vectorcraft_tools::{Action, Mods, PointerEvent, PointerKind};
|
||||
let mods = Mods { alt: true, ..Default::default() };
|
||||
let mut last = vec![];
|
||||
for (kind, x, y) in [(PointerKind::Down, 50.0, 150.0), (PointerKind::Drag, 150.0, 150.0), (PointerKind::Up, 250.0, 160.0)] {
|
||||
let ev = PointerEvent { mods, ..PointerEvent::new(kind, x, y) };
|
||||
last = s.with_tool_cx(ViewInfo::default(), |t, cx| t.pointer(cx, &ev));
|
||||
}
|
||||
last.iter().find_map(|a| match a {
|
||||
Action::Exec(c, v) if c == "path.smoothRegion" => v["fidelity"].as_f64(),
|
||||
_ => None,
|
||||
})
|
||||
}
|
||||
|
||||
/// Alt switches Pencil and Blob Brush to Smooth, using Smooth Tool Options' stored Fidelity.
|
||||
#[test]
|
||||
fn alt_smoothing_takes_the_smooth_tools_fidelity() {
|
||||
for id in ["pencil", "blobBrush"] {
|
||||
let mut s = session();
|
||||
s.execute("shape.rectangle", &json!({"x": 100, "y": 100, "width": 100, "height": 100})).unwrap();
|
||||
select(&mut s, "smooth");
|
||||
s.set_tool_option("fidelity", &json!(6));
|
||||
select(&mut s, id);
|
||||
if id == "pencil" {
|
||||
s.set_tool_option("altSmooth", &json!(true));
|
||||
}
|
||||
s.set_tool_option("fidelity", &json!(3));
|
||||
assert_eq!(alt_smooth_fidelity(&mut s), Some(6.0), "{id}");
|
||||
s.set_tool_option_cmd(&json!({"tool": "smooth", "key": "fidelity", "value": 9})).unwrap();
|
||||
assert_eq!(alt_smooth_fidelity(&mut s), Some(9.0), "{id}");
|
||||
assert_eq!(s.tool_options()["fidelity"], json!(3.0), "{id}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -216,6 +216,12 @@ impl Session {
|
||||
}
|
||||
}
|
||||
}
|
||||
// Alt switches the Pencil or Blob Brush to Smooth, using Smooth Tool Options' Fidelity.
|
||||
if matches!(t.id(), "pencil" | "blobBrush")
|
||||
&& let Some(v) = prefs.tool_settings.get("smooth").and_then(|s| s.get("fidelity"))
|
||||
{
|
||||
t.set_option("smoothFidelity", v);
|
||||
}
|
||||
}
|
||||
|
||||
/// Store the persistent options of `t` in `prefs` (so they are saved with them too).
|
||||
@@ -623,7 +629,8 @@ impl Session {
|
||||
|
||||
/// Set options of tool `id` (default: the active tool). Another tool's persistent options are
|
||||
/// stored for when it is chosen, and the active tool takes those it shares with it (the
|
||||
/// Liquify tools' Global Brush Dimensions). Returns the tool's options.
|
||||
/// Liquify tools' Global Brush Dimensions, the Smooth tool's Fidelity for the Pencil's and
|
||||
/// Blob Brush's Alt smoothing). Returns the tool's options.
|
||||
pub fn set_tool_options(&mut self, id: Option<&str>, values: &Map<String, Value>) -> Value {
|
||||
let active = id.is_none_or(|id| id == self.tool.id());
|
||||
self.tool_set_since_reset |= active;
|
||||
|
||||
@@ -34,6 +34,8 @@ const SMOOTH_RADIUS: f64 = 12.0;
|
||||
/// a fit's cost grows as its Fidelity shrinks (at 0.01 pt a long pen stroke lagged, #4565), and
|
||||
/// a preview within half a pixel of the stroke looks the same. The release fits it at its Fidelity.
|
||||
const PREVIEW_FIDELITY_PX: f64 = 0.5;
|
||||
/// The Smooth tool's Fidelity until Smooth Tool Options sets another.
|
||||
const SMOOTH_FIDELITY: f64 = 2.5;
|
||||
|
||||
pub struct GestureTool {
|
||||
/// How many points the last preview of the stroke had ([`crate::previews_at`]); 0 when it was
|
||||
@@ -87,6 +89,9 @@ pub struct GestureTool {
|
||||
/// preview shows the points joined by straight segments and the release fits them (Pencil
|
||||
/// only, on by default).
|
||||
pub live_fit: bool,
|
||||
/// The Smooth tool's Fidelity, used when Alt switches the Pencil or Blob Brush to Smooth.
|
||||
/// The engine sets it from Smooth Tool Options (`smoothFidelity`).
|
||||
smooth_fidelity: f64,
|
||||
/// Active drag is smoothing with the Pencil or the Blob Brush (Alt held).
|
||||
smoothing: bool,
|
||||
/// The pointer has moved from the press point, by any distance (a move too short to add a
|
||||
@@ -133,7 +138,7 @@ impl GestureTool {
|
||||
"join" => "join",
|
||||
_ => "pencil",
|
||||
};
|
||||
let fidelity = if id == "smooth" { 2.5 } else { 1.5 };
|
||||
let fidelity = if id == "smooth" { SMOOTH_FIDELITY } else { 1.5 };
|
||||
Self {
|
||||
id,
|
||||
previewed: 0,
|
||||
@@ -157,6 +162,7 @@ impl GestureTool {
|
||||
alt_smooth: false,
|
||||
live_preview: true,
|
||||
live_fit: true,
|
||||
smooth_fidelity: SMOOTH_FIDELITY,
|
||||
smoothing: false,
|
||||
moved: false,
|
||||
straight: false,
|
||||
@@ -383,7 +389,7 @@ impl GestureTool {
|
||||
if has_sel && pts.len() >= 2 {
|
||||
return vec![Action::Exec(
|
||||
"path.smoothRegion".into(),
|
||||
json!({"points": points_json(pts), "radius": radius, "fidelity": self.fidelity}),
|
||||
json!({"points": points_json(pts), "radius": radius, "fidelity": self.smooth_fidelity}),
|
||||
)];
|
||||
}
|
||||
return vec![];
|
||||
@@ -783,6 +789,9 @@ impl Tool for GestureTool {
|
||||
"altSmooth" => self.alt_smooth = v.as_bool().unwrap_or(self.alt_smooth),
|
||||
"livePreview" if self.id == "pencil" => self.live_preview = v.as_bool().unwrap_or(self.live_preview),
|
||||
"liveFit" if self.id == "pencil" => self.live_fit = v.as_bool().unwrap_or(self.live_fit),
|
||||
"smoothFidelity" if matches!(self.id, "pencil" | "blobBrush") => {
|
||||
self.smooth_fidelity = v.as_f64().unwrap_or(self.smooth_fidelity).clamp(super::min_fidelity("smooth"), 100.0)
|
||||
}
|
||||
"keepSelected" => self.keep_selected = v.as_bool().unwrap_or(self.keep_selected),
|
||||
"mergeOnlySelection" => self.merge_only_selection = v.as_bool().unwrap_or(self.merge_only_selection),
|
||||
"editWithin" => self.edit_within = v.as_f64().unwrap_or(self.edit_within).clamp(0.0, 100.0),
|
||||
|
||||
@@ -420,7 +420,7 @@ fn blob_brush_alt_switches_to_the_smooth_tool() {
|
||||
let acts = drag_held(&mut t, &cx, &stroke, alt);
|
||||
assert!(acts[..acts.len() - 1].iter().all(|a| a.is_empty()), "{acts:?}");
|
||||
let v = smoothed(&acts).unwrap_or_else(|| panic!("{acts:?}"));
|
||||
assert_eq!(v, json!({"points": [[50.0, 150.0], [150.0, 150.0], [250.0, 160.0]], "radius": cx.tol(12.0), "fidelity": 1.5}));
|
||||
assert_eq!(v, json!({"points": [[50.0, 150.0], [150.0, 150.0], [250.0, 160.0]], "radius": cx.tol(12.0), "fidelity": SMOOTH_FIDELITY}));
|
||||
// Mid-drag the cursor stays the Smooth tool's when Alt is let go, and the line is thin with
|
||||
// no length label.
|
||||
t.pointer(&cx, &PointerEvent::new(PointerKind::Down, 50.0, 150.0).with_mods(alt));
|
||||
@@ -872,6 +872,37 @@ fn pencil_alt_smooths_within_the_smooth_tools_radius() {
|
||||
}
|
||||
}
|
||||
|
||||
/// An Alt smoothing drag uses the Smooth tool's Fidelity for both Pencil and Blob Brush.
|
||||
#[test]
|
||||
fn alt_smoothing_uses_the_smooth_tools_fidelity() {
|
||||
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 fidelity = |acts: &[Vec<Action>]| match acts.last().and_then(|a| a.first()) {
|
||||
Some(Action::Exec(c, v)) if c == "path.smoothRegion" => v["fidelity"].as_f64().unwrap(),
|
||||
a => panic!("expected path.smoothRegion, got: {a:?}"),
|
||||
};
|
||||
let alt = Mods { alt: true, ..Default::default() };
|
||||
let want = fidelity(&drag(&mut GestureTool::new("smooth"), &cx, &pts, Mods::default()));
|
||||
for id in ["pencil", "blobBrush"] {
|
||||
let mut t = GestureTool::new(id);
|
||||
if id == "pencil" {
|
||||
t.set_option("altSmooth", &json!(true));
|
||||
}
|
||||
t.set_option("fidelity", &json!(10.0));
|
||||
assert_eq!(fidelity(&drag_held(&mut t, &cx, &pts, alt)), want, "{id}");
|
||||
t.set_option("smoothFidelity", &json!(7.5));
|
||||
assert_eq!(fidelity(&drag_held(&mut t, &cx, &pts, alt)), 7.5, "{id}");
|
||||
// Drawing keeps the tool's own Fidelity; Smooth's setting stays out of its options.
|
||||
assert_eq!(t.options()["fidelity"], json!(10.0), "{id}");
|
||||
assert!(t.options().get("smoothFidelity").is_none(), "{id}");
|
||||
}
|
||||
}
|
||||
|
||||
/// #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]
|
||||
|
||||
Reference in New Issue
Block a user