forked from 1b-agent/opencadstudio-upstream
feat(statusbar): selection cycling for overlapping objects (SC pill)
Add a click_hits_all hit-test and an SC pill that, when on, makes repeated clicks at the same spot step through the overlapping objects there (nearest first) instead of accumulating the selection. The whole cycling path is gated behind the toggle, so default picking is unchanged when it is off. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
1 parent
f7eac09b55
commit
ac042c5dbf
6 files changed
+105
No files matched your search
@@ -2909,6 +2909,46 @@ impl OpenCADStudio {
|
||||
if box_anchor.is_none() {
|
||||
let all_wires = self.tabs[i].scene.hit_test_wires();
|
||||
let vp_mat = self.tabs[i].scene.camera.borrow().view_proj(bounds);
|
||||
|
||||
// Selection cycling: step through overlapping objects
|
||||
// under the cursor on repeated clicks at the same spot.
|
||||
// Gated behind the toggle, so default picking is unchanged.
|
||||
let mut handled_by_cycling = false;
|
||||
if self.selection_cycling {
|
||||
let cands: Vec<Handle> = scene::hit_test::click_hits_all(
|
||||
p,
|
||||
&all_wires[..],
|
||||
vp_mat,
|
||||
bounds,
|
||||
)
|
||||
.into_iter()
|
||||
.filter_map(|s| Scene::handle_from_wire_name(s))
|
||||
.filter(|&h| self.tabs[i].scene.passes_selection_filter(h))
|
||||
.collect();
|
||||
if !cands.is_empty() {
|
||||
let same =
|
||||
self.cycle_state.as_ref().map_or(false, |(pt, list, _)| {
|
||||
(pt.x - p.x).abs() < 3.0
|
||||
&& (pt.y - p.y).abs() < 3.0
|
||||
&& *list == cands
|
||||
});
|
||||
let idx = if same {
|
||||
(self.cycle_state.as_ref().unwrap().2 + 1) % cands.len()
|
||||
} else {
|
||||
0
|
||||
};
|
||||
let handle = cands[idx];
|
||||
self.cycle_state = Some((p, cands, idx));
|
||||
self.tabs[i].scene.deselect_all();
|
||||
self.tabs[i].scene.select_entity(handle, false);
|
||||
self.tabs[i].scene.expand_selection_for_groups(&[handle]);
|
||||
self.refresh_properties();
|
||||
selection_just_completed = true;
|
||||
handled_by_cycling = true;
|
||||
}
|
||||
}
|
||||
|
||||
if !handled_by_cycling {
|
||||
let hit = scene::hit_test::click_hit(p, &all_wires[..], vp_mat, bounds)
|
||||
.and_then(|s| Scene::handle_from_wire_name(s))
|
||||
.or_else(|| {
|
||||
@@ -2961,6 +3001,7 @@ impl OpenCADStudio {
|
||||
sel.box_current = Some(p_full);
|
||||
sel.box_crossing = false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let a = box_anchor.unwrap();
|
||||
let crossing = box_crossing;
|
||||
@@ -3601,6 +3642,11 @@ impl OpenCADStudio {
|
||||
self.quick_properties ^= true;
|
||||
Task::none()
|
||||
}
|
||||
Message::ToggleSelectionCycling => {
|
||||
self.selection_cycling ^= true;
|
||||
self.cycle_state = None;
|
||||
Task::none()
|
||||
}
|
||||
Message::ToggleSelectionFilterPopup => {
|
||||
self.selection_filter_popup_open ^= true;
|
||||
Task::none()
|
||||
|
||||
Reference in new issue
Block a user