Global Edit: a Shift-click on a match inside a selected group deselects the group

A match that sits inside a selected object is no longer highlighted, and a
Shift-click on it with the Selection tool deselects that object as before
instead of leaving the match out of the Global Edit.
This commit is contained in:
dotCooCoo
2026-11-02 01:28:57 -08:00
parent 205e5b3e8b
commit 1cd5bc4016
3 changed files with 26 additions and 6 deletions
+6 -2
View File
@@ -716,8 +716,9 @@ pub(crate) fn propagate(before: &Document, d: &mut Document, ge: &GlobalEdit, se
edited
}
/// The outlines of the members of the active document's Global Edit that are not selected, in
/// their layer's colour: the canvas highlights them while Global Edit is on.
/// The outlines of the members of the active document's Global Edit that are not selected, hold
/// no selected object and sit inside no selected object, in their layer's colour: the canvas
/// highlights them while Global Edit is on.
pub fn highlights(s: &Session) -> Outlines {
let Some(st) = s.active() else { return vec![] };
let Some(ge) = &st.global_edit else { return vec![] };
@@ -732,6 +733,9 @@ pub fn highlights(s: &Session) -> Outlines {
.iter()
.filter_map(|(id, _)| {
let n = st.doc.node(*id).filter(|n| !holds(n, &st.selection.objects))?;
if st.doc.ancestry(*id).is_some_and(|a| a.iter().any(|p| st.selection.objects.contains(p))) {
return None;
}
let path = match n.stroke_path() {
Some(p) => p,
None => n.geometric_bounds_with(&symbols)?.to_path(0.1),
+14
View File
@@ -472,6 +472,20 @@ fn a_shift_click_inside_a_matched_group_leaves_the_whole_group_out() {
assert_eq!(members(&s), Some(vec![g, small]));
}
#[test]
fn a_shift_click_on_a_member_inside_a_selected_group_deselects_the_group() {
let mut s = session();
let [a, b, c, wide, _] = squares(&mut s);
let pair = group_of(&mut s, &[b, wide]);
let all = start(&mut s, a, json!({}));
assert_eq!(all, [a, c, b], "the copy in the group comes after the small square");
sel(&mut s, &[pair]);
assert_eq!(crate::cmd::globaledit::highlights(&s).len(), 2, "the copy inside the selected group is not highlighted");
shift_click(&mut s, 350.0, 50.0);
assert_eq!(members(&s), Some(all), "nothing is left out");
assert!(s.doc().unwrap().selection.objects.is_empty(), "the group is deselected");
}
#[test]
fn leaving_out_all_but_one_ends_global_edit_and_the_first_object_stays() {
let mut s = session();
+6 -4
View File
@@ -994,13 +994,15 @@ fn shift_press(cx: &ToolContext, h: &Hit, top: NodeId, out: &mut Vec<Action>) ->
}
/// The object of the Global Edit in progress that the click `h` lands on or inside, when it is
/// highlighted: neither the object the edit started from nor one that is selected or holds a
/// selected object (`select.globalEditExclude` leaves it out of the edit).
/// highlighted: neither the object the edit started from nor one that is selected, holds a
/// selected object or sits inside a selected object (`select.globalEditExclude` leaves it out of
/// the edit).
fn global_edit_member(cx: &ToolContext, h: &Hit) -> Option<NodeId> {
let others = cx.global_edit.get(1..)?;
let member = h.ancestry.iter().chain([&h.leaf]).find(|id| others.iter().any(|(m, _)| m == *id)).copied()?;
let selected = cx.selection.objects.iter().any(|s| cx.doc.ancestry(*s).is_some_and(|a| a.contains(&member)));
(!selected).then_some(member)
let holds = cx.selection.objects.iter().any(|s| cx.doc.ancestry(*s).is_some_and(|a| a.contains(&member)));
let inside = cx.doc.ancestry(member).is_some_and(|a| a.iter().any(|id| cx.selection.contains(*id)));
(!holds && !inside).then_some(member)
}
/// Can a click make `id` the key object? `select.key` takes only a selected top-level object. In