Files
vectorcraft/crates/tools/src/settings.rs
T
dotCooCoo ddfd08f321 Blob Brush: Keep selected and Merge only with selection options
A Blob Brush stroke merged with every touching closed path of its
color that had no stroke, and the blob it drew or merged into was
always left selected. The Blob Brush Tool Options had Size only.

The Blob Brush Tool Options now have Keep selected and Merge only
with selection, both off by default. A blob that a stroke draws or
merges into is no longer left selected unless Keep selected is on,
and the rest of the selection stays as it was. While Merge only with
selection is on, a stroke merges only with selected blobs, and with
nothing selected it draws a new blob. The options persist like the
tool's Size, and path.blob takes keepSelected and mergeOnlySelection,
both false by default. Keep selected stays on by default for the
Pencil and Paintbrush.

Docs: docs/target-app-parity.md, docs/control-protocol.md.
2026-10-16 15:27:53 +07:00

99 lines
4.0 KiB
Rust

//! Tool options that persist: a tool keeps them when another tool is chosen and they are saved
//! with the preferences, as the reference app keeps each tool's options. Options that are the
//! state of an interaction (pins, a reference point, the text being edited, the files a place
//! cursor holds) aren't listed: they start afresh.
//!
//! Each row names the tools it covers, the store their values live in and the option keys. A row
//! with a shared store gives every tool it lists one set of values: the Liquify tools share their
//! Global Brush Dimensions, the Symbolism tools their brush. Otherwise each tool has its own store,
//! named after its id.
/// (tools, the store they share (None: each tool's own), option keys).
type Row = (&'static [&'static str], Option<&'static str>, &'static [&'static str]);
/// The Liquify tools.
pub const LIQUIFY: &[&str] = &["warp", "twirl", "pucker", "bloat", "scallop", "crystallize", "wrinkle"];
/// The Symbolism tools.
pub const SYMBOLISM: &[&str] =
&["symbolSprayer", "symbolShifter", "symbolScruncher", "symbolSizer", "symbolSpinner", "symbolStainer", "symbolScreener", "symbolStyler"];
const ROWS: &[Row] = &[
(&["dimension"], None, &["mode", "style"]),
// Global Brush Dimensions.
(LIQUIFY, Some("liquify"), &["width", "height", "angle", "intensity", "usePressure", "showBrush"]),
(LIQUIFY, None, &["detail", "simplify", "simplifyOn", "rate", "complexity", "horizontal", "vertical", "affectAnchors", "affectIn", "affectOut"]),
(SYMBOLISM, Some("symbolism"), &["diameter", "intensity", "density"]),
(&["mirrorCut"], None, &["axis", "keep"]),
(&["puppetWarp"], None, &["showMesh", "expand"]),
(&["arc"], None, &["closed"]),
(&["spiral"], None, &["decay", "segments", "clockwise"]),
(&["rectangularGrid"], None, &["rows", "columns", "rowSkew", "columnSkew", "frame", "fill"]),
(&["polarGrid"], None, &["concentric", "radial", "concentricSkew", "radialSkew", "compound", "fill"]),
(&["pencil", "paintbrush"], None, &["fidelity", "fill", "keepSelected", "editWithin", "closeWithin"]),
(&["smooth"], None, &["fidelity"]),
(&["blobBrush", "eraser"], None, &["size"]),
(&["blobBrush"], None, &["keepSelected", "mergeOnlySelection"]),
(&["polygon"], None, &["sides"]),
(&["star"], None, &["points"]),
(&["freeTransform"], None, &["constrain"]),
(&["artboard"], None, &["moveArt", "scaleArt"]),
// Flare Tool Options (`extra::FLARE_OPTIONS` and the Rays and Rings checkboxes).
(
&["flare"],
None,
&[
"diameter",
"opacity",
"brightness",
"growth",
"fuzziness",
"raysOn",
"rays",
"longest",
"rayFuzziness",
"ringsOn",
"pathLength",
"rings",
"largest",
"direction",
],
),
];
/// The stores `tool`'s persistent options live in, each with the option keys it holds.
pub fn stores(tool: &str) -> impl Iterator<Item = (&'static str, &'static [&'static str])> + '_ {
ROWS.iter().filter_map(move |(tools, shared, keys)| {
let id = tools.iter().find(|t| **t == tool)?;
Some((shared.unwrap_or(id), *keys))
})
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn every_listed_option_is_one_the_tool_reports() {
for (tools, _, keys) in ROWS {
for id in *tools {
assert!(crate::tool_info(id).is_some(), "{id} is a tool");
let opts = crate::create(id).options();
for k in *keys {
assert!(opts.get(*k).is_some(), "{id} reports `{k}` in {opts}");
}
}
}
}
#[test]
fn liquify_tools_share_the_global_brush() {
let warp: Vec<_> = stores("warp").collect();
let twirl: Vec<_> = stores("twirl").collect();
assert_eq!(warp[0], twirl[0]);
assert_eq!(warp[0].0, "liquify");
assert_eq!((warp[1].0, twirl[1].0), ("warp", "twirl"));
assert_eq!(stores("selection").count(), 0);
}
}