diff --git a/src/gui_2.py b/src/gui_2.py index 3ce1534..b800898 100644 --- a/src/gui_2.py +++ b/src/gui_2.py @@ -1,6 +1,7 @@ # gui_2.py from __future__ import annotations import tomli_w +import datetime import time import math import json @@ -32,6 +33,8 @@ from src import aggregate from src import markdown_helper from src import bg_shader from src import thinking_parser +from src import history +import typing import re import difflib import subprocess @@ -45,7 +48,7 @@ else: from pydantic import BaseModel from imgui_bundle import imgui, hello_imgui, immapp, imgui_node_editor as ed, imgui_color_text_edit as ced -from src.imgui_scopes import imgui_begin, imgui_begin_child, imgui_begin_table, imgui_begin_menu_bar, imgui_begin_menu, imgui_begin_popup, imgui_begin_tooltip, imgui_begin_group, node_begin +from src import imgui_scopes as imscope COMMS_CLAMP_CHARS: int = 300 @@ -603,6 +606,7 @@ class App: imgui.push_style_color(imgui.Col_.child_bg, vec4(40, 35, 25, 180)) imgui.push_style_color(imgui.Col_.text, vec4(200, 200, 150)) imgui.indent() + show_content = True if not is_standalone: header_label = f"Monologue ({len(segments)} traces)###thinking_header_{entry_index}" @@ -610,21 +614,19 @@ class App: if show_content: h = 150 if is_standalone else 100 - imgui.begin_child(f"thinking_content_{entry_index}", imgui.ImVec2(0, h), True) + imscope.child(f"thinking_content_{entry_index}", imgui.ImVec2(0, h), True) for idx, seg in enumerate(segments): content = seg.get("content", "") - marker = seg.get("marker", "thinking") - imgui.push_id(f"think_{entry_index}_{idx}") + marker = seg.get("marker", "thinking") + imscope.id(f"think_{entry_index}_{idx}") imgui.text_colored(vec4(180, 150, 80), f"[{marker}]") if self.ui_word_wrap: - imgui.push_text_wrap_pos(imgui.get_content_region_avail().x) + imscope.text_wrap(imgui.get_content_region_avail().x) imgui.text_colored(vec4(200, 200, 150), content) - imgui.pop_text_wrap_pos() else: imgui.text_colored(vec4(200, 200, 150), content) - imgui.pop_id() imgui.separator() - imgui.end_child() + imgui.unindent() imgui.pop_style_color(2) @@ -779,38 +781,35 @@ class App: [C: tests/test_shader_live_editor.py:test_shader_live_editor_renders] """ if self.show_windows.get('Shader Editor', False): - _, opened = imgui_begin('Shader Editor', self.show_windows['Shader Editor']) - self.show_windows['Shader Editor'] = bool(opened) - if opened: - changed_crt, self.shader_uniforms['crt'] = imgui.slider_float('CRT Curvature', self.shader_uniforms['crt'], 0.0, 2.0) - changed_scan, self.shader_uniforms['scanline'] = imgui.slider_float('Scanline Intensity', self.shader_uniforms['scanline'], 0.0, 1.0) - changed_bloom, self.shader_uniforms['bloom'] = imgui.slider_float('Bloom Threshold', self.shader_uniforms['bloom'], 0.0, 1.0) + with imscope.window('Shader Editor', self.show_windows['Shader Editor']) as (exp, opened): + self.show_windows['Shader Editor'] = bool(opened) + if exp: + changed_crt, self.shader_uniforms['crt'] = imgui.slider_float('CRT Curvature', self.shader_uniforms['crt'], 0.0, 2.0) + changed_scan, self.shader_uniforms['scanline'] = imgui.slider_float('Scanline Intensity', self.shader_uniforms['scanline'], 0.0, 1.0) + changed_bloom, self.shader_uniforms['bloom'] = imgui.slider_float('Bloom Threshold', self.shader_uniforms['bloom'], 0.0, 1.0) def _render_history_window(self) -> None: if not self.show_windows.get('Undo/Redo History', False): return - - with imgui_begin("Undo/Redo History", self.show_windows['Undo/Redo History']) as (exp, opened): - 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() - with 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_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}" - _, selected = imgui.selectable(label, False) - if selected: - self._handle_jump_to_history(actual_idx) + def iterate_history(history: typing.List[typing.Dict[str, typing.Any]]): + for i, entry in enumerate(reversed(history)): + actual_idx = len(history) - 1 - i + desc = entry.get("description", "UI Change") + ts = entry.get("timestamp", 0.0) + ts_str = datetime.datetime.fromtimestamp(ts).strftime("%H:%M:%S") + label = f"[{ts_str}] {desc}##{actual_idx}" + _, selected = imgui.selectable(label, False) + if selected: self._handle_jump_to_history(actual_idx) + with imscope.window("Undo/Redo History", self.show_windows['Undo/Redo History']) as (exp, opened): + 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() + with imscope.child("history_list", imgui.ImVec2(0, 0), True): + history = self.history.get_history() + if not history: imgui.text("No history available.") + else: iterate_history() def _gui_func(self) -> None: self._render_custom_title_bar() @@ -913,7 +912,7 @@ class App: #region: Project Settings if self.show_windows.get("Project Settings", False): - with imgui_begin("Project Settings", self.show_windows["Project Settings"]) as (exp, opened): + with imscope.window("Project Settings", self.show_windows["Project Settings"]) as (exp, opened): self.show_windows["Project Settings"] = bool(opened) if exp: if imgui.begin_tab_bar('context_hub_tabs'): @@ -1048,7 +1047,7 @@ class App: #region: AI Settings if self.show_windows.get("AI Settings", False): - with imgui_begin("AI Settings", self.show_windows["AI Settings"]) as (exp, opened): + with imscope.window("AI Settings", self.show_windows["AI Settings"]) as (exp, opened): self.show_windows["AI Settings"] = bool(opened) if exp: self._render_persona_selector_panel() diff --git a/src/imgui_scopes.py b/src/imgui_scopes.py index 9024ad4..b58db45 100644 --- a/src/imgui_scopes.py +++ b/src/imgui_scopes.py @@ -2,146 +2,115 @@ from __future__ import annotations from imgui_bundle import imgui from imgui_bundle import imgui_node_editor - -def imgui_begin(name: str, visible: bool = True, flags: int = 0): - return _ImguiBegin(name, visible, flags) - - -class _ImguiBegin: +def window(name: str, visible: bool = True, flags: int = 0): return _ScopeWindow(name, visible, flags) +class _ScopeWindow: def __init__(self, name: str, visible: bool, flags: int): self._name = name self._visible = visible self._flags = flags self._result = None - def __enter__(self): self._result = imgui.begin(self._name, self._visible, self._flags) return self._result - def __exit__(self, *args): imgui.end() return False - -def imgui_begin_child(id_str: str, size_x: float = 0, size_y: float = 0, flags: int = 0): - return _ImguiBeginChild(id_str, size_x, size_y, flags) - - -class _ImguiBeginChild: +def child(id_str: str, size_x: float = 0, size_y: float = 0, flags: int = 0): return _ScopeChild(id_str, size_x, size_y, flags) +class _ScopeChild: def __init__(self, id_str: str, size_x: float, size_y: float, flags: int): self._id = id_str self._sx = size_x self._sy = size_y self._flags = flags - def __enter__(self): return imgui.begin_child(self._id, self._sx, self._sy, self._flags) - def __exit__(self, *args): imgui.end_child() return False - -def imgui_begin_table(name: str, columns: int, flags: int = 0): - return _ImguiBeginTable(name, columns, flags) - - -class _ImguiBeginTable: +def table(name: str, columns: int, flags: int = 0): return _ScopeTable(name, columns, flags) +class _ScopeTable: def __init__(self, name: str, columns: int, flags: int): self._name = name self._columns = columns self._flags = flags - def __enter__(self): return imgui.begin_table(self._name, self._columns, self._flags) - def __exit__(self, *args): imgui.end_table() return False - -def imgui_begin_menu_bar(): - return _ImguiBeginMenuBar() - - -class _ImguiBeginMenuBar: +def menu_bar(): return _ScopeMenuBar() +class _ScopeMenuBar: def __enter__(self): return imgui.begin_menu_bar() - def __exit__(self, *args): imgui.end_menu_bar() return False - -def imgui_begin_menu(label: str): - return _ImguiBeginMenu(label) - - -class _ImguiBeginMenu: +def menu(label: str): return _ScopeMenu(label) +class _ScopeMenu: def __init__(self, label: str): self._label = label - def __enter__(self): return imgui.begin_menu(self._label) - def __exit__(self, *args): imgui.end_menu() return False - -def imgui_begin_popup(id_str: str): - return _ImguiBeginPopup(id_str) - - -class _ImguiBeginPopup: +def popup(id_str: str): return _ScopePopup(id_str) +class _ScopePopup: def __init__(self, id_str: str): self._id = id_str - def __enter__(self): return imgui.begin_popup(self._id) - def __exit__(self, *args): imgui.end_popup() return False - -def imgui_begin_tooltip(): - return _ImguiBeginTooltip() - - -class _ImguiBeginTooltip: +def tooltip(): return _ScopeTooltip() +class _ScopeTooltip: def __enter__(self): return imgui.begin_tooltip() - def __exit__(self, *args): imgui.end_tooltip() return False - -def imgui_begin_group(): - return _ImguiBeginGroup() - - -class _ImguiBeginGroup: +def group(): return _ScopeGroup() +class _ScopeGroup: def __enter__(self): return imgui.begin_group() - def __exit__(self, *args): imgui.end_group() return False - -def node_begin(name: str): - return _NodeBegin(name) - - -class _NodeBegin: +def node(name: str): return _ScopeNode(name) +class _ScopeNode: def __init__(self, name: str): self._name = name - def __enter__(self): return imgui_node_editor.begin(self._name) - def __exit__(self, *args): imgui_node_editor.end() - return False \ No newline at end of file + return False + +def text_wrap(wrap_pos: float = 0.0): return _ScopeTextWrap(wrap_pos) +class _ScopeTextWrap: + def __init__(self, wrap_pos: float): + self._wrap_pos = wrap_pos + def __enter__(self): + imgui.push_text_wrap_pos(self._wrap_pos) + def __exit__(self, *args): + imgui.pop_text_wrap_pos() + return False + +def id(str_id: str): return _ScopeId(str_id) +class _ScopeId: + def __init__(self, str_id: str): + self._id = str_id + def __enter__(self): + imgui.push_id(self._id) + def __exit__(self, *args): + imgui.pop_id() + return False