Object: Unlock All and Show All with Shift+Alt act only within the selected object's group

Squashed from #4439 onto main.
This commit is contained in:
dotCooCoo
2026-10-29 11:18:38 +07:00
committed by bflatastic
parent a8c166a957
commit 02f2dd8c5a
33 changed files with 221 additions and 10 deletions
+2 -2
View File
@@ -26,8 +26,8 @@ fn preview_bounds(s: &Session, p: &Value, cmd: &str) -> Result<bool> {
}
}
/// Param `key` of the Align commands, Shear and `text.setFormat`'s lists: one of `values`, or
/// `None` when it is missing or null. Any other value is an error that lists `values`.
/// Param `key` of the Align commands, Shear, Unlock All, Show All and `text.setFormat`'s lists: one
/// of `values`, or `None` when it is missing or null. Any other value is an error that lists `values`.
pub(crate) fn choice<'a>(p: &'a Value, cmd: &str, key: &str, values: &[&str]) -> Result<Option<&'a str>> {
let Some(v) = p.get(key).filter(|v| !v.is_null()) else { return Ok(None) };
match v.as_str() {
+38 -4
View File
@@ -172,8 +172,42 @@ fn collect_flag(d: &Document, f: impl Fn(&Node) -> bool) -> Vec<NodeId> {
v
}
pub(super) fn unlock_all(s: &mut Session, _: &Value) -> Result<Value> {
let ids = collect_flag(&s.doc()?.doc, |n| n.locked);
/// The objects that `f` picks for `object.unlockAll` and `object.showAll` (`cmd`): in the whole
/// document, or with `scope: "group"` inside the groups that hold the selected objects. A selected
/// group is the group that holds its own members, and the objects of a group inside another such
/// group are taken once. With `scope: "group"` and no selected object in a group, it returns an
/// error.
fn collect_flag_in_scope(s: &Session, cmd: &str, p: &Value, f: impl Fn(&Node) -> bool) -> Result<Vec<NodeId>> {
let st = s.doc()?;
let d = &st.doc;
if choice(p, cmd, "scope", &["document", "group"])? != Some("group") {
return Ok(collect_flag(d, f));
}
let is_group = |id: &NodeId| d.node(*id).is_some_and(|n| matches!(n.kind, NodeKind::Group { .. }));
let mut groups: Vec<NodeId> = st.selection.objects.iter().filter_map(|id| d.ancestry(*id)?.into_iter().rev().find(is_group)).collect();
groups.sort();
groups.dedup();
if groups.is_empty() {
return Err(EngineError::Other("nothing selected is in a group".into()));
}
let mut v = vec![];
for g in &groups {
if d.ancestry(*g).is_some_and(|a| a.iter().any(|up| up != g && groups.contains(up))) {
continue;
}
for c in d.node(*g).and_then(Node::children).into_iter().flatten() {
c.walk(&mut |n| {
if !n.is_layer() && f(n) {
v.push(n.id)
}
});
}
}
Ok(v)
}
pub(super) fn unlock_all(s: &mut Session, p: &Value) -> Result<Value> {
let ids = collect_flag_in_scope(s, "object.unlockAll", p, |n| n.locked)?;
// With nothing locked, the document, the selection and the undo history stay as they are.
if ids.is_empty() {
return Ok(json!({ "count": 0 }));
@@ -211,8 +245,8 @@ pub(super) fn hide(s: &mut Session, _: &Value) -> Result<Value> {
ok()
}
pub(super) fn show_all(s: &mut Session, _: &Value) -> Result<Value> {
let ids = collect_flag(&s.doc()?.doc, |n| !n.visible);
pub(super) fn show_all(s: &mut Session, p: &Value) -> Result<Value> {
let ids = collect_flag_in_scope(s, "object.showAll", p, |n| !n.visible)?;
// With nothing hidden, the document, the selection and the undo history stay as they are.
if ids.is_empty() {
return Ok(json!({ "count": 0 }));
+18 -2
View File
@@ -154,7 +154,15 @@ pub fn specs() -> Vec<CommandSpec> {
has_selection_outside_isolation,
lock
),
cmd!("object.unlockAll", "Unlock All", ["Object"], Some("Cmd+Alt+2"), "{}", outside_isolation, unlock_all),
cmd!(
"object.unlockAll",
"Unlock All",
["Object"],
Some("Cmd+Alt+2"),
"{scope?: \"document\"|\"group\" (default document; group: only the objects inside the groups that hold the selected objects, a selected group holding its own; the in-window menu item chosen with Shift+Alt)} unlock the locked objects and select them → {count}",
outside_isolation,
unlock_all
),
cmd!(
"object.hide",
"Selection",
@@ -164,7 +172,15 @@ pub fn specs() -> Vec<CommandSpec> {
has_selection_outside_isolation,
hide
),
cmd!("object.showAll", "Show All", ["Object"], Some("Cmd+Alt+3"), "{}", outside_isolation, show_all),
cmd!(
"object.showAll",
"Show All",
["Object"],
Some("Cmd+Alt+3"),
"{scope?: \"document\"|\"group\" (default document; group: only the objects inside the groups that hold the selected objects, a selected group holding its own; the in-window menu item chosen with Shift+Alt)} show the hidden objects and select them → {count}",
outside_isolation,
show_all
),
cmd!(
"object.compoundPath.make",
"Make",