Private
Public Access
0
0

fix(gui): Final Phase 7 stabilization and polish

- Resolve ImportError by correctly prefixing 'src' in modular renderers.
- Fix ImGui access violation by ensuring push_id always receives string IDs.
- Restore visible role-based background tints using layered rendering (channels).
- Definitively fix horizontal Markdown table widths by forcing group expansion.
- Centralize color management in theme_2.py and ui_shared.py.
- Standardize Files & Media inventory layout and remove legacy controls.
- Update test mocks to support modular UI and theme-driven styling.
This commit is contained in:
2026-06-02 13:27:38 -04:00
parent 46f22f0df9
commit c4811f00c1
13 changed files with 310 additions and 63 deletions
+23 -12
View File
@@ -4,16 +4,24 @@ import re
import datetime
from pathlib import Path
from typing import TYPE_CHECKING, Any
from src import imscope, theme_2 as theme, project_manager, mcp_client, ui_shared
from src import imgui_scopes as imscope, theme_2 as theme, project_manager, mcp_client, ui_shared, markdown_helper
if TYPE_CHECKING:
from src.gui_2 import App
def get_role_tint(role: str) -> imgui.ImVec4:
"""Returns a subtle background tint color based on the message role."""
# Tints: User(Blue), AI(Green), Vendor(Orange), System(Dark)
if role == "User": return imgui.ImVec4(30/255, 45/255, 75/255, 0.5)
elif role == "AI": return imgui.ImVec4(35/255, 65/255, 45/255, 0.5)
elif role == "Vendor API": return imgui.ImVec4(65/255, 55/255, 35/255, 0.5)
return imgui.ImVec4(20/255, 20/255, 20/255, 0.4)
def render_thinking_trace(app: 'App', entry: dict, segments: list[dict], entry_index: int, is_standalone: bool = False) -> None:
if not segments:
return
with imscope.style_color(imgui.Col_.child_bg, ui_shared.vec4(40, 35, 25, 180)), \
theme.ai_text_style():
# Tint thinking trace background slightly differently
with imscope.style_color(imgui.Col_.child_bg, imgui.ImVec4(40/255, 35/255, 25/255, 180/255)):
with imscope.indent():
show_content = True
if not is_standalone:
@@ -24,14 +32,14 @@ def render_thinking_trace(app: 'App', entry: dict, segments: list[dict], entry_i
if imgui.button(f"[Pure]##think_pure_{entry_index}" if thinking_read_mode else f"[Read]##think_read_{entry_index}"):
entry["thinking_read_mode"] = not thinking_read_mode
imgui.same_line()
imgui.text_colored(ui_shared.vec4(180, 150, 80), "Selectable toggle")
imgui.text_colored(ui_shared.C_TC, "Selectable toggle")
h = 150 if is_standalone else 100
with imscope.child(f"thinking_content_{entry_index}", 0, h, True):
for idx, seg in enumerate(segments):
content = seg.get("content", "")
marker = seg.get("marker", "thinking")
with imscope.id(f"think_{entry_index}_{idx}"):
imgui.text_colored(ui_shared.vec4(180, 150, 80), f"[{marker}]")
imgui.text_colored(ui_shared.C_TC, f"[{marker}]")
if thinking_read_mode:
if app.ui_word_wrap:
with imscope.text_wrap(imgui.get_content_region_avail().x):
@@ -45,7 +53,7 @@ def render_thinking_trace(app: 'App', entry: dict, segments: list[dict], entry_i
def render_discussion_entry(app: 'App', entry: dict, index: int) -> None:
with imscope.id(f"disc_{index}"):
role = entry.get("role", "User")
bg_col = theme.get_role_tint(role)
bg_col = get_role_tint(role)
draw_list = imgui.get_window_draw_list()
p_min = imgui.get_cursor_screen_pos()
@@ -81,7 +89,7 @@ def render_discussion_entry(app: 'App', entry: dict, index: int) -> None:
if usage:
inp, out, cache = usage.get("input_tokens", 0), usage.get("output_tokens", 0), usage.get("cache_read_input_tokens", 0)
u_str = f" in:{inp} out:{out}" + (f" cache:{cache}" if cache else "")
imgui.same_line(); imgui.text_colored(ui_shared.vec4(100, 150, 180), u_str)
imgui.same_line(); imgui.text_colored(imgui.ImVec4(0.4, 0.6, 0.7, 1.0), u_str)
if collapsed:
imgui.same_line()
@@ -95,15 +103,16 @@ def render_discussion_entry(app: 'App', entry: dict, index: int) -> None:
if imgui.button("Branch"): app._branch_discussion(index)
imgui.same_line(); preview = entry["content"].replace("\n", " ")[:60]
if len(entry["content"]) > 60: preview += "..."
imgui.text_colored(ui_shared.vec4(160, 160, 150), preview)
imgui.text_colored(ui_shared.C_SUB, preview)
else:
# Body content
imgui.spacing()
# Body content - FORCE START ON NEW LINE
imgui.dummy(imgui.ImVec2(0, 4))
imgui.set_cursor_pos_x(imgui.get_cursor_start_pos().x)
thinking_segments, has_content = entry.get("thinking_segments", []), bool(entry.get("content", "").strip())
if thinking_segments:
render_thinking_trace(app, entry, thinking_segments, index, is_standalone=not has_content)
imgui.spacing()
imgui.dummy(imgui.ImVec2(0, 4))
if read_mode:
render_discussion_entry_read_mode(app, entry, index)
@@ -146,7 +155,8 @@ def render_discussion_entry_read_mode(app: 'App', entry: dict, index: int) -> No
pattern = re.compile(r"\[Definition: (.*?) from (.*?) \(line (\d+)\)\](\s+```[\s\S]*?```)?")
matches = list(pattern.finditer(content))
from src import markdown_helper
# FORCE A NEW GROUP with no extra constraints
imgui.begin_group()
with theme.ai_text_style():
if not matches:
markdown_helper.render(content, context_id=f"disc_{index}")
@@ -164,3 +174,4 @@ def render_discussion_entry_read_mode(app: 'App', entry: dict, index: int) -> No
last_idx = match.end()
after = content[last_idx:]
if after: markdown_helper.render(after, context_id=f"disc_{index}_a")
imgui.end_group()