diff --git a/crates/engine/src/cmd/brushsym.rs b/crates/engine/src/cmd/brushsym.rs index 8ef171d32..7b37fea76 100644 --- a/crates/engine/src/cmd/brushsym.rs +++ b/crates/engine/src/cmd/brushsym.rs @@ -125,7 +125,7 @@ pub fn specs() -> Vec { "Select All Unused", [], None, - "{} → {names: [the brushes no stroke paints with, in library order]} (the Brushes panel selects them): strokes in the art (opacity masks included), symbols, graph designs, pattern tiles and graphic styles count, and so do strokes in the art of a brush that is used", + "{} → {names: [the brushes no stroke paints with, in library order]} (the Brushes panel selects them): strokes in the art (opacity masks included), symbols, graph designs, pattern tiles (with the tiles that pattern editing's Cancel puts back) and graphic styles count, and so do strokes in the art of a brush that is used", has_doc, brush_unused ), diff --git a/crates/engine/src/cmd/brushsym/brushes.rs b/crates/engine/src/cmd/brushsym/brushes.rs index 66dd546e9..f5e5c73fc 100644 --- a/crates/engine/src/cmd/brushsym/brushes.rs +++ b/crates/engine/src/cmd/brushsym/brushes.rs @@ -362,14 +362,15 @@ fn art_brushes(n: &Node, out: &mut Vec) { } /// The brushes no stroke paints with. Strokes in the art (opacity masks included), symbols, graph -/// designs, pattern tiles and graphic styles count, and so do the strokes in the art of every brush -/// that a counted stroke paints with. +/// designs, pattern tiles and the tiles that pattern editing's Cancel puts back, and graphic styles +/// count, and so do the strokes in the art of every brush that a counted stroke paints with. pub(super) fn brush_unused(s: &mut Session, _: &Value) -> Result { let d = &s.doc()?.doc; let lib = brush::library(d); let mut todo = vec![]; let trees = d.layers.iter().chain(d.symbols.iter().map(|s| &s.art)).chain(d.graph_designs.iter().map(|g| &g.art)); - trees.chain(d.patterns.iter().flat_map(|p| &p.art)).for_each(|n| art_brushes(n, &mut todo)); + let patterns = d.patterns.iter().chain(d.pattern_edit.iter().filter_map(|pe| pe.original.as_ref())); + trees.chain(patterns.flat_map(|p| &p.art)).for_each(|n| art_brushes(n, &mut todo)); d.graphic_styles.iter().for_each(|g| stroke_brushes(&g.appearance.items, &mut todo)); let mut used = BTreeSet::new(); while let Some(name) = todo.pop() { diff --git a/crates/engine/src/tests/brushsym.rs b/crates/engine/src/tests/brushsym.rs index c6a33ffc6..bba39230b 100644 --- a/crates/engine/src/tests/brushsym.rs +++ b/crates/engine/src/tests/brushsym.rs @@ -457,6 +457,31 @@ fn brush_unused_lists_the_brushes_no_stroke_paints_with() { assert_eq!(unused(&mut s), ["3 pt. Round", "6 pt. Flat", "Charcoal"]); } +/// A stroke in the tile that pattern editing's Cancel puts back counts as a use, as `brush.delete` +/// clears it there. +#[test] +fn brush_unused_counts_pattern_edit_originals() { + let mut s = session(); + let id = rect(&mut s, 10.0, 10.0, 40.0, 20.0); + s.execute("brush.apply", &json!({"name": "6 pt. Flat", "ids": [id.0]})).unwrap(); + let name = s.execute("object.pattern.make", &json!({"ids": [id.0], "edit": false})).unwrap()["name"].clone(); + s.execute("brush.remove", &json!({"ids": [id.0]})).unwrap(); + s.execute("object.pattern.edit", &json!({ "name": name })).unwrap(); + // The tile's copies in the editing layer are selected; only the tile kept for Cancel paints with the brush. + s.execute("brush.remove", &json!({})).unwrap(); + let d = std::sync::Arc::make_mut(&mut s.doc_mut().unwrap().doc); + let original = d.pattern_edit.as_ref().and_then(|pe| pe.original.as_ref()).expect("pattern edit original"); + assert_eq!(original.art.first().and_then(|n| n.appearance.stroke()).and_then(|k| k.brush.as_deref()), Some("6 pt. Flat")); + for pattern in &mut d.patterns { + for art in &mut pattern.art { + if let Some(stroke) = std::sync::Arc::make_mut(art).appearance.stroke_mut() { + stroke.brush = None; + } + } + } + assert!(!unused(&mut s).contains(&"6 pt. Flat".to_string())); +} + /// A brush counts as used when a stroke paints with it in an opacity mask, a symbol, a graph /// design, a pattern tile, a graphic style, or the art of a brush that is used. The art of a brush /// that is not used, its own strokes included, does not count. diff --git a/crates/ui-egui/src/dialogs.rs b/crates/ui-egui/src/dialogs.rs index 488cd1d95..b2a42af49 100644 --- a/crates/ui-egui/src/dialogs.rs +++ b/crates/ui-egui/src/dialogs.rs @@ -12,6 +12,7 @@ pub mod action_set_options; pub mod artboard_options; pub mod blend_options; mod brush_art_options; +pub mod brush_delete; pub mod brush_options; pub mod color_balance; pub mod color_guide_options; @@ -293,6 +294,7 @@ registry! { FindFont: ["findFont"] => DialogSpec::window(crate::find_font::show, |app, _| crate::find_font::confirm(app)), SwatchOptions: [swatch_options::KIND] => swatch_options::SPEC, Confirm: [confirm::KIND] => confirm::SPEC, + BrushDelete: [brush_delete::KIND] => brush_delete::SPEC, Message: [confirm::MESSAGE] => confirm::MESSAGE_SPEC, Replace: [confirm::REPLACE] => confirm::REPLACE_SPEC, NewSwatch: [new_swatch::KIND] => new_swatch::SPEC, diff --git a/crates/ui-egui/src/dialogs/brush_delete.rs b/crates/ui-egui/src/dialogs/brush_delete.rs new file mode 100644 index 000000000..52a86dc16 --- /dev/null +++ b/crates/ui-egui/src/dialogs/brush_delete.rs @@ -0,0 +1,90 @@ +//! The Brushes panel's Delete Brush question ([`ask`]): Yes or No when none of the brushes is in +//! use, else Remove Strokes or Cancel. Yes and Remove Strokes run `brush.delete`, which leaves the +//! strokes that used the brushes as plain strokes. +//! +//! Fields: `message` (the question, shown as the heading), `used` (whether a brush is in use), +//! `params` (the `brush.delete` params) and `__doc` (the uid of the document it asks about). + +use serde_json::{Value, json}; + +use super::{DialogAction, DialogSpec}; +use crate::VectorcraftApp; +use crate::state::Dialog; +use crate::widgets; + +/// The dialog kind of the Delete Brush question. +pub const KIND: &str = "brushDelete"; + +pub(super) const SPEC: DialogSpec = + DialogSpec { heading: |d| d.str("message"), body_with_actions: Some(body), confirm, ok: None, max_width: Some(540.0), ..DialogSpec::FORM }; + +/// Ask whether to delete the brushes `params` names (`used`: one of them is in use). +pub fn ask(app: &mut VectorcraftApp, params: Value, used: bool) { + let message = if used { + tl!("Strokes use one or more of these brushes. Take the brushes off those strokes and delete the brushes?") + } else { + tl!("Delete the selected brushes?") + }; + let doc = app.session.active().map(|d| d.uid); + app.ui.dialog = Some(Dialog::new(KIND, json!({"params": params, "used": used, "message": message, DOC: doc}))); +} + +/// The field that holds the uid of the document the question is about. +const DOC: &str = "__doc"; + +/// Whether a stroke uses one of `names` (`brush.unused`), or `None` when the query fails. +pub fn used(app: &mut VectorcraftApp, names: &[String]) -> Option { + let unused = app.run("brush.unused", json!({})).ok()?; + let unused = unused.get("names").and_then(Value::as_array).cloned().unwrap_or_default(); + Some(names.iter().any(|name| !unused.iter().any(|n| n.as_str() == Some(name)))) +} + +/// The brush names in `brush.delete` params (`name` or `names`). +fn names(params: &Value) -> Vec { + match params.get("name").and_then(Value::as_str) { + Some(name) => vec![name.to_string()], + None => params.get("names").and_then(Value::as_array).into_iter().flatten().filter_map(Value::as_str).map(str::to_string).collect(), + } +} + +fn body(_: &mut VectorcraftApp, ui: &mut egui::Ui, d: &mut Dialog) -> DialogAction { + let mut action = DialogAction::None; + ui.horizontal(|ui| { + if d.bool("used") { + if widgets::primary_button_enabled(ui, tl!("Remove Strokes"), true).clicked() { + action = DialogAction::Confirm; + } + if widgets::secondary_button(ui, tl!("Cancel")).clicked() { + action = DialogAction::Cancel; + } + } else { + if widgets::primary_button_enabled(ui, tl!("Yes"), true).clicked() { + action = DialogAction::Confirm; + } + if widgets::secondary_button(ui, tl!("No")).clicked() { + action = DialogAction::Cancel; + } + } + }); + action +} + +/// Closes before running, so a dialog the command opens stays open. Yes on brushes that a stroke +/// has started to use since the question opened asks again with Remove Strokes and Cancel. When +/// another document has become the active one, it closes as Cancel does and deletes nothing. +fn confirm(app: &mut VectorcraftApp, d: &Dialog) -> Result { + let params = d.fields.get("params").cloned().unwrap_or_else(|| json!({})); + if d.fields.get(DOC).and_then(Value::as_u64) != app.session.active().map(|doc| doc.uid) { + app.ui.dialog = None; + return Ok(json!({})); + } + if !d.bool("used") && used(app, &names(¶ms)) == Some(true) { + ask(app, params, true); + return Ok(json!({})); + } + app.ui.dialog = None; + app.run("brush.delete", params) +} + +#[cfg(test)] +mod tests; diff --git a/crates/ui-egui/src/dialogs/brush_delete/tests.rs b/crates/ui-egui/src/dialogs/brush_delete/tests.rs new file mode 100644 index 000000000..4092d6338 --- /dev/null +++ b/crates/ui-egui/src/dialogs/brush_delete/tests.rs @@ -0,0 +1,106 @@ +use egui::{Pos2, Rect, pos2, vec2}; +use serde_json::json; +use vectorcraft_doc::NodeId; +use vectorcraft_engine::Session; + +use super::*; + +fn frame(ctx: &egui::Context, app: &mut VectorcraftApp, events: Vec, time: f64) -> egui::FullOutput { + let screen_rect = Some(Rect::from_min_size(Pos2::ZERO, vec2(800.0, 600.0))); + let input = egui::RawInput { screen_rect, time: Some(time), events, ..Default::default() }; + let mut out = ctx.run_ui(input, |ui| crate::dialogs::show(app, ui.ctx())); + out.textures_delta.clear(); + out +} + +fn press(ctx: &egui::Context, app: &mut VectorcraftApp, label: &str, time: f64) { + frame(ctx, app, vec![], time); + let out = frame(ctx, app, vec![], time + 0.1); + let nodes = &out.platform_output.accesskit_update.as_ref().expect("dialog accessibility tree").nodes; + let button = nodes.iter().find(|(_, node)| node.label().map(str::trim) == Some(label)); + let bounds = button.and_then(|(_, node)| node.bounds()).expect("visible button"); + let at = pos2(((bounds.x0 + bounds.x1) / 2.0) as f32, ((bounds.y0 + bounds.y1) / 2.0) as f32); + let button = |pressed| egui::Event::PointerButton { pos: at, button: egui::PointerButton::Primary, pressed, modifiers: egui::Modifiers::NONE }; + frame(ctx, app, vec![egui::Event::PointerMoved(at), button(true), button(false)], time + 0.2); +} + +fn context() -> egui::Context { + let ctx = egui::Context::default(); + ctx.enable_accesskit(); + crate::theme::install_fonts(&ctx); + crate::theme::apply(&ctx, Default::default()); + ctx +} + +#[test] +fn visible_yes_and_no_buttons_control_unused_deletion() { + let mut app = VectorcraftApp::new(Session::new(), Default::default()); + app.run("file.new", json!({"width": 200, "height": 100})).unwrap(); + let name = app.run("brush.list", json!({})).unwrap()["brushes"][0]["name"].as_str().unwrap().to_string(); + let ctx = context(); + let before = app.session.active().unwrap().history.undo.len(); + ask(&mut app, json!({"name": name}), false); + press(&ctx, &mut app, "No", 0.0); + assert!(app.ui.dialog.is_none()); + assert_eq!(app.session.active().unwrap().history.undo.len(), before); + assert!(app.run("brush.get", json!({"name": name})).is_ok()); + ask(&mut app, json!({"name": name}), false); + press(&ctx, &mut app, "Yes", 1.0); + assert!(app.run("brush.get", json!({"name": name})).is_err()); + assert_eq!(app.session.active().unwrap().history.undo.len(), before + 1); +} + +#[test] +fn yes_asks_again_when_a_stroke_started_using_the_brush() { + let mut app = VectorcraftApp::new(Session::new(), Default::default()); + app.run("file.new", json!({"width": 200, "height": 100})).unwrap(); + let name = "10 pt. Oval"; + let ctx = context(); + ask(&mut app, json!({"names": [name]}), false); + let path = NodeId(app.run("shape.rectangle", json!({"x": 10, "y": 10, "width": 60, "height": 40})).unwrap()["id"].as_u64().unwrap()); + app.run("brush.apply", json!({"name": name})).unwrap(); + let before = app.session.active().unwrap().history.undo.len(); + press(&ctx, &mut app, "Yes", 0.0); + assert!(app.ui.dialog.as_ref().is_some_and(|d| d.kind == KIND && d.bool("used")), "asks again with Remove Strokes"); + assert_eq!(app.session.active().unwrap().history.undo.len(), before); + let stroke = app.session.active().unwrap().doc.node(path).and_then(|n| n.appearance.stroke()).unwrap(); + assert_eq!(stroke.brush.as_deref(), Some(name)); + press(&ctx, &mut app, "Remove Strokes", 1.0); + assert!(app.run("brush.get", json!({"name": name})).is_err()); +} + +#[test] +fn yes_deletes_nothing_after_another_document_became_active() { + let mut app = VectorcraftApp::new(Session::new(), Default::default()); + app.run("file.new", json!({"width": 200, "height": 100})).unwrap(); + let name = app.run("brush.list", json!({})).unwrap()["brushes"][0]["name"].as_str().unwrap().to_string(); + let ctx = context(); + ask(&mut app, json!({"name": name}), false); + app.run("file.new", json!({"width": 200, "height": 100})).unwrap(); + app.run("document.activate", json!({"index": 1})).unwrap(); + press(&ctx, &mut app, "Yes", 0.0); + assert!(app.ui.dialog.is_none()); + assert!(app.run("brush.get", json!({"name": name})).is_ok(), "the second document keeps the brush"); + app.run("document.activate", json!({"index": 0})).unwrap(); + assert!(app.run("brush.get", json!({"name": name})).is_ok(), "the first document keeps the brush"); +} + +#[test] +fn visible_remove_strokes_and_cancel_buttons_control_used_deletion() { + for choice in ["Cancel", "Remove Strokes"] { + let mut app = VectorcraftApp::new(Session::new(), Default::default()); + app.run("file.new", json!({"width": 200, "height": 100})).unwrap(); + let path = NodeId(app.run("shape.rectangle", json!({"x": 10, "y": 10, "width": 60, "height": 40})).unwrap()["id"].as_u64().unwrap()); + let name = "10 pt. Oval"; + app.run("brush.apply", json!({"name": name})).unwrap(); + let before = app.session.active().unwrap().history.undo.len(); + let ctx = context(); + ask(&mut app, json!({"name": name}), true); + press(&ctx, &mut app, choice, 0.0); + assert!(app.ui.dialog.is_none()); + assert_eq!(app.session.active().unwrap().history.undo.len(), before + usize::from(choice != "Cancel")); + let stroke = app.session.active().unwrap().doc.node(path).and_then(|n| n.appearance.stroke()).unwrap(); + assert_eq!(stroke.brush.as_deref(), (choice == "Cancel").then_some(name)); + assert!(stroke.width > 0.0); + } +} diff --git a/crates/ui-egui/src/i18n/bg.tsv b/crates/ui-egui/src/i18n/bg.tsv index dabb1c8e9..0888ac645 100644 --- a/crates/ui-egui/src/i18n/bg.tsv +++ b/crates/ui-egui/src/i18n/bg.tsv @@ -3631,6 +3631,7 @@ imageTrace Outline Контур @plural {n} item|{n} items {n} обект|{n} обекта @plural Color Table ({n} color)|Color Table ({n} colors) Цветна таблица ({n} цвят)|Цветна таблица ({n} цвята) @plural Delete this {n} graphic style?|Delete these {n} graphic styles? Изтриване на този графичен стил ({n})?|Изтриване на тези графични стилове ({n})? +@plural Delete this {n} brush?|Delete these {n} brushes? Изтриване на тази четка ({n})?|Изтриване на тези четки ({n})? @plural Delete this {n} swatch or group?|Delete these {n} swatches and groups? Изтриване на този {n} образец или група?|Изтриване на тези {n} образца и групи? @plural {n} Layer|{n} Layers {n} слой|{n} слоя @plural {n} Object|{n} Objects {n} обект|{n} обекта @@ -5898,6 +5899,9 @@ breakText Glyphs Глифи Gap 4 Разстояние 4 Dash 5 Тире 5 Gap 5 Разстояние 5 + Delete the selected brushes? Да се изтрият избраните четки? + Strokes use one or more of these brushes. Take the brushes off those strokes and delete the brushes? Щрихи използват една или повече от тези четки. Да се премахнат ли четките от тези щрихи и да се изтрият четките? + Remove Strokes Премахване на щрихи # Arrange Tools add-on (Object › Plug-ins › Arrange Tools). Arrange Tools Инструменти за подреждане Arrange in Grid… Подреждане в мрежа… diff --git a/crates/ui-egui/src/i18n/bs.tsv b/crates/ui-egui/src/i18n/bs.tsv index da8c5d134..d89af156f 100644 --- a/crates/ui-egui/src/i18n/bs.tsv +++ b/crates/ui-egui/src/i18n/bs.tsv @@ -5931,6 +5931,9 @@ shape Open Otvoren @msg `follow` must be "average", "a" or "b" `follow` mora biti "average", "a" ili "b" @msg the paths have nothing to merge there putanje tu nemaju šta spojiti @msg the path is locked or hidden putanja je zaključana ili skrivena + Delete the selected brushes? Izbrisati odabrane četkice? + Strokes use one or more of these brushes. Take the brushes off those strokes and delete the brushes? Potezi koriste jednu ili više ovih četkica. Ukloniti četkice s tih poteza i izbrisati četkice? + Remove Strokes Ukloni poteze # Arrange Tools add-on (Object › Plug-ins › Arrange Tools). Arrange Tools Alati za raspoređivanje Arrange in Grid… Rasporedi u mrežu… diff --git a/crates/ui-egui/src/i18n/ca.tsv b/crates/ui-egui/src/i18n/ca.tsv index 59984a519..15bd85222 100644 --- a/crates/ui-egui/src/i18n/ca.tsv +++ b/crates/ui-egui/src/i18n/ca.tsv @@ -4691,6 +4691,7 @@ @plural agrees with {n} default shortcut|agrees with {n} default shortcuts coincideix amb {n} drecera per defecte|coincideix amb {n} dreceres per defecte @plural Color Table ({n} color)|Color Table ({n} colors) Taula de colors ({n} color)|Taula de colors ({n} colors) @plural Delete this {n} graphic style?|Delete these {n} graphic styles? Voleu suprimir aquest {n} estil gràfic?|Voleu suprimir aquests {n} estils gràfics? +@plural Delete this {n} brush?|Delete these {n} brushes? Voleu suprimir aquest {n} pinzell?|Voleu suprimir aquests {n} pinzells? @plural Delete this {n} swatch or group?|Delete these {n} swatches and groups? Voleu suprimir aquesta {n} mostra o grup?|Voleu suprimir aquestes {n} mostres i grups? @plural {n} area highlighted|{n} areas highlighted {n} àrea ressaltada|{n} àrees ressaltades @plural {n} color|{n} colors {n} color|{n} colors @@ -5998,6 +5999,9 @@ breakText Glyphs Glifs Gap 4 Separació 4 Dash 5 Guió 5 Gap 5 Separació 5 + Delete the selected brushes? Voleu suprimir els pinzells seleccionats? + Strokes use one or more of these brushes. Take the brushes off those strokes and delete the brushes? Hi ha traços que fan servir un o més d’aquests pinzells. Voleu treure els pinzells d’aquests traços i suprimir els pinzells? + Remove Strokes Elimina els traços # Arrange Tools add-on (Object › Plug-ins › Arrange Tools). Arrange Tools Eines d’organització Arrange in Grid… Organitza en quadrícula… diff --git a/crates/ui-egui/src/i18n/cs.tsv b/crates/ui-egui/src/i18n/cs.tsv index 11d38443b..fe80401bc 100644 --- a/crates/ui-egui/src/i18n/cs.tsv +++ b/crates/ui-egui/src/i18n/cs.tsv @@ -4135,6 +4135,7 @@ imageTrace Outline Obrys @plural {n} item|{n} items {n} položka|{n} položky|{n} položek @plural Color Table ({n} color)|Color Table ({n} colors) Tabulka barev ({n} barva)|Tabulka barev ({n} barvy)|Tabulka barev ({n} barev) @plural Delete this {n} graphic style?|Delete these {n} graphic styles? Odstranit {n} grafický styl?|Odstranit {n} grafické styly?|Odstranit {n} grafických stylů? +@plural Delete this {n} brush?|Delete these {n} brushes? Odstranit {n} štětec?|Odstranit {n} štětce?|Odstranit {n} štětců? @plural Delete this {n} swatch or group?|Delete these {n} swatches and groups? Odstranit {n} položku vzorníku nebo skupinu?|Odstranit {n} položky vzorníku a skupiny?|Odstranit {n} položek vzorníku a skupin? @plural {n} Layer|{n} Layers {n} vrstva|{n} vrstvy|{n} vrstev @plural {n} Object|{n} Objects {n} objekt|{n} objekty|{n} objektů @@ -6007,6 +6008,9 @@ breakText Glyphs Glyfy Gap 4 Mezera 4 Dash 5 Čárka 5 Gap 5 Mezera 5 + Delete the selected brushes? Odstranit vybrané štětce? + Strokes use one or more of these brushes. Take the brushes off those strokes and delete the brushes? Tahy používají jeden nebo více z těchto štětců. Odebrat štětce z těchto tahů a odstranit štětce? + Remove Strokes Odebrat tahy # Arrange Tools add-on (Object › Plug-ins › Arrange Tools). Arrange Tools Nástroje uspořádání Arrange in Grid… Uspořádat do mřížky… diff --git a/crates/ui-egui/src/i18n/da.tsv b/crates/ui-egui/src/i18n/da.tsv index 1203b3d36..74107e22c 100644 --- a/crates/ui-egui/src/i18n/da.tsv +++ b/crates/ui-egui/src/i18n/da.tsv @@ -3867,6 +3867,7 @@ imageTrace Outline Kontur @plural {n} item|{n} items {n} element|{n} elementer @plural Color Table ({n} color)|Color Table ({n} colors) Farvetabel ({n} farve)|Farvetabel ({n} farver) @plural Delete this {n} graphic style?|Delete these {n} graphic styles? Vil du slette denne {n} grafikstil?|Vil du slette disse {n} grafikstile? +@plural Delete this {n} brush?|Delete these {n} brushes? Vil du slette denne {n} pensel?|Vil du slette disse {n} pensler? @plural Delete this {n} swatch or group?|Delete these {n} swatches and groups? Slet denne {n} farveprøve eller gruppe?|Slet disse {n} farveprøver og grupper? @plural {n} Layer|{n} Layers {n} lag|{n} lag @plural {n} Object|{n} Objects {n} objekt|{n} objekter @@ -5912,6 +5913,9 @@ breakText Glyphs Glyffer Gap 4 Mellemrum 4 Dash 5 Streg 5 Gap 5 Mellemrum 5 + Delete the selected brushes? Slet de valgte pensler? + Strokes use one or more of these brushes. Take the brushes off those strokes and delete the brushes? Streger bruger en eller flere af disse pensler. Fjern penslerne fra stregerne, og slet penslerne? + Remove Strokes Fjern streger # Arrange Tools add-on (Object › Plug-ins › Arrange Tools). Arrange Tools Arrangeringsværktøjer Arrange in Grid… Arrangér i gitter… diff --git a/crates/ui-egui/src/i18n/de.tsv b/crates/ui-egui/src/i18n/de.tsv index e832311b0..447c98350 100644 --- a/crates/ui-egui/src/i18n/de.tsv +++ b/crates/ui-egui/src/i18n/de.tsv @@ -3618,6 +3618,7 @@ imageTrace Outline Kontur @plural {n} item|{n} items {n} Element|{n} Elemente @plural Color Table ({n} color)|Color Table ({n} colors) Farbtabelle ({n} Farbe)|Farbtabelle ({n} Farben) @plural Delete this {n} graphic style?|Delete these {n} graphic styles? Diesen {n} Grafikstil löschen?|Diese {n} Grafikstile löschen? +@plural Delete this {n} brush?|Delete these {n} brushes? Diesen {n} Pinsel löschen?|Diese {n} Pinsel löschen? @plural Delete this {n} swatch or group?|Delete these {n} swatches and groups? {n} Farbfeld oder Gruppe löschen?|Diese {n} Farbfelder und Gruppen löschen? @plural {n} Layer|{n} Layers {n} Ebene|{n} Ebenen @plural {n} Object|{n} Objects {n} Objekt|{n} Objekte @@ -5593,6 +5594,9 @@ breakText Glyphs Glyphen Gap 4 Lücke 4 Dash 5 Strich 5 Gap 5 Lücke 5 + Delete the selected brushes? Ausgewählte Pinsel löschen? + Strokes use one or more of these brushes. Take the brushes off those strokes and delete the brushes? Konturen verwenden einen oder mehrere dieser Pinsel. Pinsel von diesen Konturen entfernen und die Pinsel löschen? + Remove Strokes Konturen entfernen # Arrange Tools add-on (Object › Plug-ins › Arrange Tools). Arrange Tools Anordnungswerkzeuge Arrange in Grid… In Raster anordnen… diff --git a/crates/ui-egui/src/i18n/el.tsv b/crates/ui-egui/src/i18n/el.tsv index 90709397a..8dea59f7f 100644 --- a/crates/ui-egui/src/i18n/el.tsv +++ b/crates/ui-egui/src/i18n/el.tsv @@ -2029,6 +2029,7 @@ imageTrace Outline Περίγραμμα @plural {n} item|{n} items {n} στοιχείο|{n} στοιχεία @plural Color Table ({n} color)|Color Table ({n} colors) Πίνακας χρωμάτων ({n} χρώμα)|Πίνακας χρωμάτων ({n} χρώματα) @plural Delete this {n} graphic style?|Delete these {n} graphic styles? Να διαγραφεί αυτό το {n} στυλ γραφικών;|Να διαγραφούν αυτά τα {n} στυλ γραφικών; +@plural Delete this {n} brush?|Delete these {n} brushes? Να διαγραφεί αυτό το {n} πινέλο;|Να διαγραφούν αυτά τα {n} πινέλα; @plural Delete this {n} swatch or group?|Delete these {n} swatches and groups? Να διαγραφεί αυτό το {n} δείγμα χρώματος ή ομάδα;|Να διαγραφούν αυτά τα {n} δείγματα χρωμάτων και οι ομάδες; @plural {n} Layer|{n} Layers {n} επίπεδο|{n} επίπεδα @plural {n} Object|{n} Objects {n} αντικείμενο|{n} αντικείμενα @@ -5960,6 +5961,9 @@ breakText Glyphs Γλύφοι Gap 4 Διάκενο 4 Dash 5 Παύλα 5 Gap 5 Διάκενο 5 + Delete the selected brushes? Να διαγραφούν τα επιλεγμένα πινέλα; + Strokes use one or more of these brushes. Take the brushes off those strokes and delete the brushes? Περιγράμματα χρησιμοποιούν ένα ή περισσότερα από αυτά τα πινέλα. Να αφαιρεθούν τα πινέλα από αυτά τα περιγράμματα και να διαγραφούν τα πινέλα; + Remove Strokes Αφαίρεση περιγραμμάτων # Arrange Tools add-on (Object › Plug-ins › Arrange Tools). Arrange Tools Εργαλεία διάταξης Arrange in Grid… Διάταξη σε πλέγμα… diff --git a/crates/ui-egui/src/i18n/es.tsv b/crates/ui-egui/src/i18n/es.tsv index f90a4b047..e6c7dd769 100644 --- a/crates/ui-egui/src/i18n/es.tsv +++ b/crates/ui-egui/src/i18n/es.tsv @@ -3703,6 +3703,7 @@ imageTrace Outline Contorno @plural {n} item|{n} items {n} elemento|{n} elementos @plural Color Table ({n} color)|Color Table ({n} colors) Tabla de colores ({n} color)|Tabla de colores ({n} colores) @plural Delete this {n} graphic style?|Delete these {n} graphic styles? ¿Eliminar {n} estilo gráfico?|¿Eliminar estos {n} estilos gráficos? +@plural Delete this {n} brush?|Delete these {n} brushes? ¿Eliminar {n} pincel?|¿Eliminar estos {n} pinceles? @plural Delete this {n} swatch or group?|Delete these {n} swatches and groups? ¿Eliminar {n} muestra o grupo?|¿Eliminar estas {n} muestras y grupos? @plural {n} Layer|{n} Layers {n} capa|{n} capas @plural {n} Object|{n} Objects {n} objeto|{n} objetos @@ -5950,6 +5951,9 @@ breakText Glyphs Glifos Gap 4 Hueco 4 Dash 5 Guion 5 Gap 5 Hueco 5 + Delete the selected brushes? ¿Eliminar los pinceles seleccionados? + Strokes use one or more of these brushes. Take the brushes off those strokes and delete the brushes? Algunos trazos usan uno o más de estos pinceles. ¿Quitar los pinceles de esos trazos y eliminar los pinceles? + Remove Strokes Quitar trazos # Arrange Tools add-on (Object › Plug-ins › Arrange Tools). Arrange Tools Herramientas de organización Arrange in Grid… Organizar en cuadrícula… diff --git a/crates/ui-egui/src/i18n/fi.tsv b/crates/ui-egui/src/i18n/fi.tsv index 8c4bc1fc1..08122ed02 100644 --- a/crates/ui-egui/src/i18n/fi.tsv +++ b/crates/ui-egui/src/i18n/fi.tsv @@ -4053,6 +4053,7 @@ imageTrace Outline Ääriviiva @plural {n} item|{n} items {n} kohde|{n} kohdetta @plural Color Table ({n} color)|Color Table ({n} colors) Väritaulukko ({n} väri)|Väritaulukko ({n} väriä) @plural Delete this {n} graphic style?|Delete these {n} graphic styles? Poistetaanko tämä {n} grafiikkatyyli?|Poistetaanko nämä {n} grafiikkatyyliä? +@plural Delete this {n} brush?|Delete these {n} brushes? Poistetaanko tämä {n} sivellin?|Poistetaanko nämä {n} sivellintä? @plural Delete this {n} swatch or group?|Delete these {n} swatches and groups? Poistetaanko tämä {n} värimalli tai ryhmä?|Poistetaanko nämä {n} värimallia ja ryhmää? @plural {n} Layer|{n} Layers {n} taso|{n} tasoa @plural {n} Object|{n} Objects {n} objekti|{n} objektia @@ -6038,6 +6039,9 @@ breakText Glyphs Merkit Gap 4 Väli 4 Dash 5 Viiva 5 Gap 5 Väli 5 + Delete the selected brushes? Poistetaanko valitut siveltimet? + Strokes use one or more of these brushes. Take the brushes off those strokes and delete the brushes? Viivat käyttävät yhtä tai useampaa näistä siveltimistä. Irrotetaanko siveltimet näistä viivoista ja poistetaanko siveltimet? + Remove Strokes Poista viivat # Arrange Tools add-on (Object › Plug-ins › Arrange Tools). Arrange Tools Järjestelytyökalut Arrange in Grid… Järjestä ruudukkoon… diff --git a/crates/ui-egui/src/i18n/fr.tsv b/crates/ui-egui/src/i18n/fr.tsv index 7db8ee535..b35297550 100644 --- a/crates/ui-egui/src/i18n/fr.tsv +++ b/crates/ui-egui/src/i18n/fr.tsv @@ -6006,6 +6006,9 @@ breakText Glyphs Glyphes Gap 4 Écart 4 Dash 5 Tiret 5 Gap 5 Écart 5 + Delete the selected brushes? Supprimer les formes sélectionnées ? + Strokes use one or more of these brushes. Take the brushes off those strokes and delete the brushes? Des contours utilisent une ou plusieurs de ces formes. Retirer les formes de ces contours et supprimer les formes ? + Remove Strokes Supprimer les contours # Arrange Tools add-on (Object › Plug-ins › Arrange Tools). Arrange Tools Outils de disposition Arrange in Grid… Disposer en grille… diff --git a/crates/ui-egui/src/i18n/hu.tsv b/crates/ui-egui/src/i18n/hu.tsv index 0aceab5ab..cac7189ed 100644 --- a/crates/ui-egui/src/i18n/hu.tsv +++ b/crates/ui-egui/src/i18n/hu.tsv @@ -4456,6 +4456,7 @@ theme Appearance Kinézet imageTrace Outline Körvonal @plural Color Table ({n} color)|Color Table ({n} colors) Színtábla ({n} szín) @plural Delete this {n} graphic style?|Delete these {n} graphic styles? {n} grafikai stílus törlése? +@plural Delete this {n} brush?|Delete these {n} brushes? {n} ecset törlése? @plural Delete this {n} swatch or group?|Delete these {n} swatches and groups? {n} színminta és csoport törlése? @plural {n} area highlighted|{n} areas highlighted Kiemelt terület: {n} @plural {n} color|{n} colors {n} szín @@ -5994,6 +5995,9 @@ breakText Glyphs Glifák Gap 4 Hézag 4 Dash 5 Vonal 5 Gap 5 Hézag 5 + Delete the selected brushes? Törlöd a kijelölt ecseteket? + Strokes use one or more of these brushes. Take the brushes off those strokes and delete the brushes? Körvonalak használnak egyet vagy többet ezek közül az ecsetek közül. Leveszed az ecseteket ezekről a körvonalakról, és törlöd az ecseteket? + Remove Strokes Körvonalak eltávolítása # Arrange Tools add-on (Object › Plug-ins › Arrange Tools). Arrange Tools Elrendezőeszközök Arrange in Grid… Elrendezés rácsba… diff --git a/crates/ui-egui/src/i18n/id.tsv b/crates/ui-egui/src/i18n/id.tsv index 95a303633..29e87826a 100644 --- a/crates/ui-egui/src/i18n/id.tsv +++ b/crates/ui-egui/src/i18n/id.tsv @@ -3867,6 +3867,7 @@ imageTrace Outline Kontur @plural {n} item|{n} items {n} item @plural Color Table ({n} color)|Color Table ({n} colors) Tabel warna ({n} warna) @plural Delete this {n} graphic style?|Delete these {n} graphic styles? Hapus {n} gaya grafis ini? +@plural Delete this {n} brush?|Delete these {n} brushes? Hapus {n} kuas ini? @plural Delete this {n} swatch or group?|Delete these {n} swatches and groups? Hapus {n} swatch dan grup ini? @plural {n} Layer|{n} Layers {n} lapisan @plural {n} Object|{n} Objects {n} objek @@ -5912,6 +5913,9 @@ breakText Glyphs Glif Gap 4 Jarak 4 Dash 5 Garis 5 Gap 5 Jarak 5 + Delete the selected brushes? Hapus kuas yang dipilih? + Strokes use one or more of these brushes. Take the brushes off those strokes and delete the brushes? Stroke menggunakan satu atau beberapa kuas ini. Lepaskan kuas dari stroke tersebut dan hapus kuasnya? + Remove Strokes Hapus Stroke # Arrange Tools add-on (Object › Plug-ins › Arrange Tools). Arrange Tools Alat penyusunan Arrange in Grid… Susun dalam grid… diff --git a/crates/ui-egui/src/i18n/it.tsv b/crates/ui-egui/src/i18n/it.tsv index a9c16d3ba..51870220a 100644 --- a/crates/ui-egui/src/i18n/it.tsv +++ b/crates/ui-egui/src/i18n/it.tsv @@ -3739,6 +3739,7 @@ imageTrace Outline Contorno @plural {n} item|{n} items {n} elemento|{n} elementi @plural Color Table ({n} color)|Color Table ({n} colors) Tabella colori ({n} colore)|Tabella colori ({n} colori) @plural Delete this {n} graphic style?|Delete these {n} graphic styles? Eliminare {n} stile grafico?|Eliminare questi {n} stili grafici? +@plural Delete this {n} brush?|Delete these {n} brushes? Eliminare {n} pennello?|Eliminare questi {n} pennelli? @plural Delete this {n} swatch or group?|Delete these {n} swatches and groups? Eliminare {n} campione o gruppo?|Eliminare questi {n} campioni e gruppi? @plural {n} Layer|{n} Layers {n} livello|{n} livelli @plural {n} Object|{n} Objects {n} oggetto|{n} oggetti @@ -5627,6 +5628,9 @@ breakText Glyphs Glifi Gap 4 Spazio 4 Dash 5 Tratto 5 Gap 5 Spazio 5 + Delete the selected brushes? Eliminare i pennelli selezionati? + Strokes use one or more of these brushes. Take the brushes off those strokes and delete the brushes? Alcune tracce usano uno o più di questi pennelli. Rimuovere i pennelli da queste tracce ed eliminare i pennelli? + Remove Strokes Rimuovi tracce # Arrange Tools add-on (Object › Plug-ins › Arrange Tools). Arrange Tools Strumenti di disposizione Arrange in Grid… Disponi in griglia… diff --git a/crates/ui-egui/src/i18n/ja.tsv b/crates/ui-egui/src/i18n/ja.tsv index 01c25917b..c6c4227b6 100644 --- a/crates/ui-egui/src/i18n/ja.tsv +++ b/crates/ui-egui/src/i18n/ja.tsv @@ -3722,6 +3722,7 @@ file-filter Templates テンプレート imageTrace Outline アウトライン @plural Color Table ({n} color)|Color Table ({n} colors) カラーテーブル ({n} 色) @plural Delete this {n} graphic style?|Delete these {n} graphic styles? {n} 個のグラフィックスタイルを削除しますか? +@plural Delete this {n} brush?|Delete these {n} brushes? {n} 個のブラシを削除しますか? @plural Delete this {n} swatch or group?|Delete these {n} swatches and groups? これら {n} 個のスウォッチとグループを削除しますか? @plural {n} Layer|{n} Layers {n} レイヤー @plural {n} Object|{n} Objects {n} オブジェクト @@ -5693,6 +5694,9 @@ breakText Glyphs 字形 Gap 4 間隔 4 Dash 5 線分 5 Gap 5 間隔 5 + Delete the selected brushes? 選択したブラシを削除しますか? + Strokes use one or more of these brushes. Take the brushes off those strokes and delete the brushes? これらのブラシの 1 つ以上が線で使われています。それらの線からブラシを外して、ブラシを削除しますか? + Remove Strokes 線を削除 # Arrange Tools add-on (Object › Plug-ins › Arrange Tools). Arrange Tools 配置ツール Arrange in Grid… グリッドに配置… diff --git a/crates/ui-egui/src/i18n/ka.tsv b/crates/ui-egui/src/i18n/ka.tsv index e0e1a1095..c02d40eb1 100644 --- a/crates/ui-egui/src/i18n/ka.tsv +++ b/crates/ui-egui/src/i18n/ka.tsv @@ -3633,6 +3633,7 @@ font-technology Variable ცვლადი @plural {n} item|{n} items ელემენტი: {n} @plural Color Table ({n} color)|Color Table ({n} colors) ფერების ცხრილი (ფერი: {n}) @plural Delete this {n} graphic style?|Delete these {n} graphic styles? წაიშალოს გრაფიკული სტილები ({n})? +@plural Delete this {n} brush?|Delete these {n} brushes? წაიშალოს ეს ფუნჯი ({n})? @plural Delete this {n} swatch or group?|Delete these {n} swatches and groups? წაიშალოს ეს ფერის ნიმუშები და ჯგუფები ({n})? @plural {n} Layer|{n} Layers შრე: {n} @plural {n} Object|{n} Objects ობიექტი: {n} @@ -5997,6 +5998,9 @@ breakText Glyphs გლიფები Gap 4 შუალედი 4 Dash 5 ტირე 5 Gap 5 შუალედი 5 + Delete the selected brushes? წაიშალოს არჩეული ფუნჯები? + Strokes use one or more of these brushes. Take the brushes off those strokes and delete the brushes? კონტურები იყენებს ამ ფუნჯებიდან ერთს ან მეტს. მოიხსნას ფუნჯები ამ კონტურებიდან და წაიშალოს ფუნჯები? + Remove Strokes კონტურების მოხსნა # Arrange Tools add-on (Object › Plug-ins › Arrange Tools). Arrange Tools განლაგების ხელსაწყოები Arrange in Grid… ბადეში განლაგება… diff --git a/crates/ui-egui/src/i18n/ko.tsv b/crates/ui-egui/src/i18n/ko.tsv index 45ce73252..5c24bd9ca 100644 --- a/crates/ui-egui/src/i18n/ko.tsv +++ b/crates/ui-egui/src/i18n/ko.tsv @@ -3711,6 +3711,7 @@ file-filter Templates 템플릿 imageTrace Outline 윤곽선 @plural Color Table ({n} color)|Color Table ({n} colors) 색상 표 ({n}색)|색상 표 ({n}색) @plural Delete this {n} graphic style?|Delete these {n} graphic styles? 그래픽 스타일 {n}개를 삭제하시겠습니까?|그래픽 스타일 {n}개를 삭제하시겠습니까? +@plural Delete this {n} brush?|Delete these {n} brushes? 브러시 {n}개를 삭제하시겠습니까?|브러시 {n}개를 삭제하시겠습니까? @plural Delete this {n} swatch or group?|Delete these {n} swatches and groups? 견본과 그룹 {n}개를 삭제하시겠습니까? @plural {n} Layer|{n} Layers 레이어 {n}개|레이어 {n}개 @plural {n} Object|{n} Objects 개체 {n}개|개체 {n}개 @@ -5590,6 +5591,9 @@ breakText Glyphs 글리프 Gap 4 간격 4 Dash 5 대시 5 Gap 5 간격 5 + Delete the selected brushes? 선택한 브러시를 삭제하시겠습니까? + Strokes use one or more of these brushes. Take the brushes off those strokes and delete the brushes? 선에서 이 브러시 중 하나 이상을 사용합니다. 해당 선에서 브러시를 제거하고 브러시를 삭제하시겠습니까? + Remove Strokes 선 제거 # Arrange Tools add-on (Object › Plug-ins › Arrange Tools). Arrange Tools 배치 도구 Arrange in Grid… 격자로 배치… diff --git a/crates/ui-egui/src/i18n/nl.tsv b/crates/ui-egui/src/i18n/nl.tsv index e4cca253f..282b0a4aa 100644 --- a/crates/ui-egui/src/i18n/nl.tsv +++ b/crates/ui-egui/src/i18n/nl.tsv @@ -3881,6 +3881,7 @@ imageTrace Outline Contour @plural {n} item|{n} items {n} item|{n} items @plural Color Table ({n} color)|Color Table ({n} colors) Kleurentabel ({n} kleur)|Kleurentabel ({n} kleuren) @plural Delete this {n} graphic style?|Delete these {n} graphic styles? Deze {n} grafische stijl verwijderen?|Deze {n} grafische stijlen verwijderen? +@plural Delete this {n} brush?|Delete these {n} brushes? Deze {n} kwast verwijderen?|Deze {n} kwasten verwijderen? @plural Delete this {n} swatch or group?|Delete these {n} swatches and groups? Deze {n} staal of groep verwijderen?|Deze {n} stalen en groepen verwijderen? @plural {n} Layer|{n} Layers {n} laag|{n} lagen @plural {n} Object|{n} Objects {n} object|{n} objecten @@ -5956,6 +5957,9 @@ breakText Glyphs Glyphs Gap 4 Tussenruimte 4 Dash 5 Streepje 5 Gap 5 Tussenruimte 5 + Delete the selected brushes? Geselecteerde kwasten verwijderen? + Strokes use one or more of these brushes. Take the brushes off those strokes and delete the brushes? Contouren gebruiken een of meer van deze kwasten. De kwasten van deze contouren halen en de kwasten verwijderen? + Remove Strokes Contouren verwijderen # Arrange Tools add-on (Object › Plug-ins › Arrange Tools). Arrange Tools Schikgereedschappen Arrange in Grid… In raster schikken… diff --git a/crates/ui-egui/src/i18n/pl.tsv b/crates/ui-egui/src/i18n/pl.tsv index 027f7198e..399971447 100644 --- a/crates/ui-egui/src/i18n/pl.tsv +++ b/crates/ui-egui/src/i18n/pl.tsv @@ -3961,6 +3961,7 @@ imageTrace Outline Kontur @plural {n} item|{n} items {n} element|{n} elementy|{n} elementów @plural Color Table ({n} color)|Color Table ({n} colors) Tablica kolorów ({n} kolor)|Tablica kolorów ({n} kolory)|Tablica kolorów ({n} kolorów) @plural Delete this {n} graphic style?|Delete these {n} graphic styles? Usunąć {n} styl graficzny?|Usunąć {n} style graficzne?|Usunąć {n} stylów graficznych? +@plural Delete this {n} brush?|Delete these {n} brushes? Usunąć {n} pędzel?|Usunąć {n} pędzle?|Usunąć {n} pędzli? @plural Delete this {n} swatch or group?|Delete these {n} swatches and groups? Usunąć {n} próbkę lub grupę?|Usunąć {n} próbki i grupy?|Usunąć {n} próbek i grup? @plural {n} Layer|{n} Layers {n} warstwa|{n} warstwy|{n} warstw @plural {n} Object|{n} Objects {n} obiekt|{n} obiekty|{n} obiektów @@ -5863,6 +5864,9 @@ breakText Glyphs Glify Gap 4 Odstęp 4 Dash 5 Kreska 5 Gap 5 Odstęp 5 + Delete the selected brushes? Usunąć zaznaczone pędzle? + Strokes use one or more of these brushes. Take the brushes off those strokes and delete the brushes? Obrysy używają co najmniej jednego z tych pędzli. Zdjąć pędzle z tych obrysów i usunąć pędzle? + Remove Strokes Usuń obrysy # Arrange Tools add-on (Object › Plug-ins › Arrange Tools). Arrange Tools Narzędzia układania Arrange in Grid… Ułóż w siatce… diff --git a/crates/ui-egui/src/i18n/pt-br.tsv b/crates/ui-egui/src/i18n/pt-br.tsv index e9ee07994..4f75dd659 100644 --- a/crates/ui-egui/src/i18n/pt-br.tsv +++ b/crates/ui-egui/src/i18n/pt-br.tsv @@ -3041,6 +3041,7 @@ imageTrace Outline Contorno @plural {n} item|{n} items {n} item|{n} itens @plural Color Table ({n} color)|Color Table ({n} colors) Tabela de Cores ({n} cor)|Tabela de Cores ({n} cores) @plural Delete this {n} graphic style?|Delete these {n} graphic styles? Excluir este {n} estilo gráfico?|Excluir estes {n} estilos gráficos? +@plural Delete this {n} brush?|Delete these {n} brushes? Excluir este {n} pincel?|Excluir estes {n} pincéis? @plural Delete this {n} swatch or group?|Delete these {n} swatches and groups? Excluir esta {n} amostra ou grupo?|Excluir estas {n} amostras e grupos? @plural {n} Layer|{n} Layers {n} Camada|{n} Camadas @plural {n} Object|{n} Objects {n} Objeto|{n} Objetos @@ -5927,6 +5928,9 @@ breakText Glyphs Glifos Gap 4 Lacuna 4 Dash 5 Traço 5 Gap 5 Lacuna 5 + Delete the selected brushes? Excluir os pincéis selecionados? + Strokes use one or more of these brushes. Take the brushes off those strokes and delete the brushes? Traçados usam um ou mais destes pincéis. Remover os pincéis desses traçados e excluir os pincéis? + Remove Strokes Remover Traçados # Arrange Tools add-on (Object › Plug-ins › Arrange Tools). Arrange Tools Ferramentas de Organização Arrange in Grid… Organizar em Grade… diff --git a/crates/ui-egui/src/i18n/ru.tsv b/crates/ui-egui/src/i18n/ru.tsv index dea1bee84..d412fa13b 100644 --- a/crates/ui-egui/src/i18n/ru.tsv +++ b/crates/ui-egui/src/i18n/ru.tsv @@ -3735,6 +3735,7 @@ imageTrace Outline Контур @plural {n} item|{n} items {n} элемент|{n} элемента|{n} элементов @plural Color Table ({n} color)|Color Table ({n} colors) Цветовая таблица ({n} цвет)|Цветовая таблица ({n} цвета)|Цветовая таблица ({n} цветов) @plural Delete this {n} graphic style?|Delete these {n} graphic styles? Удалить этот графический стиль ({n})?|Удалить эти графические стили ({n})?|Удалить эти графические стили ({n})? +@plural Delete this {n} brush?|Delete these {n} brushes? Удалить эту кисть ({n})?|Удалить эти кисти ({n})?|Удалить {n} кистей? @plural Delete this {n} swatch or group?|Delete these {n} swatches and groups? Удалить образцы и группы ({n})?|Удалить {n} образца и группы?|Удалить {n} образцов и групп? @plural {n} Layer|{n} Layers {n} слой|{n} слоя|{n} слоёв @plural {n} Object|{n} Objects {n} объект|{n} объекта|{n} объектов @@ -5985,6 +5986,9 @@ breakText Glyphs Глифы Gap 4 Зазор 4 Dash 5 Штрих 5 Gap 5 Зазор 5 + Delete the selected brushes? Удалить выбранные кисти? + Strokes use one or more of these brushes. Take the brushes off those strokes and delete the brushes? Обводки используют одну или несколько из этих кистей. Убрать кисти с этих обводок и удалить кисти? + Remove Strokes Убрать обводки # Arrange Tools add-on (Object › Plug-ins › Arrange Tools). Arrange Tools Инструменты размещения Arrange in Grid… Разместить по сетке… diff --git a/crates/ui-egui/src/i18n/sv.tsv b/crates/ui-egui/src/i18n/sv.tsv index fcd0427a7..2a1ba3745 100644 --- a/crates/ui-egui/src/i18n/sv.tsv +++ b/crates/ui-egui/src/i18n/sv.tsv @@ -3631,6 +3631,7 @@ imageTrace Outline Kontur @plural {n} item|{n} items {n} objekt|{n} objekt @plural Color Table ({n} color)|Color Table ({n} colors) Färgtabell ({n} färg)|Färgtabell ({n} färger) @plural Delete this {n} graphic style?|Delete these {n} graphic styles? Radera {n} grafisk stil?|Radera de här {n} grafiska stilarna? +@plural Delete this {n} brush?|Delete these {n} brushes? Radera {n} pensel?|Radera dessa {n} penslar? @plural Delete this {n} swatch or group?|Delete these {n} swatches and groups? Radera {n} färgruta eller grupp?|Radera dessa {n} färgrutor och grupper? @plural {n} Layer|{n} Layers {n} lager|{n} lager @plural {n} Object|{n} Objects {n} objekt|{n} objekt @@ -6060,6 +6061,9 @@ breakText Glyphs Glyfer Gap 4 Mellanrum 4 Dash 5 Streck 5 Gap 5 Mellanrum 5 + Delete the selected brushes? Radera de valda penslarna? + Strokes use one or more of these brushes. Take the brushes off those strokes and delete the brushes? Konturer använder en eller flera av de här penslarna. Ta bort penslarna från konturerna och radera penslarna? + Remove Strokes Ta bort konturer # Arrange Tools add-on (Object › Plug-ins › Arrange Tools). Arrange Tools Ordningsverktyg Arrange in Grid… Ordna i rutnät… diff --git a/crates/ui-egui/src/i18n/tr.tsv b/crates/ui-egui/src/i18n/tr.tsv index 7a1ea3647..215b7f8e6 100644 --- a/crates/ui-egui/src/i18n/tr.tsv +++ b/crates/ui-egui/src/i18n/tr.tsv @@ -3525,6 +3525,7 @@ imageTrace Outline Kontur @plural {n} item|{n} items {n} öğe @plural Color Table ({n} color)|Color Table ({n} colors) Renk Tablosu ({n} renk) @plural Delete this {n} graphic style?|Delete these {n} graphic styles? Bu {n} grafik stili silinsin mi? +@plural Delete this {n} brush?|Delete these {n} brushes? Bu {n} fırça silinsin mi? @plural Delete this {n} swatch or group?|Delete these {n} swatches and groups? Bu {n} renk örneği ve grup silinsin mi? @plural {n} Layer|{n} Layers {n} Katman @plural {n} Object|{n} Objects {n} Nesne @@ -5965,6 +5966,9 @@ breakText Glyphs Glifler Gap 4 Boşluk 4 Dash 5 Çizgi 5 Gap 5 Boşluk 5 + Delete the selected brushes? Seçili fırçalar silinsin mi? + Strokes use one or more of these brushes. Take the brushes off those strokes and delete the brushes? Konturlar bu fırçalardan birini veya daha fazlasını kullanıyor. Fırçalar bu konturlardan kaldırılsın ve fırçalar silinsin mi? + Remove Strokes Konturları Kaldır # Arrange Tools add-on (Object › Plug-ins › Arrange Tools). Arrange Tools Düzenleme Araçları Arrange in Grid… Izgarada Düzenle… diff --git a/crates/ui-egui/src/i18n/uk.tsv b/crates/ui-egui/src/i18n/uk.tsv index 58693ddfd..13fab3c51 100644 --- a/crates/ui-egui/src/i18n/uk.tsv +++ b/crates/ui-egui/src/i18n/uk.tsv @@ -3732,6 +3732,7 @@ imageTrace Outline Контур @plural {n} item|{n} items {n} елемент|{n} елементи|{n} елементів @plural Color Table ({n} color)|Color Table ({n} colors) Таблиця кольорів ({n} колір)|Таблиця кольорів ({n} кольори)|Таблиця кольорів ({n} кольорів) @plural Delete this {n} graphic style?|Delete these {n} graphic styles? Видалити цей графічний стиль ({n})?|Видалити ці графічні стилі ({n})?|Видалити ці графічні стилі ({n})? +@plural Delete this {n} brush?|Delete these {n} brushes? Видалити цей пензель ({n})?|Видалити ці пензлі ({n})?|Видалити {n} пензлів? @plural Delete this {n} swatch or group?|Delete these {n} swatches and groups? Видалити зразки та групи ({n})?|Видалити {n} зразки та групи?|Видалити {n} зразків і груп? @plural {n} Layer|{n} Layers {n} шар|{n} шари|{n} шарів @plural {n} Object|{n} Objects {n} об’єкт|{n} об’єкти|{n} об’єктів @@ -5607,6 +5608,9 @@ breakText Glyphs Гліфи Gap 4 Проміжок 4 Dash 5 Штрих 5 Gap 5 Проміжок 5 + Delete the selected brushes? Видалити вибрані пензлі? + Strokes use one or more of these brushes. Take the brushes off those strokes and delete the brushes? Обведення використовують один або кілька з цих пензлів. Забрати пензлі з цих обведень і видалити пензлі? + Remove Strokes Забрати обведення # Arrange Tools add-on (Object › Plug-ins › Arrange Tools). Arrange Tools Інструменти розміщення Arrange in Grid… Розмістити сіткою… diff --git a/crates/ui-egui/src/i18n/vi.tsv b/crates/ui-egui/src/i18n/vi.tsv index aaa74d0e7..f45d5d04a 100644 --- a/crates/ui-egui/src/i18n/vi.tsv +++ b/crates/ui-egui/src/i18n/vi.tsv @@ -4097,6 +4097,7 @@ gradient-kind Radial Hướng tâm imageTrace Outline Đường viền @plural Color Table ({n} color)|Color Table ({n} colors) Bảng màu ({n} màu) @plural Delete this {n} graphic style?|Delete these {n} graphic styles? Xóa {n} kiểu đồ họa này? +@plural Delete this {n} brush?|Delete these {n} brushes? Xóa {n} cọ này? @plural Delete this {n} swatch or group?|Delete these {n} swatches and groups? Xóa {n} mẫu màu và nhóm này? @plural {n} area highlighted|{n} areas highlighted {n} vùng được tô sáng @plural {n} color|{n} colors {n} màu @@ -5609,6 +5610,9 @@ breakText Glyphs Glyph Gap 4 Khoảng hở 4 Dash 5 Nét 5 Gap 5 Khoảng hở 5 + Delete the selected brushes? Xóa các cọ đã chọn? + Strokes use one or more of these brushes. Take the brushes off those strokes and delete the brushes? Có nét đang dùng một hoặc nhiều cọ này. Gỡ cọ khỏi các nét đó và xóa cọ? + Remove Strokes Gỡ nét # Arrange Tools add-on (Object › Plug-ins › Arrange Tools). Arrange Tools Công cụ sắp xếp Arrange in Grid… Sắp xếp theo lưới… diff --git a/crates/ui-egui/src/i18n/zh-hans.tsv b/crates/ui-egui/src/i18n/zh-hans.tsv index 71b1fead1..4e105573f 100644 --- a/crates/ui-egui/src/i18n/zh-hans.tsv +++ b/crates/ui-egui/src/i18n/zh-hans.tsv @@ -3578,6 +3578,7 @@ imageTrace Outline 轮廓 @plural {n} item|{n} items {n} 个项目 @plural Color Table ({n} color)|Color Table ({n} colors) 颜色表 ({n} 色) @plural Delete this {n} graphic style?|Delete these {n} graphic styles? 要删除这 {n} 个图形样式吗? +@plural Delete this {n} brush?|Delete these {n} brushes? 要删除这 {n} 个画笔吗? @plural Delete this {n} swatch or group?|Delete these {n} swatches and groups? 要删除这 {n} 个色板和编组吗? @plural {n} Layer|{n} Layers {n} 个图层 @plural {n} Object|{n} Objects {n} 个对象 @@ -5849,6 +5850,9 @@ breakText Glyphs 字形 Gap 4 间隔 4 Dash 5 虚线 5 Gap 5 间隔 5 + Delete the selected brushes? 删除选中的画笔吗? + Strokes use one or more of these brushes. Take the brushes off those strokes and delete the brushes? 有描边使用了其中一个或多个画笔。要从这些描边移除画笔并删除画笔吗? + Remove Strokes 移除描边 # Arrange Tools add-on (Object › Plug-ins › Arrange Tools). Arrange Tools 排列工具 Arrange in Grid… 按网格排列… diff --git a/crates/ui-egui/src/i18n/zh-hant.tsv b/crates/ui-egui/src/i18n/zh-hant.tsv index a89fd28cc..acb829199 100644 --- a/crates/ui-egui/src/i18n/zh-hant.tsv +++ b/crates/ui-egui/src/i18n/zh-hant.tsv @@ -4557,6 +4557,7 @@ imageTrace Outline 輪廓 @plural {n} item|{n} items {n} 個項目 @plural Color Table ({n} color)|Color Table ({n} colors) 色彩表 ({n} 色) @plural Delete this {n} graphic style?|Delete these {n} graphic styles? 要刪除這 {n} 個繪圖樣式嗎? +@plural Delete this {n} brush?|Delete these {n} brushes? 要刪除這 {n} 個筆刷嗎? @plural Delete this {n} swatch or group?|Delete these {n} swatches and groups? 要刪除這 {n} 個色票和群組嗎? @plural {n} Layer|{n} Layers {n} 個圖層 @plural {n} Object|{n} Objects {n} 個物件 @@ -5646,6 +5647,9 @@ breakText Glyphs 字符 Gap 4 間隙 4 Dash 5 虛線 5 Gap 5 間隙 5 + Delete the selected brushes? 要刪除選取的筆刷嗎? + Strokes use one or more of these brushes. Take the brushes off those strokes and delete the brushes? 有筆畫使用了其中一個或多個筆刷。要從這些筆畫移除筆刷並刪除筆刷嗎? + Remove Strokes 移除筆畫 # Arrange Tools add-on (Object › Plug-ins › Arrange Tools). Arrange Tools 排列工具 Arrange in Grid… 依格狀排列… diff --git a/crates/ui-egui/src/panels/brushes.rs b/crates/ui-egui/src/panels/brushes.rs index cf95c5a9f..6f99c8a36 100644 --- a/crates/ui-egui/src/panels/brushes.rs +++ b/crates/ui-egui/src/panels/brushes.rs @@ -204,6 +204,23 @@ fn run_on(app: &mut VectorcraftApp, id: &str, names: &[String]) { app.run(id, p).ok(); } +/// Delete `names` after asking: Yes or No when none of them is in use, else Remove Strokes or +/// Cancel. With `now` (Alt-click on the bottom button), brushes that are not in use go at once. +fn delete(app: &mut VectorcraftApp, names: &[String], now: bool) { + let Some(used) = crate::dialogs::brush_delete::used(app, names) else { + return; + }; + if now && !used { + run_on(app, "brush.delete", names); + return; + } + let params = match names { + [name] => json!({ "name": name }), + _ => json!({ "names": names }), + }; + crate::dialogs::brush_delete::ask(app, params, used); +} + /// The names in `list` in the order the panel shows them: by type in [`KINDS`] order, without the /// hidden types. fn shown<'a>(list: &'a [(String, String)], hidden: &[String]) -> Vec<&'a str> { @@ -417,7 +434,7 @@ pub fn show(app: &mut VectorcraftApp, ui: &mut Ui) { app.status(e); } if widgets::icon_button_enabled(ui, "trash-2", tl!("Delete Brush"), false, !targets.is_empty(), 24.0).clicked() { - run_on(app, "brush.delete", &targets); + delete(app, &targets, ui.input(|i| i.modifiers.alt)); } }); } @@ -452,7 +469,7 @@ pub fn menu(app: &mut VectorcraftApp, ui: &mut Ui) { run_on(app, "brush.duplicate", &targets); } if menu_item(ui, tl!("Delete Brush"), !targets.is_empty(), false) { - run_on(app, "brush.delete", &targets); + delete(app, &targets, false); } if menu_item(ui, tl!("Remove Brush Stroke"), sel.is_some(), false) { app.run("brush.remove", json!({})).ok(); diff --git a/crates/ui-egui/src/panels/brushes/tests.rs b/crates/ui-egui/src/panels/brushes/tests.rs index 47fc962c6..0aef4fb63 100644 --- a/crates/ui-egui/src/panels/brushes/tests.rs +++ b/crates/ui-egui/src/panels/brushes/tests.rs @@ -146,6 +146,42 @@ fn names(app: &mut VectorcraftApp) -> Vec { brushes(app).0.into_iter().map(|b| b.0).collect() } +fn undo_count(app: &VectorcraftApp) -> usize { + app.session.active().unwrap().history.undo.len() +} + +fn delete_button(ctx: &egui::Context, app: &mut VectorcraftApp, modifiers: egui::Modifiers, time: f64) { + let out = frame_with(ctx, app, vec![], egui::Modifiers::NONE, time, show); + let at = clickable(&out).into_iter().find(|(label, _)| label.as_deref() == Some("Delete Brush")).expect("Delete Brush button").1.center(); + click(ctx, app, at, modifiers, time + 0.5, show); +} + +fn assert_delete_dialog(app: &VectorcraftApp, message: &str) { + let d = app.ui.dialog.as_ref().expect("Delete Brush asks first"); + assert_eq!(d.kind, crate::dialogs::brush_delete::KIND); + assert_eq!(d.str("message"), message); + assert_eq!(d.bool("used"), message == IN_USE); +} + +/// The Delete Brush question when a stroke uses one of the brushes. +const IN_USE: &str = "Strokes use one or more of these brushes. Take the brushes off those strokes and delete the brushes?"; + +/// Deleting several unused brushes asks one question about the selection, with no count in it. +#[test] +fn deleting_five_brushes_uses_one_selection_question() { + let mut app = VectorcraftApp::new(Session::new(), Default::default()); + app.run("file.new", json!({"width": 200, "height": 100})).unwrap(); + let five: Vec = names(&mut app).into_iter().take(5).collect(); + assert_eq!(five.len(), 5); + let previous = crate::i18n::current(); + let polish = crate::i18n::Lang::from_code("pl").unwrap(); + crate::i18n::set_current(polish); + delete(&mut app, &five, false); + let message = app.ui.dialog.as_ref().map(|d| d.str("message")); + crate::i18n::set_current(previous); + assert_eq!(message, Some("Usunąć zaznaczone pędzle?".to_string())); +} + /// Click the panel menu's item `label` (frames at `time`, `time + 0.5`). fn menu_click(ctx: &egui::Context, app: &mut VectorcraftApp, label: &str, time: f64) { let out = frame_with(ctx, app, vec![], egui::Modifiers::NONE, time, menu); @@ -186,21 +222,23 @@ fn shift_and_command_clicks_select_brushes_for_delete_and_duplicate() { click(&ctx, &mut app, tiles[1].center(), egui::Modifiers::COMMAND, 3.0, show); let out = frame_with(&ctx, &mut app, vec![], egui::Modifiers::NONE, 3.5, show); assert_eq!(lit_tiles(&out), [0, 2]); - let undo = |app: &VectorcraftApp| app.session.active().unwrap().history.undo.len(); - let before = (names(&mut app), undo(&app)); + let before = (names(&mut app), undo_count(&app)); menu_click(&ctx, &mut app, "Duplicate Brush", 4.0); let copies = [format!("{} copy", three[0]), format!("{} copy", three[2])]; assert_eq!(names(&mut app)[before.0.len()..], copies); - assert_eq!(undo(&app), before.1 + 1); + assert_eq!(undo_count(&app), before.1 + 1); // The bottom bar's last button, Delete Brush. - let out = frame_with(&ctx, &mut app, vec![], egui::Modifiers::NONE, 5.0, show); - let trash = clickable(&out).last().unwrap().1.center(); - click(&ctx, &mut app, trash, egui::Modifiers::NONE, 6.0, show); + delete_button(&ctx, &mut app, egui::Modifiers::NONE, 5.0); + assert_delete_dialog(&app, IN_USE); + assert_eq!(names(&mut app), [before.0.clone(), copies.to_vec()].concat()); + assert_eq!(brush_of(&app, rect).as_deref(), Some(three[0].as_str())); + assert_eq!(undo_count(&app), before.1 + 1); + crate::dialogs::confirm(&mut app).unwrap(); let left = names(&mut app); assert!(!left.contains(&three[0]) && !left.contains(&three[2]) && left.contains(&three[1]), "{left:?}"); assert!(copies.iter().all(|c| left.contains(c)), "{left:?}"); assert_eq!(brush_of(&app, rect), None); - assert_eq!(undo(&app), before.1 + 2); + assert_eq!(undo_count(&app), before.1 + 2); } /// Selecting other art ends the multi-selection: selecting the first art again does not bring @@ -231,6 +269,9 @@ fn selecting_other_art_ends_the_brush_multi_selection() { let out = frame_with(&ctx, &mut app, vec![], egui::Modifiers::NONE, 4.0, show); assert_eq!(lit_tiles(&out), [1]); menu_click(&ctx, &mut app, "Delete Brush", 5.0); + assert_delete_dialog(&app, IN_USE); + assert!(names(&mut app).contains(&three[1])); + crate::dialogs::confirm(&mut app).unwrap(); let left = names(&mut app); assert!(left.contains(&three[0]) && !left.contains(&three[1]) && left.contains(&three[2]), "{left:?}"); assert_eq!((brush_of(&app, a).as_deref(), brush_of(&app, c)), (Some(three[0].as_str()), None)); @@ -297,10 +338,97 @@ fn select_all_unused_selects_the_brushes_no_stroke_paints_with() { let on: Vec = (0..tiles.len()).filter(|i| lit(&ctx, &out).contains(&tiles[*i])).collect(); assert_eq!(on, (0..tiles.len()).filter(|i| *i != 1).collect::>()); menu_click(&ctx, &mut app, "Delete Brush", 3.0); + assert_delete_dialog(&app, "Delete the selected brushes?"); + assert_eq!(names(&mut app).len(), list.len()); + crate::dialogs::confirm(&mut app).unwrap(); assert_eq!(names(&mut app), [list[1].0.clone()]); assert_eq!(brush_of(&app, a), Some(list[1].0.clone())); } +#[test] +fn delete_button_cancel_keeps_selected_brushes_strokes_and_history() { + let mut app = VectorcraftApp::new(Session::new(), Default::default()); + app.run("file.new", json!({"width": 200, "height": 100})).unwrap(); + let rect = NodeId(app.run("shape.rectangle", json!({"x": 10, "y": 10, "width": 50, "height": 40})).unwrap()["id"].as_u64().unwrap()); + let ctx = egui::Context::default(); + ctx.enable_accesskit(); + let (three, _) = select_three(&ctx, &mut app, rect); + let before = (names(&mut app), brush_of(&app, rect), undo_count(&app)); + delete_button(&ctx, &mut app, egui::Modifiers::NONE, 3.0); + assert_delete_dialog(&app, IN_USE); + assert_eq!((names(&mut app), brush_of(&app, rect), undo_count(&app)), before); + crate::dialogs::cancel(&mut app); + assert!(app.ui.dialog.is_none()); + assert_eq!((names(&mut app), brush_of(&app, rect), undo_count(&app)), before); + assert_eq!(before.1.as_deref(), Some(three[0].as_str())); + app.run("brush.delete", json!({"name": three[0]})).unwrap(); + assert!(app.ui.dialog.is_none()); + assert_eq!(undo_count(&app), before.2 + 1); + app.run("brush.delete", json!({"names": [three[1], three[2]]})).unwrap(); + assert!(app.ui.dialog.is_none()); + assert_eq!(undo_count(&app), before.2 + 2); +} + +#[test] +fn alt_delete_button_asks_when_a_selected_brush_is_used() { + let mut app = VectorcraftApp::new(Session::new(), Default::default()); + app.run("file.new", json!({"width": 200, "height": 100})).unwrap(); + let rect = NodeId(app.run("shape.rectangle", json!({"x": 10, "y": 10, "width": 50, "height": 40})).unwrap()["id"].as_u64().unwrap()); + let ctx = egui::Context::default(); + ctx.enable_accesskit(); + let (three, _) = select_three(&ctx, &mut app, rect); + let before = undo_count(&app); + delete_button(&ctx, &mut app, egui::Modifiers::NONE, 3.0); + assert_delete_dialog(&app, IN_USE); + crate::dialogs::cancel(&mut app); + delete_button(&ctx, &mut app, egui::Modifiers::ALT, 4.0); + assert_delete_dialog(&app, IN_USE); + crate::dialogs::cancel(&mut app); + let left = names(&mut app); + assert!(three.iter().all(|name| left.contains(name))); + assert_eq!(brush_of(&app, rect).as_deref(), Some(three[0].as_str())); + assert_eq!(undo_count(&app), before); +} + +#[test] +fn alt_delete_button_deletes_unused_brush_without_a_question() { + let mut app = VectorcraftApp::new(Session::new(), Default::default()); + app.run("file.new", json!({"width": 200, "height": 100})).unwrap(); + let ctx = egui::Context::default(); + ctx.enable_accesskit(); + let first = names(&mut app)[0].clone(); + let out = frame_with(&ctx, &mut app, vec![], egui::Modifiers::NONE, 0.0, show); + let tile = clickable(&out).into_iter().find(|(label, _)| label.as_deref() == Some(first.as_str())).expect("brush tile").1.center(); + click(&ctx, &mut app, tile, egui::Modifiers::NONE, 1.0, show); + let before = undo_count(&app); + delete_button(&ctx, &mut app, egui::Modifiers::ALT, 2.0); + assert!(app.ui.dialog.is_none()); + assert!(!names(&mut app).contains(&first)); + assert_eq!(undo_count(&app), before + 1); +} + +#[test] +fn menu_delete_used_brush_requires_remove_strokes_or_cancel() { + let mut app = VectorcraftApp::new(Session::new(), Default::default()); + app.run("file.new", json!({"width": 200, "height": 100})).unwrap(); + let rect = NodeId(app.run("shape.rectangle", json!({"x": 10, "y": 10, "width": 50, "height": 40})).unwrap()["id"].as_u64().unwrap()); + let ctx = egui::Context::default(); + ctx.enable_accesskit(); + let (three, _) = select_three(&ctx, &mut app, rect); + let before = undo_count(&app); + menu_click(&ctx, &mut app, "Delete Brush", 3.0); + assert_delete_dialog(&app, IN_USE); + crate::dialogs::cancel(&mut app); + assert_eq!(undo_count(&app), before); + assert_eq!(brush_of(&app, rect).as_deref(), Some(three[0].as_str())); + menu_click(&ctx, &mut app, "Delete Brush", 4.0); + crate::dialogs::confirm(&mut app).unwrap(); + assert_eq!(undo_count(&app), before + 1); + assert_eq!(brush_of(&app, rect), None); + assert!(app.session.active().unwrap().doc.node(rect).unwrap().appearance.stroke().is_some()); + assert!(three.iter().all(|name| !names(&mut app).contains(name))); +} + #[test] fn art_dropped_on_the_panel_becomes_an_art_brush_and_a_brush_drags_out() { let mut app = VectorcraftApp::new(Session::new(), Default::default()); diff --git a/docs/mcp.md b/docs/mcp.md index 6f342c98c..1f843271e 100644 --- a/docs/mcp.md +++ b/docs/mcp.md @@ -1557,8 +1557,10 @@ already walks Image Trace. Short agent entry points: name they are given, as `symbol.options` trims `newName`; a blank one gives "New Symbol" or " copy". - The Brushes panel menu's Select All Unused: `brush.unused` (a query) lists the brushes no stroke paints with, in library order, and the panel selects them. Strokes in the art (opacity masks included), symbols, graph designs, - pattern tiles and graphic styles count, and so do the strokes in the art of a brush that is used. The art of a brush - that is not used does not count, so a brush whose own art is the only art that paints with it is listed. + pattern tiles (with the tiles that pattern editing's Cancel puts back) and graphic styles count, and so do the + strokes in the art of a brush that is used. The art of a brush that is not used does not count, so a brush whose own + art is the only art that paints with it is listed. The panel's Delete Brush asks Yes/No when every brush it deletes + is unused, and offers Remove Strokes or Cancel when one of them is in use. - Brushes: `brush.list`, `brush.get {name}`, `brush.apply {name, ids?}`, `brush.new {type, name?, params?, ids?}`, `brush.setCurrent {name}`, `brush.options {name, params?, newName?}`, `brush.delete {name} | {names}`, `brush.duplicate {name, newName?} | {names}`, `brush.freehand`, `object.expandBrush {ids?}`. `brush.new`, diff --git a/docs/target-app-parity.md b/docs/target-app-parity.md index 05985f9f1..c53382a21 100644 --- a/docs/target-app-parity.md +++ b/docs/target-app-parity.md @@ -962,6 +962,7 @@ Moved from the ROADMAP's "Shipped so far" on 2026-10-10. Update it when a featur Hue Shift set by `brush.new` or `brush.options` without a key color takes the color the art's fills and strokes use most, as Brush Options already offers it, following the Brushes page, where the key color defaults to the color that stands out most in the art (). The page does not state how prominence is measured. Counting the fills and strokes that use each solid color, with the first one found winning a tie and black for art with no solid color, is VectorCraft's own rule. A `brush.options` edit that gives only the method keeps the brush's key color, and one that gives only an art brush's start guide keeps its end guide. Evidence: `tests_brushsym::hue_shift_without_a_key_takes_the_most_used_art_color`, `tests_brushsym::art_brush_options_keep_the_scale_fields_an_edit_leaves_out`. Bristle Brush Options and `brush.new` take a bristle brush name of at most 31 characters, as the Brushes page states for the Bristle Brush Options. The Name field stops taking characters at 31, and `brush.new` and `brush.options` refuse a longer new name with an error that names the limit. The page does not say how the limit counts characters or what happens to longer names already saved; counting characters and the number added to a taken name, keeping longer saved names, and leaving `brush.duplicate` unlimited are VectorCraft's own rules. A bristle brush that a document or a saved file already holds under a longer name keeps it, and the other brush types take a name of any length. Test: `bristle_brush_names_have_at_most_31_characters` in `tests/brushsym.rs`. Public reference: [Brushes](https://web.archive.org/web/20241230205225/https://helpx.adobe.com/illustrator/using/brushes.html) (archived copy). In the Brushes panel, Shift-click selects a range of brushes and Ctrl/Cmd-click adds or removes one. Delete Brush and Duplicate Brush then act on all of them (`brush.delete {names}`, `brush.duplicate {names}`). + The Brushes panel's Delete Brush button and panel menu item ask "Delete the selected brushes?" with Yes and No when none of the brushes is in use. Alt-click (Option-click on macOS) on the button deletes them without asking, as the [Default keyboard shortcuts](https://web.archive.org/web/20260726060015/https://helpx.adobe.com/illustrator/using/default-keyboard-shortcuts.html) page (archived copy) lists ("Delete without confirmation (except for Layers panel)"). When a stroke uses one of the brushes, the button, Alt-click and the menu item all ask with Remove Strokes and Cancel; Remove Strokes deletes the brushes and the strokes that used them become plain strokes. Tests: `panels::brushes::tests`, `dialogs::brush_delete::tests`. Document Info has a Brushes category after Graphic Styles. It lists the Brushes panel's brushes, or with Selection Only it lists the brushes that the selected objects' strokes use. The Document Info report and Package's report list them too (`document.info {category: "brushes"}`, `brushNames`). Document Info has a Repeat Objects category after Embedded Images. It lists each radial, grid and mirror Repeat object by name with its kind and the number of instances it makes. For a grid it gives the rows and columns instead, followed by the number of instances it draws when that is fewer. With Selection Only it lists the Repeat objects in the selection. The Document Info report and Package's report list them too (`document.info {category: "repeats"}`, `repeatObjects`). The Brushes panel menu's Select All Unused selects the brushes that are not used in the document, as the [Brushes](https://web.archive.org/web/20241230205225/https://helpx.adobe.com/illustrator/using/brushes.html) page (archived copy) describes. A brush counts as used when a stroke paints with it in the art (opacity masks included), in symbols, graph designs, pattern tiles or graphic styles, or in the art of a used brush (`brush.unused`).