forked from 1b-agent/opencadstudio-upstream
perf: make edit history incremental
Replace full-document snapshots with Arc first-touch deltas and batch cache invalidation. Reuse interaction and GPU category caches across unrelated edits.
This commit is contained in:
1 parent
90714d34b2
commit
ea93e169ea
19 files changed
+979
-339
No files matched your search
@@ -168,10 +168,9 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
}
|
||||
// A typed grip-menu value reshapes dimensions too — drop a
|
||||
// stale baked *D block (no-op for non-dims). (#398)
|
||||
crate::modules::draw::modify::explode::invalidate_dim_block(
|
||||
&mut self.tabs[i].scene.document,
|
||||
pending.handle,
|
||||
);
|
||||
self.tabs[i]
|
||||
.scene
|
||||
.invalidate_dim_block_recorded(pending.handle);
|
||||
self.tabs[i].scene.bump_geometry();
|
||||
self.tabs[i].dirty = true;
|
||||
self.refresh_selected_grips();
|
||||
@@ -987,10 +986,9 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
}
|
||||
// Menu actions reshape dimensions too — drop a stale baked *D
|
||||
// block so the edit is visible (no-op for non-dims). (#398)
|
||||
crate::modules::draw::modify::explode::invalidate_dim_block(
|
||||
&mut self.tabs[i].scene.document,
|
||||
popup.handle,
|
||||
);
|
||||
self.tabs[i]
|
||||
.scene
|
||||
.invalidate_dim_block_recorded(popup.handle);
|
||||
self.tabs[i].scene.bump_geometry();
|
||||
self.tabs[i].dirty = true;
|
||||
self.refresh_selected_grips();
|
||||
@@ -1918,7 +1916,7 @@ pub(super) fn on_tab_close(&mut self, idx: usize) -> Task<Message> {
|
||||
self.tabs[i].dirty = true;
|
||||
} else {
|
||||
// Nothing changed — drop the snapshot pushed a moment ago.
|
||||
let _ = self.tabs[i].history.undo_stack.pop();
|
||||
self.discard_last_undo_entry(i);
|
||||
}
|
||||
self.refresh_properties();
|
||||
Task::none()
|
||||
|
||||
@@ -134,6 +134,9 @@ impl OpenCADStudio {
|
||||
}
|
||||
}
|
||||
let task = self.update_inner(msg);
|
||||
// Close the document-level first-touch transaction started by
|
||||
// push_undo_snapshot at this message boundary.
|
||||
self.finish_all_pending_history();
|
||||
// After every message, mirror the active command step's prompt so
|
||||
// its history line stays pinned (non-fading) until the step changes.
|
||||
let prompt = self.tabs[self.active_tab]
|
||||
@@ -2228,7 +2231,7 @@ impl OpenCADStudio {
|
||||
// Stash the erased entities so OOPS can restore them.
|
||||
self.oops_cache = handles
|
||||
.iter()
|
||||
.filter_map(|h| self.tabs[i].scene.document.get_entity(*h).cloned())
|
||||
.filter_map(|h| self.tabs[i].scene.document.get_entity_arc(*h))
|
||||
.collect();
|
||||
self.tabs[i].scene.erase_entities(&handles);
|
||||
self.tabs[i].dirty = true;
|
||||
|
||||
@@ -1932,29 +1932,20 @@ impl OpenCADStudio {
|
||||
// once, dropping the overlay preview.
|
||||
if let Some(h) = self.grip_preview_handle.take() {
|
||||
// Undo entry for the drag (#332): the pre-drag backup
|
||||
// swaps in, the PRE state is snapshotted, then the
|
||||
// dragged result swaps back. Without this a grip edit
|
||||
// (e.g. reshaping a polyline vertex) was un-undoable —
|
||||
// the drag mutated the document without any history.
|
||||
// and live dragged image form a one-entity Arc delta. The old
|
||||
// swap/full-document snapshot made a vertex drag O(document).
|
||||
if let Some(orig) = self.grip_original.take() {
|
||||
if let Some(e) = self.tabs[i].scene.document.get_entity_mut(h) {
|
||||
let dragged = std::mem::replace(e, orig);
|
||||
let snap = self.capture_history_snapshot(i, "GRIP");
|
||||
if let Some(e2) = self.tabs[i].scene.document.get_entity_mut(h) {
|
||||
*e2 = dragged;
|
||||
}
|
||||
self.tabs[i].history.undo_stack.push(snap);
|
||||
self.tabs[i].history.redo_stack.clear();
|
||||
self.tabs[i].dirty = true;
|
||||
}
|
||||
self.push_single_entity_history(i, "GRIP", h, std::sync::Arc::new(orig));
|
||||
self.tabs[i].dirty = true;
|
||||
}
|
||||
self.grip_text_verts = Vec::new();
|
||||
self.grip_text_slide = false;
|
||||
self.tabs[i].scene.hidden.remove(&h);
|
||||
self.tabs[i].scene.clear_preview_wire();
|
||||
// Only the dragged entity changed — re-tessellate just it.
|
||||
self.tabs[i].scene.mark_entity_dirty(h);
|
||||
self.tabs[i].scene.bump_geometry_no_blocks();
|
||||
self.tabs[i]
|
||||
.scene
|
||||
.bump_entities(&[(h, crate::scene::ChangeKind::Modified)]);
|
||||
}
|
||||
// Placement confirmed — keep the just-added leader.
|
||||
self.grip_add_provisional = None;
|
||||
|
||||
Reference in new issue
Block a user