mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-31 21:27:00 -06:00
Path Precision Tools gains the Shared Edge Merge Tool, kept out of the toolbars (All Tools drawer and Object › Plug-ins › Path Precision Tools, no shortcut), and Keep Shared Points Together: - Shared Edge Merge Tool (sharedEdge): over two paths touching at two coincident anchors (tolerance 0 to 3 pt) hovering shows the two stretches and the merged edge; a click replaces both with it, half way between them, or following the upper (Shift) or lower (Alt) path. Both paths stay closed or open, anchors either stretch has inside are matched on the other, one undo step. - Making ends: near anchors meet on a click and an anchor one path lacks is added to match; Shift+Alt asks for this inside a stretch. - Keep Shared Points Together: an option that makes Slide Anchor Along Path, Extend Path and Set Anchor take coincident anchors along. Nothing else in the app changes. - Shared Edges section in the Anchor Inspector: brush diameter, coincidence and the option. - Commands addon.pathtools.mergeEdge and movePointsTogether, params validated and covered by the command sweep. - Cursor stand-in, catalog rows in every language, docs and tests.
135 lines
6.0 KiB
Rust
135 lines
6.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", "lengthX", "lengthY", "reference", "baseAlong", "slope", "fillArc"]),
|
|
(&["spiral"], None, &["decay", "segments", "clockwise"]),
|
|
// The grids' Tool Options: the dividers and switches the drag uses, the Default Size and
|
|
// Reference Point a click's dialog opens with.
|
|
(&["rectangularGrid"], None, &["rows", "columns", "rowSkew", "columnSkew", "frame", "fill", "width", "height", "reference"]),
|
|
(&["polarGrid"], None, &["concentric", "radial", "concentricSkew", "radialSkew", "compound", "fill", "width", "height", "reference"]),
|
|
// Line Segment Tool Options: the Length and Angle a click's dialog opens with, Fill Line.
|
|
(&["lineSegment"], None, &["length", "angle", "fillLine"]),
|
|
(&["pencil", "paintbrush"], None, &["fidelity", "fill", "keepSelected", "editWithin", "closeWithin"]),
|
|
// Pencil Tool Options' Alt key toggles to Smooth Tool, Live preview and Live curve fitting (the
|
|
// Paintbrush has none of them).
|
|
(&["pencil"], None, &["altSmooth", "livePreview", "liveFit"]),
|
|
(&["smooth"], None, &["fidelity"]),
|
|
(&["blobBrush", "eraser"], None, &["size", "sizeMode", "sizeVariation"]),
|
|
(&["blobBrush"], None, &["fidelity", "keepSelected", "mergeOnlySelection"]),
|
|
// Eraser Tool Options' tip shape.
|
|
(&["eraser"], None, &["angle", "roundness"]),
|
|
// Live Paint Selection Tool Options (`builder::LivePaintSelectionTool`).
|
|
(&["livePaintSelection"], None, &["selectFills", "selectStrokes", "color", "width"]),
|
|
(&["polygon"], None, &["sides"]),
|
|
(&["star"], None, &["points"]),
|
|
(&["freeTransform"], None, &["constrain"]),
|
|
// Shape Builder Tool Options (`builder::ShapeBuilderOptions`).
|
|
(
|
|
&["shapeBuilder"],
|
|
None,
|
|
&[
|
|
"openFilledAsClosed",
|
|
"pickColorFrom",
|
|
"cursorSwatchPreview",
|
|
"selection",
|
|
"highlightFill",
|
|
"gapDetection",
|
|
"gapLength",
|
|
"clickStrokeSplitsPath",
|
|
"highlightStroke",
|
|
"highlightColor",
|
|
],
|
|
),
|
|
(&["artboard"], None, &["moveArt", "scaleArt"]),
|
|
// The add-ons' tools (`crate::addons`).
|
|
(&[crate::addons::anchor_eraser::ID], None, &["size", "tolerance", "pressure"]),
|
|
(&[crate::addons::extend_path::ID], None, &["mode"]),
|
|
(&[crate::addons::corner_tool::ID], None, &["radius", "kind"]),
|
|
(&[crate::addons::shared_edge::ID], None, &["diameter", "tolerance", "together"]),
|
|
(&[crate::addons::smart_pen::ID], None, &["next"]),
|
|
// The kind first: a new kind resets the values after it.
|
|
(&[crate::addons::parametric_shape::ID], None, &["kind", "count", "a", "b", "radius", "width", "height", "rotation"]),
|
|
// 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);
|
|
}
|
|
}
|