diff --git a/src/app/commands/count.rs b/src/app/commands/count.rs index 642fc031f..2dd406536 100644 --- a/src/app/commands/count.rs +++ b/src/app/commands/count.rs @@ -546,6 +546,9 @@ impl OpenCADStudio { /// its attributes and the texts of its block definition; a table, the /// cell texts of its drawing (its `*T` block). fn update_fields(&mut self, i: usize, handles: &[Handle]) { + // Every run is an undo step, as in the reference, even with nothing + // selected, no field found or no value changed. + self.push_undo_mark(i, "UPDATEFIELD"); if handles.is_empty() { return; } @@ -588,7 +591,6 @@ impl OpenCADStudio { } // The reference counts fields, not the texts holding them, and // reports every field it evaluated as updated, changed or not. - self.push_undo_snapshot(i, "UPDATEFIELD"); let (changed, found) = self.tabs[i].scene.update_fields(32, Some(&hosts)); if changed > 0 { self.tabs[i].dirty = true; diff --git a/src/app/document.rs b/src/app/document.rs index bc47e8ea0..f9bef2bbb 100644 --- a/src/app/document.rs +++ b/src/app/document.rs @@ -901,4 +901,6 @@ pub(super) struct PendingHistorySnapshot { pub(super) dirty_before: bool, pub(super) structure_before: CadDocument, pub(super) recorder: Arc, + /// Kept as an undo step even when nothing changed. + pub(super) keep_empty: bool, } diff --git a/src/app/history.rs b/src/app/history.rs index ef97360a3..ffe243c3c 100644 --- a/src/app/history.rs +++ b/src/app/history.rs @@ -313,7 +313,8 @@ impl OpenCADStudio { let selected_after: Vec = self.tabs[i].scene.selected.iter().copied().collect(); let dirty_after = self.tabs[i].dirty; let active_layer_after = self.tabs[i].active_layer.clone(); - if entities.is_empty() + if !pending.keep_empty + && entities.is_empty() && !structure_changed && pending.selected_before == selected_after && pending.dirty_before == dirty_after @@ -365,9 +366,19 @@ impl OpenCADStudio { dirty_before, structure_before, recorder, + keep_empty: false, }); } + /// [`Self::push_undo_snapshot`] for a command that is an undo step even + /// when it changes nothing (UNDO and U then name it and undo nothing). + pub(super) fn push_undo_mark(&mut self, i: usize, label: impl Into) { + self.push_undo_snapshot(i, label); + if let Some(pending) = self.tabs[i].history.pending.as_mut() { + pending.keep_empty = true; + } + } + /// Begin undo capture for an entity edit that will touch `touched` entities. /// Starts a cheap Scene delta recording and returns the pre-command state to /// pass to [`OpenCADStudio::commit_undo_delta`] after the mutation. A command diff --git a/src/modules/annotate/count_cmd.rs b/src/modules/annotate/count_cmd.rs index 9ac6c3d3f..60833d8b2 100644 --- a/src/modules/annotate/count_cmd.rs +++ b/src/modules/annotate/count_cmd.rs @@ -434,9 +434,7 @@ impl CadCommand for UpdateFieldCommand { } fn on_enter(&mut self) -> CmdResult { - if self.selected.is_empty() { - return CmdResult::Cancel; - } + // An empty selection still runs (the reference keeps an undo step). let handles: Vec = self.selected.iter().map(|h| format!("{:X}", h.value())).collect(); CmdResult::Dispatch(format!("_UPDATEFIELDRUN {}", handles.join(","))) }