From d25289a3becac3a9d980ff4cc18b043c61d09daa Mon Sep 17 00:00:00 2001 From: MortenHusted Date: Sun, 18 Oct 2026 17:52:12 +0200 Subject: [PATCH] Select: select.color picks objects by fill and stroke colour, no object needed Scripts had to know an object id before they could select art by colour (select.same.* and select.magicWand start from one). select.color {fill?, stroke?} takes colours as paint.setFill does and selects the objects whose fill and stroke read as them in #rrggbb, as document.inspect reports colours, with Select > Same's selection rules. The label is translated in each of the 23 catalogs, which complete_languages_translate_every_menu_string requires. --- crates/engine/src/cmd/select.rs | 25 ++++++++++++++++++++++ crates/engine/src/tests_menucmds.rs | 32 +++++++++++++++++++++++++++++ crates/ui-egui/src/i18n/bg.tsv | 2 ++ crates/ui-egui/src/i18n/cs.tsv | 2 ++ crates/ui-egui/src/i18n/da.tsv | 2 ++ crates/ui-egui/src/i18n/de.tsv | 2 ++ crates/ui-egui/src/i18n/el.tsv | 2 ++ crates/ui-egui/src/i18n/es.tsv | 2 ++ crates/ui-egui/src/i18n/fi.tsv | 2 ++ crates/ui-egui/src/i18n/fr.tsv | 2 ++ crates/ui-egui/src/i18n/hu.tsv | 2 ++ crates/ui-egui/src/i18n/id.tsv | 2 ++ crates/ui-egui/src/i18n/it.tsv | 2 ++ crates/ui-egui/src/i18n/ja.tsv | 2 ++ crates/ui-egui/src/i18n/ka.tsv | 2 ++ crates/ui-egui/src/i18n/ko.tsv | 2 ++ crates/ui-egui/src/i18n/nl.tsv | 2 ++ crates/ui-egui/src/i18n/pl.tsv | 2 ++ crates/ui-egui/src/i18n/pt-br.tsv | 2 ++ crates/ui-egui/src/i18n/ru.tsv | 2 ++ crates/ui-egui/src/i18n/sv.tsv | 2 ++ crates/ui-egui/src/i18n/uk.tsv | 2 ++ crates/ui-egui/src/i18n/vi.tsv | 2 ++ crates/ui-egui/src/i18n/zh-hans.tsv | 2 ++ crates/ui-egui/src/i18n/zh-hant.tsv | 2 ++ 25 files changed, 103 insertions(+) diff --git a/crates/engine/src/cmd/select.rs b/crates/engine/src/cmd/select.rs index eadd37680..d169b3903 100644 --- a/crates/engine/src/cmd/select.rs +++ b/crates/engine/src/cmd/select.rs @@ -89,6 +89,15 @@ pub fn specs() -> Vec { has_doc, anchors_many ), + cmd!( + "select.color", + "Select by Color", + [], + None, + "{fill?: colour, stroke?: colour (as paint.setFill's color; at least one)} select the objects whose fill (and stroke) reads as that colour in #rrggbb, as document.inspect reports colours, whatever its swatch or tint; with both, the objects that match both. No object needs to be selected first; Select > Reselect repeats it → {count}", + has_doc, + select_color + ), cmd!( "select.same.fillColor", "Fill Color", @@ -528,6 +537,22 @@ fn stroke_weight(n: &Node) -> f64 { if paint.is_none() { 0.0 } else { width } } +/// Select by Color: the objects whose fill and stroke read as the colours given, compared as the +/// `#rrggbb` `document.inspect` reports, so a script can pick art by colour without an object id. +fn select_color(s: &mut Session, p: &Value) -> Result { + const C: &str = "select.color"; + let hex = |key: &str| match p.get(key).filter(|v| !v.is_null()) { + None => Ok(None), + Some(v) => color_value(v).map(|c| Some(c.to_hex())).ok_or_else(|| bad(C, format!("`{key}`: not a colour: {v}"))), + }; + let (fill, stroke) = (hex("fill")?, hex("stroke")?); + if fill.is_none() && stroke.is_none() { + return Err(bad(C, "give `fill`, `stroke` or both")); + } + let reads_as = |paint: Paint, hex: Option<&str>| hex.is_none_or(|h| paint.color().is_some_and(|c| c.to_hex() == h)); + select_where(s, C, p, |_, n| !n.is_container() && reads_as(fill_of(n), fill.as_deref()) && reads_as(stroke_of(n).0, stroke.as_deref())) +} + fn same(s: &mut Session, cmd: &str, eq: impl Fn(&Node, &Node) -> bool) -> Result { let st = s.doc()?; let refn = st.selection.objects.first().and_then(|id| st.doc.node(*id)).cloned().ok_or_else(|| bad(cmd, "nothing selected"))?; diff --git a/crates/engine/src/tests_menucmds.rs b/crates/engine/src/tests_menucmds.rs index ea28d3252..17bae9209 100644 --- a/crates/engine/src/tests_menucmds.rs +++ b/crates/engine/src/tests_menucmds.rs @@ -1026,6 +1026,38 @@ fn select_same_paint_reads_type_characters() { assert_eq!(same(&mut s, t1, "select.same.fillAndStroke"), vec![t1, r]); } +/// Select by Color needs no object to start from: it matches fills and strokes as +/// `document.inspect` reports them, `#rrggbb`. +#[test] +fn select_color_matches_fill_and_stroke_without_a_selection() { + let mut s = session(); + let [a, b, c] = [0.0, 20.0, 40.0].map(|x| rect(&mut s, x, 0.0, 10.0, 10.0)); + let t = text(&mut s, "a"); + fill(&mut s, a, "#000000"); + fill(&mut s, t, "#000000"); + // A grey as a PDF stores it reads as #fefefe. + s.execute("paint.setFill", &json!({"ids": [b.0], "color": [0.996, 0.996, 0.996]})).unwrap(); + fill(&mut s, c, "#ff0000"); + s.execute("paint.setStroke", &json!({"ids": [a.0, c.0], "color": "#0000ff"})).unwrap(); + s.execute("select.none", &json!({})).unwrap(); + let pick = |s: &mut Session, p: Value| { + s.execute("select.color", &p).unwrap(); + let mut v = selected(s); + v.sort(); + v + }; + assert_eq!(pick(&mut s, json!({"fill": "#000000"})), vec![a, t]); + assert_eq!(pick(&mut s, json!({"fill": "#fefefe"})), vec![b]); + assert_eq!(pick(&mut s, json!({"stroke": "#0000ff"})), vec![a, c]); + assert_eq!(pick(&mut s, json!({"fill": "#000000", "stroke": "#0000ff"})), vec![a]); + // Select > Reselect repeats it. + s.execute("select.none", &json!({})).unwrap(); + s.execute("select.reselect", &json!({})).unwrap(); + assert_eq!(selected(&s), vec![a]); + assert!(s.execute("select.color", &json!({})).is_err()); + assert!(s.execute("select.color", &json!({"fill": "not a colour"})).is_err()); +} + #[test] fn select_direction_handles_selects_all_anchors() { let mut s = session(); diff --git a/crates/ui-egui/src/i18n/bg.tsv b/crates/ui-egui/src/i18n/bg.tsv index 7e4606e8b..1b0ef718c 100644 --- a/crates/ui-egui/src/i18n/bg.tsv +++ b/crates/ui-egui/src/i18n/bg.tsv @@ -5170,3 +5170,5 @@ theme Appearance Външен вид Minimum must not exceed Desired, nor Desired Maximum. Минималната стойност не може да надвишава желаната, нито желаната – максималната. Justification Подравняване @msg the file's variables and data sets weren't read (variables: {variables}, data sets: {data_sets}): the Variables panel doesn't list them променливите и наборите от данни на файла не бяха прочетени (променливи: {variables}, набори от данни: {data_sets}): панелът „Променливи“ не ги показва +# Select by Color (select.color) + Select by Color Избиране по цвят diff --git a/crates/ui-egui/src/i18n/cs.tsv b/crates/ui-egui/src/i18n/cs.tsv index a51e35a34..04b2fbec8 100644 --- a/crates/ui-egui/src/i18n/cs.tsv +++ b/crates/ui-egui/src/i18n/cs.tsv @@ -5205,3 +5205,5 @@ mark-style Japanese Japonské Minimum must not exceed Desired, nor Desired Maximum. Minimum nesmí překročit požadovanou hodnotu ani požadovaná hodnota maximum. Justification Zarovnání do bloku @msg the file's variables and data sets weren't read (variables: {variables}, data sets: {data_sets}): the Variables panel doesn't list them proměnné a sady dat souboru nebyly načteny (proměnné: {variables}, sady dat: {data_sets}): panel Proměnné je nezobrazuje +# Select by Color (select.color) + Select by Color Vybrat podle barvy diff --git a/crates/ui-egui/src/i18n/da.tsv b/crates/ui-egui/src/i18n/da.tsv index 8f91ea563..88b3bdceb 100644 --- a/crates/ui-egui/src/i18n/da.tsv +++ b/crates/ui-egui/src/i18n/da.tsv @@ -5188,3 +5188,5 @@ swatch Bright Violet Kraftig violet Full Justify Lige margener Minimum must not exceed Desired, nor Desired Maximum. Minimum må ikke overstige Ønsket, og Ønsket ikke Maksimum. Justification Justering +# Select by Color (select.color) + Select by Color Markér efter farve diff --git a/crates/ui-egui/src/i18n/de.tsv b/crates/ui-egui/src/i18n/de.tsv index a70098d98..6b5aa6291 100644 --- a/crates/ui-egui/src/i18n/de.tsv +++ b/crates/ui-egui/src/i18n/de.tsv @@ -4785,3 +4785,5 @@ effect Soft Weich Minimum Minimum Justification Abstände @msg the file's variables and data sets weren't read (variables: {variables}, data sets: {data_sets}): the Variables panel doesn't list them die Variablen und Datensätze der Datei wurden nicht gelesen (Variablen: {variables}, Datensätze: {data_sets}): Das Bedienfeld „Variablen“ listet sie nicht auf +# Select by Color (select.color) + Select by Color Nach Farbe auswählen diff --git a/crates/ui-egui/src/i18n/el.tsv b/crates/ui-egui/src/i18n/el.tsv index 171c5239f..8ed6f13a8 100644 --- a/crates/ui-egui/src/i18n/el.tsv +++ b/crates/ui-egui/src/i18n/el.tsv @@ -5157,3 +5157,5 @@ effect Points Σημεία Minimum must not exceed Desired, nor Desired Maximum. Το ελάχιστο δεν πρέπει να υπερβαίνει το επιθυμητό, ούτε το επιθυμητό το μέγιστο. Justification Πλήρης στοίχιση @msg the file's variables and data sets weren't read (variables: {variables}, data sets: {data_sets}): the Variables panel doesn't list them οι μεταβλητές και τα σύνολα δεδομένων του αρχείου δεν διαβάστηκαν (μεταβλητές: {variables}, σύνολα δεδομένων: {data_sets}): ο πίνακας Μεταβλητές δεν τα εμφανίζει +# Select by Color (select.color) + Select by Color Επιλογή βάσει χρώματος diff --git a/crates/ui-egui/src/i18n/es.tsv b/crates/ui-egui/src/i18n/es.tsv index 6f42a03e8..23ca1e1f0 100644 --- a/crates/ui-egui/src/i18n/es.tsv +++ b/crates/ui-egui/src/i18n/es.tsv @@ -5147,3 +5147,5 @@ mark-style Japanese Japonesas Minimum must not exceed Desired, nor Desired Maximum. El mínimo no puede superar el deseado, ni el deseado el máximo. Justification Justificación @msg the file's variables and data sets weren't read (variables: {variables}, data sets: {data_sets}): the Variables panel doesn't list them no se leyeron las variables ni los conjuntos de datos del archivo (variables: {variables}, conjuntos de datos: {data_sets}): el panel Variables no los muestra +# Select by Color (select.color) + Select by Color Seleccionar por color diff --git a/crates/ui-egui/src/i18n/fi.tsv b/crates/ui-egui/src/i18n/fi.tsv index f59da5487..e8c505393 100644 --- a/crates/ui-egui/src/i18n/fi.tsv +++ b/crates/ui-egui/src/i18n/fi.tsv @@ -5169,3 +5169,5 @@ mark-style Japanese Japanilainen Minimum must not exceed Desired, nor Desired Maximum. Minimi ei saa ylittää haluttua arvoa eikä haluttu arvo maksimia. Justification Tasaus @msg the file's variables and data sets weren't read (variables: {variables}, data sets: {data_sets}): the Variables panel doesn't list them tiedoston muuttujia ja tietojoukkoja ei luettu (muuttujia: {variables}, tietojoukkoja: {data_sets}): Muuttujat-paneeli ei näytä niitä +# Select by Color (select.color) + Select by Color Valitse värin mukaan diff --git a/crates/ui-egui/src/i18n/fr.tsv b/crates/ui-egui/src/i18n/fr.tsv index 04666b8a3..f012d8183 100644 --- a/crates/ui-egui/src/i18n/fr.tsv +++ b/crates/ui-egui/src/i18n/fr.tsv @@ -5204,3 +5204,5 @@ theme Appearance Apparence Minimum must not exceed Desired, nor Desired Maximum. Le minimum ne doit pas dépasser la valeur optimale, ni la valeur optimale le maximum. Justification Justification @msg the file's variables and data sets weren't read (variables: {variables}, data sets: {data_sets}): the Variables panel doesn't list them les variables et jeux de données du fichier n’ont pas été lus (variables : {variables}, jeux de données : {data_sets}) : le panneau Variables ne les affiche pas +# Select by Color (select.color) + Select by Color Sélectionner par couleur diff --git a/crates/ui-egui/src/i18n/hu.tsv b/crates/ui-egui/src/i18n/hu.tsv index 030147265..afec09a3f 100644 --- a/crates/ui-egui/src/i18n/hu.tsv +++ b/crates/ui-egui/src/i18n/hu.tsv @@ -5191,3 +5191,5 @@ imageTrace Outline Körvonal Minimum must not exceed Desired, nor Desired Maximum. A minimum nem haladhatja meg a kívánt értéket, sem a kívánt érték a maximumot. Justification Sorkizárás @msg the file's variables and data sets weren't read (variables: {variables}, data sets: {data_sets}): the Variables panel doesn't list them a fájl változói és adatkészletei nem lettek beolvasva (változók: {variables}, adatkészletek: {data_sets}): a Változók panel nem listázza őket +# Select by Color (select.color) + Select by Color Kijelölés szín szerint diff --git a/crates/ui-egui/src/i18n/id.tsv b/crates/ui-egui/src/i18n/id.tsv index 3336f0745..8f3312b08 100644 --- a/crates/ui-egui/src/i18n/id.tsv +++ b/crates/ui-egui/src/i18n/id.tsv @@ -5188,3 +5188,5 @@ swatch Bright Violet Violet cerah Full Justify Rata Penuh Minimum must not exceed Desired, nor Desired Maximum. Minimum tidak boleh melebihi Diinginkan, dan Diinginkan tidak boleh melebihi Maksimum. Justification Justifikasi +# Select by Color (select.color) + Select by Color Pilih berdasarkan warna diff --git a/crates/ui-egui/src/i18n/it.tsv b/crates/ui-egui/src/i18n/it.tsv index b1b3fb642..068730fb3 100644 --- a/crates/ui-egui/src/i18n/it.tsv +++ b/crates/ui-egui/src/i18n/it.tsv @@ -4819,3 +4819,5 @@ lighting Light Luce Minimum Minimo Justification Giustificazione @msg the file's variables and data sets weren't read (variables: {variables}, data sets: {data_sets}): the Variables panel doesn't list them le variabili e i set di dati del file non sono stati letti (variabili: {variables}, set di dati: {data_sets}): il pannello Variabili non li elenca +# Select by Color (select.color) + Select by Color Seleziona per colore diff --git a/crates/ui-egui/src/i18n/ja.tsv b/crates/ui-egui/src/i18n/ja.tsv index a2378fbe7..1408c146e 100644 --- a/crates/ui-egui/src/i18n/ja.tsv +++ b/crates/ui-egui/src/i18n/ja.tsv @@ -4859,3 +4859,5 @@ lighting Light ライト Minimum 最小 Justification 文字組み @msg the file's variables and data sets weren't read (variables: {variables}, data sets: {data_sets}): the Variables panel doesn't list them ファイルの変数とデータセットは読み込まれませんでした (変数: {variables}、データセット: {data_sets})。変数パネルには表示されません +# Select by Color (select.color) + Select by Color カラーで選択 diff --git a/crates/ui-egui/src/i18n/ka.tsv b/crates/ui-egui/src/i18n/ka.tsv index a06996bd6..02d680ebe 100644 --- a/crates/ui-egui/src/i18n/ka.tsv +++ b/crates/ui-egui/src/i18n/ka.tsv @@ -5112,3 +5112,5 @@ imageTrace Outline კონტური @msg its zlib compression is damaged მისი zlib შეკუმშვა დაზიანებულია @msg its Zstandard compression is damaged მისი Zstandard შეკუმშვა დაზიანებულია @msg it decompresses to more than {_1} MB გაშლისას {_1} MB-ს აღემატება +# Select by Color (select.color) + Select by Color მონიშვნა ფერის მიხედვით diff --git a/crates/ui-egui/src/i18n/ko.tsv b/crates/ui-egui/src/i18n/ko.tsv index a0610c043..2270d6e77 100644 --- a/crates/ui-egui/src/i18n/ko.tsv +++ b/crates/ui-egui/src/i18n/ko.tsv @@ -4782,3 +4782,5 @@ lighting Light 광원 Minimum 최소 Justification 양끝 맞춤 @msg the file's variables and data sets weren't read (variables: {variables}, data sets: {data_sets}): the Variables panel doesn't list them 파일의 변수와 데이터 세트를 읽지 않았습니다(변수: {variables}, 데이터 세트: {data_sets}). 변수 패널에 표시되지 않습니다 +# Select by Color (select.color) + Select by Color 색상별 선택 diff --git a/crates/ui-egui/src/i18n/nl.tsv b/crates/ui-egui/src/i18n/nl.tsv index 3a196972b..7b75e476c 100644 --- a/crates/ui-egui/src/i18n/nl.tsv +++ b/crates/ui-egui/src/i18n/nl.tsv @@ -5231,3 +5231,5 @@ swatch Bright Violet Felviolet Full Justify Volledig uitvullen Minimum must not exceed Desired, nor Desired Maximum. Minimum mag niet groter zijn dan Gewenst, en Gewenst niet groter dan Maximum. Justification Uitvullen +# Select by Color (select.color) + Select by Color Selecteren op kleur diff --git a/crates/ui-egui/src/i18n/pl.tsv b/crates/ui-egui/src/i18n/pl.tsv index 1ff840ccd..0643950d9 100644 --- a/crates/ui-egui/src/i18n/pl.tsv +++ b/crates/ui-egui/src/i18n/pl.tsv @@ -5057,3 +5057,5 @@ mark-style Japanese Japońskie Minimum must not exceed Desired, nor Desired Maximum. Minimum nie może przekraczać wartości optymalnej, a wartość optymalna maksimum. Justification Justowanie @msg the file's variables and data sets weren't read (variables: {variables}, data sets: {data_sets}): the Variables panel doesn't list them zmienne i zestawy danych pliku nie zostały wczytane (zmienne: {variables}, zestawy danych: {data_sets}): panel Zmienne ich nie wyświetla +# Select by Color (select.color) + Select by Color Zaznacz według koloru diff --git a/crates/ui-egui/src/i18n/pt-br.tsv b/crates/ui-egui/src/i18n/pt-br.tsv index 910546581..423403558 100644 --- a/crates/ui-egui/src/i18n/pt-br.tsv +++ b/crates/ui-egui/src/i18n/pt-br.tsv @@ -5122,3 +5122,5 @@ mark-style Japanese Japonesas Minimum must not exceed Desired, nor Desired Maximum. O mínimo não pode passar do desejado, nem o desejado do máximo. Justification Justificação @msg the file's variables and data sets weren't read (variables: {variables}, data sets: {data_sets}): the Variables panel doesn't list them as variáveis e os conjuntos de dados do arquivo não foram lidos (variáveis: {variables}, conjuntos de dados: {data_sets}): o painel Variáveis não os lista +# Select by Color (select.color) + Select by Color Selecionar por Cor diff --git a/crates/ui-egui/src/i18n/ru.tsv b/crates/ui-egui/src/i18n/ru.tsv index 7738d1a79..ef5297d85 100644 --- a/crates/ui-egui/src/i18n/ru.tsv +++ b/crates/ui-egui/src/i18n/ru.tsv @@ -4815,3 +4815,5 @@ lighting Light Свет Minimum Минимум Justification Выключка @msg the file's variables and data sets weren't read (variables: {variables}, data sets: {data_sets}): the Variables panel doesn't list them переменные и наборы данных файла не прочитаны (переменных: {variables}, наборов данных: {data_sets}): панель «Переменные» их не показывает +# Select by Color (select.color) + Select by Color Выделить по цвету diff --git a/crates/ui-egui/src/i18n/sv.tsv b/crates/ui-egui/src/i18n/sv.tsv index 6b2cae93a..d2939baeb 100644 --- a/crates/ui-egui/src/i18n/sv.tsv +++ b/crates/ui-egui/src/i18n/sv.tsv @@ -5161,3 +5161,5 @@ theme Appearance Utseende Minimum must not exceed Desired, nor Desired Maximum. Minimum får inte överstiga Önskat, och Önskat inte Maximum. Justification Justering @msg the file's variables and data sets weren't read (variables: {variables}, data sets: {data_sets}): the Variables panel doesn't list them filens variabler och datauppsättningar lästes inte (variabler: {variables}, datauppsättningar: {data_sets}): panelen Variabler visar dem inte +# Select by Color (select.color) + Select by Color Markera efter färg diff --git a/crates/ui-egui/src/i18n/uk.tsv b/crates/ui-egui/src/i18n/uk.tsv index 992a85ce9..c6e109a5c 100644 --- a/crates/ui-egui/src/i18n/uk.tsv +++ b/crates/ui-egui/src/i18n/uk.tsv @@ -4799,3 +4799,5 @@ lighting Light Світло Minimum Мінімум Justification Вирівнювання за шириною @msg the file's variables and data sets weren't read (variables: {variables}, data sets: {data_sets}): the Variables panel doesn't list them змінні та набори даних файлу не прочитано (змінних: {variables}, наборів даних: {data_sets}): панель «Змінні» їх не показує +# Select by Color (select.color) + Select by Color Виділити за кольором diff --git a/crates/ui-egui/src/i18n/vi.tsv b/crates/ui-egui/src/i18n/vi.tsv index 4d51bdd30..cd6550f5c 100644 --- a/crates/ui-egui/src/i18n/vi.tsv +++ b/crates/ui-egui/src/i18n/vi.tsv @@ -4799,3 +4799,5 @@ theme Appearance Giao diện Minimum Tối thiểu Justification Căn đều @msg the file's variables and data sets weren't read (variables: {variables}, data sets: {data_sets}): the Variables panel doesn't list them các biến và tập dữ liệu của tệp chưa được đọc (biến: {variables}, tập dữ liệu: {data_sets}): bảng Biến không liệt kê chúng +# Select by Color (select.color) + Select by Color Chọn theo màu diff --git a/crates/ui-egui/src/i18n/zh-hans.tsv b/crates/ui-egui/src/i18n/zh-hans.tsv index 75199ed1d..5be82a74b 100644 --- a/crates/ui-egui/src/i18n/zh-hans.tsv +++ b/crates/ui-egui/src/i18n/zh-hans.tsv @@ -5041,3 +5041,5 @@ lighting Light 光源 Minimum 最小值 Justification 对齐设置 @msg the file's variables and data sets weren't read (variables: {variables}, data sets: {data_sets}): the Variables panel doesn't list them 文件的变量和数据集未被读取(变量:{variables},数据集:{data_sets}):“变量”面板不会列出它们 +# Select by Color (select.color) + Select by Color 按颜色选择 diff --git a/crates/ui-egui/src/i18n/zh-hant.tsv b/crates/ui-egui/src/i18n/zh-hant.tsv index d825da0a2..2270dd675 100644 --- a/crates/ui-egui/src/i18n/zh-hant.tsv +++ b/crates/ui-egui/src/i18n/zh-hant.tsv @@ -4094,3 +4094,5 @@ lighting Light 光源 Minimum must not exceed Desired, nor Desired Maximum. 最小值不可超過所需值,所需值不可超過最大值。 Minimum 最小值 Justification 對齊設定 +# Select by Color (select.color) + Select by Color 依顏色選取