feat(gui): Refactor text viewer to use rich rendering and toolbar
This commit is contained in:
38
src/gui_2.py
38
src/gui_2.py
@@ -40,7 +40,7 @@ else:
|
|||||||
win32con = None
|
win32con = None
|
||||||
|
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
from imgui_bundle import imgui, hello_imgui, immapp, imgui_node_editor as ed
|
from imgui_bundle import imgui, hello_imgui, immapp, imgui_node_editor as ed, imgui_color_text_edit as ced
|
||||||
|
|
||||||
PROVIDERS: list[str] = ["gemini", "anthropic", "gemini_cli", "deepseek", "minimax"]
|
PROVIDERS: list[str] = ["gemini", "anthropic", "gemini_cli", "deepseek", "minimax"]
|
||||||
COMMS_CLAMP_CHARS: int = 300
|
COMMS_CLAMP_CHARS: int = 300
|
||||||
@@ -107,6 +107,7 @@ class App:
|
|||||||
self.controller.init_state()
|
self.controller.init_state()
|
||||||
self.show_windows.setdefault("Diagnostics", False)
|
self.show_windows.setdefault("Diagnostics", False)
|
||||||
self.controller.start_services(self)
|
self.controller.start_services(self)
|
||||||
|
self.controller._predefined_callbacks['_render_text_viewer'] = self._render_text_viewer
|
||||||
self.show_preset_manager_window = False
|
self.show_preset_manager_window = False
|
||||||
self.show_tool_preset_manager_window = False
|
self.show_tool_preset_manager_window = False
|
||||||
self.show_persona_editor_window = False
|
self.show_persona_editor_window = False
|
||||||
@@ -115,6 +116,7 @@ class App:
|
|||||||
self.text_viewer_content = ''
|
self.text_viewer_content = ''
|
||||||
self.text_viewer_type = 'text'
|
self.text_viewer_type = 'text'
|
||||||
self.text_viewer_wrap = True
|
self.text_viewer_wrap = True
|
||||||
|
self._text_viewer_editor: Optional[ced.TextEditor] = None
|
||||||
self.ui_active_tool_preset = ""
|
self.ui_active_tool_preset = ""
|
||||||
self.ui_active_bias_profile = ""
|
self.ui_active_bias_profile = ""
|
||||||
self.ui_active_persona = ""
|
self.ui_active_persona = ""
|
||||||
@@ -286,9 +288,9 @@ class App:
|
|||||||
f.write(data)
|
f.write(data)
|
||||||
# ---------------------------------------------------------------- helpers
|
# ---------------------------------------------------------------- helpers
|
||||||
|
|
||||||
def _render_text_viewer(self, label: str, content: str, text_type: str = 'text') -> None:
|
def _render_text_viewer(self, label: str, content: str, text_type: str = 'text', force_open: bool = False) -> None:
|
||||||
self.text_viewer_type = text_type
|
self.text_viewer_type = text_type
|
||||||
if imgui.button("[+]##" + str(id(content))):
|
if imgui.button("[+]##" + str(id(content))) or force_open:
|
||||||
self.show_text_viewer = True
|
self.show_text_viewer = True
|
||||||
self.text_viewer_title = label
|
self.text_viewer_title = label
|
||||||
self.text_viewer_content = content
|
self.text_viewer_content = content
|
||||||
@@ -1003,7 +1005,35 @@ class App:
|
|||||||
expanded, opened = imgui.begin(f"Text Viewer - {self.text_viewer_title}", self.show_text_viewer)
|
expanded, opened = imgui.begin(f"Text Viewer - {self.text_viewer_title}", self.show_text_viewer)
|
||||||
self.show_text_viewer = bool(opened)
|
self.show_text_viewer = bool(opened)
|
||||||
if expanded:
|
if expanded:
|
||||||
if self.ui_word_wrap:
|
# Toolbar
|
||||||
|
if imgui.button("Copy"):
|
||||||
|
imgui.set_clipboard_text(self.text_viewer_content)
|
||||||
|
imgui.same_line()
|
||||||
|
_, self.text_viewer_wrap = imgui.checkbox("Word Wrap", self.text_viewer_wrap)
|
||||||
|
imgui.separator()
|
||||||
|
|
||||||
|
renderer = markdown_helper.get_renderer()
|
||||||
|
tv_type = getattr(self, "text_viewer_type", "text")
|
||||||
|
|
||||||
|
if tv_type == 'markdown':
|
||||||
|
imgui.begin_child("tv_md_scroll", imgui.ImVec2(-1, -1), True)
|
||||||
|
markdown_helper.render(self.text_viewer_content, context_id='text_viewer')
|
||||||
|
imgui.end_child()
|
||||||
|
elif tv_type in renderer._lang_map:
|
||||||
|
if self._text_viewer_editor is None:
|
||||||
|
self._text_viewer_editor = ced.TextEditor()
|
||||||
|
self._text_viewer_editor.set_read_only_enabled(True)
|
||||||
|
self._text_viewer_editor.set_show_line_numbers_enabled(True)
|
||||||
|
|
||||||
|
# Sync text and language
|
||||||
|
lang_id = renderer._lang_map[tv_type]
|
||||||
|
if self._text_viewer_editor.get_text().strip() != self.text_viewer_content.strip():
|
||||||
|
self._text_viewer_editor.set_text(self.text_viewer_content)
|
||||||
|
self._text_viewer_editor.set_language_definition(lang_id)
|
||||||
|
|
||||||
|
self._text_viewer_editor.render('##tv_editor', a_size=imgui.ImVec2(-1, -1))
|
||||||
|
else:
|
||||||
|
if self.text_viewer_wrap:
|
||||||
imgui.begin_child("tv_wrap", imgui.ImVec2(-1, -1), False)
|
imgui.begin_child("tv_wrap", imgui.ImVec2(-1, -1), False)
|
||||||
imgui.push_text_wrap_pos(imgui.get_content_region_avail().x)
|
imgui.push_text_wrap_pos(imgui.get_content_region_avail().x)
|
||||||
imgui.text(self.text_viewer_content)
|
imgui.text(self.text_viewer_content)
|
||||||
|
|||||||
28
tests/test_gui_text_viewer.py
Normal file
28
tests/test_gui_text_viewer.py
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
import pytest
|
||||||
|
import time
|
||||||
|
from src.api_hook_client import ApiHookClient
|
||||||
|
|
||||||
|
def test_text_viewer_state_update(live_gui) -> None:
|
||||||
|
"""
|
||||||
|
Verifies that we can set text viewer state and it is reflected in GUI state.
|
||||||
|
"""
|
||||||
|
client = ApiHookClient()
|
||||||
|
label = "Test Viewer Label"
|
||||||
|
content = "This is test content for the viewer."
|
||||||
|
text_type = "markdown"
|
||||||
|
|
||||||
|
# Add a task to push a custom callback that mutates the app state
|
||||||
|
def set_viewer_state(app):
|
||||||
|
app.show_text_viewer = True
|
||||||
|
app.text_viewer_title = label
|
||||||
|
app.text_viewer_content = content
|
||||||
|
app.text_viewer_type = text_type
|
||||||
|
|
||||||
|
client.push_event("custom_callback", {"callback": set_viewer_state})
|
||||||
|
time.sleep(0.5)
|
||||||
|
|
||||||
|
state = client.get_gui_state()
|
||||||
|
assert state is not None
|
||||||
|
assert state.get('show_text_viewer') == True
|
||||||
|
assert state.get('text_viewer_title') == label
|
||||||
|
assert state.get('text_viewer_type') == text_type
|
||||||
Reference in New Issue
Block a user