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:
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user