mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-10-30 04:37:29 -06:00
Selection: a selected object's masked art counts only where a click reaches it
The selected object itself was checked for being hidden, locked or a template, but not as a click checks it: a selected guide path was grabbed where a mask hid it while guides were locked or hidden, though a click on it there hits nothing. The selected object now passes the same test a click applies to it before its art is tried: guides while guides are locked or hidden, and a Shaper group's hidden part, don't count. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EjfPR4a1jPek7r3nyFFNYv
This commit is contained in:
committed by
bflatastic
co-authored by
Claude Opus 5.5
parent
6ecea97fdb
commit
f793547a7f
@@ -115,8 +115,8 @@ pub fn hit_test_visible(doc: &Document, p: Point, opt: HitOptions) -> Option<Hit
|
||||
/// click there hits nothing ([`hit_test`]), so the selection tools grab the selection by that
|
||||
/// art instead of starting a marquee: an image in a mask, picked in the Layers panel, can be
|
||||
/// dragged by its hidden part, whose frame shows while it is selected. An object that a click
|
||||
/// can't hit anyway doesn't count: hidden, locked, a template, outside the isolated container
|
||||
/// (`opt.scope`) or on a locked artboard.
|
||||
/// can't hit anyway doesn't count: hidden, locked, a template, a guide while guides are locked
|
||||
/// or hidden, outside the isolated container (`opt.scope`) or on a locked artboard.
|
||||
pub fn selected_hidden_at(doc: &Document, p: Point, opt: HitOptions, selected: &[NodeId]) -> Option<NodeId> {
|
||||
let symbols = doc.symbol_boxes();
|
||||
let locks = doc.locked_artboards();
|
||||
@@ -136,9 +136,13 @@ pub fn selected_hidden_at(doc: &Document, p: Point, opt: HitOptions, selected: &
|
||||
.rev()
|
||||
.skip(1)
|
||||
.any(|n| n.clips() && n.children().and_then(|c| c.first()).is_some_and(|clip| clip.id != id && !clip_contains(clip, p)));
|
||||
// Its own art is what a click would hit in it: a group's hidden, locked or masked
|
||||
// contents don't count.
|
||||
masked && nodes.last().is_some_and(|n| object_hit(n, p, opt, &symbols, true))
|
||||
// A click may reach it there ([`may_hit`]: not a guide while guides are locked or
|
||||
// hidden, nor a Shaper group's hidden part), and its own art is what a click would hit
|
||||
// in it: a group's hidden, locked or masked contents don't count.
|
||||
let [.., parent, n] = nodes.as_slice() else { return false };
|
||||
let reachable =
|
||||
parent.children().and_then(|c| c.iter().position(|c| c.id == id)).is_some_and(|i| may_hit(parent, i, n, p, opt, &symbols, true));
|
||||
masked && reachable && object_hit(n, p, opt, &symbols, true)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -155,6 +155,25 @@ fn a_selected_groups_hidden_art_counts_only_where_a_click_would_hit_it() {
|
||||
assert_eq!(selected_hidden_at(&d, hidden, opt, &[g]), None, "its own mask");
|
||||
}
|
||||
|
||||
/// A selected guide path where a mask hides it counts only while guides can be clicked: not
|
||||
/// while they are locked or hidden (`skip_guides`), as a click on it then hits nothing.
|
||||
#[test]
|
||||
fn a_selected_guide_hidden_by_a_mask_counts_only_while_guides_can_be_clicked() {
|
||||
let mut d = Document::new(300.0, 200.0);
|
||||
let l = d.layers[0].id;
|
||||
let (mask, mut art) = half_clipped(&mut d);
|
||||
if let NodeKind::Path { guide, .. } = &mut art.kind {
|
||||
*guide = true;
|
||||
}
|
||||
let (g, guide_id) = (d.alloc_id(), art.id);
|
||||
let mut clip = Node::group(g, vec![Arc::new(mask), Arc::new(art)]);
|
||||
clip.set_clips(true);
|
||||
d.insert(Some(l), 0, clip).unwrap();
|
||||
let (hidden, opt) = (Point::new(150.0, 50.0), HitOptions::default());
|
||||
assert_eq!(selected_hidden_at(&d, hidden, opt, &[guide_id]), Some(guide_id));
|
||||
assert_eq!(selected_hidden_at(&d, hidden, HitOptions { skip_guides: true, ..opt }, &[guide_id]), None);
|
||||
}
|
||||
|
||||
/// #2345: a marquee touches a clip group only where its art shows. Over the clipped-away
|
||||
/// half alone it selects nothing, and around a rectangle drawn beside the group's mask it
|
||||
/// takes that rectangle alone; reaching into the mask takes the group. The same holds for
|
||||
|
||||
Reference in New Issue
Block a user