fix(scene): clear selection after erase
This commit is contained in:
parent
05b044f367
commit
8050fc79fd
7 changed files with 50 additions and 11 deletions
|
|
@ -334,7 +334,9 @@ impl OpenCADStudio {
|
||||||
n += 1;
|
n += 1;
|
||||||
}
|
}
|
||||||
// Draw the text in front of its newly-added masks.
|
// Draw the text in front of its newly-added masks.
|
||||||
self.tabs[i].scene.selected = handles.iter().cloned().collect();
|
self.tabs[i]
|
||||||
|
.scene
|
||||||
|
.replace_selection(handles.iter().cloned().collect());
|
||||||
self.tabs[i].dirty = true;
|
self.tabs[i].dirty = true;
|
||||||
self.command_line
|
self.command_line
|
||||||
.push_output(&format!("TEXTMASK: masked {n} text object(s)."));
|
.push_output(&format!("TEXTMASK: masked {n} text object(s)."));
|
||||||
|
|
|
||||||
|
|
@ -754,7 +754,7 @@ impl OpenCADStudio {
|
||||||
.push_info(&format!("{cmd}: no text or dimension objects."));
|
.push_info(&format!("{cmd}: no text or dimension objects."));
|
||||||
return Some(Task::none());
|
return Some(Task::none());
|
||||||
}
|
}
|
||||||
self.tabs[i].scene.selected = handles;
|
self.tabs[i].scene.replace_selection(handles);
|
||||||
return self.dispatch_view(
|
return self.dispatch_view(
|
||||||
if to_front {
|
if to_front {
|
||||||
"DRAWORDER FRONT"
|
"DRAWORDER FRONT"
|
||||||
|
|
|
||||||
|
|
@ -875,7 +875,13 @@ impl OpenCADStudio {
|
||||||
.copied()
|
.copied()
|
||||||
.filter(|h| scene.document.get_entity(*h).is_some())
|
.filter(|h| scene.document.get_entity(*h).is_some())
|
||||||
.collect();
|
.collect();
|
||||||
scene.selected = restored;
|
scene.replace_selection(restored);
|
||||||
|
if scene
|
||||||
|
.hover_highlight
|
||||||
|
.is_some_and(|handle| scene.document.get_entity(handle).is_none())
|
||||||
|
{
|
||||||
|
scene.set_hover_highlight(None);
|
||||||
|
}
|
||||||
// Entity deltas currently preserve the layout; direct assignment avoids
|
// Entity deltas currently preserve the layout; direct assignment avoids
|
||||||
// clearing layout render caches between steps and keeps future widened
|
// clearing layout render caches between steps and keeps future widened
|
||||||
// deltas batchable.
|
// deltas batchable.
|
||||||
|
|
@ -903,11 +909,13 @@ impl OpenCADStudio {
|
||||||
let mut affected = scene.object_isolation.hidden.clone();
|
let mut affected = scene.object_isolation.hidden.clone();
|
||||||
affected.extend(state.hidden.iter().copied());
|
affected.extend(state.hidden.iter().copied());
|
||||||
scene.object_isolation = state.clone();
|
scene.object_isolation = state.clone();
|
||||||
scene.selected = selected
|
scene.replace_selection(
|
||||||
.iter()
|
selected
|
||||||
.copied()
|
.iter()
|
||||||
.filter(|handle| scene.document.get_entity(*handle).is_some())
|
.copied()
|
||||||
.collect();
|
.filter(|handle| scene.document.get_entity(*handle).is_some())
|
||||||
|
.collect(),
|
||||||
|
);
|
||||||
let changes: Vec<_> = affected
|
let changes: Vec<_> = affected
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|handle| (handle, crate::scene::ChangeKind::Modified))
|
.map(|handle| (handle, crate::scene::ChangeKind::Modified))
|
||||||
|
|
|
||||||
|
|
@ -801,7 +801,9 @@ pub(super) fn on_open_file(&mut self) -> Task<Message> {
|
||||||
if let Some(prepared) = prepared_geometry {
|
if let Some(prepared) = prepared_geometry {
|
||||||
self.tabs[i].scene.install_prepared_open_geometry(prepared);
|
self.tabs[i].scene.install_prepared_open_geometry(prepared);
|
||||||
}
|
}
|
||||||
self.tabs[i].scene.selected = rustc_hash::FxHashSet::default();
|
self.tabs[i]
|
||||||
|
.scene
|
||||||
|
.replace_selection(rustc_hash::FxHashSet::default());
|
||||||
self.tabs[i].scene.preview_wires = vec![];
|
self.tabs[i].scene.preview_wires = vec![];
|
||||||
// Reopen in whichever space the file was saved in — the CTAB
|
// Reopen in whichever space the file was saved in — the CTAB
|
||||||
// tab name when recorded, else the $TILEMODE model/paper flag —
|
// tab name when recorded, else the $TILEMODE model/paper flag —
|
||||||
|
|
|
||||||
|
|
@ -2473,7 +2473,7 @@ impl Scene {
|
||||||
pub fn clear(&mut self) {
|
pub fn clear(&mut self) {
|
||||||
self.document.record_all_entities_for_transaction();
|
self.document.record_all_entities_for_transaction();
|
||||||
self.document = CadDocument::new();
|
self.document = CadDocument::new();
|
||||||
self.selected = HashSet::default();
|
self.replace_selection(HashSet::default());
|
||||||
self.preview_wires = vec![];
|
self.preview_wires = vec![];
|
||||||
self.preview_text = vec![];
|
self.preview_text = vec![];
|
||||||
self.current_layout = "Model".to_string();
|
self.current_layout = "Model".to_string();
|
||||||
|
|
|
||||||
|
|
@ -8715,6 +8715,9 @@ mod delta_undo_tests {
|
||||||
let orig1 = scene.document.get_entity(h1).cloned().unwrap();
|
let orig1 = scene.document.get_entity(h1).cloned().unwrap();
|
||||||
let orig2 = scene.document.get_entity(h2).cloned().unwrap();
|
let orig2 = scene.document.get_entity(h2).cloned().unwrap();
|
||||||
let count = scene.document.entities().count();
|
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.begin_undo_recording();
|
||||||
scene.erase_entities(&[h2]);
|
scene.erase_entities(&[h2]);
|
||||||
|
|
@ -8725,6 +8728,12 @@ mod delta_undo_tests {
|
||||||
);
|
);
|
||||||
let delta = build_delta(&scene, rec);
|
let delta = build_delta(&scene, rec);
|
||||||
assert!(scene.document.get_entity(h2).is_none(), "h2 must be erased");
|
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
|
// Undo re-inserts h2 with its ORIGINAL handle and image, exactly once in
|
||||||
// the block record (the strip prevents a duplicated dangling entry),
|
// the block record (the strip prevents a duplicated dangling entry),
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,16 @@ impl Scene {
|
||||||
self.bump_selection();
|
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).
|
/// Remove a single entity from the selection (Shift+click subtractive pick).
|
||||||
pub fn deselect_entity(&mut self, handle: Handle) {
|
pub fn deselect_entity(&mut self, handle: Handle) {
|
||||||
if self.selected.remove(&handle) {
|
if self.selected.remove(&handle) {
|
||||||
|
|
@ -333,6 +343,7 @@ impl Scene {
|
||||||
pub fn erase_entities(&mut self, handles: &[Handle]) {
|
pub fn erase_entities(&mut self, handles: &[Handle]) {
|
||||||
let mut handle_set: HashSet<Handle> = HashSet::default();
|
let mut handle_set: HashSet<Handle> = HashSet::default();
|
||||||
let mut erased: Vec<(Handle, ChangeKind)> = Vec::new();
|
let mut erased: Vec<(Handle, ChangeKind)> = Vec::new();
|
||||||
|
let mut highlight_changed = false;
|
||||||
for &h in handles {
|
for &h in handles {
|
||||||
// Objects on a locked layer can't be erased.
|
// Objects on a locked layer can't be erased.
|
||||||
if self.is_layer_locked(h) {
|
if self.is_layer_locked(h) {
|
||||||
|
|
@ -345,7 +356,11 @@ impl Scene {
|
||||||
}
|
}
|
||||||
self.remember_removed_cache_categories(h);
|
self.remember_removed_cache_categories(h);
|
||||||
self.document.remove_entity_arc(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.hatches.remove(&h);
|
||||||
self.images.remove(&h);
|
self.images.remove(&h);
|
||||||
self.meshes.remove(&h);
|
self.meshes.remove(&h);
|
||||||
|
|
@ -354,6 +369,9 @@ impl Scene {
|
||||||
handle_set.insert(h);
|
handle_set.insert(h);
|
||||||
erased.push((h, ChangeKind::Removed));
|
erased.push((h, ChangeKind::Removed));
|
||||||
}
|
}
|
||||||
|
if highlight_changed {
|
||||||
|
self.bump_selection();
|
||||||
|
}
|
||||||
// Capture exactly the group objects that this erase will rewrite, plus
|
// Capture exactly the group objects that this erase will rewrite, plus
|
||||||
// the group dictionary when an emptied group will be removed. Do this
|
// the group dictionary when an emptied group will be removed. Do this
|
||||||
// before taking mutable object-map borrows below.
|
// before taking mutable object-map borrows below.
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue