conductor(checkpoint): Checkpoint end of Phase 4 - UI Features & History List
This commit is contained in:
@@ -229,6 +229,7 @@ class App:
|
||||
self.show_windows.setdefault("Tier 4: QA", False)
|
||||
self.show_windows.setdefault('External Tools', False)
|
||||
self.show_windows.setdefault('Shader Editor', False)
|
||||
self.show_windows.setdefault('Undo/Redo History', False)
|
||||
self.ui_multi_viewport = gui_cfg.get("multi_viewport", False)
|
||||
self.layout_presets = self.config.get("layout_presets", {})
|
||||
self._new_preset_name = ""
|
||||
@@ -357,6 +358,14 @@ class App:
|
||||
sys.stderr.flush()
|
||||
self._apply_snapshot(entry.state)
|
||||
|
||||
def _handle_jump_to_history(self, index: int) -> None:
|
||||
sys.stderr.write(f"[DEBUG History] Jumping to index {index}\n")
|
||||
sys.stderr.flush()
|
||||
current = self._take_snapshot()
|
||||
entry = self.history.jump_to_undo(index, current, "Before Jump")
|
||||
if entry:
|
||||
self._apply_snapshot(entry.state)
|
||||
|
||||
def _handle_redo(self) -> None:
|
||||
sys.stderr.write(f"[DEBUG History] _handle_redo called. can_redo={self.history.can_redo}\n")
|
||||
sys.stderr.flush()
|
||||
@@ -654,9 +663,43 @@ class App:
|
||||
changed_bloom, self.shader_uniforms['bloom'] = imgui.slider_float('Bloom Threshold', self.shader_uniforms['bloom'], 0.0, 1.0)
|
||||
imgui.end()
|
||||
|
||||
def _render_history_window(self) -> None:
|
||||
if not self.show_windows.get('Undo/Redo History', False):
|
||||
return
|
||||
|
||||
exp, opened = imgui.begin("Undo/Redo History", self.show_windows['Undo/Redo History'])
|
||||
self.show_windows['Undo/Redo History'] = bool(opened)
|
||||
if exp:
|
||||
if imgui.button("Undo") and self.history.can_undo:
|
||||
self._handle_undo()
|
||||
imgui.same_line()
|
||||
if imgui.button("Redo") and self.history.can_redo:
|
||||
self._handle_redo()
|
||||
|
||||
imgui.separator()
|
||||
imgui.begin_child("history_list", imgui.ImVec2(0, 0), True)
|
||||
history = self.history.get_history()
|
||||
if not history:
|
||||
imgui.text("No history available.")
|
||||
else:
|
||||
for i, entry in enumerate(reversed(history)):
|
||||
# Actual index in undo stack
|
||||
actual_idx = len(history) - 1 - i
|
||||
desc = entry.get("description", "UI Change")
|
||||
ts = entry.get("timestamp", 0.0)
|
||||
import datetime
|
||||
ts_str = datetime.datetime.fromtimestamp(ts).strftime("%H:%M:%S")
|
||||
|
||||
label = f"[{ts_str}] {desc}##{actual_idx}"
|
||||
if imgui.selectable(label)[0]:
|
||||
self._handle_jump_to_history(actual_idx)
|
||||
imgui.end_child()
|
||||
imgui.end()
|
||||
|
||||
def _gui_func(self) -> None:
|
||||
self._render_custom_title_bar()
|
||||
self._render_shader_live_editor()
|
||||
self._render_history_window()
|
||||
pushed_prior_tint = False
|
||||
# Render background shader
|
||||
bg = bg_shader.get_bg()
|
||||
|
||||
@@ -112,3 +112,20 @@ class HistoryManager:
|
||||
{"description": e.description, "timestamp": e.timestamp}
|
||||
for e in self._undo_stack
|
||||
]
|
||||
|
||||
def jump_to_undo(self, index: int, current_state: typing.Any, current_description: str = "Before Jump") -> typing.Optional[HistoryEntry]:
|
||||
"""
|
||||
Jumps to a specific state in the undo stack by moving subsequent states
|
||||
and the current_state to the redo stack.
|
||||
"""
|
||||
if index < 0 or index >= len(self._undo_stack):
|
||||
return None
|
||||
|
||||
# Move current state to redo
|
||||
self._redo_stack.append(HistoryEntry(state=current_state, description=current_description))
|
||||
|
||||
# Move states between index and top of undo to redo
|
||||
while len(self._undo_stack) > index + 1:
|
||||
self._redo_stack.append(self._undo_stack.pop())
|
||||
|
||||
return self._undo_stack.pop()
|
||||
|
||||
@@ -73,3 +73,21 @@ def test_redo_cleared_on_push():
|
||||
assert hm.can_redo is True
|
||||
hm.push("S2", "D2")
|
||||
assert hm.can_redo is False
|
||||
|
||||
def test_jump_to_undo():
|
||||
hm = HistoryManager(max_capacity=10)
|
||||
hm.push("S0", "D0")
|
||||
hm.push("S1", "D1")
|
||||
hm.push("S2", "D2")
|
||||
hm.push("S3", "D3")
|
||||
|
||||
# Current state is S4
|
||||
# Jump to S1 (index 1)
|
||||
entry = hm.jump_to_undo(1, "S4", "Before Jump")
|
||||
assert entry.state == "S1"
|
||||
assert hm.can_undo is True # S0 is still there
|
||||
assert len(hm._undo_stack) == 1
|
||||
assert hm.can_redo is True
|
||||
# Redo stack should have [S4, S3, S2]
|
||||
assert len(hm._redo_stack) == 3
|
||||
assert hm._redo_stack[-1].state == "S2"
|
||||
|
||||
Reference in New Issue
Block a user