vectorcraft/crates/tools/src/catalog.rs

196 lines
8.9 KiB
Rust

//! The tool catalogue: ids, labels, shortcuts and toolbar groups (Illustrator's Advanced toolbar order).
use serde::Serialize;
#[derive(Clone, Copy, Debug, Serialize)]
pub struct ToolInfo {
pub id: &'static str,
pub label: &'static str,
/// Single-key shortcut (Shift+key shown as "Shift+X").
pub shortcut: Option<&'static str>,
/// Icon name in the UI icon set.
pub icon: &'static str,
}
const fn t(id: &'static str, label: &'static str, shortcut: Option<&'static str>, icon: &'static str) -> ToolInfo {
ToolInfo { id, label, shortcut, icon }
}
/// Toolbar groups in order; the first tool of each group is the default visible one.
pub const TOOL_GROUPS: &[&[ToolInfo]] = &[
&[t("selection", "Selection Tool", Some("V"), "tool-selection")],
&[
t("directSelection", "Direct Selection Tool", Some("A"), "tool-direct"),
t("groupSelection", "Group Selection Tool", None, "tool-group-select"),
],
&[t("magicWand", "Magic Wand Tool", Some("Y"), "tool-magic-wand")],
&[t("lasso", "Lasso Tool", Some("Q"), "tool-lasso")],
&[
t("pen", "Pen Tool", Some("P"), "tool-pen"),
t("addAnchor", "Add Anchor Point Tool", Some("+"), "tool-pen-add"),
t("deleteAnchor", "Delete Anchor Point Tool", Some("-"), "tool-pen-delete"),
t("anchorPoint", "Anchor Point Tool", Some("Shift+C"), "tool-anchor"),
],
&[t("curvature", "Curvature Tool", Some("Shift+~"), "tool-curvature")],
&[
t("type", "Type Tool", Some("T"), "tool-type"),
t("areaType", "Area Type Tool", None, "tool-type-area"),
t("typeOnPath", "Type on a Path Tool", None, "tool-type-path"),
t("verticalType", "Vertical Type Tool", None, "tool-type-vertical"),
t("verticalAreaType", "Vertical Area Type Tool", None, "tool-type-vertical"),
t("verticalTypeOnPath", "Vertical Type on a Path Tool", None, "tool-type-path"),
t("touchType", "Touch Type Tool", Some("Shift+T"), "tool-touch-type"),
],
&[
t("lineSegment", "Line Segment Tool", Some("\\"), "tool-line"),
t("arc", "Arc Tool", None, "tool-arc"),
t("spiral", "Spiral Tool", None, "tool-spiral"),
t("rectangularGrid", "Rectangular Grid Tool", None, "tool-rect-grid"),
t("polarGrid", "Polar Grid Tool", None, "tool-polar-grid"),
],
&[
t("rectangle", "Rectangle Tool", Some("M"), "tool-rect"),
t("roundedRectangle", "Rounded Rectangle Tool", None, "tool-rounded-rect"),
t("ellipse", "Ellipse Tool", Some("L"), "tool-ellipse"),
t("polygon", "Polygon Tool", None, "tool-polygon"),
t("star", "Star Tool", None, "tool-star"),
t("flare", "Flare Tool", None, "tool-flare"),
],
&[t("paintbrush", "Paintbrush Tool", Some("B"), "tool-brush"), t("blobBrush", "Blob Brush Tool", Some("Shift+B"), "tool-blob-brush")],
&[
t("shaper", "Shaper Tool", Some("Shift+N"), "tool-shaper"),
t("pencil", "Pencil Tool", Some("N"), "tool-pencil"),
t("smooth", "Smooth Tool", None, "tool-smooth"),
t("pathEraser", "Path Eraser Tool", None, "tool-path-eraser"),
t("join", "Join Tool", None, "tool-join"),
],
&[
t("eraser", "Eraser Tool", Some("Shift+E"), "tool-eraser"),
t("scissors", "Scissors Tool", Some("C"), "tool-scissors"),
t("knife", "Knife", None, "tool-knife"),
t("mirrorCut", "Mirror & Cut Tool", None, "tool-mirror-cut"),
t("lineCut", "Line Cut Tool", None, "tool-line-cut"),
t("rectCut", "Rectangle Cut Tool", None, "tool-rect-cut"),
],
&[t("rotate", "Rotate Tool", Some("R"), "tool-rotate"), t("reflect", "Reflect Tool", Some("O"), "tool-reflect")],
&[
t("scale", "Scale Tool", Some("S"), "tool-scale"),
t("shear", "Shear Tool", None, "tool-shear"),
t("reshape", "Reshape Tool", None, "tool-reshape"),
],
&[
t("width", "Width Tool", Some("Shift+W"), "tool-width"),
t("warp", "Warp Tool", Some("Shift+R"), "tool-warp"),
t("twirl", "Twirl Tool", None, "tool-twirl"),
t("pucker", "Pucker Tool", None, "tool-pucker"),
t("bloat", "Bloat Tool", None, "tool-bloat"),
t("scallop", "Scallop Tool", None, "tool-scallop"),
t("crystallize", "Crystallize Tool", None, "tool-crystallize"),
t("wrinkle", "Wrinkle Tool", None, "tool-wrinkle"),
],
&[t("freeTransform", "Free Transform Tool", Some("E"), "tool-free-transform"), t("puppetWarp", "Puppet Warp Tool", None, "tool-puppet")],
&[
t("shapeBuilder", "Shape Builder Tool", Some("Shift+M"), "tool-shape-builder"),
t("livePaintBucket", "Live Paint Bucket", Some("K"), "tool-bucket"),
t("livePaintSelection", "Live Paint Selection Tool", Some("Shift+L"), "tool-live-select"),
],
&[
t("perspectiveGrid", "Perspective Grid Tool", Some("Shift+P"), "tool-perspective"),
t("perspectiveSelection", "Perspective Selection Tool", Some("Shift+V"), "tool-perspective-select"),
],
&[t("mesh", "Mesh Tool", Some("U"), "tool-mesh")],
&[t("gradient", "Gradient Tool", Some("G"), "tool-gradient")],
&[t("eyedropper", "Eyedropper Tool", Some("I"), "tool-eyedropper"), t("measure", "Measure Tool", None, "tool-measure")],
&[t("blend", "Blend Tool", Some("W"), "tool-blend")],
&[
t("symbolSprayer", "Symbol Sprayer Tool", Some("Shift+S"), "tool-symbol"),
t("symbolShifter", "Symbol Shifter Tool", None, "tool-symbol"),
t("symbolScruncher", "Symbol Scruncher Tool", None, "tool-symbol"),
t("symbolSizer", "Symbol Sizer Tool", None, "tool-symbol"),
t("symbolSpinner", "Symbol Spinner Tool", None, "tool-symbol"),
t("symbolStainer", "Symbol Stainer Tool", None, "tool-symbol"),
t("symbolScreener", "Symbol Screener Tool", None, "tool-symbol"),
t("symbolStyler", "Symbol Styler Tool", None, "tool-symbol"),
],
&[
t("columnGraph", "Column Graph Tool", Some("J"), "tool-graph"),
t("stackedColumnGraph", "Stacked Column Graph Tool", None, "tool-graph"),
t("barGraph", "Bar Graph Tool", None, "tool-graph"),
t("stackedBarGraph", "Stacked Bar Graph Tool", None, "tool-graph"),
t("lineGraph", "Line Graph Tool", None, "tool-graph"),
t("areaGraph", "Area Graph Tool", None, "tool-graph"),
t("scatterGraph", "Scatter Graph Tool", None, "tool-graph"),
t("pieGraph", "Pie Graph Tool", None, "tool-graph"),
t("radarGraph", "Radar Graph Tool", None, "tool-graph"),
],
&[
t("artboard", "Artboard Tool", Some("Shift+O"), "tool-artboard"),
t("slice", "Slice Tool", Some("Shift+K"), "tool-slice"),
t("sliceSelection", "Slice Selection Tool", None, "tool-slice"),
],
&[
t("hand", "Hand Tool", Some("H"), "tool-hand"),
t("rotateView", "Rotate View Tool", Some("Shift+H"), "tool-rotate-view"),
t("printTiling", "Print Tiling Tool", None, "tool-print-tiling"),
],
&[t("zoom", "Zoom Tool", Some("Z"), "tool-zoom")],
];
pub fn all_tools() -> impl Iterator<Item = &'static ToolInfo> {
TOOL_GROUPS.iter().flat_map(|g| g.iter())
}
pub fn tool_info(id: &str) -> Option<&'static ToolInfo> {
all_tools().find(|t| t.id == id)
}
/// Tool for a single-key shortcut such as "V" or "Shift+M".
pub fn tool_for_shortcut(s: &str) -> Option<&'static ToolInfo> {
all_tools().find(|t| t.shortcut == Some(s))
}
/// Index of the group containing `id`.
pub fn group_of(id: &str) -> Option<usize> {
TOOL_GROUPS.iter().position(|g| g.iter().any(|t| t.id == id))
}
/// Selection, Direct Selection and Group Selection: the tools Cmd held lends the others for a drag.
pub fn is_selection_tool(id: &str) -> bool {
matches!(id, "selection" | "directSelection" | "groupSelection")
}
/// The tools that show a selected path's anchors and handles as Direct Selection does, and drag
/// them: a Cmd drag with one of them is a Direct Selection drag until a selection tool is chosen.
pub fn edits_anchors(id: &str) -> bool {
matches!(id, "directSelection" | "pen" | "addAnchor" | "deleteAnchor" | "anchorPoint" | "curvature")
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn unique_ids_and_shortcuts() {
let mut ids: Vec<&str> = all_tools().map(|t| t.id).collect();
let n = ids.len();
ids.sort();
ids.dedup();
assert_eq!(ids.len(), n, "duplicate tool ids");
let mut sc: Vec<&str> = all_tools().filter_map(|t| t.shortcut).collect();
let n = sc.len();
sc.sort();
sc.dedup();
assert_eq!(sc.len(), n, "duplicate shortcuts");
assert!(n > 40);
}
#[test]
fn lookups() {
assert_eq!(tool_for_shortcut("V").unwrap().id, "selection");
assert_eq!(tool_for_shortcut("Shift+M").unwrap().id, "shapeBuilder");
assert_eq!(group_of("star"), group_of("rectangle"));
assert!(is_selection_tool("groupSelection") && !is_selection_tool("pen"));
assert!(edits_anchors("pen") && !edits_anchors("rectangle"));
}
}