UsdLayerManager/openspec/changes/undo-redo-scene-editing/specs/command-history/spec.md

65 lines
3.5 KiB
Markdown

## ADDED Requirements
### Requirement: ICommand interface
The system SHALL provide an `ICommand` pure-virtual interface with `Execute()`, `Undo()`, and `GetDescription()` methods that all reversible operations implement.
#### Scenario: Execute runs the operation
- **WHEN** `ICommand::Execute()` is called on a newly created command
- **THEN** the operation is applied to the USD stage and the scene reflects the new state
#### Scenario: Undo reverses the operation
- **WHEN** `ICommand::Undo()` is called after `Execute()`
- **THEN** the USD stage returns to the state it was in before `Execute()` was called
### Requirement: CommandHistory stack management
The system SHALL maintain two stacks (undo stack, redo stack). `Push(cmd)` executes the command, pushes it onto the undo stack, and clears the redo stack. `Undo()` pops from the undo stack, calls `Undo()` on the command, and pushes it onto the redo stack. `Redo()` pops from the redo stack, calls `Execute()` on the command, and pushes it back onto the undo stack.
#### Scenario: Push clears redo stack
- **WHEN** the user undoes two steps and then makes a new edit
- **THEN** the redo stack is cleared and the new command is the top of the undo stack
#### Scenario: Undo with empty stack is a no-op
- **WHEN** `CommandHistory::Undo()` is called and the undo stack is empty
- **THEN** no crash occurs and the scene is unchanged
#### Scenario: Redo with empty stack is a no-op
- **WHEN** `CommandHistory::Redo()` is called and the redo stack is empty
- **THEN** no crash occurs and the scene is unchanged
### Requirement: Ctrl+Z / Ctrl+Y hotkeys
The application SHALL process `Ctrl+Z` to invoke `Undo()` and `Ctrl+Y` (and `Ctrl+Shift+Z`) to invoke `Redo()` during the ImGui main loop, unless an ImGui text input widget has keyboard focus.
#### Scenario: Ctrl+Z triggers undo
- **WHEN** the user presses `Ctrl+Z` and the undo stack is non-empty
- **THEN** the most recent command is undone and the viewport reflects the reverted state
#### Scenario: Ctrl+Y triggers redo
- **WHEN** the user presses `Ctrl+Y` and the redo stack is non-empty
- **THEN** the most recent undone command is reapplied and the viewport reflects the restored state
#### Scenario: Hotkeys ignored in text inputs
- **WHEN** an ImGui `InputText` widget has keyboard focus and the user presses `Ctrl+Z`
- **THEN** ImGui handles the keypress as text-widget undo and `CommandHistory::Undo()` is NOT called
### Requirement: Edit menu Undo/Redo items
The application SHALL provide **Edit → Undo** and **Edit → Redo** menu items. Each item SHALL display the description of the command that would be affected. Items SHALL be greyed out (disabled) when the respective stack is empty.
#### Scenario: Undo item shows command description
- **WHEN** the undo stack is non-empty and the Edit menu is opened
- **THEN** the Undo item reads "Undo: <description of top command>" and is enabled
#### Scenario: Undo item disabled when stack empty
- **WHEN** the undo stack is empty and the Edit menu is opened
- **THEN** the Undo item is greyed out and clicking it has no effect
### Requirement: History cleared on stage lifecycle events
The system SHALL call `CommandHistory::Clear()` whenever a stage is opened, closed, or replaced, so that stale USD object references cannot be dereferenced.
#### Scenario: History clears on stage open
- **WHEN** the user opens a new USD file
- **THEN** both undo and redo stacks are empty after the stage loads
#### Scenario: History clears on stage close
- **WHEN** the user closes the current stage
- **THEN** both undo and redo stacks are empty