mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-11 22:22:25 +00:00
Recolor: a nested pattern copy that only takes swatch links is not a color change
When a tile's inner pattern only took swatch links, the outer pattern's copy still named the inner copy, so the trial pass counted a locked object filled with the outer pattern as left unchanged. Copies are now compared with the link-only copies they use mapped back to their originals, repeated until no more copies qualify.
This commit is contained in:
@@ -228,19 +228,31 @@ impl<'a> Recolor<'a> {
|
||||
}
|
||||
|
||||
/// The patterns this pass has copied whose copy differs from the original only by swatch
|
||||
/// links: the copy's name → the original's.
|
||||
/// links: the copy's name → the original's. A copy whose tile uses other copies counts when
|
||||
/// those copies do.
|
||||
fn link_only_copies(&self, d: &Document) -> HashMap<String, String> {
|
||||
let none = HashMap::new();
|
||||
let art = |v: &[Arc<Node>]| v.iter().map(|n| without_links((**n).clone(), &none)).collect::<Vec<_>>();
|
||||
let art = |v: &[Arc<Node>], same: &HashMap<String, String>| v.iter().map(|n| without_links((**n).clone(), same)).collect::<Vec<_>>();
|
||||
let copies: HashMap<&str, &PatternDef> = self.new_patterns.iter().map(|p| (p.name.as_str(), p)).collect();
|
||||
self.patterns
|
||||
let pairs: Vec<(&String, &String, &PatternDef, &PatternDef)> = self
|
||||
.patterns
|
||||
.iter()
|
||||
.filter_map(|(old, new)| {
|
||||
let new = new.as_ref()?;
|
||||
let copy = copies.get(new.as_str())?;
|
||||
(art(&d.pattern(old)?.art) == art(©.art)).then(|| (new.clone(), old.clone()))
|
||||
Some((new, old, d.pattern(old)?, *copies.get(new.as_str())?))
|
||||
})
|
||||
.collect()
|
||||
.collect();
|
||||
let mut same = HashMap::new();
|
||||
loop {
|
||||
let found: Vec<(String, String)> = pairs
|
||||
.iter()
|
||||
.filter(|(new, _, original, copy)| !same.contains_key(*new) && art(&original.art, &same) == art(©.art, &same))
|
||||
.map(|(new, old, _, _)| ((*new).clone(), (*old).clone()))
|
||||
.collect();
|
||||
if found.is_empty() {
|
||||
return same;
|
||||
}
|
||||
same.extend(found);
|
||||
}
|
||||
}
|
||||
|
||||
/// Recolour the objects `ids` and everything inside them (each once), add the new images and
|
||||
|
||||
@@ -720,6 +720,31 @@ fn recolor_of_everything_does_not_count_locked_art_that_would_only_take_a_swatch
|
||||
assert!(r.get("warning").is_none(), "{r}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn recolor_of_everything_does_not_count_locked_art_whose_nested_pattern_would_only_take_a_swatch_link() {
|
||||
let mut s = session();
|
||||
run(&mut s, "swatch.new", json!({"name": "Red", "color": "#ff0000", "global": true}));
|
||||
// "Dots": an unlinked red tile; "Rings": a tile filled with "Dots".
|
||||
let tile = rect(&mut s, json!("#ff0000"));
|
||||
run(&mut s, "select.set", json!({"ids": [tile.0]}));
|
||||
run(&mut s, "object.pattern.make", json!({"name": "Dots", "width": 20, "height": 20}));
|
||||
run(&mut s, "object.pattern.done", json!({}));
|
||||
let outer = rect(&mut s, json!("#000000"));
|
||||
run(&mut s, "paint.setFill", json!({"ids": [outer.0], "swatch": "Dots"}));
|
||||
run(&mut s, "select.set", json!({"ids": [outer.0]}));
|
||||
run(&mut s, "object.pattern.make", json!({"name": "Rings", "width": 40, "height": 40}));
|
||||
run(&mut s, "object.pattern.done", json!({}));
|
||||
rect(&mut s, json!("#ff0000"));
|
||||
let rings = rect(&mut s, json!("#000000"));
|
||||
run(&mut s, "paint.setFill", json!({"ids": [rings.0], "swatch": "Rings"}));
|
||||
set_props(&mut s, &[rings], json!({"locked": true}));
|
||||
select_all(&mut s);
|
||||
// The inner tile would only take the link to the document's red swatch.
|
||||
let r = run(&mut s, "recolor.apply", json!({"map": {"#ff0000": "#ff0000"}, "limitTo": "document"}));
|
||||
assert_eq!(r["notChanged"], json!({"locked": 0, "hidden": 0}), "{r}");
|
||||
assert!(r.get("warning").is_none(), "{r}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn locked_and_hidden_members_of_a_selected_group_are_recolored_and_not_counted() {
|
||||
let mut s = session();
|
||||
|
||||
Reference in New Issue
Block a user