mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-28 11:47:21 -06:00
M3.72: Tile Edge Color dialog and Show Swatch Bounds in pattern editing
Object > Pattern > Tile Edge Color... picks the colour of the tile edge
(a layer-colour preset or a custom colour), stored in the preference
patternTileEdgeColor and passed to the renderer. Pattern Options gains
Show Swatch Bounds: a dashed outline of the part of the tiling the swatch
repeats (the period of brick and hex tilings).
Commands: prefs.set {patternTileEdgeColor}, pattern.options
{showSwatchBounds}, ui.tileEdgeColor. Model: PatternDef.show_swatch_bounds.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
d8b942c43d
commit
b36fd67bf4
@@ -65,7 +65,7 @@ pub fn specs() -> Vec<CommandSpec> {
|
||||
"Pattern Options",
|
||||
["Window", "Pattern Options"],
|
||||
None,
|
||||
"{name? (default: the pattern being edited), newName?, tileType?, brickOffset?, width?, height?, hSpacing?, vSpacing?, sizeTileToArt?: bool, overlap?: {h: left|right, v: top|bottom}, copies?: 3|5|7|9, dimCopies?: %, showTileEdge?: bool}",
|
||||
"{name? (default: the pattern being edited), newName?, tileType?, brickOffset?, width?, height?, hSpacing?, vSpacing?, sizeTileToArt?: bool, overlap?: {h: left|right, v: top|bottom}, copies?: 3|5|7|9, dimCopies?: %, showTileEdge?: bool, showSwatchBounds?: bool (outline the part of the tiling the swatch repeats, dashed)}",
|
||||
has_doc,
|
||||
pattern_options
|
||||
),
|
||||
@@ -457,6 +457,9 @@ fn pattern_options(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
if let Some(v) = p.get("showTileEdge").and_then(Value::as_bool) {
|
||||
def.show_tile_edge = v;
|
||||
}
|
||||
if let Some(v) = p.get("showSwatchBounds").and_then(Value::as_bool) {
|
||||
def.show_swatch_bounds = v;
|
||||
}
|
||||
if def.size_tile_to_art {
|
||||
let saved = std::mem::take(&mut def.art);
|
||||
def.art = live_art.clone().unwrap_or_else(|| saved.clone());
|
||||
@@ -574,6 +577,7 @@ fn pattern_list(s: &mut Session, _: &Value) -> Result<Value> {
|
||||
"copies": p.copies,
|
||||
"dimCopies": p.dim_copies,
|
||||
"showTileEdge": p.show_tile_edge,
|
||||
"showSwatchBounds": p.show_swatch_bounds,
|
||||
"artCount": p.art.len(),
|
||||
})
|
||||
})
|
||||
|
||||
@@ -292,6 +292,8 @@ pub const PREF_SPECS: &[PrefSpec] = &[
|
||||
p!("touchGestures", "Devices", "", "Enable Touch Gestures", bool),
|
||||
// Graphic Styles panel menu
|
||||
p!("overrideCharColor", "Type", "Graphic Styles", "Override Character Color", bool),
|
||||
// Object → Pattern → Tile Edge Color
|
||||
p!("patternTileEdgeColor", "Guides & Grid", "Pattern Editing", "Tile Edge Color", color),
|
||||
];
|
||||
|
||||
pub fn spec(key: &str) -> Option<&'static PrefSpec> {
|
||||
@@ -377,6 +379,7 @@ impl Session {
|
||||
pub fn apply_prefs(&mut self, p: Prefs) {
|
||||
let grid_changed = p.gridline_every != self.prefs.gridline_every || p.grid_subdivisions != self.prefs.grid_subdivisions;
|
||||
let history_changed = p.history_states != self.prefs.history_states;
|
||||
let tile_edge_changed = p.pattern_tile_edge_color != self.prefs.pattern_tile_edge_color;
|
||||
self.prefs = p;
|
||||
vectorcraft_render::set_default_threads(u16::try_from(self.prefs.render_threads).ok());
|
||||
for st in &mut self.docs {
|
||||
@@ -385,6 +388,10 @@ impl Session {
|
||||
let over = st.history.undo.len().saturating_sub(st.history.limit);
|
||||
st.history.undo.drain(..over);
|
||||
}
|
||||
// Documents in pattern editing mode redraw their tile edge.
|
||||
if tile_edge_changed && st.doc.pattern_edit.is_some() {
|
||||
st.revision += 1;
|
||||
}
|
||||
if grid_changed {
|
||||
let d = std::sync::Arc::make_mut(&mut st.doc);
|
||||
d.grid.spacing = self.prefs.gridline_every;
|
||||
|
||||
@@ -310,6 +310,10 @@ pub struct Prefs {
|
||||
/// Override Character Color: a graphic style applied to type replaces its characters' fill
|
||||
/// and stroke with the style's fills and strokes.
|
||||
pub override_char_color: bool,
|
||||
// Pattern editing
|
||||
/// Object → Pattern → Tile Edge Color (`#rrggbb`): the tile edge and swatch bounds in pattern
|
||||
/// editing mode.
|
||||
pub pattern_tile_edge_color: String,
|
||||
}
|
||||
|
||||
impl Default for Prefs {
|
||||
@@ -423,6 +427,10 @@ impl Default for Prefs {
|
||||
touch_workspace: true,
|
||||
touch_gestures: true,
|
||||
override_char_color: true,
|
||||
pattern_tile_edge_color: {
|
||||
let [r, g, b] = vectorcraft_doc::LAYER_COLORS[0].1;
|
||||
Color::rgb8(r, g, b).to_hex()
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -828,4 +836,6 @@ mod tests_swatchlib;
|
||||
#[cfg(test)]
|
||||
mod tests_textedit;
|
||||
#[cfg(test)]
|
||||
mod tests_tileedge;
|
||||
#[cfg(test)]
|
||||
mod tests_xform;
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
//! Pattern editing: the Tile Edge Color preference and Pattern Options' Show Swatch Bounds.
|
||||
|
||||
use serde_json::{Value, json};
|
||||
use vectorcraft_doc::pattern::PatternDef;
|
||||
|
||||
use super::*;
|
||||
|
||||
fn run(s: &mut Session, id: &str, p: Value) -> Value {
|
||||
s.execute(id, &p).unwrap_or_else(|e| panic!("{id} {p}: {e}"))
|
||||
}
|
||||
|
||||
/// A session editing pattern "Dots" made from a 10×10 rectangle.
|
||||
fn editing() -> Session {
|
||||
let mut s = Session::new();
|
||||
run(&mut s, "file.new", json!({"width": 200, "height": 200}));
|
||||
run(&mut s, "shape.rectangle", json!({"x": 0, "y": 0, "width": 10, "height": 10}));
|
||||
run(&mut s, "object.pattern.make", json!({"name": "Dots", "width": 20, "height": 20}));
|
||||
s
|
||||
}
|
||||
|
||||
fn def(s: &Session) -> PatternDef {
|
||||
s.doc().unwrap().doc.pattern("Dots").unwrap().clone()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn show_swatch_bounds_is_a_pattern_option_that_saves() {
|
||||
let mut s = editing();
|
||||
assert!(!def(&s).show_swatch_bounds);
|
||||
run(&mut s, "pattern.options", json!({"showSwatchBounds": true}));
|
||||
assert!(def(&s).show_swatch_bounds);
|
||||
assert_eq!(run(&mut s, "pattern.list", json!({}))["patterns"][0]["showSwatchBounds"], true);
|
||||
// One undo step.
|
||||
run(&mut s, "edit.undo", json!({}));
|
||||
assert!(!def(&s).show_swatch_bounds);
|
||||
run(&mut s, "edit.redo", json!({}));
|
||||
// Saved with the document; files from before the option load with it off.
|
||||
let bytes = vectorcraft_format::save(&s.doc().unwrap().doc, false);
|
||||
let back = vectorcraft_format::load(&bytes).unwrap();
|
||||
assert_eq!(back.patterns, s.doc().unwrap().doc.patterns);
|
||||
assert!(back.pattern("Dots").unwrap().show_swatch_bounds);
|
||||
let mut old = serde_json::to_value(def(&s)).unwrap();
|
||||
old.as_object_mut().unwrap().remove("showSwatchBounds");
|
||||
assert!(!serde_json::from_value::<PatternDef>(old).unwrap().show_swatch_bounds);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tile_edge_color_is_a_preference_that_redraws_pattern_editing() {
|
||||
let mut s = editing();
|
||||
let default = run(&mut s, "prefs.get", json!({"key": "patternTileEdgeColor"}));
|
||||
let [r, g, b] = vectorcraft_doc::LAYER_COLORS[0].1;
|
||||
assert_eq!(default, vectorcraft_color::Color::rgb8(r, g, b).to_hex());
|
||||
let rev = s.doc().unwrap().revision;
|
||||
run(&mut s, "prefs.set", json!({"key": "patternTileEdgeColor", "value": "FF0000"}));
|
||||
assert_eq!(s.prefs.pattern_tile_edge_color, "#ff0000");
|
||||
assert!(s.doc().unwrap().revision > rev, "the canvas redraws the tile edge");
|
||||
assert!(s.execute("prefs.set", &json!({"key": "patternTileEdgeColor", "value": "red"})).is_err());
|
||||
// Saved with the preferences; older preferences get the default.
|
||||
let back: Prefs = serde_json::from_value(s.prefs.to_json()).unwrap();
|
||||
assert_eq!(back.pattern_tile_edge_color, "#ff0000");
|
||||
let mut old = s.prefs.to_json();
|
||||
old.as_object_mut().unwrap().remove("patternTileEdgeColor");
|
||||
assert_eq!(json!(serde_json::from_value::<Prefs>(old).unwrap().pattern_tile_edge_color), default);
|
||||
}
|
||||
Reference in New Issue
Block a user