fix(scene): clear selection after erase

This commit is contained in:
Hakan Seven 2026-07-28 17:35:21 +03:00
commit 8050fc79fd
7 changed files with 50 additions and 11 deletions

View file

@ -2473,7 +2473,7 @@ impl Scene {
pub fn clear(&mut self) {
self.document.record_all_entities_for_transaction();
self.document = CadDocument::new();
self.selected = HashSet::default();
self.replace_selection(HashSet::default());
self.preview_wires = vec![];
self.preview_text = vec![];
self.current_layout = "Model".to_string();

View file

@ -8715,6 +8715,9 @@ mod delta_undo_tests {
let orig1 = scene.document.get_entity(h1).cloned().unwrap();
let orig2 = scene.document.get_entity(h2).cloned().unwrap();
let count = scene.document.entities().count();
scene.select_entity(h2, false);
scene.set_hover_highlight(Some(h2));
let selection_generation = scene.selection_generation;
scene.begin_undo_recording();
scene.erase_entities(&[h2]);
@ -8725,6 +8728,12 @@ mod delta_undo_tests {
);
let delta = build_delta(&scene, rec);
assert!(scene.document.get_entity(h2).is_none(), "h2 must be erased");
assert!(!scene.selected.contains(&h2));
assert_eq!(scene.hover_highlight, None);
assert_ne!(
scene.selection_generation, selection_generation,
"erase must invalidate the stale selection overlay"
);
// Undo re-inserts h2 with its ORIGINAL handle and image, exactly once in
// the block record (the strip prevents a duplicated dangling entry),

View file

@ -17,6 +17,16 @@ impl Scene {
self.bump_selection();
}
/// Replace the complete selection and invalidate the GPU highlight overlay
/// only when its contents actually changed. History/file/command paths must
/// use this instead of assigning `selected` directly.
pub(crate) fn replace_selection(&mut self, selected: HashSet<Handle>) {
if self.selected != selected {
self.selected = selected;
self.bump_selection();
}
}
/// Remove a single entity from the selection (Shift+click subtractive pick).
pub fn deselect_entity(&mut self, handle: Handle) {
if self.selected.remove(&handle) {
@ -333,6 +343,7 @@ impl Scene {
pub fn erase_entities(&mut self, handles: &[Handle]) {
let mut handle_set: HashSet<Handle> = HashSet::default();
let mut erased: Vec<(Handle, ChangeKind)> = Vec::new();
let mut highlight_changed = false;
for &h in handles {
// Objects on a locked layer can't be erased.
if self.is_layer_locked(h) {
@ -345,7 +356,11 @@ impl Scene {
}
self.remember_removed_cache_categories(h);
self.document.remove_entity_arc(h);
self.selected.remove(&h);
highlight_changed |= self.selected.remove(&h);
if self.hover_highlight == Some(h) {
self.hover_highlight = None;
highlight_changed = true;
}
self.hatches.remove(&h);
self.images.remove(&h);
self.meshes.remove(&h);
@ -354,6 +369,9 @@ impl Scene {
handle_set.insert(h);
erased.push((h, ChangeKind::Removed));
}
if highlight_changed {
self.bump_selection();
}
// Capture exactly the group objects that this erase will rewrite, plus
// the group dictionary when an emptied group will be removed. Do this
// before taking mutable object-map borrows below.