## 1. Core Command Infrastructure - [x] 1.1 Create `src/core/CommandHistory.h` — define `ICommand` pure-virtual interface (`Execute`, `Undo`, `GetDescription`) and `CommandHistory` class with `Push`, `Undo`, `Redo`, `Clear`, `CanUndo`, `CanRedo`, `GetUndoDescription`, `GetRedoDescription` - [x] 1.2 Create `src/core/CommandHistory.cpp` — implement `CommandHistory` with undo/redo stacks (`std::vector>`); `Push` executes command, pushes to undo stack, clears redo stack - [x] 1.3 Add `CommandHistory` as a member of `Application` and pass `CommandHistory*` into all panel and manager constructors/init methods - [x] 1.4 Call `m_commandHistory.Clear()` inside `Application::RefreshManagers()` so history resets on every stage lifecycle event - [x] 1.5 Add `CMakeLists.txt` entries for all new source files (`CommandHistory.cpp` and all command `.cpp` files added in subsequent tasks) ## 2. Transform Commands - [x] 2.1 Create `src/core/commands/TransformCommand.h/.cpp` — stores prim `SdfPath`, `SdfLayerHandle` edit target, and pre/post TRS (`GfVec3d` translate, `GfVec3f` rotate, `GfVec3f` scale); `Execute()` applies post-values, `Undo()` applies pre-values via `UsdGeomXformCommonAPI` + `UsdEditContext` - [x] 2.2 Modify `TransformManipulator` — accept `CommandHistory*` in constructor/init; on drag-begin snapshot TRS into `m_dragStartTRS`; on drag-end (detect `wasDrawing && !m_isDragging`) push `TransformCommand` only when delta is non-zero - [x] 2.3 Modify `PropertyPanel` — accept `CommandHistory*`; capture pre-edit TRS before field edit begins; push `TransformCommand` inside `ImGui::IsItemDeactivatedAfterEdit()` blocks for translate, rotate, and scale fields ## 3. Scene Hierarchy Commands - [x] 3.1 Create `src/core/commands/CreatePrimCommand.h/.cpp` — stores `SdfPath`, `TfToken typeName`, `SdfLayerHandle`; `Execute()` calls `stage->DefinePrim`; `Undo()` calls `stage->RemovePrim` - [x] 3.2 Create `src/core/commands/DeletePrimCommand.h/.cpp` — on construction serialises the target prim's spec via `SdfCopySpec` into an anonymous layer; `Execute()` removes the prim; `Undo()` restores from the anonymous layer via `SdfCopySpec` - [x] 3.3 Create `src/core/commands/AddReferenceCommand.h/.cpp` — stores created prim path and `SdfReference`; `Execute()` wraps in Xform and adds reference; `Undo()` removes the prim - [x] 3.4 Create `src/core/commands/ReplaceReferenceCommand.h/.cpp` — stores prim path, old `SdfReference`, new `SdfReference`; `Execute()` applies new reference; `Undo()` restores old - [x] 3.5 Modify `SceneHierarchyPanel` — accept `CommandHistory*`; replace direct `Application::CreatePrimOnStage` calls with `Push(CreatePrimCommand)`; replace direct delete with `Push(DeletePrimCommand)`; replace `AddReferenceToStage` with `Push(AddReferenceCommand)`; replace `ProcessPendingReplaceRef` with `Push(ReplaceReferenceCommand)` ## 4. Attribute Edit Commands - [x] 4.1 Create `src/core/commands/AttributeSetCommand.h/.cpp` — stores `std::string description`, `std::function executeFunc`, `std::function undoFunc`; captures old value before set using `UsdAttribute::Get` at the call site - [ ] 4.2 Modify `PropertyManager::SetPropertyValue` and `SetPropertyValueInLayer` — read old value, construct `AttributeSetCommand` with closures for old/new applies, push to `CommandHistory` ## 5. Layer Operation Commands - [x] 5.1 Create `src/core/commands/LayerCreateCommand.h/.cpp` — stores layer file path and insertion index; `Execute()` calls `LayerManager::CreateSublayer`; `Undo()` calls `LayerManager::RemoveSublayer` - [x] 5.2 Create `src/core/commands/LayerRemoveCommand.h/.cpp` — stores layer path and original index; `Execute()` removes; `Undo()` re-inserts at saved index - [x] 5.3 Create `src/core/commands/LayerReorderCommand.h/.cpp` — stores full ordered-path list before and after; `Execute()` applies new order; `Undo()` restores old order by rewriting `rootLayer->GetSubLayerPaths()` - [x] 5.4 Modify `LayerPanel` — accept `CommandHistory*`; wrap Create, Remove, MoveUp, and MoveDown calls with the corresponding commands ## 6. Hotkeys and Menu Integration - [x] 6.1 In `Application`'s main-loop (or `ImGuiContext`), detect `Ctrl+Z` and `Ctrl+Y` / `Ctrl+Shift+Z` key combinations when no ImGui text widget has input focus (`!ImGui::GetIO().WantTextInput`); call `m_commandHistory.Undo()` / `m_commandHistory.Redo()` accordingly - [x] 6.2 Add **Edit** menu (or extend existing menu bar) with **Undo** and **Redo** items; display `GetUndoDescription()` / `GetRedoDescription()` in item labels; disable items via `ImGui::BeginDisabled(!CanUndo())` / `(!CanRedo())` ## 7. Build and Verification - [x] 7.1 Run `cmake --preset default` and `cmake --build build --config Release` — compilation succeeds; LNK1104 only occurs because `UsdLayerManager.exe` is currently running (expected) - [ ] 7.2 Run `cmake --install build --config Release` and launch `install/bin/App.exe`; manually verify: create a prim, undo removes it, redo restores it - [ ] 7.3 Manually verify gizmo drag undo: translate a prim with the Move gizmo, press Ctrl+Z, confirm prim returns to original position - [ ] 7.4 Run `ctest --test-dir build -C Release` and confirm all tests pass