diff --git a/crates/ui-egui/src/dialogs/recolor.rs b/crates/ui-egui/src/dialogs/recolor.rs index 3bdddb3498..238205216e 100644 --- a/crates/ui-egui/src/dialogs/recolor.rs +++ b/crates/ui-egui/src/dialogs/recolor.rs @@ -11,7 +11,9 @@ //! model), New Row (a row with no current colors above the first selected row, or at the top, //! with that row's new color; it recolors nothing until Merge moves colors into it), Merge and //! Separate, Randomize order or -//! saturation and brightness, Reset, the Method and Limit to Library (its folder button imports a +//! saturation and brightness, Find (with it on, the art of the selected rows shows as the preview +//! shows it, their current colors with Preview off, and the rest of the selected art shows its +//! current colors dimmed; a second click shows the art as before), Reset, the Method and Limit to Library (its folder button imports a //! library file and limits to it; a library's colours apply as its swatches: a spot colour stays a //! spot colour, and joins the document's swatches). Edit tab: a hue and //! saturation wheel with a marker per new colour (drag one; with linked handles they all turn and @@ -50,7 +52,8 @@ //! `globalAdjust` in every slider mode), `display` (the Edit tab's `smooth`, `segmented` or `bars`; //! unset: `smooth`), `themePicker` (the Color Theme Picker is on), `themePicks` (its picks, as //! `recolor.pickTheme`'s `picks`; a new list recolors the rows), `weights` (one per row, as -//! `recolor.weigh`'s; a new list moves the rows' current colors toward them). Changing `colors`, a +//! `recolor.weigh`'s; a new list moves the rows' current colors toward them), `findColors` (Find is +//! on; it shows the art so on the Assign tab, with art and rows selected). Changing `colors`, a //! preserve flag or `limitTo` reduces the rows again (and drops `weights`). use egui::{Rect, Sense, Ui, pos2, vec2}; @@ -163,7 +166,7 @@ pub fn open(app: &mut VectorcraftApp, p: &Value) -> Result { "preserveWhite": kept("preserveWhite", true), "preserveBlack": kept("preserveBlack", true), "preserveGrays": kept("preserveGrays", false), "limitTo": limit, "group": group, "groupName": if new_group { Some(NEW_GROUP) } else { group }, "tab": "assign", "rule": Harmony::Complementary.id(), "linked": true, - "preview": true, THEME_PICKER: false, THEME_PICKS: [], WEIGHTS: null, "__art": art, "__assign": assign, "__newGroup": new_group, + "preview": true, THEME_PICKER: false, THEME_PICKS: [], WEIGHTS: null, FIND: false, "__art": art, "__assign": assign, "__newGroup": new_group, }); let mut d = Dialog::new(KIND, fields); // Without art the rows are there from the start: limit them now (art's rows snap as they reduce). @@ -217,6 +220,8 @@ fn sync(app: &mut VectorcraftApp, d: &mut Dialog) { } snap(app, d, &mut rows); d.fields.insert("rows".into(), Value::Array(rows)); + // Find dims the preserved colors with the rows that aren't selected. + d.fields.insert(PRESERVED.into(), r["preserved"].clone()); d.fields.insert("__sel".into(), json!([])); // The new rows hold no slider edit. d.fields.remove(COMPS); @@ -590,6 +595,102 @@ fn apply_params(d: &Dialog) -> Value { p } +/// The Find button's field, and the tint of its current color that the art of the rows that +/// aren't selected shows while it is on (VectorCraft's own amount: [`Color::tinted`]). +const FIND: &str = "findColors"; +const FIND_DIM: f32 = 0.25; +/// The tints tried when a dimmed color is one a selected row lists: [`FIND_DIM`] and each lighter +/// one a percent apart, down to 1%. +const FIND_TRIES: usize = 25; +/// The colors of the art that the rows leave out (Preserve White, Black and Grays), as +/// `recolor.reduce` returned them. +const PRESERVED: &str = "__preserved"; + +/// A row's current color as `recolor.apply` matches it: an exact color (its key, parsed whatever +/// its case or spacing), or `Err` with the hex of a "#rrggbb" entry, which matches every color +/// shown as that hex. +type FindEntry = Result; + +fn find_entry(k: &Value) -> Option { + match k.as_str() { + Some(s) => ColorKey::parse(s).map(Ok).or_else(|| color_value(k).map(|c| Err(c.to_hex()))), + None => color_value(k).map(|c| Ok(ColorKey::of(&c))), + } +} + +/// While Find is on, on the Assign tab with art and rows selected: what the art previews instead of +/// [`apply_params`], as `command.batch` parameters. A first `recolor.apply` gives each current color +/// of the rows that aren't selected, and each preserved color, its [`FIND_DIM`] tint, or the nearest lighter one when that is a +/// color a selected row lists (a color a selected row also lists stays); +/// with Preview on, a second recolors the selected rows as [`apply_params`] would (the other rows +/// excluded, no color group rewritten). None otherwise, and when there is nothing to dim with +/// Preview off. OK still applies [`apply_params`]. +fn find_params(d: &Dialog) -> Option { + if !d.bool(FIND) || !d.bool("__art") || d.str("tab") == "edit" { + return None; + } + let rs = rows(d); + let sel: Vec = selection(d).into_iter().filter(|i| *i < rs.len()).collect(); + if sel.is_empty() { + return None; + } + let keys = |r: &Value| r["from"].as_array().cloned().unwrap_or_default(); + let found: Vec = sel.iter().flat_map(|&i| keys(&rs[i])).collect(); + // The selected rows' entries as `recolor.apply` reads them: exact colors and "#rrggbb" ones. + let found: Vec = found.iter().filter_map(find_entry).collect(); + let found_keys: Vec = found.iter().filter_map(|e| e.as_ref().ok().copied()).collect(); + let found_hex_entries: Vec = found.iter().filter_map(|e| e.as_ref().err().cloned()).collect(); + let found_hex: Vec = found.iter().map(|e| e.as_ref().map_or_else(Clone::clone, |k| k.color().to_hex())).collect(); + // A dimmed color must not be one the second step recolors (by its key, or by its hex as a + // "#rrggbb" entry matches): the nearest lighter tint that is none of them is taken instead. + let dimmed = |c: Color| { + (0..FIND_TRIES) + .map(|n| c.tinted(FIND_DIM - n as f32 * 0.01)) + .find(|t| !found_keys.contains(&ColorKey::of(t)) && !found_hex_entries.contains(&t.to_hex())) + .map(|t| key(&t)) + }; + // The current colors of the rows that aren't selected, and the preserved colors. + let preserved = d.fields.get(PRESERVED).and_then(Value::as_array).cloned().unwrap_or_default(); + let others = rs.iter().enumerate().filter(|(i, _)| !sel.contains(i)).flat_map(|(_, r)| keys(r)).chain(preserved); + let mut dim = serde_json::Map::new(); + // A color a selected row lists stays, and so does one shown as the same hex when either entry is + // "#rrggbb" (it matches both). Two keys of the same hex are separate colors. + let listed = |k: &Value| match find_entry(k) { + Some(Ok(key)) => found_keys.contains(&key) || found_hex_entries.contains(&key.color().to_hex()), + Some(Err(hex)) => found_hex.contains(&hex), + None => false, + }; + for k in others.filter(|k| !listed(k)) { + // A string entry keeps its own form ("#rrggbb" matches by hex); a color value goes by its key. + let name = match k.as_str() { + Some(s) => Some(s.to_string()), + None => color_value(&k).map(|c| ColorKey::of(&c).to_string()), + }; + if let (Some(to), Some(name)) = (color_value(&k).and_then(dimmed), name) { + dim.insert(name, to); + } + } + let mut commands = vec![]; + if !dim.is_empty() { + commands.push(json!({"command": CMD, "params": {"map": dim}})); + } + if d.bool("preview") { + let mut p = apply_params(d); + let mut only = rs; + for (_, r) in only.iter_mut().enumerate().filter(|(i, _)| !sel.contains(i)) { + r["exclude"] = json!(true); + } + p["map"] = Value::Array(only); + if let Some(p) = p.as_object_mut() { + for k in ["group", "groupColors", "rename"] { + p.remove(k); + } + } + commands.push(json!({"command": CMD, "params": p})); + } + (!commands.is_empty()).then(|| json!({"commands": commands})) +} + fn body(app: &mut VectorcraftApp, ui: &mut Ui, d: &mut Dialog) -> bool { sync(app, d); sync_theme(app, d); @@ -650,7 +751,15 @@ fn body(app: &mut VectorcraftApp, ui: &mut Ui, d: &mut Dialog) -> bool { } sync(app, d); if d.bool("__art") { - form::preview(app, ui, d, "Recolor Artwork", CMD, apply_params(d)); + match find_params(d) { + // Find shows the art so with Preview off too. + Some(p) => { + ui.add_space(8.0); + form::preview_check(ui, d); + form::preview_now(app, d, "Recolor Artwork", "command.batch", p); + } + None => form::preview(app, ui, d, "Recolor Artwork", CMD, apply_params(d)), + } } if let Some(c) = pick.and_then(|i| Some((i, to_color(rows(d).get(i)?)?))) { *d = super::color_picker::over_recolor(d, c.1, c.0); @@ -874,6 +983,10 @@ fn assign_tab(app: &mut VectorcraftApp, ui: &mut Ui, d: &mut Dialog, rows: &mut } } } + let finding = d.bool(FIND); + if widgets::icon_button_enabled(ui, "search", tl!("Find the selected colors in the artwork"), finding, d.bool("__art"), 24.0).clicked() { + d.fields.insert(FIND.into(), json!(!finding)); + } if widgets::icon_button(ui, "rotate-ccw", tl!("Reset the rows to the artwork's colors"), false, 24.0).clicked() { d.fields.remove("__reduced"); d.fields.remove(COMPS); @@ -2104,6 +2217,172 @@ mod tests { assert_eq!(new_colors(&app), [json!("rgb 0 255 0"), json!("rgb 255 255 0")]); } + /// Find previews nothing of its own while it is off, on the Edit tab, without art or without a + /// selected row. On, a first `recolor.apply` dims each current color of the other rows (a color + /// a selected row also lists stays), and with Preview on a second recolors the selected rows + /// alone, without rewriting the color group. + #[test] + fn find_dims_the_colors_of_the_rows_not_selected() { + let mut d = Dialog::new( + KIND, + json!({"rows": rows(), "__art": true, "preview": true, "method": "exact", "limitTo": "", "group": "G", "groupName": "H", "__sel": [0]}), + ); + assert_eq!(find_params(&d), None, "off"); + d.fields.insert(FIND.into(), json!(true)); + let dim = |k: &str| key(&color_value(&json!(k)).unwrap().tinted(FIND_DIM)); + let p = find_params(&d).expect("on"); + let cmds = p["commands"].as_array().unwrap(); + assert_eq!(cmds.len(), 2); + assert_eq!(cmds[0]["command"], CMD); + assert_eq!( + cmds[0]["params"]["map"], + json!({"rgb 0 0 255": dim("rgb 0 0 255"), "rgb 0 0 128": dim("rgb 0 0 128"), "rgb 0 255 0": dim("rgb 0 255 0")}) + ); + assert_eq!(dim("rgb 0 0 255"), json!("rgb 191.25 191.25 255"), "a quarter of the color, the rest white"); + let second = &cmds[1]["params"]; + assert_eq!(second["map"][0], rows()[0], "the selected row recolors as it would"); + assert_eq!((second["map"][1]["exclude"].clone(), second["map"][2]["exclude"].clone()), (json!(true), json!(true))); + assert!(second.get("group").is_none() && second.get("rename").is_none(), "{second}"); + // A color that a selected row lists as a hex stays. + let mut e = d.clone(); + let mut rs = rows(); + rs[0]["from"] = json!(["#0000ff"]); + e.fields.insert("rows".into(), json!(rs)); + let map = find_params(&e).unwrap()["commands"][0]["params"]["map"].clone(); + assert!(map.get("rgb 0 0 255").is_none() && map.get("rgb 0 0 128").is_some(), "{map}"); + // A color a selected row lists by its key keeps only that color: another key of the same hex + // dims, and a hex entry of it stays (it would dim the selected color too). + let mut e = d.clone(); + let mut rs = rows(); + rs[0]["from"] = json!(["rgb 191 191 255"]); + rs[1]["from"] = json!(["rgb 191.25 191.25 255", "#bfbfff"]); + e.fields.insert("rows".into(), json!(rs)); + let map = find_params(&e).unwrap()["commands"][0]["params"]["map"].clone(); + assert!(map.get("rgb 191.25 191.25 255").is_some() && map.get("#bfbfff").is_none(), "{map}"); + // A key is read whatever its case or spacing, as `recolor.apply` reads it. + let mut e = d.clone(); + let mut rs = rows(); + rs[0]["from"] = json!(["RGB 191 191 255"]); + rs[1]["from"] = json!(["rgb 191 191 255", "rgb 0 0 128"]); + e.fields.insert("rows".into(), json!(rs)); + let map = find_params(&e).unwrap()["commands"][0]["params"]["map"].clone(); + assert!(map.get("rgb 191 191 255").is_none() && map.get("rgb 0 0 128").is_some(), "{map}"); + // The preserved colors dim too. + let mut e = d.clone(); + e.fields.insert(PRESERVED.into(), json!(["rgb 0 0 0"])); + assert_eq!(find_params(&e).unwrap()["commands"][0]["params"]["map"]["rgb 0 0 0"], dim("rgb 0 0 0")); + // A color given as a value instead of a string dims under its key, as `recolor.apply` reads it. + let mut e = d.clone(); + let mut rs = rows(); + rs[1]["from"] = json!([[0.0, 0.0, 1.0], {"c": 0, "m": 100, "y": 100, "k": 0}]); + e.fields.insert("rows".into(), json!(rs)); + let map = find_params(&e).unwrap()["commands"][0]["params"]["map"].clone(); + assert_eq!(map["rgb 0 0 255"], dim("rgb 0 0 255"), "{map}"); + assert_eq!(map["cmyk 0 100 100 0"], dim("cmyk 0 100 100 0"), "{map}"); + // A color a selected row lists is not dimmed; with Preview off only the dimming runs. + let mut rs = rows(); + rs[2]["from"] = json!(["rgb 0 255 0", "rgb 255 0 0"]); + d.fields.insert("rows".into(), json!(rs)); + d.fields.insert("preview".into(), json!(false)); + let p = find_params(&d).unwrap(); + assert_eq!(p["commands"].as_array().map(Vec::len), Some(1)); + assert!(p["commands"][0]["params"]["map"].get("rgb 255 0 0").is_none(), "{p}"); + // A dimmed color that a selected row lists would be recolored with it: a lighter tint is taken. + let mut rs = rows(); + rs[0]["from"] = json!(["rgb 255 0 0", "rgb 191.25 191.25 255"]); + d.fields.insert("rows".into(), json!(rs)); + let p = find_params(&d).unwrap(); + let to = color_value(&p["commands"][0]["params"]["map"]["rgb 0 0 255"]).unwrap(); + assert_eq!(to.to_hex(), "#c2c2ff", "{p}"); + // So is one that a selected "#rrggbb" entry matches by its hex. + rs[0]["from"] = json!(["rgb 255 0 0", "#bfbfff"]); + d.fields.insert("rows".into(), json!(rs)); + let p = find_params(&d).unwrap(); + let to = color_value(&p["commands"][0]["params"]["map"]["rgb 0 0 255"]).unwrap(); + assert_eq!(to.to_hex(), "#c2c2ff", "{p}"); + // When the twenty tints from 25% through 6% are all listed, the 5% tint is taken. + let blue = color_value(&json!("rgb 0 0 255")).unwrap(); + let tint = |n: usize| key(&blue.tinted(FIND_DIM - n as f32 * 0.01)); + let mut from = vec![json!("rgb 255 0 0")]; + from.extend((0..20).map(tint)); + rs[0]["from"] = json!(from); + d.fields.insert("rows".into(), json!(rs)); + let p = find_params(&d).unwrap(); + assert_eq!(p["commands"][0]["params"]["map"]["rgb 0 0 255"], tint(20), "{p}"); + // Another key of the same hex matches only itself, so the tint is kept. + rs[0]["from"] = json!(["rgb 255 0 0", "rgb 191 191 255"]); + d.fields.insert("rows".into(), json!(rs)); + let p = find_params(&d).unwrap(); + assert_eq!(p["commands"][0]["params"]["map"]["rgb 0 0 255"], dim("rgb 0 0 255"), "{p}"); + // Every row selected with Preview off: nothing to show. + d.fields.insert("__sel".into(), json!([0, 1, 2])); + assert_eq!(find_params(&d), None); + for (k, v) in [("__sel", json!([])), ("__sel", json!([7])), ("tab", json!("edit")), ("__art", json!(false))] { + let mut e = d.clone(); + e.fields.insert("preview".into(), json!(true)); + e.fields.insert("__sel".into(), json!([0])); + e.fields.insert(k.into(), v.clone()); + assert_eq!(find_params(&e), None, "{k}: {v}"); + } + } + + /// In the dialog, Find with the red art's row selected shows the red art's new color and the + /// blue art dimmed, with Preview off the red art's own color; off again, the art shows as the + /// preview has it. Cancel leaves the art as it was with no undo step, and OK with Find on + /// applies the rows to all the art, as one undo step. + #[test] + fn find_shows_the_selected_rows_art_and_dims_the_rest() { + let mut app = VectorcraftApp::new(vectorcraft_engine::Session::new(), Default::default()); + let ctx = egui::Context::default(); + let [red, blue] = theme_setup(&mut app, &ctx); + let undo = app.session.doc().unwrap().history.undo.len(); + let set = |app: &mut VectorcraftApp, k: &str, v: Value| { + app.ui.dialog.as_mut().unwrap().fields.insert(k.into(), v); + }; + let rs = json!([{"from": ["rgb 255 0 0"], "to": "rgb 0 255 0"}, {"from": ["rgb 0 0 255"], "to": "rgb 255 255 0"}]); + set(&mut app, "rows", rs.clone()); + set(&mut app, "__sel", json!([0])); + frame(&mut app, &ctx, 0.1, vec![], 0); + let fills = |app: &VectorcraftApp| (fill_hex(app, red), fill_hex(app, blue)); + assert_eq!(fills(&app), ("#00ff00".into(), "#ffff00".into()), "off: the preview"); + set(&mut app, FIND, json!(true)); + frame(&mut app, &ctx, 0.2, vec![], 0); + assert_eq!(fills(&app), ("#00ff00".into(), "#bfbfff".into()), "on: the other art dimmed"); + set(&mut app, "preview", json!(false)); + frame(&mut app, &ctx, 0.3, vec![], 0); + assert_eq!(fills(&app), ("#ff0000".into(), "#bfbfff".into()), "Preview off: the current colors"); + set(&mut app, "__sel", json!([1])); + frame(&mut app, &ctx, 0.4, vec![], 0); + assert_eq!(fills(&app), ("#ffbfbf".into(), "#0000ff".into()), "the other row selected"); + set(&mut app, FIND, json!(false)); + frame(&mut app, &ctx, 0.5, vec![], 0); + assert_eq!(fills(&app), ("#ff0000".into(), "#0000ff".into()), "off with Preview off: the art as it is"); + assert_eq!(app.session.doc().unwrap().history.undo.len(), undo, "Find records no undo step"); + set(&mut app, FIND, json!(true)); + frame(&mut app, &ctx, 0.6, vec![], 0); + crate::dialogs::cancel(&mut app); + assert!(app.ui.dialog.is_none()); + assert_eq!(fills(&app), ("#ff0000".into(), "#0000ff".into()), "Cancel: the art as it was"); + assert_eq!(app.session.doc().unwrap().history.undo.len(), undo); + // A black square joins the selection: Preserve Black leaves it out of the rows. + let black = square(&mut app, 70.0, "#000000"); + let undo = app.session.doc().unwrap().history.undo.len(); + app.run("select.set", json!({"ids": [red, blue, black]})).unwrap(); + app.run("ui.recolorDialog", json!({})).unwrap(); + set(&mut app, "method", json!(Method::Exact.id())); + frame(&mut app, &ctx, 1.0, vec![], 0); + set(&mut app, "rows", rs); + set(&mut app, "__sel", json!([0])); + set(&mut app, FIND, json!(true)); + frame(&mut app, &ctx, 1.1, vec![], 0); + assert_eq!(fills(&app), ("#00ff00".into(), "#bfbfff".into())); + assert_eq!(fill_hex(&app, black), "#bfbfbf", "the preserved black dims too"); + crate::dialogs::confirm(&mut app).unwrap(); + assert_eq!(fills(&app), ("#00ff00".into(), "#ffff00".into()), "OK applies the rows to all the art"); + assert_eq!(fill_hex(&app, black), "#000000", "and keeps the preserved black"); + assert_eq!(app.session.doc().unwrap().history.undo.len(), undo + 1, "one undo step"); + } + /// In a CMYK document colors opened alone are saved as a new color group in their own model. #[test] fn a_new_group_from_colors_keeps_their_model_in_a_cmyk_document() { diff --git a/crates/ui-egui/src/i18n/bg.tsv b/crates/ui-egui/src/i18n/bg.tsv index 7a13094582..da1516f349 100644 --- a/crates/ui-egui/src/i18n/bg.tsv +++ b/crates/ui-egui/src/i18n/bg.tsv @@ -1493,6 +1493,7 @@ font-technology Variable Променливи Show smooth color wheel Показване на плавно цветово колело Show segmented color wheel Показване на сегментирано цветово колело Show color bars Показване на цветни ленти + Find the selected colors in the artwork Намиране на избраните цветове в илюстрацията Harmony Sets Набори от хармонии Height Височина Height: Височина: diff --git a/crates/ui-egui/src/i18n/bs.tsv b/crates/ui-egui/src/i18n/bs.tsv index cd07f3f270..e5b28f72a0 100644 --- a/crates/ui-egui/src/i18n/bs.tsv +++ b/crates/ui-egui/src/i18n/bs.tsv @@ -2908,6 +2908,7 @@ digits Malayalam Malajalam Show smooth color wheel Prikaži glatki kotač boja Show segmented color wheel Prikaži segmentirani kotač boja Show color bars Prikaži trake boja + Find the selected colors in the artwork Pronađi odabrane boje u crtežu Harmony Rules Pravila harmonije Keep this row's colors (exclude) Zadrži boje ovog reda (isključi) Limit to Library: Ograniči na biblioteku: diff --git a/crates/ui-egui/src/i18n/ca.tsv b/crates/ui-egui/src/i18n/ca.tsv index 87ce2c3730..2631c1274e 100644 --- a/crates/ui-egui/src/i18n/ca.tsv +++ b/crates/ui-egui/src/i18n/ca.tsv @@ -2025,6 +2025,7 @@ digits Malayalam Malaiàlam Show smooth color wheel Mostra la roda de color contínua Show segmented color wheel Mostra la roda de color segmentada Show color bars Mostra les barres de color + Find the selected colors in the artwork Troba els colors seleccionats a l’obra Harmony Sets Conjunts d’harmonia HDTV 1080p HDTV 1080p HDTV 720p HDTV 720p diff --git a/crates/ui-egui/src/i18n/cs.tsv b/crates/ui-egui/src/i18n/cs.tsv index ffc55aad5a..5e9a9c8200 100644 --- a/crates/ui-egui/src/i18n/cs.tsv +++ b/crates/ui-egui/src/i18n/cs.tsv @@ -2986,6 +2986,7 @@ digits Malayalam Malajálamské Show smooth color wheel Zobrazit plynulé barevné kolo Show segmented color wheel Zobrazit segmentované barevné kolo Show color bars Zobrazit barevné pruhy + Find the selected colors in the artwork Najít vybrané barvy v kresbě Harmony Rules Pravidla harmonie Keep this row's colors (exclude) Ponechat barvy tohoto řádku (vyloučit) Limit to Library: Omezit na knihovnu: diff --git a/crates/ui-egui/src/i18n/da.tsv b/crates/ui-egui/src/i18n/da.tsv index edce184e8e..dd4e39f33d 100644 --- a/crates/ui-egui/src/i18n/da.tsv +++ b/crates/ui-egui/src/i18n/da.tsv @@ -3384,6 +3384,7 @@ digits Malayalam Malayalam Show smooth color wheel Vis glat farvehjul Show segmented color wheel Vis segmenteret farvehjul Show color bars Vis farvebjælker + Find the selected colors in the artwork Find de valgte farver i grafikken Harmony Rules Harmoniregler Keep this row's colors (exclude) Behold farverne i denne række (ekskludér) Limit to Library: Begræns til bibliotek: diff --git a/crates/ui-egui/src/i18n/de.tsv b/crates/ui-egui/src/i18n/de.tsv index c456cd5bc1..a533a2a0c5 100644 --- a/crates/ui-egui/src/i18n/de.tsv +++ b/crates/ui-egui/src/i18n/de.tsv @@ -1536,6 +1536,7 @@ file-filter Templates Vorlagen Show smooth color wheel Stufenlosen Farbkreis anzeigen Show segmented color wheel Segmentierten Farbkreis anzeigen Show color bars Farbbalken anzeigen + Find the selected colors in the artwork Ausgewählte Farben in der Grafik finden Harmony Sets Harmoniesätze Height Höhe Height: Höhe: diff --git a/crates/ui-egui/src/i18n/el.tsv b/crates/ui-egui/src/i18n/el.tsv index 4e30f47e3f..a8568bf32d 100644 --- a/crates/ui-egui/src/i18n/el.tsv +++ b/crates/ui-egui/src/i18n/el.tsv @@ -1468,6 +1468,7 @@ font-technology Variable Μεταβλητές Show smooth color wheel Εμφάνιση ομαλού χρωματικού τροχού Show segmented color wheel Εμφάνιση τμηματοποιημένου χρωματικού τροχού Show color bars Εμφάνιση χρωματικών ράβδων + Find the selected colors in the artwork Εύρεση των επιλεγμένων χρωμάτων στο σχέδιο Harmony Sets Σύνολα χρωματικής αρμονίας Height Ύψος Height: Ύψος: diff --git a/crates/ui-egui/src/i18n/es.tsv b/crates/ui-egui/src/i18n/es.tsv index 6719052a94..3d8026dee4 100644 --- a/crates/ui-egui/src/i18n/es.tsv +++ b/crates/ui-egui/src/i18n/es.tsv @@ -1547,6 +1547,7 @@ font-technology Variable Variables Show smooth color wheel Mostrar rueda de color continua Show segmented color wheel Mostrar rueda de color segmentada Show color bars Mostrar barras de color + Find the selected colors in the artwork Buscar los colores seleccionados en la ilustración Harmony Sets Conjuntos de armonía Height Altura Height: Altura: diff --git a/crates/ui-egui/src/i18n/fi.tsv b/crates/ui-egui/src/i18n/fi.tsv index 2ed3c5e427..1b96267e8d 100644 --- a/crates/ui-egui/src/i18n/fi.tsv +++ b/crates/ui-egui/src/i18n/fi.tsv @@ -2930,6 +2930,7 @@ digits Malayalam Malajalam Show smooth color wheel Näytä liukuva väriympyrä Show segmented color wheel Näytä segmentoitu väriympyrä Show color bars Näytä väripalkit + Find the selected colors in the artwork Etsi valitut värit kuvituksesta Harmony Rules Harmoniasäännöt Keep this row's colors (exclude) Säilytä tämän rivin värit (jätä pois) Limit to Library: Rajoita kirjastoon: diff --git a/crates/ui-egui/src/i18n/fr.tsv b/crates/ui-egui/src/i18n/fr.tsv index 6a735eb1eb..68021064ec 100644 --- a/crates/ui-egui/src/i18n/fr.tsv +++ b/crates/ui-egui/src/i18n/fr.tsv @@ -1540,6 +1540,7 @@ font-technology Variable Variables Show smooth color wheel Afficher la roue chromatique continue Show segmented color wheel Afficher la roue chromatique segmentée Show color bars Afficher les barres de couleur + Find the selected colors in the artwork Rechercher les couleurs sélectionnées dans l’illustration Harmony Rules: Règles d’harmonie : Harmony Sets Ensembles d’harmonies Height Hauteur diff --git a/crates/ui-egui/src/i18n/gu.tsv b/crates/ui-egui/src/i18n/gu.tsv index 167668fd89..233400b2e2 100644 --- a/crates/ui-egui/src/i18n/gu.tsv +++ b/crates/ui-egui/src/i18n/gu.tsv @@ -3563,6 +3563,7 @@ Show all plates બધી પ્લેટ બતાવો Show axis અક્ષ બતાવો Show color bars રંગ બાર બતાવો + Find the selected colors in the artwork પસંદ કરેલા રંગો આર્ટવર્કમાં શોધો Show handles when multiple anchors are selected બહુવિધ એન્કર પસંદ હોય ત્યારે હૅન્ડલ બતાવો Show in Folder ફોલ્ડરમાં બતાવો Show its progress, see Cancel and write log lines તેની પ્રગતિ બતાવવી, રદ કરવાની વિનંતી જોવી અને લૉગ લાઇનો લખવી diff --git a/crates/ui-egui/src/i18n/hi.tsv b/crates/ui-egui/src/i18n/hi.tsv index aedec9da73..9fece569ce 100644 --- a/crates/ui-egui/src/i18n/hi.tsv +++ b/crates/ui-egui/src/i18n/hi.tsv @@ -4649,6 +4649,7 @@ antiAlias Sharp शार्प Show Center Mark शो सेंटर मार्क Show Code कोड दिखाएं Show color bars रंग सलाखों दिखाएँ + Find the selected colors in the artwork चयनित रंगों को आर्टवर्क में खोजें Show Color Groups रंग समूह दिखाएँ Show Color Swatches रंग स्वॉचेस दिखाएँ Show Corner Widget शो कॉर्नर विजेट diff --git a/crates/ui-egui/src/i18n/hu.tsv b/crates/ui-egui/src/i18n/hu.tsv index 80a39e7c70..6458c1fc66 100644 --- a/crates/ui-egui/src/i18n/hu.tsv +++ b/crates/ui-egui/src/i18n/hu.tsv @@ -1953,6 +1953,7 @@ file-filter Templates Sablonok Show smooth color wheel Folytonos színkör megjelenítése Show segmented color wheel Szegmentált színkör megjelenítése Show color bars Színsávok megjelenítése + Find the selected colors in the artwork A kijelölt színek keresése a grafikában Harmony Sets Harmóniakészletek HDTV 1080p HDTV 1080p HDTV 720p HDTV 720p diff --git a/crates/ui-egui/src/i18n/id.tsv b/crates/ui-egui/src/i18n/id.tsv index f14fdee240..f94362b373 100644 --- a/crates/ui-egui/src/i18n/id.tsv +++ b/crates/ui-egui/src/i18n/id.tsv @@ -2718,6 +2718,7 @@ digits Malayalam Malayalam Show smooth color wheel Tampilkan roda warna halus Show segmented color wheel Tampilkan roda warna bersegmen Show color bars Tampilkan bilah warna + Find the selected colors in the artwork Temukan warna yang dipilih di karya seni Harmony Rules Aturan harmoni Keep this row's colors (exclude) Pertahankan warna baris ini (kecualikan) Limit to Library: Batasi ke pustaka: diff --git a/crates/ui-egui/src/i18n/it.tsv b/crates/ui-egui/src/i18n/it.tsv index 66d162f02c..7d9223d989 100644 --- a/crates/ui-egui/src/i18n/it.tsv +++ b/crates/ui-egui/src/i18n/it.tsv @@ -1566,6 +1566,7 @@ file-filter Templates Modelli Show smooth color wheel Mostra ruota dei colori continua Show segmented color wheel Mostra ruota dei colori segmentata Show color bars Mostra barre di colore + Find the selected colors in the artwork Trova i colori selezionati nella grafica Harmony Sets Gruppi di armonia Height Altezza Height: Altezza: diff --git a/crates/ui-egui/src/i18n/ja.tsv b/crates/ui-egui/src/i18n/ja.tsv index e6fcd47ccc..a211916385 100644 --- a/crates/ui-egui/src/i18n/ja.tsv +++ b/crates/ui-egui/src/i18n/ja.tsv @@ -1938,6 +1938,7 @@ antiAlias Sharp シャープ Show smooth color wheel 滑らかなカラーホイールを表示 Show segmented color wheel 分割カラーホイールを表示 Show color bars カラーバーを表示 + Find the selected colors in the artwork 選択したカラーをアートワーク内で検索 Height 高さ Height: 高さ: Help › Search Commands… ヘルプ › コマンドを検索… diff --git a/crates/ui-egui/src/i18n/ka.tsv b/crates/ui-egui/src/i18n/ka.tsv index 9475bb917c..3903eb0a87 100644 --- a/crates/ui-egui/src/i18n/ka.tsv +++ b/crates/ui-egui/src/i18n/ka.tsv @@ -4762,6 +4762,7 @@ digits Malayalam მალაიალამური Show smooth color wheel გლუვი ფერთა წრის ჩვენება Show segmented color wheel სეგმენტირებული ფერთა წრის ჩვენება Show color bars ფერთა ზოლების ჩვენება + Find the selected colors in the artwork არჩეული ფერების პოვნა ნახატში Keep this row's colors (exclude) ამ სტრიქონის ფერების შენარჩუნება (გამორიცხვა) Limit to Library: ბიბლიოთეკით შეზღუდვა: Link harmony colors ჰარმონიის ფერების დაკავშირება diff --git a/crates/ui-egui/src/i18n/ko.tsv b/crates/ui-egui/src/i18n/ko.tsv index ea9a413f88..c2583fc364 100644 --- a/crates/ui-egui/src/i18n/ko.tsv +++ b/crates/ui-egui/src/i18n/ko.tsv @@ -1928,6 +1928,7 @@ antiAlias Sharp 날카롭게 Show smooth color wheel 부드러운 색상환 표시 Show segmented color wheel 분할 색상환 표시 Show color bars 색상 막대 표시 + Find the selected colors in the artwork 선택한 색상을 아트웍에서 찾기 Height 높이 Height: 높이: Help › Search Commands… 도움말 › 명령 검색… diff --git a/crates/ui-egui/src/i18n/nl.tsv b/crates/ui-egui/src/i18n/nl.tsv index bf8fd86aa3..998ef5a5d6 100644 --- a/crates/ui-egui/src/i18n/nl.tsv +++ b/crates/ui-egui/src/i18n/nl.tsv @@ -3280,6 +3280,7 @@ digits Malayalam Malayalam Show smooth color wheel Vloeiend kleurenwiel tonen Show segmented color wheel Gesegmenteerd kleurenwiel tonen Show color bars Kleurbalken tonen + Find the selected colors in the artwork De geselecteerde kleuren zoeken in de artwork Harmony Rules Harmonieregels Keep this row's colors (exclude) De kleuren van deze rij behouden (uitsluiten) Limit to Library: Beperken tot bibliotheek: diff --git a/crates/ui-egui/src/i18n/pl.tsv b/crates/ui-egui/src/i18n/pl.tsv index da2304edad..464d83f211 100644 --- a/crates/ui-egui/src/i18n/pl.tsv +++ b/crates/ui-egui/src/i18n/pl.tsv @@ -2896,6 +2896,7 @@ digits Malayalam Malajalam Show smooth color wheel Pokaż płynne koło kolorów Show segmented color wheel Pokaż segmentowe koło kolorów Show color bars Pokaż paski kolorów + Find the selected colors in the artwork Znajdź zaznaczone kolory w kompozycji Keep this row's colors (exclude) Zachowaj kolory tego wiersza (wyklucz) Limit to Library: Ogranicz do biblioteki: Link harmony colors Połącz kolory harmonii diff --git a/crates/ui-egui/src/i18n/pt-br.tsv b/crates/ui-egui/src/i18n/pt-br.tsv index 772a72544a..4a19e2ecea 100644 --- a/crates/ui-egui/src/i18n/pt-br.tsv +++ b/crates/ui-egui/src/i18n/pt-br.tsv @@ -1334,6 +1334,7 @@ antiAlias Sharp Nítido Show smooth color wheel Mostrar roda de cores contínua Show segmented color wheel Mostrar roda de cores segmentada Show color bars Mostrar barras de cores + Find the selected colors in the artwork Localizar as cores selecionadas na arte Harmony Sets Conjuntos de Harmonia Height Altura Height: Altura: diff --git a/crates/ui-egui/src/i18n/ru.tsv b/crates/ui-egui/src/i18n/ru.tsv index 02cdb08e31..eac1b395a3 100644 --- a/crates/ui-egui/src/i18n/ru.tsv +++ b/crates/ui-egui/src/i18n/ru.tsv @@ -1557,6 +1557,7 @@ file-filter Templates Шаблоны Show smooth color wheel Показать плавный цветовой круг Show segmented color wheel Показать сегментированный цветовой круг Show color bars Показать цветовые полосы + Find the selected colors in the artwork Найти выбранные цвета в рисунке Harmony Sets Наборы гармонии Height Высота Height: Высота: diff --git a/crates/ui-egui/src/i18n/sv.tsv b/crates/ui-egui/src/i18n/sv.tsv index d4d0d0a4b5..750b0db89b 100644 --- a/crates/ui-egui/src/i18n/sv.tsv +++ b/crates/ui-egui/src/i18n/sv.tsv @@ -1504,6 +1504,7 @@ font-technology Variable Variabla Show smooth color wheel Visa steglöst färghjul Show segmented color wheel Visa segmenterat färghjul Show color bars Visa färgstaplar + Find the selected colors in the artwork Hitta de markerade färgerna i teckningen Harmony Sets Harmoniuppsättningar Height Höjd Height: Höjd: diff --git a/crates/ui-egui/src/i18n/tr.tsv b/crates/ui-egui/src/i18n/tr.tsv index cd471d910c..d59d3b022b 100644 --- a/crates/ui-egui/src/i18n/tr.tsv +++ b/crates/ui-egui/src/i18n/tr.tsv @@ -1461,6 +1461,7 @@ font-technology Variable Değişken Show smooth color wheel Kesintisiz renk tekerleğini göster Show segmented color wheel Bölümlü renk tekerleğini göster Show color bars Renk çubuklarını göster + Find the selected colors in the artwork Seçili renkleri resimde bul Harmony Sets Armoni Setleri Height Yükseklik Height: Yükseklik: diff --git a/crates/ui-egui/src/i18n/uk.tsv b/crates/ui-egui/src/i18n/uk.tsv index bc0ffe5928..78ef42775c 100644 --- a/crates/ui-egui/src/i18n/uk.tsv +++ b/crates/ui-egui/src/i18n/uk.tsv @@ -1560,6 +1560,7 @@ file-filter Templates Шаблони Show smooth color wheel Показати плавне колірне коло Show segmented color wheel Показати сегментоване колірне коло Show color bars Показати колірні смуги + Find the selected colors in the artwork Знайти вибрані кольори в малюнку Harmony Sets Набори гармонії Height Висота Height: Висота: diff --git a/crates/ui-egui/src/i18n/vi.tsv b/crates/ui-egui/src/i18n/vi.tsv index a8543b90ae..66bd01ec15 100644 --- a/crates/ui-egui/src/i18n/vi.tsv +++ b/crates/ui-egui/src/i18n/vi.tsv @@ -1800,6 +1800,7 @@ file-filter Templates Mẫu Show smooth color wheel Hiện bánh xe màu liền mạch Show segmented color wheel Hiện bánh xe màu phân đoạn Show color bars Hiện các thanh màu + Find the selected colors in the artwork Tìm các màu đã chọn trong tác phẩm Harmony Sets Bộ hài hòa màu Height Chiều cao Height: Chiều cao: diff --git a/crates/ui-egui/src/i18n/zh-hans.tsv b/crates/ui-egui/src/i18n/zh-hans.tsv index 04dedf4229..9a03388ecf 100644 --- a/crates/ui-egui/src/i18n/zh-hans.tsv +++ b/crates/ui-egui/src/i18n/zh-hans.tsv @@ -1494,6 +1494,7 @@ file-filter Templates 模板 Show smooth color wheel 显示平滑色轮 Show segmented color wheel 显示分段色轮 Show color bars 显示颜色条 + Find the selected colors in the artwork 在图稿中查找所选颜色 Harmony Sets 色彩调和组 Height 高度 Height: 高度: diff --git a/crates/ui-egui/src/i18n/zh-hant.tsv b/crates/ui-egui/src/i18n/zh-hant.tsv index 7e3cb24439..c9f0379511 100644 --- a/crates/ui-egui/src/i18n/zh-hant.tsv +++ b/crates/ui-egui/src/i18n/zh-hant.tsv @@ -1531,6 +1531,7 @@ file-filter Templates 範本 Show smooth color wheel 顯示平滑色輪 Show segmented color wheel 顯示分段色輪 Show color bars 顯示顏色條 + Find the selected colors in the artwork 在圖稿中尋找所選顏色 Harmony Sets 色彩調和組 Height 高度 Height: 高度: diff --git a/docs/mcp.md b/docs/mcp.md index b7b4905ef4..404323e5e6 100644 --- a/docs/mcp.md +++ b/docs/mcp.md @@ -4585,6 +4585,18 @@ of the rows that are not excluded, in row order, and Save Prominent Colors saves {"name":"run_command","arguments":{"command":"recolor.weigh","params":{"map":[{"from":["rgb 255 0 0","rgb 128 0 204"],"to":"#00ff00"},{"from":["rgb 0 0 255"],"to":"#ffff00"}],"weights":[1,1]}}} ``` +The Assign tab's Find button (the dialog field `findColors`) finds the colors of the selected rows in the art +([Advanced recolor options overview](https://helpx.adobe.com/illustrator/desktop/manage-colors/learn-color-basics/edit-colors-dialog-overview.html)). +While it is on and rows are selected, the art of those rows shows as the preview shows it (its current colors with +Preview off), and the rest of the selected art shows dimmed; a second click shows the art as before +([archived help, Recolor Artwork](https://help.adobe.com/archive/en_US/illustrator/cs5/illustrator_cs5_help.pdf#page=149)). +As VectorCraft's own rules, a dimmed color is a 25% tint of its current color, or the nearest lighter tint (in steps +of 1%) when that tint is a color a selected row lists (`recolor.apply` gives each current color of the other rows +and the preserved colors that tint, then recolors the selected rows), a color that a selected row also lists is not +dimmed, so art that mixes colors dims only its other colors, and nothing is dimmed on the Edit tab or with no row +selected. Find changes only what the canvas shows: it records no undo step, Cancel leaves the art as it was, and OK +applies every row to the art as it does with Find off. + The `recolor.*` commands refuse parameters of the wrong form. A `limitTo` or `method` that is not a string gets the error for an unknown library or method. Other wrong-form parameters get an error that names them. `includeImages`, `includePatterns`, a row's `exclude`, `order`, `saturationBrightness` and the `white`, `black` and diff --git a/docs/target-app-parity.md b/docs/target-app-parity.md index cc8a4e9002..727f481bbc 100644 --- a/docs/target-app-parity.md +++ b/docs/target-app-parity.md @@ -1629,6 +1629,7 @@ Moved from the ROADMAP's "Shipped so far" on 2026-10-10. Update it when a featur - **Document Color Mode for effects and graphs:** File › Document Color Mode and `document.open {colorMode}` convert the colors of effects (Drop Shadow, Inner Glow, Outer Glow and the other effects with a color, on objects, their fills and strokes and in graphic styles) and the series paints and label styles that a graph keeps, so a graph drawn again from new data keeps the converted colors; File › Document Color Mode also converts the fill and stroke that new art takes. Undo restores the original new-art fill and stroke and Redo applies the conversion again. - **Recolor Artwork layout (#3416):** the Edit chip list uses the modal scroll helper and its actual remaining height; the tab's minimum-height space scrolls with the chips. `tests_recolor` covers 5/20/200/400 colors, window resizing, 100/125/150/200% UI scaling, scrolling to and editing the final chip, Preview, Cancel, Confirm and Undo, alongside the existing #1733 drag regressions. Scores and estimates unchanged. - **Recolor Artwork Edit displays:** buttons beside the Edit tab's wheel show the colors on a smooth color wheel, a segmented color wheel or as color bars ([Edit colors using Recolor Artwork](https://helpx.adobe.com/illustrator/desktop/manage-colors/modify-colors/edit-colors-using-edit-colors-dialog.html)). The segmented wheel draws 24 hues by 5 saturations as solid patches, and its markers move freely as on the smooth wheel. The bars show one solid bar per recolored color in row order: a click selects a bar for the color sliders, and a drag moves its row without changing a color ([Advanced recolor options overview](https://helpx.adobe.com/illustrator/desktop/manage-colors/learn-color-basics/edit-colors-dialog-overview.html)). The dialog opens on the smooth wheel; `display` (`smooth`, `segmented`, `bars`) is the dialog field. `tests_recolor` covers switching, the dialog height, segmented dragging and Brightness, and bar selection, editing, reordering, scrolling, Preview, Cancel and OK. Scores and estimates unchanged. + - **Recolor Artwork Find:** the Assign tab's Find button finds the colors of the selected rows in the art ([Advanced recolor options overview](https://helpx.adobe.com/illustrator/desktop/manage-colors/learn-color-basics/edit-colors-dialog-overview.html)): while it is on, their art shows as the preview shows it and the rest of the selected art shows dimmed, until a second click ([archived help, Recolor Artwork](https://help.adobe.com/archive/en_US/illustrator/cs5/illustrator_cs5_help.pdf#page=149)). VectorCraft's own rules: a dimmed color is a 25% tint of its current color (or the nearest lighter tint when that one is a color a selected row lists), a color a selected row also lists is not dimmed, and Find records no undo step. `findColors` is the dialog field. Tests: `find_dims_the_colors_of_the_rows_not_selected` and `find_shows_the_selected_rows_art_and_dims_the_rest` in `crates/ui-egui/src/dialogs/recolor.rs`. Scores and estimates unchanged. - **Recolor Artwork New Row:** the Assign tab's New Row button adds a row with no current colors, so current colors can be moved into it and take its new color ([Advanced recolor options overview](https://helpx.adobe.com/illustrator/desktop/manage-colors/learn-color-basics/edit-colors-dialog-overview.html), [Assign new colors to selected artworks](https://helpx.adobe.com/illustrator/desktop/manage-colors/modify-colors/assign-new-colors-to-selected-artwork.html)). VectorCraft's own rules: the row goes above the first selected row (at the top when none is selected) with that row's new color and becomes the selection, and Merge with it as the first selected row moves the other rows' colors into it. The button needs selected art. An empty row recolors nothing, does not count toward Colors, adds no library swatch and gives a rewritten color group no color. Tests: `a_new_row_goes_above_the_selection_and_takes_merged_colors`, `an_empty_row_gives_the_group_no_color` and `colors_merged_into_a_new_row_take_its_new_color` in `crates/ui-egui/src/dialogs/recolor.rs`, `an_empty_row_recolors_nothing` and `an_empty_row_adds_no_swatch_and_no_group_color` in `crates/engine/src/tests/recolor.rs`. - **Edit Colors parameters:** `edit.colors.saturate` needs a number `intensity`, the value from -100% to 100% that Saturate takes ([Adjusting colors](https://web.archive.org/web/20230128232631/https://helpx.adobe.com/illustrator/using/adjusting-colors.html)), and answers "missing number `intensity`" without one; a number outside the range counts as its nearest end. A value that is not a number, such as `"40"`, is refused with `` `intensity` must be a number, not "40" ``, as in every command that needs a number (`tests::params::a_malformed_required_number_is_not_reported_as_missing`). `edit.colors.adjustBalance` refuses a channel and `color.harmony` refuses `steps` or `amount` that is not a number; both read `null` as a value left out. `tests::editcolors` and `tests::colorguide` cover them. - **Convert to Indexed Color:** Edit › Edit Colors › Convert to Indexed Color… (`edit.colors.toIndexed`) stores the embedded images in the selection as indexed-color PNGs of at most 256 colors. The palette is chosen as for a PNG-8 export, as evenly spaced levels of red, green and blue, or from the document's swatches, with diffusion, pattern or noise dithering; pixels under half opacity become transparent. The dialog previews live, and OK is one undo step. This is VectorCraft's own command and counts toward no score. `tests::editcolors` and `encode::tests_palette` cover it. Scores and estimates unchanged.