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
+2 -1
View File
@@ -4886,7 +4886,8 @@ doesn't exist, a `port` other than `in` or `out`, and a side where no frame of a
`select.same.linkBlockSeries` (Select › Same › Link Block Series) selects every frame of the threads that the selected
type objects, and the type inside selected groups, are in, in thread order, and returns `{count}`. Type in no thread
selects itself, and other selected objects are left out. With frames of several threads selected, it selects the frames
of all of them. It is off while no type is selected, and records no undo step.
of all of them. Hidden or locked type inside a selected group does not count as selected, and hidden or locked frames of
a thread are left out. It is off while no type is selected, and records no undo step.
In every thread, a paragraph that continues from one frame into the next has its first line, first-line indent and
bullet or number in the frame where it starts. In the next frame its first line starts where its wrapped lines start,