Merge pull request #7086 from dotCooCoo/feat/library-charstyle-menu

Libraries: a character style's menu offers Apply, Add to Character Styles, Rename and Delete
This commit is contained in:
BFlat
2026-11-13 22:24:41 +07:00
committed by GitHub
34 changed files with 606 additions and 11 deletions
+158 -2
View File
@@ -346,6 +346,36 @@ impl Library {
}
}
/// Name item `r` `name`, in its place in its kind's list; an item keyed by its name keeps its
/// group under the new name (a graphic is keyed by its id, which stays).
fn rename_item(&mut self, r: &ItemRef, name: &str) {
fn set<'a>(mut names: impl Iterator<Item = &'a mut String>, from: &str, to: &str) {
if let Some(n) = names.find(|n| n.as_str() == from) {
*n = to.to_string();
}
}
let from = r.item.as_str();
match r.kind {
ItemKind::Color => set(self.colors.iter_mut().map(|c| &mut c.name), from, name),
ItemKind::Gradient => set(self.gradients.iter_mut().map(|g| &mut g.name), from, name),
ItemKind::Pattern => set(self.patterns.iter_mut().map(|p| &mut p.name), from, name),
ItemKind::CharStyle => set(self.char_styles.iter_mut().map(|t| &mut t.name), from, name),
ItemKind::ParaStyle => set(self.para_styles.iter_mut().map(|t| &mut t.name), from, name),
ItemKind::Graphic => {
if let Some(g) = self.graphics.iter_mut().find(|g| g.id == from) {
g.name = name.to_string();
}
return;
}
ItemKind::Unknown => return,
}
for x in self.groups.iter_mut().flat_map(|g| g.items.iter_mut()) {
if x == r {
x.item = name.to_string();
}
}
}
/// Move item `r` next to `to`, an item of its kind: just before it, or just after it when
/// `after`, in their kind's list (the order the panel shows them in).
fn place_next_to(&mut self, r: &ItemRef, to: &ItemRef, after: bool) {
@@ -683,7 +713,7 @@ pub fn specs() -> Vec<CommandSpec> {
"Use Library Item",
[],
None,
"{library?, kind, item: name (graphic: id or name), center?: [x, y] (graphic; default: the first artboard's centre), to?: fill|stroke (colors, gradients, patterns; default: the kind's), recorded?: the item as it was when used (recorded in the journal so a replay matches)} graphic: place a copy centred on `center`, its resources pasted along, selected, one undo step; colors and gradients: paint the selection (and the defaults) as paint.setFill/paint.setStroke, a gradient fitting each object; a spot color links to the document's spot swatch of its ink's name, added when the document has none of that colour (a name taken by another colour gets a number), one undo step; patterns: add the pattern and its swatch to the document (a name the document gives another pattern gets a number; the same pattern is reused) and paint the selection (and the defaults) with it, one undo step; charStyle/paraStyle: add the style to the document (a name taken by different attributes gets a number) and apply it to the selected text, one undo step → {kind, ids?, style?}",
"{library?, kind, item: name (graphic: id or name), center?: [x, y] (graphic; default: the first artboard's centre), to?: fill|stroke (colors, gradients, patterns; default: the kind's), recorded?: the item as it was when used (recorded in the journal so a replay matches)} graphic: place a copy centred on `center`, its resources pasted along, selected, one undo step; colors and gradients: paint the selection (and the defaults) as paint.setFill/paint.setStroke, a gradient fitting each object; a spot color links to the document's spot swatch of its ink's name, added when the document has none of that colour (a name taken by another colour gets a number), one undo step; patterns: add the pattern and its swatch to the document (a name the document gives another pattern gets a number; the same pattern is reused) and paint the selection (and the defaults) with it, one undo step; charStyle/paraStyle: add the style to the document (a name taken by different attributes gets a number; a character style's color linked to a swatch that isn't a global or spot swatch of the document keeps the color it shows, unlinked) and apply it to the selected text, one undo step → {kind, ids?, style?}",
has_doc,
use_item
),
@@ -696,6 +726,24 @@ pub fn specs() -> Vec<CommandSpec> {
always,
remove_item
),
cmd!(
"library.renameItem",
"Rename Library Item",
[],
None,
"{library?, kind, item: name (graphic: id or name), name: string (trimmed; 1 to 256 characters)} rename an item; it keeps its place and its group; another item of its kind with that name is an error, and its own name changes nothing; not undoable → {library, kind, item: its key now (graphic: its id), name}",
always,
rename_item
),
cmd!(
"library.addToCharacterStyles",
"Add to Character Styles",
[],
None,
"{library?, item: a character style's name, recorded?: the style as it was when added (recorded in the journal so a replay matches)} add a library character style to the document's character styles without applying it (no text needs to be selected): a document style of that name with the same attributes is reused, a name taken by different attributes gets a number; a color linked to a swatch that isn't a global or spot swatch of the document keeps the color it shows, unlinked; a new style is one undo step, a reused one none → {style: its name in the document, existing: bool}",
has_doc,
add_to_char_styles
),
cmd!(
"library.createGroup",
"New Library Group",
@@ -1231,8 +1279,13 @@ fn use_item(s: &mut Session, p: &Value) -> Result<Value> {
Kind::CharStyle | Kind::ParaStyle => {
let para = kind == Kind::ParaStyle;
let name = data.get("name").and_then(Value::as_str).map(str::trim).filter(|n| !n.is_empty()).unwrap_or("Style").to_string();
let attrs = data.get("attrs").and_then(Value::as_object).cloned().unwrap_or_default();
let mut attrs = data.get("attrs").and_then(Value::as_object).cloned().unwrap_or_default();
let doc = &s.doc()?.doc;
if !para {
unlink_missing_swatches(doc, &mut attrs);
}
// Compared in the form the document stores them in.
let attrs = super::textstyles::stored_style_attrs(doc, para, &attrs).unwrap_or(attrs);
// The document's style of that name when it is the same; else a new one.
let same = super::textstyles::style_attrs(doc, para, &name).is_some_and(|a| a == attrs);
let style = if same { name } else { unique(&name, |n| super::textstyles::style_attrs(doc, para, n).is_some()) };
@@ -1361,6 +1414,109 @@ fn remove_item(s: &mut Session, p: &Value) -> Result<Value> {
ok()
}
fn rename_item(s: &mut Session, p: &Value) -> Result<Value> {
const C: &str = "library.renameItem";
let (id, kind, item) = item_param(s, p, C)?;
let name = match p.get("name") {
None | Some(Value::Null) => return Err(bad(C, "missing `name`")),
Some(Value::String(n)) => n.trim().to_string(),
Some(_) => return Err(bad(C, "`name` must be a string")),
};
if name.is_empty() {
return Err(bad(C, "missing `name`"));
}
if name.chars().count() > MAX_NAME {
let (label, max) = ("`name`", MAX_NAME);
return Err(bad(C, format!("{label} must be at most {max} characters")));
}
let lib = s.libraries.get(&id).ok_or_else(|| bad(C, format!("no library `{id}`")))?;
let r = lib.item_ref(kind.item_kind(), item).ok_or_else(|| bad(C, format!("the library has no item `{item}`")))?;
// The item's name now, and whether another item of its kind has the new one.
let mut same = false;
let mut taken = false;
for (_, key, shown) in lib.items().filter(|(k, ..)| *k == r.kind) {
if key == r.item {
same = shown == name;
} else if shown == name {
taken = true;
}
}
let key = if r.kind == ItemKind::Graphic { r.item.clone() } else { name.clone() };
let out = json!({ "library": id, "kind": str_param(p, "kind"), "item": key, "name": name });
if same {
return Ok(out);
}
if taken {
return Err(bad(C, format!("the library has another item of that kind named `{name}`")));
}
s.libraries.change(&id, |lib| {
lib.rename_item(&r, &name);
Ok(())
})?;
Ok(out)
}
fn add_to_char_styles(s: &mut Session, p: &Value) -> Result<Value> {
const C: &str = "library.addToCharacterStyles";
// A replay (the journal) carries what the style was, so it doesn't depend on the library.
let data = match p.get("recorded").cloned() {
Some(r) => r,
None => {
let id = library_id(s, p, C)?;
let item = str_param(p, "item").ok_or_else(|| bad(C, "missing `item`"))?;
let lib = s.libraries.get(&id).ok_or_else(|| bad(C, format!("no library `{id}`")))?;
let t = lib.char_styles.iter().find(|t| t.name == item).ok_or_else(|| bad(C, format!("the library has no item `{item}`")))?;
let data = json!({ "name": t.name, "attrs": t.attrs });
s.note_journal("recorded", data.clone());
data
}
};
let name = data.get("name").and_then(Value::as_str).map(str::trim).filter(|n| !n.is_empty()).unwrap_or("Style").to_string();
let mut attrs = data.get("attrs").and_then(Value::as_object).cloned().ok_or_else(|| bad(C, "the library item is damaged"))?;
let doc = &s.doc()?.doc;
unlink_missing_swatches(doc, &mut attrs);
// Compared in the form the document stores them in.
let attrs = super::textstyles::stored_style_attrs(doc, false, &attrs).unwrap_or(attrs);
// The document's style of that name when it is the same; else a new one, which isn't applied.
if super::textstyles::style_attrs(doc, false, &name).is_some_and(|a| a == attrs) {
return Ok(json!({ "style": name, "existing": true }));
}
let style = unique(&name, |n| super::textstyles::style_attrs(doc, false, n).is_some());
s.execute("charStyle.new", &json!({ "name": style, "attrs": attrs }))?;
Ok(json!({ "style": style, "existing": false }))
}
/// Unlink a library character style's `fill` and `stroke` colors (solid, and each gradient stop)
/// from swatches that are not global or spot swatches of `doc`: an unlinked color keeps the color
/// it shows at full tint, as [`clean_gradient`] keeps a library gradient's stops. A link to a
/// global or spot swatch `doc` has stays, and takes that swatch's color.
fn unlink_missing_swatches(doc: &vectorcraft_doc::Document, attrs: &mut Map<String, Value>) {
let keep = |name: &str| doc.global_color(name).is_some();
for key in ["fill", "stroke"] {
let Some(mut paint) = attrs.get(key).and_then(|v| serde_json::from_value::<Paint>(v.clone()).ok()) else { continue };
let mut changed = false;
let mut unlink = |swatch: &mut Option<String>, tint: &mut f32| {
if swatch.as_deref().is_some_and(|n| !keep(n)) {
*swatch = None;
*tint = 1.0;
changed = true;
}
};
match &mut paint {
Paint::Solid { swatch, tint, .. } => unlink(swatch, tint),
Paint::Gradient(g) => {
for st in &mut g.gradient.stops {
unlink(&mut st.swatch, &mut st.tint);
}
}
_ => {}
}
if changed && let Ok(v) = serde_json::to_value(&paint) {
attrs.insert(key.to_string(), v);
}
}
}
/// `p`'s `name`, trimmed and clipped, else `default`.
fn name_param(p: &Value, default: &str) -> String {
let mut name = str_param(p, "name").map(str::trim).filter(|n| !n.is_empty()).unwrap_or(default).to_string();
+7
View File
@@ -506,6 +506,13 @@ pub(crate) fn style_attrs(d: &Document, para: bool, name: &str) -> Option<Map<St
if para { Kind::Para } else { Kind::Char }.attrs(d, name)
}
/// `attrs` in the form `charStyle.new` (`para`: `paraStyle.new`) stores them in `d`, or `None`
/// when they don't pass its checks.
pub(crate) fn stored_style_attrs(d: &Document, para: bool, attrs: &Map<String, Value>) -> Option<Map<String, Value>> {
let kind = if para { Kind::Para } else { Kind::Char };
attrs_param(d, &json!({ "attrs": attrs }), kind, "new", None).ok().flatten()
}
/// The name `charStyle.new` (`para`: `paraStyle.new`) gives a style when it is given none: the
/// first "Character Style N" ("Paragraph Style N") that no character style (paragraph style) of the
/// document has.
+204
View File
@@ -635,6 +635,210 @@ fn a_library_style_named_with_spaces_comes_in_trimmed() {
assert_eq!((text.runs[0].style.size, text.runs[0].style.style_name.as_deref()), (31.0, Some("Body")));
}
/// The size of the first run of text object `id`.
fn run_size(s: &Session, id: &Value) -> f64 {
match &s.doc().unwrap().doc.node(NodeId(id.as_u64().unwrap())).unwrap().kind {
vectorcraft_doc::NodeKind::Text(t) => t.runs[0].style.size,
_ => 0.0,
}
}
/// Add to Character Styles puts a library character style into the document's character styles
/// without applying it, with or without type selected, in one undo step; the same style there is
/// reused without a step, and a name taken by other attributes gets a number. A bad call changes
/// nothing.
#[test]
fn a_library_character_style_is_added_to_the_document_without_applying_it() {
let mut s = session();
let data = json!({"name": "Kept", "charStyles": [{"name": "Headline", "attrs": {"size": 31.0}}, {"name": "Broken", "attrs": {"size": "big"}}]});
let lib = run(&mut s, "library.import", json!({"data": data.to_string()}))["id"].as_str().unwrap().to_string();
let styles = |s: &Session| s.doc().unwrap().doc.char_styles.iter().map(|c| c.name.clone()).collect::<Vec<_>>();
let undo = |s: &Session| s.doc().unwrap().history.undo.len();
// Nothing selected.
let before = undo(&s);
let r = run(&mut s, "library.addToCharacterStyles", json!({"library": lib, "item": "Headline"}));
assert_eq!((r["style"].as_str(), r["existing"].as_bool()), (Some("Headline"), Some(false)));
assert_eq!(styles(&s), ["Headline"]);
assert_eq!(undo(&s), before + 1, "one undo step");
let attrs = &s.doc().unwrap().doc.char_styles[0].attrs;
assert_eq!(attrs.get("size"), Some(&json!(31.0)));
// Selected type keeps its look.
let t = run(&mut s, "text.create", json!({"x": 10, "y": 50, "text": "Body", "size": 9}))["id"].clone();
run(&mut s, "select.set", json!({"ids": [t]}));
let before = undo(&s);
let r = run(&mut s, "library.addToCharacterStyles", json!({"library": lib, "item": "Headline"}));
assert_eq!((r["style"].as_str(), r["existing"].as_bool()), (Some("Headline"), Some(true)));
assert_eq!((undo(&s), run_size(&s, &t), styles(&s).len()), (before, 9.0, 1), "reused: no step, the type unchanged");
// Another style of that name: numbered, still not applied.
run(&mut s, "charStyle.setAttrs", json!({"name": "Headline", "attrs": {"size": 5}}));
let r = run(&mut s, "library.addToCharacterStyles", json!({"library": lib, "item": "Headline"}));
assert_eq!((r["style"].as_str(), r["existing"].as_bool()), (Some("Headline 2"), Some(false)));
assert_eq!(run_size(&s, &t), 9.0);
let vectorcraft_doc::NodeKind::Text(text) = &s.doc().unwrap().doc.node(NodeId(t.as_u64().unwrap())).unwrap().kind else { panic!("not text") };
assert_eq!(text.runs[0].style.style_name, None, "no style applied");
// Undo takes the added style back alone.
run(&mut s, "edit.undo", json!({}));
assert_eq!(styles(&s), ["Headline"]);
// Bad calls: nothing changes.
let before = (undo(&s), styles(&s));
for bad in [
json!({"library": lib}),
json!({"library": lib, "item": 3}),
json!({"library": lib, "item": "Nope"}),
json!({"library": "Nope", "item": "Headline"}),
json!({"library": lib, "item": "Broken"}),
json!({"recorded": {"name": "X", "attrs": "damaged"}}),
] {
assert!(s.execute("library.addToCharacterStyles", &bad).is_err(), "{bad}");
assert_eq!((undo(&s), styles(&s)), before, "{bad}");
}
// Without a document it isn't available.
run(&mut s, "file.close", json!({}));
assert!(s.active().is_none());
assert!(s.execute("library.addToCharacterStyles", &json!({"library": lib, "item": "Headline"})).is_err());
}
/// A library character style whose fill links to a swatch the document lacks is added and applied
/// with the color it shows, unlinked at full tint; a global swatch of that name in the document
/// keeps the link and gives its color.
#[test]
fn a_library_character_style_linked_to_a_missing_swatch_is_added_unlinked() {
let base = vectorcraft_color::Color::rgb(0.2, 0.4, 0.6);
let shown = base.tinted(0.5);
let linked = vectorcraft_color::Paint::Solid { color: shown, swatch: Some("Brand".into()), tint: 0.5 };
let data = json!({"name": "Kept", "charStyles": [{"name": "Accent", "attrs": {"size": 20.0, "fill": linked}}]});
let mut s = session();
let lib = run(&mut s, "library.import", json!({"data": data.to_string()}))["id"].as_str().unwrap().to_string();
let fill = |s: &Session, name: &str| {
let st = s.doc().unwrap().doc.char_styles.iter().find(|c| c.name == name).map(|c| c.attrs.clone()).unwrap();
serde_json::from_value::<vectorcraft_color::Paint>(st["fill"].clone()).unwrap()
};
run(&mut s, "library.addToCharacterStyles", json!({"library": lib, "item": "Accent"}));
assert_eq!(fill(&s, "Accent"), vectorcraft_color::Paint::Solid { color: shown, swatch: None, tint: 1.0 });
// Apply as well, on selected type.
let t = run(&mut s, "text.create", json!({"x": 10, "y": 50, "text": "Body", "size": 9}))["id"].clone();
run(&mut s, "select.set", json!({"ids": [t]}));
let r = run(&mut s, "library.use", json!({"library": lib, "kind": "charStyle", "item": "Accent"}));
assert_eq!(r["style"], "Accent", "the added style is reused");
assert_eq!(run_size(&s, &t), 20.0);
// A document with a global swatch of that name keeps the link.
run(&mut s, "file.new", json!({"width": 200, "height": 200}));
let other = vectorcraft_color::Color::rgb(0.8, 0.1, 0.1);
run(&mut s, "swatch.new", json!({"name": "Brand", "color": other, "global": true}));
run(&mut s, "library.addToCharacterStyles", json!({"library": lib, "item": "Accent"}));
let vectorcraft_color::Paint::Solid { swatch, tint, .. } = fill(&s, "Accent") else { panic!("not a solid fill") };
assert_eq!((swatch.as_deref(), tint), (Some("Brand"), 0.5));
// The style with the document's swatch color is the same style: added again, it is reused.
let r = run(&mut s, "library.addToCharacterStyles", json!({"library": lib, "item": "Accent"}));
assert_eq!((r["style"].as_str(), r["existing"].as_bool()), (Some("Accent"), Some(true)));
}
/// A library style is compared with the document's in the form the document stores it in, so a
/// style whose file writes a size as a whole number is reused, by Add to Character Styles and by a
/// click alike.
#[test]
fn a_library_style_is_reused_whatever_form_its_file_writes_it_in() {
let data = json!({"name": "Kept", "charStyles": [{"name": "Whole", "attrs": {"size": 31}}], "paraStyles": [{"name": "Para", "attrs": {"left_indent": 4}}]});
let mut s = session();
let lib = run(&mut s, "library.import", json!({"data": data.to_string()}))["id"].as_str().unwrap().to_string();
run(&mut s, "library.addToCharacterStyles", json!({"library": lib, "item": "Whole"}));
let r = run(&mut s, "library.addToCharacterStyles", json!({"library": lib, "item": "Whole"}));
assert_eq!((r["style"].as_str(), r["existing"].as_bool()), (Some("Whole"), Some(true)));
let t = run(&mut s, "text.create", json!({"x": 10, "y": 50, "text": "Body", "size": 9}))["id"].clone();
run(&mut s, "select.set", json!({"ids": [t]}));
for (kind, item) in [("charStyle", "Whole"), ("paraStyle", "Para"), ("paraStyle", "Para")] {
assert_eq!(run(&mut s, "library.use", json!({"library": lib, "kind": kind, "item": item}))["style"], item);
}
let d = &s.doc().unwrap().doc;
assert_eq!((d.char_styles.len(), d.para_styles.iter().filter(|p| p.name.starts_with("Para")).count()), (1, 1));
}
/// Rename gives a library item a new name, trimmed, in its place and its group; a character style
/// keeps its attributes, a graphic its id. Another item of its kind with that name, an empty or
/// too long name, a name that isn't text and an unknown item or library are errors that change
/// nothing; a name with path characters is a name like any other; the item's own name writes
/// nothing; and the document's history is not touched.
#[test]
fn library_items_are_renamed_in_place() {
let (mut s, g, c, st) = brand();
let t = run(&mut s, "text.create", json!({"x": 10, "y": 120, "text": "Body", "size": 9}))["id"].clone();
run(&mut s, "select.set", json!({"ids": [t]}));
let other = run(&mut s, "library.add", json!({"kind": "charStyle", "name": "Body"}))["name"].as_str().unwrap().to_string();
run(&mut s, "library.createGroup", json!({"name": "Brand", "items": [{"kind": "charStyle", "item": st}, {"kind": "fillColor", "item": c}]}));
let undo = s.doc().unwrap().history.undo.len();
let attrs = run(&mut s, "library.get", json!({}))["charStyles"][0]["attrs"].clone();
let r = run(&mut s, "library.renameItem", json!({"kind": "charStyle", "item": st, "name": " Title "}));
assert_eq!((r["item"].as_str(), r["name"].as_str()), (Some("Title"), Some("Title")));
let got = run(&mut s, "library.get", json!({}));
assert_eq!(got["charStyles"][0], json!({"name": "Title", "attrs": attrs}), "first still, the attributes kept");
assert_eq!(got["charStyles"][1]["name"], other.as_str());
assert_eq!(groups(&mut s), [("Brand".into(), refs(&[("charStyle", "Title"), ("color", &c)]))]);
// A colour keeps its group under its new name; a graphic keeps its id.
run(&mut s, "library.renameItem", json!({"kind": "strokeColor", "item": c, "name": "Navy"}));
assert_eq!(groups(&mut s), [("Brand".into(), refs(&[("charStyle", "Title"), ("color", "Navy")]))]);
let r = run(&mut s, "library.renameItem", json!({"kind": "graphic", "item": "Logo", "name": "Mark"}));
assert_eq!(r["item"], g.as_str());
let graphic = run(&mut s, "library.get", json!({}))["graphics"][0].clone();
assert_eq!((graphic["id"].as_str(), graphic["name"].as_str()), (Some(g.as_str()), Some("Mark")));
// Path characters are kept.
run(&mut s, "library.renameItem", json!({"kind": "charStyle", "item": "Title", "name": "a/b\\c:d"}));
assert_eq!(style_order_of(&mut s)[0], "a/b\\c:d");
// Errors change nothing.
let before = run(&mut s, "library.get", json!({}));
let long = "x".repeat(257);
for bad in [
json!({"kind": "charStyle", "item": "a/b\\c:d", "name": other}),
json!({"kind": "charStyle", "item": "a/b\\c:d", "name": " "}),
json!({"kind": "charStyle", "item": "a/b\\c:d", "name": long}),
json!({"kind": "charStyle", "item": "a/b\\c:d", "name": 5}),
json!({"kind": "charStyle", "item": "a/b\\c:d"}),
json!({"kind": "charStyle", "item": "Nope", "name": "X"}),
json!({"kind": "paraStyle", "item": "a/b\\c:d", "name": "X"}),
json!({"kind": "brush", "item": "a/b\\c:d", "name": "X"}),
json!({"library": "Nope", "kind": "charStyle", "item": "a/b\\c:d", "name": "X"}),
] {
assert!(s.execute("library.renameItem", &bad).is_err(), "{bad}");
assert_eq!(run(&mut s, "library.get", json!({})), before, "{bad}");
}
// A style of another kind may have the name, and 256 characters are allowed.
run(&mut s, "library.renameItem", json!({"kind": "charStyle", "item": "a/b\\c:d", "name": "Navy"}));
run(&mut s, "library.renameItem", json!({"kind": "charStyle", "item": "Navy", "name": "y".repeat(256)}));
assert_eq!(s.doc().unwrap().history.undo.len(), undo, "no document undo step");
}
/// The current library's character style names, in order.
fn style_order_of(s: &mut Session) -> Vec<String> {
order(s, "charStyles", "name")
}
/// A rename is kept in the library's file; renaming an item to its own name writes nothing; and a
/// rename whose file can't be written is taken back.
#[cfg(not(target_arch = "wasm32"))]
#[test]
fn a_library_item_rename_is_saved_or_taken_back() {
let dir = vectorcraft_testkit::temp_dir("library-rename-item");
let folder = dir.to_string_lossy().to_string();
let mut s = session();
s.libraries.set_dir(Some(folder.clone()));
let lib = run(&mut s, "library.create", json!({"name": "Kept"}))["id"].as_str().unwrap().to_string();
let t = run(&mut s, "text.create", json!({"x": 10, "y": 50, "text": "Body", "size": 12}))["id"].clone();
run(&mut s, "select.set", json!({"ids": [t]}));
run(&mut s, "library.add", json!({"kind": "charStyle", "name": "Body"}));
run(&mut s, "library.renameItem", json!({"kind": "charStyle", "item": "Body", "name": "Text"}));
let mut t2 = session();
t2.libraries.set_dir(Some(folder.clone()));
assert_eq!(style_order_of(&mut t2), ["Text"], "kept in the file");
// The file can't be written (a folder stands where it goes): its own name still succeeds, as
// it writes nothing; a new name fails and is taken back.
let file = dir.join(format!("{lib}.vclibrary"));
std::fs::remove_file(&file).unwrap();
std::fs::create_dir(&file).unwrap();
run(&mut s, "library.renameItem", json!({"kind": "charStyle", "item": "Text", "name": " Text "}));
assert!(s.execute("library.renameItem", &json!({"kind": "charStyle", "item": "Text", "name": "Copy"})).is_err());
assert_eq!(style_order_of(&mut s), ["Text"], "taken back");
let _ = std::fs::remove_dir_all(&dir);
}
#[cfg(not(target_arch = "wasm32"))]
#[test]
fn libraries_are_kept_in_files_across_sessions() {
+3
View File
@@ -3491,6 +3491,8 @@ digits Malayalam Малаялам
Rename Library Group Преименуване на библиотечна група
Delete Library Group Изтриване на библиотечна група
Move Library Item to Group Преместване на библиотечен елемент в група
Rename Library Item Преименуване на елемент от библиотека
Add to Character Styles Добавяне към стилове на знаци
Library Библиотека
Rename Library Преименуване на библиотека
Show Library Показване на библиотека
@@ -4064,6 +4066,7 @@ axis Both И двете
Drag to the window's left or right edge to dock Плъзнете до левия или десния ръб на прозореца за закотвяне
Float Tool Group Плаваща група инструменти
@msg no library `{id}` няма библиотека `{id}`
@msg the library has another item of that kind named `{name}` библиотеката вече има друг елемент от този вид с име `{name}`
@msg select some type first първо изберете текст
@msg kerning must be a number, "auto", or "optical" kerning трябва да е число, „auto“ или „optical“
@msg {_1} has no {_2} style {_1} няма стил {_2}
Can't render this file because it contains an unexpected character in line 2 and column 73.
+3
View File
@@ -3550,6 +3550,8 @@ theme Appearance Izgled
Rename Library Group Preimenuj grupu biblioteke
Delete Library Group Izbriši grupu biblioteke
Move Library Item to Group Premjesti stavku biblioteke u grupu
Rename Library Item Preimenuj stavku biblioteke
Add to Character Styles Dodaj u stilove znakova
Rename Library Preimenuj biblioteku
Show Library Prikaži biblioteku
Use Library Item Koristi stavku biblioteke
@@ -4416,6 +4418,7 @@ imageTrace Outline Obris
@plural {n} step|{n} steps {n} korak|{n} koraka|{n} koraka
@plural {n} stroke|{n} strokes {n} potez|{n} poteza|{n} poteza
@msg no library `{id}` nema biblioteke `{id}`
@msg the library has another item of that kind named `{name}` biblioteka već ima drugu stavku te vrste s imenom `{name}`
@msg select some type first prvo odaberite tekst
@msg kerning must be a number, "auto", or "optical" kerning mora biti broj, „auto” ili „optical”
@msg the selection has no gradient fill odabir nema ispunu gradijentom
Can't render this file because it contains an unexpected character in line 2 and column 73.
+3
View File
@@ -2634,6 +2634,8 @@ digits Malayalam Malaiàlam
Move in Perspective Mou en perspectiva
Move Library Group Mou el grup de la biblioteca
Move Library Item to Group Mou l’element de la biblioteca al grup
Rename Library Item Canvia el nom de l’element de la biblioteca
Add to Character Styles Afegeix als estils de caràcter
Move Locked and Hidden Artwork with Artboard Mou la il·lustració bloquejada i oculta amb el tauler
Move Mesh Point Mou el punt de malla
Move Mesh Points Mou els punts de malla
@@ -5730,6 +5732,7 @@ digits Malayalam Malaiàlam
@msg no interaction in progress no hi ha cap interacció en curs
@msg no key object no hi ha objecte clau
@msg no library `{id}` no hi ha la biblioteca `{id}`
@msg the library has another item of that kind named `{name}` la biblioteca ja té un altre element d’aquest tipus anomenat `{name}`
@msg no library `{key}` (see {list}) no hi ha la biblioteca `{key}` (vegeu {list})
@msg No linked files to look for No hi ha fitxers enllaçats per buscar
@msg no Live Paint edge near that point no hi ha cap aresta de pintura interactiva a prop d’aquell punt
Can't render this file because it contains an unexpected character in line 2 and column 73.
+3
View File
@@ -3604,6 +3604,8 @@ theme Appearance Motiv
Rename Library Group Přejmenovat skupinu knihovny
Delete Library Group Odstranit skupinu knihovny
Move Library Item to Group Přesunout položku knihovny do skupiny
Rename Library Item Přejmenovat položku knihovny
Add to Character Styles Přidat do stylů znaků
Rename Library Přejmenovat knihovnu
Show Library Zobrazit knihovnu
Use Library Item Použít položku knihovny
@@ -4477,6 +4479,7 @@ imageTrace Outline Obrys
# Status and error messages
@msg no library `{id}` knihovna `{id}` neexistuje
@msg the library has another item of that kind named `{name}` knihovna už má jinou položku tohoto druhu s názvem `{name}`
@msg select some type first nejprve vyberte text
@msg kerning must be a number, "auto", or "optical" kerning musí být číslo, „auto“ nebo „optical“
@msg the selection has no gradient fill výběr nemá přechodovou výplň
Can't render this file because it contains an unexpected character in line 2 and column 73.
+3
View File
@@ -3337,6 +3337,8 @@ theme Appearance Udseende
Rename Library Group Omdøb biblioteksgruppe
Delete Library Group Slet biblioteksgruppe
Move Library Item to Group Flyt bibliotekselement til gruppe
Rename Library Item Omdøb bibliotekselement
Add to Character Styles Føj til tegnstile
Rename Library Omdøb bibliotek
Show Library Vis bibliotek
Use Library Item Brug bibliotekselement
@@ -4183,6 +4185,7 @@ imageTrace Outline Kontur
@plural {n} step|{n} steps {n} trin|{n} trin
@plural {n} stroke|{n} strokes {n} kontur|{n} konturer
@msg no library `{id}` intet bibliotek `{id}`
@msg the library has another item of that kind named `{name}` biblioteket har allerede et andet element af den type med navnet `{name}`
@msg select some type first markér først noget tekst
@msg kerning must be a number, "auto", or "optical" kerning skal være et tal, „auto“ eller „optical“
@msg {_1} has no {_2} style {_1} har ingen {_2}-stil
Can't render this file because it contains an unexpected character in line 2 and column 73.
+3
View File
@@ -4091,6 +4091,7 @@ theme Appearance Erscheinungsbild
# (`untranslated_report` lists any that are missing). Command ids, parameter
# names and values in backticks or code (`colorModel rgb`, `document.export`) stay as they are.
@msg no library `{id}` keine Bibliothek `{id}`
@msg the library has another item of that kind named `{name}` die Bibliothek hat bereits ein anderes Element dieser Art namens `{name}`
@msg select some type first wählen Sie zuerst Text aus
@msg kerning must be a number, "auto", or "optical" kerning muss eine Zahl, „auto“ oder „optical“ sein
@msg the selection has no gradient fill die Auswahl hat keinen Flächenverlauf
@@ -5124,6 +5125,8 @@ theme Appearance Erscheinungsbild
Rename Library Group Bibliotheksgruppe umbenennen
Delete Library Group Bibliotheksgruppe löschen
Move Library Item to Group Bibliothekselement in Gruppe verschieben
Rename Library Item Bibliothekselement umbenennen
Add to Character Styles Zu Zeichenformaten hinzufügen
Import Library Bibliothek importieren
Export Library Bibliothek exportieren
New Group Neue Gruppe
Can't render this file because it contains an unexpected character in line 2 and column 73.
+3
View File
@@ -2266,6 +2266,7 @@ axis Both Και τα δύο
Document Options Επιλογές εγγράφου
Dock Control Bar Αγκύρωση γραμμής ελέγχου
@msg no library `{id}` Δεν υπάρχει βιβλιοθήκη με αναγνωριστικό `{id}`
@msg the library has another item of that kind named `{name}` η βιβλιοθήκη έχει ήδη άλλο στοιχείο αυτού του είδους με όνομα `{name}`
@msg select some type first Επιλέξτε πρώτα κάποιο κείμενο
@msg kerning must be a number, "auto", or "optical" το kerning πρέπει να είναι αριθμός, «auto» ή «optical»
@msg the selection has no gradient fill η επιλογή δεν έχει ντεγκραντέ γεμίσματος
@@ -4051,6 +4052,8 @@ digits Malayalam Μαλαγιάλαμ
Rename Library Group Μετονομασία ομάδας βιβλιοθήκης
Delete Library Group Διαγραφή ομάδας βιβλιοθήκης
Move Library Item to Group Μετακίνηση στοιχείου βιβλιοθήκης σε ομάδα
Rename Library Item Μετονομασία στοιχείου βιβλιοθήκης
Add to Character Styles Προσθήκη στα στυλ χαρακτήρων
Rename Library Μετονομασία βιβλιοθήκης
Show Library Εμφάνιση βιβλιοθήκης
Use Library Item Χρήση στοιχείου βιβλιοθήκης
Can't render this file because it is too large.
+3
View File
@@ -3583,6 +3583,8 @@ digits Malayalam Malayálam
Rename Library Group Cambiar nombre del grupo de biblioteca
Delete Library Group Eliminar grupo de biblioteca
Move Library Item to Group Mover elemento de la biblioteca al grupo
Rename Library Item Cambiar nombre del elemento de la biblioteca
Add to Character Styles Agregar a estilos de carácter
Library Biblioteca
Rename Library Cambiar nombre de la biblioteca
Show Library Mostrar biblioteca
@@ -4167,6 +4169,7 @@ axis Both Ambos
# (`untranslated_report` lists any that are missing). Command ids, parameter
# names and values in backticks or code (`colorModel rgb`, `document.export`) stay as they are.
@msg no library `{id}` no hay ninguna biblioteca `{id}`
@msg the library has another item of that kind named `{name}` la biblioteca ya tiene otro elemento de ese tipo llamado `{name}`
@msg select some type first selecciona primero algún texto
@msg kerning must be a number, "auto", or "optical" kerning debe ser un número, «auto» u «optical»
@msg the selection has no gradient fill la selección no tiene un degradado de relleno
Can't render this file because it contains an unexpected character in line 2 and column 73.
+3
View File
@@ -3542,6 +3542,8 @@ theme Appearance Ulkoasu
Rename Library Group Nimeä kirjastoryhmä uudelleen
Delete Library Group Poista kirjastoryhmä
Move Library Item to Group Siirrä kirjaston kohde ryhmään
Rename Library Item Nimeä kirjaston kohde uudelleen
Add to Character Styles Lisää merkkityyleihin
Rename Library Nimeä kirjasto uudelleen
Show Library Näytä kirjasto
Use Library Item Käytä kirjaston kohdetta
@@ -4392,6 +4394,7 @@ imageTrace Outline Ääriviiva
@plural {n} step|{n} steps {n} vaihe|{n} vaihetta
@plural {n} stroke|{n} strokes {n} viiva|{n} viivaa
@msg no library `{id}` ei kirjastoa `{id}`
@msg the library has another item of that kind named `{name}` kirjastossa on jo toinen samanlainen kohde nimeltä `{name}`
@msg select some type first valitse ensin tekstiä
@msg kerning must be a number, "auto", or "optical" kerning-arvon on oltava luku, ”auto” tai ”optical”
@msg the selection has no gradient fill valinnalla ei ole liukuväritäyttöä
Can't render this file because it contains an unexpected character in line 2 and column 73.
+3
View File
@@ -3575,6 +3575,8 @@ digits Malayalam Malayalam
Rename Library Group Renommer le groupe de bibliothèque
Delete Library Group Supprimer le groupe de bibliothèque
Move Library Item to Group Déplacer l’élément de la bibliothèque vers un groupe
Rename Library Item Renommer l’élément de la bibliothèque
Add to Character Styles Ajouter aux styles de caractère
Library Bibliothèque
Rename Library Renommer la bibliothèque
Show Library Afficher la bibliothèque
@@ -4156,6 +4158,7 @@ axis Both Les deux
# (`untranslated_report` lists any that are missing). Command ids, parameter
# names and values in backticks or code (`colorModel rgb`, `document.export`) stay as they are.
@msg no library `{id}` aucune bibliothèque `{id}`
@msg the library has another item of that kind named `{name}` la bibliothèque a déjà un autre élément de ce type nommé `{name}`
@msg select some type first sélectionnez d’abord du texte
@msg kerning must be a number, "auto", or "optical" kerning doit être un nombre, « auto » ou « optical »
@msg the selection has no gradient fill la sélection n’a pas de dégradé de fond
Can't render this file because it contains an unexpected character in line 2 and column 73.
+3
View File
@@ -2873,6 +2873,8 @@ antiAlias Sharp शार्प
Move in Perspective पर्सपेक्टिव में मूव करें
Move Library Group लाइब्रेरी ग्रुप मूव करें
Move Library Item to Group लाइब्रेरी आइटम को ग्रुप में मूव करें
Rename Library Item लाइब्रेरी आइटम का नाम बदलें
Add to Character Styles कैरेक्टर स्टाइल्स में जोड़ें
Move Locked and Hidden Artwork with Artboard आर्टबोर्ड के साथ लॉक्ड और छिपा हुआ आर्टवर्क मूव करें
Move Mesh Point मेश पॉइंट मूव करें
Move Mesh Points मेश पॉइंट मूव करें
@@ -7234,6 +7236,7 @@ antiAlias Sharp शार्प
@msg no layer {id} (see layer.list) कोई लेयर {id} (layer.list देखें)
@msg no layers to export निर्यात करने के लिए कोई लेयरें नहीं
@msg no library `{id}` नहीं लाइब्रेरी `{id}`
@msg the library has another item of that kind named `{name}` लाइब्रेरी में इस प्रकार का एक और आइटम `{name}` नाम से पहले से है
@msg no library `{key}` नहीं लाइब्रेरी `{key}`
@msg no library `{key}` (see {list}) कोई लाइब्रेरी `{key}` ({list} देखें)
@msg No line breaks to remove हटाने के लिए कोई लाइन ब्रेक नहीं
Can't render this file because it is too large.
+3
View File
@@ -2605,6 +2605,8 @@ file-filter Templates Sablonok
Move Guide to Layer Segédvonal áthelyezése rétegre
Move in Perspective Áthelyezés perspektívában
Move Library Item to Group Könyvtárelem áthelyezése csoportba
Rename Library Item Könyvtárelem átnevezése
Add to Character Styles Hozzáadás a karakterstílusokhoz
Move Locked and Hidden Artwork with Artboard Zárolt és rejtett grafika mozgatása a rajztáblával
Move Mesh Point Hálópont áthelyezése
Move Mesh Points Hálópontok áthelyezése
@@ -5314,6 +5316,7 @@ imageTrace Outline Körvonal
@msg no interaction in progress nincs folyamatban lévő művelet
@msg no key object nincs kulcsobjektum
@msg no library `{id}` nincs ilyen könyvtár: `{id}`
@msg the library has another item of that kind named `{name}` a könyvtárban már van egy másik ilyen fajta elem `{name}` néven
@msg no library `{key}` (see {list}) nincs ilyen könyvtár: `{key}` (lásd: {list})
@msg no Live Paint edge near that point annál a pontnál nincs élőfestés-él
@msg no Live Paint face at that point annál a pontnál nincs élőfestés-felület
Can't render this file because it contains an unexpected character in line 2 and column 73.
+3
View File
@@ -3337,6 +3337,8 @@ theme Appearance Tampilan
Rename Library Group Ganti nama grup pustaka
Delete Library Group Hapus grup pustaka
Move Library Item to Group Pindahkan item pustaka ke grup
Rename Library Item Ganti nama item pustaka
Add to Character Styles Tambahkan ke gaya karakter
Rename Library Ganti nama pustaka
Show Library Tampilkan pustaka
Use Library Item Gunakan item pustaka
@@ -4183,6 +4185,7 @@ imageTrace Outline Kontur
@plural {n} step|{n} steps {n} langkah
@plural {n} stroke|{n} strokes {n} goresan
@msg no library `{id}` tidak ada pustaka `{id}`
@msg the library has another item of that kind named `{name}` pustaka sudah memiliki item lain dari jenis itu bernama `{name}`
@msg select some type first pilih beberapa teks terlebih dahulu
@msg kerning must be a number, "auto", or "optical" kerning harus berupa angka, “auto”, atau “optical”
@msg {_1} has no {_2} style {_1} tidak memiliki gaya {_2}
Can't render this file because it contains an unexpected character in line 2418 and column 5.
+3
View File
@@ -3628,6 +3628,8 @@ digits Malayalam Malayalam
Rename Library Group Rinomina gruppo di libreria
Delete Library Group Elimina gruppo di libreria
Move Library Item to Group Sposta elemento della libreria nel gruppo
Rename Library Item Rinomina elemento della libreria
Add to Character Styles Aggiungi agli stili carattere
Library Libreria
Rename Library Rinomina libreria
Show Library Mostra libreria
@@ -4218,6 +4220,7 @@ axis Both Entrambi
# (`untranslated_report` lists any that are missing). Command ids, parameter
# names and values in backticks or code (`colorModel rgb`, `document.export`) stay as they are.
@msg no library `{id}` nessuna libreria `{id}`
@msg the library has another item of that kind named `{name}` la libreria ha già un altro elemento di questo tipo chiamato `{name}`
@msg select some type first seleziona prima del testo
@msg kerning must be a number, "auto", or "optical" kerning deve essere un numero, «auto» o «optical»
@msg the selection has no gradient fill la selezione non ha una sfumatura di riempimento
Can't render this file because it contains an unexpected character in line 2 and column 73.
+3
View File
@@ -3364,6 +3364,8 @@ mark-style Japanese 日本式
Rename Library Group ライブラリグループ名を変更
Delete Library Group ライブラリグループを削除
Move Library Item to Group ライブラリ項目をグループに移動
Rename Library Item ライブラリ項目名を変更
Add to Character Styles 文字スタイルに追加
Library ライブラリ
Rename Library ライブラリ名を変更
Show Library ライブラリを表示
@@ -4491,6 +4493,7 @@ swatch Bright Violet ビビッドバイオレット
@msg the layer to flatten into is hidden 統合先のレイヤーが非表示になっています
@msg there are no objects to release レイヤーに分配するオブジェクトがありません
@msg no library `{id}` ライブラリ `{id}` が見つかりません
@msg the library has another item of that kind named `{name}` ライブラリには同じ種類の項目 `{name}` がすでにあります
@msg {path}: not a file {path}: ファイルではありません
@msg {path}: {e} {path}: {e}
@msg can't write .{ext} images .{ext} 画像は書き出せません
Can't render this file because it contains an unexpected character in line 2 and column 73.
+3
View File
@@ -3183,6 +3183,8 @@ theme Appearance იერსახე
Rename Library Group ბიბლიოთეკის ჯგუფის სახელის შეცვლა
Delete Library Group ბიბლიოთეკის ჯგუფის წაშლა
Move Library Item to Group ბიბლიოთეკის ელემენტის ჯგუფში გადატანა
Rename Library Item ბიბლიოთეკის ელემენტის სახელის შეცვლა
Add to Character Styles სიმბოლოს სტილებში დამატება
Rename Library ბიბლიოთეკის სახელის შეცვლა
Show Library ბიბლიოთეკის ჩვენება
Use Library Item ბიბლიოთეკის ელემენტის გამოყენება
@@ -3986,6 +3988,7 @@ font-technology Variable ცვლადი
@plural {n} step|{n} steps ნაბიჯი: {n}
@plural {n} stroke|{n} strokes კონტური: {n}
@msg no library `{id}` ბიბლიოთეკა `{id}` არ არსებობს
@msg the library has another item of that kind named `{name}` ბიბლიოთეკას უკვე აქვს ამ ტიპის სხვა ელემენტი სახელით `{name}`
@msg select some type first ჯერ მონიშნეთ ტექსტი
@msg kerning must be a number, "auto", or "optical" kerning უნდა იყოს რიცხვი, „auto“ ან „optical“
@msg the selection has no gradient fill მონიშნულს შევსების გრადიენტი არ აქვს
Can't render this file because it is too large.
+3
View File
@@ -3353,6 +3353,8 @@ mark-style Japanese 일본식
Rename Library Group 라이브러리 그룹 이름 바꾸기
Delete Library Group 라이브러리 그룹 삭제
Move Library Item to Group 라이브러리 항목을 그룹으로 이동
Rename Library Item 라이브러리 항목 이름 바꾸기
Add to Character Styles 문자 스타일에 추가
Library 라이브러리
Rename Library 라이브러리 이름 바꾸기
Show Library 라이브러리 표시
@@ -4418,6 +4420,7 @@ theme Appearance 외관
@msg the layer to flatten into is hidden 병합 대상 레이어가 숨겨져 있습니다
@msg there are no objects to release 해제할 개체가 없습니다
@msg no library `{id}` `{id}` 라이브러리가 없습니다
@msg the library has another item of that kind named `{name}` 라이브러리에 같은 종류의 다른 항목 `{name}`이(가) 이미 있습니다
@msg {path}: not a file {path}: 파일이 아닙니다
@msg {path}: {e} {path}: {e}
@msg can't write .{ext} images .{ext} 이미지는 쓸 수 없습니다
Can't render this file because it contains an unexpected character in line 2 and column 73.
+3
View File
@@ -3351,6 +3351,8 @@ theme Appearance Vormgeving
Rename Library Group Bibliotheekgroep hernoemen
Delete Library Group Bibliotheekgroep verwijderen
Move Library Item to Group Bibliotheekitem naar groep verplaatsen
Rename Library Item Bibliotheekitem hernoemen
Add to Character Styles Aan tekenstijlen toevoegen
Rename Library Bibliotheek hernoemen
Show Library Bibliotheek weergeven
Use Library Item Bibliotheekitem gebruiken
@@ -4197,6 +4199,7 @@ imageTrace Outline Contour
@plural {n} step|{n} steps {n} stap|{n} stappen
@plural {n} stroke|{n} strokes {n} lijn|{n} lijnen
@msg no library `{id}` geen bibliotheek `{id}`
@msg the library has another item of that kind named `{name}` de bibliotheek heeft al een ander item van die soort met de naam `{name}`
@msg select some type first selecteer eerst wat tekst
@msg kerning must be a number, "auto", or "optical" kerning moet een getal, ‘auto’ of ‘optical’ zijn
@msg {_1} has no {_2} style {_1} heeft geen {_2}stijl
Can't render this file because it contains an unexpected character in line 2 and column 73.
+3
View File
@@ -3483,6 +3483,8 @@ theme Appearance Wygląd
Rename Library Group Zmień nazwę grupy biblioteki
Delete Library Group Usuń grupę biblioteki
Move Library Item to Group Przenieś element biblioteki do grupy
Rename Library Item Zmień nazwę elementu biblioteki
Add to Character Styles Dodaj do stylów znakowych
Rename Library Zmień nazwę biblioteki
Show Library Pokaż bibliotekę
Use Library Item Użyj elementu biblioteki
@@ -4300,6 +4302,7 @@ imageTrace Outline Kontur
@plural {n} step|{n} steps {n} krok|{n} kroki|{n} kroków
@plural {n} stroke|{n} strokes {n} obrys|{n} obrysy|{n} obrysów
@msg no library `{id}` brak biblioteki `{id}`
@msg the library has another item of that kind named `{name}` biblioteka ma już inny element tego rodzaju o nazwie `{name}`
@msg select some type first najpierw zaznacz tekst
@msg kerning must be a number, "auto", or "optical" kerning musi być liczbą, „auto” lub „optical”
@msg the selection has no gradient fill zaznaczenie nie ma gradientu wypełnienia
Can't render this file because it contains an unexpected character in line 2 and column 73.
+3
View File
@@ -3705,6 +3705,8 @@ font-technology Variable Variáveis
Rename Library Group Renomear grupo de biblioteca
Delete Library Group Excluir grupo de biblioteca
Move Library Item to Group Mover item da biblioteca para o grupo
Rename Library Item Renomear item da biblioteca
Add to Character Styles Adicionar aos Estilos de Caractere
Library Biblioteca
Rename Library Renomear biblioteca
Show Library Mostrar biblioteca
@@ -3742,6 +3744,7 @@ axis Both Ambos
Drag to float the toolbar Arraste para flutuar a barra de ferramentas
Drag to the window's left or right edge to dock Arraste até a borda esquerda ou direita da janela para encaixar
@msg no library `{id}` nenhuma biblioteca `{id}`
@msg the library has another item of that kind named `{name}` a biblioteca já tem outro item desse tipo chamado `{name}`
@msg select some type first selecione algum texto primeiro
@msg kerning must be a number, "auto", or "optical" O kerning deve ser um número, “auto” ou “optical”
@msg the selection has no gradient fill a seleção não tem gradiente de preenchimento
Can't render this file because it contains an unexpected character in line 6 and column 47.
+3
View File
@@ -3615,6 +3615,8 @@ digits Malayalam Малаялам
Rename Library Group Переименовать группу библиотеки
Delete Library Group Удалить группу библиотеки
Move Library Item to Group Переместить элемент библиотеки в группу
Rename Library Item Переименовать элемент библиотеки
Add to Character Styles Добавить в стили символов
Library Библиотека
Rename Library Переименовать библиотеку
Show Library Показать библиотеку
@@ -4204,6 +4206,7 @@ axis Both Оба
# (`untranslated_report` lists any that are missing). Command ids, parameter
# names and values in backticks or code (`colorModel rgb`, `document.export`) stay as they are.
@msg no library `{id}` нет библиотеки `{id}`
@msg the library has another item of that kind named `{name}` в библиотеке уже есть другой элемент этого вида с именем `{name}`
@msg select some type first сначала выделите текст
@msg kerning must be a number, "auto", or "optical" kerning должен быть числом, «auto» или «optical»
@msg the selection has no gradient fill у выделения нет градиентной заливки
Can't render this file because it is too large.
+3
View File
@@ -3505,6 +3505,8 @@ digits Malayalam Malayalam
Rename Library Group Byt namn på biblioteksgrupp
Delete Library Group Radera biblioteksgrupp
Move Library Item to Group Flytta biblioteksobjekt till grupp
Rename Library Item Byt namn på biblioteksobjekt
Add to Character Styles Lägg till i teckenstilar
Library Bibliotek
Rename Library Byt namn på bibliotek
Show Library Visa bibliotek
@@ -4078,6 +4080,7 @@ axis Both Båda
Drag to the window's left or right edge to dock Dra till fönstrets vänster- eller högerkant för att docka
Float Tool Group Gör verktygsgruppen flytande
@msg no library `{id}` inget bibliotek `{id}`
@msg the library has another item of that kind named `{name}` biblioteket har redan ett annat objekt av den sorten med namnet `{name}`
@msg select some type first markera någon text först
@msg kerning must be a number, "auto", or "optical" kerning måste vara ett tal, ”auto” eller ”optical”
@msg the selection has no gradient fill markeringen har ingen fyllnadsgradient
Can't render this file because it is too large.
+3
View File
@@ -3394,6 +3394,8 @@ digits Malayalam Malayalam
Rename Library Group Kitaplık Grubunu Yeniden Adlandır
Delete Library Group Kütüphane Grubunu Sil
Move Library Item to Group Kitaplık Öğesini Gruba Taşı
Rename Library Item Kitaplık Öğesini Yeniden Adlandır
Add to Character Styles Karakter Stillerine Ekle
Library Kütüphane
Rename Library Kitaplığı Yeniden Adlandır
Show Library Kitaplığı Göster
@@ -3962,6 +3964,7 @@ axis Both Her İkisi
Drag to the window's left or right edge to dock Sabitlemek için pencerenin sol veya sağ kenarına sürükleyin
Float Tool Group Araç Grubunu Yüzer Yap
@msg no library `{id}` `{id}` kütüphanesi yok
@msg the library has another item of that kind named `{name}` kitaplıkta zaten bu türden `{name}` adlı başka bir öğe var
@msg select some type first önce bir tür seçin
@msg kerning must be a number, "auto", or "optical" kerning bir sayı, “auto” veya “optical” olmalıdır
@msg the selection has no gradient fill seçimin degrade dolgusu yok
Can't render this file because it contains an unexpected character in line 5 and column 25.
+3
View File
@@ -3621,6 +3621,8 @@ effect Points Точки
Rename Library Group Перейменувати групу бібліотеки
Delete Library Group Видалити групу бібліотеки
Move Library Item to Group Перемістити елемент бібліотеки в групу
Rename Library Item Перейменувати елемент бібліотеки
Add to Character Styles Додати до стилів символів
Library Бібліотека
Rename Library Перейменувати бібліотеку
Show Library Показати бібліотеку
@@ -4202,6 +4204,7 @@ axis Both Обидві
Drag to the window's left or right edge to dock Перетягніть до лівого або правого краю вікна для прикріплення
Float Tool Group Від’єднати групу інструментів
@msg no library `{id}` немає бібліотеки `{id}`
@msg the library has another item of that kind named `{name}` у бібліотеці вже є інший елемент цього виду з назвою `{name}`
@msg select some type first спочатку виділіть текст
@msg kerning must be a number, "auto", or "optical" kerning має бути числом, «auto» або «optical»
@msg the selection has no gradient fill виділення не має градієнтної заливки
Can't render this file because it is too large.
+3
View File
@@ -2424,6 +2424,8 @@ digits Hindi Hindi
Move Guide to Layer Di chuyển đường căn vào lớp
Move in Perspective Di chuyển theo phối cảnh
Move Library Item to Group Di chuyển mục thư viện vào nhóm
Rename Library Item Đổi tên mục thư viện
Add to Character Styles Thêm vào các kiểu ký tự
Move Locked and Hidden Artwork with Artboard Di chuyển tác phẩm đã khóa và ẩn cùng bảng vẽ
Move Mesh Point Di chuyển điểm lưới
Move Mesh Points Di chuyển các điểm lưới
@@ -4974,6 +4976,7 @@ theme Appearance Giao diện
@msg no interaction in progress không có tương tác nào đang tiến hành
@msg no key object không có đối tượng khóa
@msg no library `{id}` không có thư viện `{id}`
@msg the library has another item of that kind named `{name}` thư viện đã có một mục khác cùng loại tên là `{name}`
@msg no library `{key}` (see {list}) không có thư viện `{key}` (xem {list})
@msg No linked files to look for Không có tệp liên kết để tìm kiếm
@msg no Live Paint edge near that point không có cạnh tô trực tiếp gần điểm đó
Can't render this file because it contains an unexpected character in line 204 and column 5.
+3
View File
@@ -3444,6 +3444,8 @@ digits Malayalam 马拉雅拉姆数字
Rename Library Group 重命名库组
Delete Library Group 删除库组
Move Library Item to Group 将库项目移到组
Rename Library Item 重命名库项目
Add to Character Styles 添加到字符样式
Library 库
Rename Library 重命名库
Show Library 显示库
@@ -4195,6 +4197,7 @@ imageTrace Outline 轮廓
@msg the layer to flatten into is hidden 要拼合到的图层已隐藏
@msg there are no objects to release 没有可释放的对象
@msg no library `{id}` 没有库 `{id}`
@msg the library has another item of that kind named `{name}` 库中已有另一个同类项目名为 `{name}`
@msg {path}: not a file {path}:不是文件
@msg {path}: {e} {path}:{e}
@msg can't write .{ext} images 无法写入 .{ext} 图像
Can't render this file because it contains an unexpected character in line 2 and column 73.
+3
View File
@@ -1959,6 +1959,7 @@ file-filter Templates 範本
@msg the layer to flatten into is hidden 要平面化到的圖層已隱藏
@msg there are no objects to release 沒有可釋放的物件
@msg no library `{id}` 沒有資料庫 `{id}`
@msg the library has another item of that kind named `{name}` 資料庫中已有另一個同類項目名為 `{name}`
@msg {path}: not a file {path}:不是檔案
@msg {path}: {e} {path}:{e}
@msg can't write .{ext} images 無法寫入 .{ext} 影像
@@ -4680,6 +4681,8 @@ digits Malayalam 馬來亞拉姆數字
Rename Library Group 重新命名資料庫群組
Delete Library Group 刪除資料庫群組
Move Library Item to Group 將資料庫項目移至群組
Rename Library Item 重新命名資料庫項目
Add to Character Styles 新增至字元樣式
Library 資料庫
Rename Library 重新命名資料庫
Show Library 顯示資料庫
Can't render this file because it contains an unexpected character in line 6 and column 47.
+63 -8
View File
@@ -4,8 +4,10 @@
//! patterns), are added to it; the + button adds the selection's graphic, fill or stroke color,
//! pattern or gradient, or text styles. A click on a color, gradient or pattern paints the
//! selection through the active Fill/Stroke proxy, a style click applies it to the selected type,
//! and a graphic is dragged onto the canvas (or double-clicked) to place a copy. Libraries are
//! kept on this machine.
//! and a graphic is dragged onto the canvas (or double-clicked) to place a copy. A character
//! style's context menu also applies it, adds it to the document's character styles without
//! applying it (`library.addToCharacterStyles`) and renames it (`library.renameItem`). Libraries
//! are kept on this machine.
//!
//! The search field filters the items by name; items can be moved into user-named groups, shown as
//! collapsible sections after the ungrouped items; and the panel menu exports the library to a
@@ -94,12 +96,22 @@ fn ask_group_name(app: &mut VectorcraftApp, library: &str, rename: Option<&str>,
app.ui.dialog = Some(crate::state::Dialog::new("command", d));
}
/// The name dialog for renaming item `item` (its key) of `kind` in `library`, filled with its name.
fn ask_item_name(app: &mut VectorcraftApp, library: &str, kind: ItemKind, item: &str) {
let name = app.session.libraries.get(library).and_then(|l| l.items().find(|(k, key, _)| *k == kind && *key == item)).map(|(.., n)| n.to_string());
let fixed = json!({ "library": library, "kind": kind_param(kind), "item": item });
let d = json!({ "__command": "library.renameItem", "__label": "Rename Library Item", "name": name.unwrap_or_else(|| item.to_string()), "__params": fixed });
app.ui.dialog = Some(crate::state::Dialog::new("command", d));
}
/// What a click in the panel asks for, done once the list is drawn.
enum Act {
Run(&'static str, Value),
/// The New Group dialog; the items (`[{kind, item}]`) go into the new group.
NewGroup(Value),
RenameGroup(String),
/// The Rename dialog for an item (its kind and key).
RenameItem(ItemKind, String),
}
/// What a drag in the panel holds for the library shown: one of its items, one of its groups (by
@@ -164,6 +176,9 @@ struct Items<'a> {
grab: Option<Grab>,
/// Whether the items show in a list (else colours and graphics as icons).
list: bool,
/// Whether a document is open, and whether type is selected there for a style to apply to.
has_doc: bool,
can_apply: bool,
}
impl Items<'_> {
@@ -214,7 +229,10 @@ pub fn show(app: &mut VectorcraftApp, ui: &mut Ui) {
let searching = !query.is_empty();
let shown = |name: &str| !searching || name.to_lowercase().contains(&query);
let grab = egui::DragAndDrop::payload::<PanelDrag>(ui.ctx()).and_then(|d| grabbed(&d, &lib_id));
let items = Items { library: &lib_id, lib, groups: lib.group_index(), fill_active, grab, list };
// Whether a character style's Apply Character Style is enabled (looked up only when the library has one).
let can_apply =
has_doc && !lib.char_styles.is_empty() && vectorcraft_engine::cmd::textstyles::target_style_attrs(&app.session, &json!({}), false).is_some();
let items = Items { library: &lib_id, lib, groups: lib.group_index(), fill_active, grab, list, has_doc, can_apply };
// The items shown in each section: the ungrouped ones first, then each group's.
let mut counts = vec![0usize; lib.groups.len() + 1];
for (kind, key, _) in lib.items().filter(|(_, _, name)| shown(name)) {
@@ -374,6 +392,7 @@ pub fn show(app: &mut VectorcraftApp, ui: &mut Ui) {
}
Some(Act::NewGroup(items)) => ask_group_name(app, &lib_id, None, items),
Some(Act::RenameGroup(g)) => ask_group_name(app, &lib_id, Some(&g), Value::Null),
Some(Act::RenameItem(kind, item)) => ask_item_name(app, &lib_id, kind, &item),
None => {}
}
}
@@ -466,7 +485,13 @@ impl Items<'_> {
if resp.clicked() {
*act = Some(Act::Run("library.use", json!({ "kind": kind_param(kind), "item": st.name })));
}
resp.context_menu(|ui| self.item_menu(ui, act, kind, &st.name));
resp.context_menu(|ui| {
if kind == ItemKind::CharStyle {
self.char_style_menu(ui, act, &st.name);
} else {
self.item_menu(ui, act, kind, &st.name);
}
});
}
ui.add_space(6.0);
}
@@ -597,6 +622,40 @@ impl Items<'_> {
/// An item's context menu entries: Move to Group (No Group, the library's groups, New
/// Group…) and Delete.
fn item_menu(&self, ui: &mut Ui, act: &mut Option<Act>, kind: ItemKind, key: &str) {
self.group_menu(ui, act, kind, key);
if menu_item(ui, "Delete", true, false) {
*act = Some(Act::Run("library.removeItem", json!({ "kind": kind_param(kind), "item": key })));
ui.close();
}
}
/// A character style's context menu: Apply Character Style (with type selected), Add to
/// Character Styles (the document's, not applied), Move to Group, Rename… and Delete.
fn char_style_menu(&self, ui: &mut Ui, act: &mut Option<Act>, key: &str) {
let item = json!({ "kind": "charStyle", "item": key });
if menu_item(ui, "Apply Character Style", self.can_apply, false) {
*act = Some(Act::Run("library.use", item.clone()));
ui.close();
}
if menu_item(ui, "Add to Character Styles", self.has_doc, false) {
*act = Some(Act::Run("library.addToCharacterStyles", json!({ "item": key })));
ui.close();
}
ui.separator();
self.group_menu(ui, act, ItemKind::CharStyle, key);
if menu_item(ui, "Rename…", true, false) {
*act = Some(Act::RenameItem(ItemKind::CharStyle, key.to_string()));
ui.close();
}
if menu_item(ui, "Delete", true, false) {
*act = Some(Act::Run("library.removeItem", item));
ui.close();
}
}
/// The Move to Group submenu of an item's context menu: No Group, the library's groups and
/// New Group….
fn group_menu(&self, ui: &mut Ui, act: &mut Option<Act>, kind: ItemKind, key: &str) {
let at = self.group_of(kind, key);
let item = json!({ "kind": kind_param(kind), "item": key });
ui.menu_button(format!(" {}", tl!("Move to Group")), |ui| {
@@ -624,10 +683,6 @@ impl Items<'_> {
}
});
});
if menu_item(ui, "Delete", true, false) {
*act = Some(Act::Run("library.removeItem", item));
ui.close();
}
}
}
@@ -416,6 +416,89 @@ fn group_dialogs_run_with_their_library_and_group() {
assert_eq!(got["groups"], json!([{"name": "Cold", "items": [{"kind": "color", "item": "Blue"}]}]));
}
/// A `button` click at `pos`, pressed in one frame and released in the next.
fn click_at(app: &mut VectorcraftApp, ctx: &egui::Context, pos: egui::Pos2, button: egui::PointerButton) -> Vec<(String, Rect)> {
let event = |pressed| egui::Event::PointerButton { pos, button, pressed, modifiers: Default::default() };
frame_at(app, ctx, 600.0, vec![egui::Event::PointerMoved(pos), event(true)]);
frame_at(app, ctx, 600.0, vec![event(false)]);
frame_at(app, ctx, 600.0, vec![]).0
}
/// The menu entries shown in `texts`, in order from the top: the labels starting with the menu's
/// indent.
fn menu_entries(texts: &[(String, Rect)]) -> Vec<String> {
let mut entries: Vec<_> = texts.iter().filter(|(t, _)| t.starts_with(" ")).map(|(t, r)| (t.trim().to_string(), r.top())).collect();
entries.sort_by(|a, b| a.1.total_cmp(&b.1));
entries.into_iter().map(|(t, _)| t).collect()
}
/// A right-click on a library character style opens its menu without applying it: Apply
/// Character Style (only with type selected), Add to Character Styles, Move to Group, Rename… and
/// Delete. Add puts the style in the document's character styles and leaves the selected type as
/// it was; Rename… opens a dialog with the style's name that renames it on OK and changes nothing
/// on Cancel. A paragraph style's menu stays Move to Group and Delete.
#[test]
fn a_character_style_s_menu_applies_adds_renames_and_deletes() {
let mut app = VectorcraftApp::new(Session::new(), Default::default());
app.run("file.new", json!({"width": 200, "height": 200})).unwrap();
let data = json!({"name": "Type", "charStyles": [{"name": "Headline", "attrs": {"size": 31.0}}], "paraStyles": [{"name": "Body", "attrs": {}}]});
let lib = app.run("library.import", json!({"data": data.to_string()})).unwrap()["id"].as_str().unwrap().to_string();
let ctx = egui::Context::default();
crate::theme::install_fonts(&ctx);
let (texts, _) = frame_at(&mut app, &ctx, 600.0, vec![]);
// No type selected: Apply is there but does nothing.
let menu = click_at(&mut app, &ctx, at(&texts, "Headline").center(), egui::PointerButton::Secondary);
assert_eq!(menu_entries(&menu), ["Apply Character Style", "Add to Character Styles", "Move to Group", "Rename…", "Delete"]);
click_at(&mut app, &ctx, at(&menu, " Apply Character Style").center(), egui::PointerButton::Primary);
assert!(app.session.active().unwrap().doc.char_styles.is_empty(), "disabled without type");
// With type selected: a right-click applies nothing; Add adds the style, unapplied.
let t = app.run("text.create", json!({"x": 10, "y": 80, "text": "Type", "size": 9})).unwrap()["id"].as_u64().unwrap();
app.run("select.set", json!({"ids": [t]})).unwrap();
let style_of = |app: &VectorcraftApp| match &app.session.active().unwrap().doc.node(vectorcraft_doc::NodeId(t)).unwrap().kind {
vectorcraft_doc::NodeKind::Text(text) => (text.runs[0].style.size, text.runs[0].style.style_name.clone()),
_ => panic!("not text"),
};
let (texts, _) = frame_at(&mut app, &ctx, 600.0, vec![]);
let menu = click_at(&mut app, &ctx, at(&texts, "Headline").center(), egui::PointerButton::Secondary);
assert_eq!(style_of(&app), (9.0, None), "a right-click applies nothing");
let undo = app.session.active().unwrap().history.undo.len();
click_at(&mut app, &ctx, at(&menu, " Add to Character Styles").center(), egui::PointerButton::Primary);
let doc = &app.session.active().unwrap().doc;
assert_eq!(doc.char_styles.iter().map(|c| c.name.as_str()).collect::<Vec<_>>(), ["Headline"]);
assert_eq!(style_of(&app), (9.0, None), "added, not applied");
assert_eq!(app.session.active().unwrap().history.undo.len(), undo + 1);
// Apply applies it.
let (texts, _) = frame_at(&mut app, &ctx, 600.0, vec![]);
let menu = click_at(&mut app, &ctx, at(&texts, "Headline").center(), egui::PointerButton::Secondary);
click_at(&mut app, &ctx, at(&menu, " Apply Character Style").center(), egui::PointerButton::Primary);
assert_eq!(style_of(&app), (31.0, Some("Headline".into())));
// Rename…: Cancel keeps the name, OK renames.
for (ok, want) in [(false, "Headline"), (true, "Title")] {
let (texts, _) = frame_at(&mut app, &ctx, 600.0, vec![]);
let menu = click_at(&mut app, &ctx, at(&texts, "Headline").center(), egui::PointerButton::Secondary);
click_at(&mut app, &ctx, at(&menu, " Rename…").center(), egui::PointerButton::Primary);
let d = app.ui.dialog.as_mut().expect("the Rename dialog");
assert_eq!((d.str("__command"), d.str("name")), ("library.renameItem".to_string(), "Headline".to_string()));
d.fields.insert("name".into(), json!("Title"));
if ok {
crate::dialogs::confirm(&mut app).unwrap();
} else {
crate::dialogs::cancel(&mut app);
}
assert_eq!(style_order(&mut app), [want]);
}
// The paragraph style's menu.
let (texts, _) = frame_at(&mut app, &ctx, 600.0, vec![]);
let menu = click_at(&mut app, &ctx, at(&texts, "Body").center(), egui::PointerButton::Secondary);
assert_eq!(menu_entries(&menu), ["Move to Group", "Delete"]);
// Delete removes the character style from the library only.
let (texts, _) = frame_at(&mut app, &ctx, 600.0, vec![]);
let menu = click_at(&mut app, &ctx, at(&texts, "Title").center(), egui::PointerButton::Secondary);
click_at(&mut app, &ctx, at(&menu, " Delete").center(), egui::PointerButton::Primary);
assert!(app.session.libraries.get(&lib).unwrap().char_styles.is_empty());
assert_eq!(app.session.active().unwrap().doc.char_styles.len(), 1, "the document's style stays");
}
/// Export Library… writes the library's file and Import Library… adds it back as a new library.
#[cfg(not(target_arch = "wasm32"))]
#[test]
+9 -1
View File
@@ -4051,7 +4051,15 @@ center?, to?}` uses one: a graphic is placed centred on `center` (pasted with it
gives another colour merges into the document's), a colour paints the selection's fill or stroke, and a style is added
to the document under its name without the white space around it (numbered when that name is taken by other
attributes) and applied to the selected text, each as one undo step. `library.removeItem {library?, kind, item}` removes
one.
one. `library.addToCharacterStyles {library?, item}` adds a character style to the document's character styles without
applying it, so no text needs to be selected: a document style of that name with the same attributes is reused
(`existing: true`, no undo step), and a name taken by other attributes gets a number, as `library.use` names it; a new
style is one undo step. With either command, a character style's color linked to a swatch that is not a global or spot
swatch of the document keeps the color it shows without the link. `library.renameItem {library?, kind, item, name}` renames an item in place, its group keeping it
(a graphic keeps its id); the name is trimmed and has 1 to 256 characters, another item of its kind with that name is
an error, renaming an item to its own name writes nothing, and a rename is not a document undo step. A right-click on a
character style in the panel offers Apply Character Style (with type selected), Add to Character Styles, Move to Group,
Rename… and Delete ([help page](https://helpx.adobe.com/illustrator/desktop/design-with-text/fonts-and-scripts/add-and-use-text-and-character-styles-in-libraries.html)).
Gradients and patterns are kinds of their own (the panel's + button lists Fill Gradient, Stroke Gradient, Fill Pattern
and Stroke Pattern, and a gradient or pattern swatch dragged from the Swatches panel onto the list is added).
+1
View File
@@ -1471,6 +1471,7 @@ Moved from the ROADMAP's "Shipped so far" on 2026-10-10. Update it when a featur
- **Neutral wording:** labels, MCP tool text, docs and packaging use neutral names, and `cargo xtask brands` (part of `cargo xtask ci`) fails on vendor names.
- **Colour, type and file workflows:** Recolor Artwork (dialog with harmonies), Edit Colors, Find & Replace, Change Case, Smart Punctuation, Guides, Lock/Hide Above, Transform Each, Rasterize.
The Libraries panel holds gradients and patterns: its + button adds the selection's fill or stroke gradient or pattern, a gradient or pattern swatch dragged from the Swatches panel is added, and a click paints the selection through the active Fill/Stroke proxy, a pattern bringing its definition and swatch into the document. A spot colour stays a spot colour: the library keeps its ink name and tint, and using it in any document links the paint to that document's spot swatch of that name, adding it when missing (#5812).
A right-click on a character style in the Libraries panel offers Apply Character Style, Add to Character Styles, Move to Group, Rename… and Delete ([help page](https://helpx.adobe.com/illustrator/desktop/design-with-text/fonts-and-scripts/add-and-use-text-and-character-styles-in-libraries.html)): Apply works on the selected type, Add puts the style in the document's character styles without applying it (`library.addToCharacterStyles`), Rename… renames the library's style in place (`library.renameItem`) and Delete removes it from the library only. Opening the menu applies nothing. Tests: `tests::library::a_library_character_style_is_added_to_the_document_without_applying_it`, `library_items_are_renamed_in_place`, `panels::libraries::tests::a_character_style_s_menu_applies_adds_renames_and_deletes`.
Object › Lock › All Artwork Above and Object › Hide › All Artwork Above deselect the selected objects they lock or hide, the key object included.
Object › Hide › Unselected Artwork (Cmd/Ctrl+Alt+Shift+3, `object.hide.unselected`) hides, in one undo step, every object Select All takes that is not selected and holds no selected object; the members of a group that holds a selected object are hidden one by one, and Object › Show All shows them again. In isolation mode it hides only unselected objects inside the isolated object. Public reference: [Default keyboard shortcuts](https://web.archive.org/web/20260726060015/https://helpx.adobe.com/illustrator/using/default-keyboard-shortcuts.html), "Hide unselected artwork".
Cmd/Ctrl+Alt+Shift+2 (`object.lock.unselected`) locks unselected artwork in one undo step and has no Object › Lock menu item. It locks unselected members of partly selected groups, clipping groups and compound paths, and unselected guides while Lock Guides is on. In ordinary isolation mode it locks only unselected art inside the isolated object. Object › Unlock All unlocks all locked art in the document, or inside the isolated object in isolation mode. The [public shortcut page](https://web.archive.org/web/20260726060015/https://helpx.adobe.com/illustrator/using/default-keyboard-shortcuts.html) calls the action "Lock all deselected artwork".