Select: Link Block Series skips hidden and locked type in selected groups

Select › Same › Link Block Series no longer counts hidden or locked type
inside a selected group, or type inside a hidden or locked object there,
as selected. A group that holds only such type leaves the command off, and
the command does not select the other frames of that type's thread.
This commit is contained in:
dotCooCoo
2026-11-02 15:21:51 +07:00
committed by bflatastic
parent 67032aece6
commit 012a50815f
3 changed files with 32 additions and 8 deletions
+15 -7
View File
@@ -32,7 +32,7 @@ pub fn specs() -> Vec<CommandSpec> {
"Link Block Series",
["Select", "Same"],
None,
"{} select every frame of the threads of the selected type objects (and of the type inside selected groups); type in no thread selects itself; frames that are hidden or locked, inside a hidden or locked object or layer, on a template layer, or outside the isolated group or layer are left out → {count}",
"{} select every frame of the threads of the selected type objects (and of the visible, unlocked type inside selected groups); type in no thread selects itself; frames that are hidden or locked, inside a hidden or locked object or layer, on a template layer, or outside the isolated group or layer are left out → {count}",
has_text_selection,
same_link_block_series
),
@@ -322,16 +322,24 @@ fn same_text(s: &mut Session, cmd: &str, eq: fn(&CharStyle, &CharStyle) -> bool)
finish_same(s, cmd, ids)
}
/// The type objects among the selected objects and inside them, in selection order.
/// The type objects among the selected objects and inside them, in selection order, leaving out
/// every hidden or locked object with what it holds.
fn selected_text(s: &Session) -> Vec<NodeId> {
fn inside(n: &Node, out: &mut Vec<NodeId>) {
if !n.visible || n.locked {
return;
}
if matches!(n.kind, NodeKind::Text(_)) && !out.contains(&n.id) {
out.push(n.id);
}
for c in n.children().into_iter().flatten() {
inside(c, out);
}
}
let Some(st) = s.active() else { return vec![] };
let mut out = vec![];
for n in st.selection.objects.iter().filter_map(|id| st.doc.node(*id)) {
n.walk(&mut |c| {
if matches!(c.kind, NodeKind::Text(_)) && !out.contains(&c.id) {
out.push(c.id);
}
});
inside(n, &mut out);
}
out
}
+15
View File
@@ -1978,6 +1978,21 @@ fn select_same_link_block_series_selects_the_frames_of_a_thread() {
// With no type selected the command is not available.
sel(&mut s, &[r]);
assert!(s.execute("select.same.linkBlockSeries", &json!({})).is_err());
// A selected group counts the type inside it, but not hidden or locked type.
let box_ = rect(&mut s, 400.0, 400.0, 10.0, 10.0);
sel(&mut s, &[d, box_]);
let g = id_of(&s.execute("object.group", &json!({})).unwrap());
sel(&mut s, &[g]);
assert!(find_command("select.same.linkBlockSeries").unwrap().info(&s).enabled);
assert_eq!(s.execute("select.same.linkBlockSeries", &json!({})).unwrap()["count"], 2);
assert_eq!(selected(&s), vec![d, e]);
for props in [json!({"id": d.0, "visible": false}), json!({"id": d.0, "visible": true, "locked": true})] {
s.execute("layer.setProps", &props).unwrap();
sel(&mut s, &[g]);
assert!(!find_command("select.same.linkBlockSeries").unwrap().info(&s).enabled, "{props}");
assert!(s.execute("select.same.linkBlockSeries", &json!({})).is_err(), "{props}");
assert_eq!(selected(&s), vec![g], "{props}");
}
}
/// #1737: Select > Same reads type's fill and stroke from its characters (the first run), so type