Symbols: Break Link selects no art inside a hidden or locked group

Break Link to Symbol on a selected group selected the art of every
instance it expanded that was itself shown and unlocked, including art in
a hidden or locked group inside the selection. The art now goes into the
selection only when it and every group and layer holding it are shown and
unlocked, the check Select All uses (select::is_selectable).
This commit is contained in:
dotCooCoo
2026-11-10 21:08:57 -08:00
parent 22ec820569
commit d069e0e4be
2 changed files with 33 additions and 2 deletions
+5 -2
View File
@@ -493,10 +493,13 @@ pub(super) fn symbol_break_link(s: &mut Session, p: &Value) -> Result<Value> {
if ids.is_empty() {
return Err(EngineError::Other("no symbol instances selected".into()));
}
let iso = s.doc()?.isolation;
let out = s.edit("Break Link to Symbol", |d, sel| {
let out = break_links(d, &ids, true)?;
// Hidden or locked art is left out of the selection.
sel.set(out.iter().copied().filter(|id| d.node(*id).is_some_and(|n| n.visible && !n.locked)));
// Art that is hidden or locked, or in a hidden or locked group or layer, is left out of the
// selection.
let locks = d.locked_artboards();
sel.set(out.iter().copied().filter(|id| crate::cmd::select::is_selectable(d, iso, &locks, *id)));
Ok(out)
})?;
Ok(json!({ "ids": ids_json(&out) }))
+28
View File
@@ -1358,6 +1358,34 @@ fn break_link_keeps_hidden_and_locked_instances_hidden_and_locked() {
assert!(selected.iter().all(|id| d.node(*id).is_some_and(|n| n.visible && !n.locked)), "{selected:?}");
}
/// Break Link to Symbol on a selected group does not select the art of a shown, unlocked instance
/// that sits in a hidden or a locked group inside it.
#[test]
fn break_link_leaves_art_in_hidden_or_locked_groups_unselected() {
let mut s = session();
let (shown, name, _) = make_symbol(&mut s);
let subgroup = |s: &mut Session, y: i64| {
let id = NodeId(s.execute("symbol.place", &json!({"name": name, "x": 300, "y": y})).unwrap()["id"].as_u64().unwrap());
select(s, &[id]);
NodeId(s.execute("object.group", &json!({})).unwrap()["id"].as_u64().unwrap())
};
let hidden = subgroup(&mut s, 200);
let locked = subgroup(&mut s, 100);
select(&mut s, &[shown, hidden, locked]);
let group = NodeId(s.execute("object.group", &json!({})).unwrap()["id"].as_u64().unwrap());
let doc = std::sync::Arc::make_mut(&mut s.doc_mut().unwrap().doc);
doc.node_mut(hidden).unwrap().visible = false;
doc.node_mut(locked).unwrap().locked = true;
select(&mut s, &[group]);
let r = s.execute("symbol.breakLink", &json!({})).unwrap();
assert_eq!(r["ids"].as_array().unwrap().len(), 3, "{r}");
let d = &s.doc().unwrap().doc;
let selected: Vec<NodeId> = s.doc().unwrap().selection.objects.to_vec();
assert_eq!(selected.len(), 1, "{selected:?}");
let a = d.ancestry(selected[0]).unwrap();
assert!(!a.contains(&hidden) && !a.contains(&locked), "{a:?}");
}
/// Delete Symbol, expanding the instances, keeps a hidden instance's art hidden and a locked
/// instance's art locked.
#[test]