From 7735b6cba78066986aff8785d03bbbdb959a1f3d Mon Sep 17 00:00:00 2001 From: Ed_ Date: Fri, 5 Jun 2026 00:21:19 -0400 Subject: [PATCH] feat(theme): lift all hardcoded colors and finalize semantic theming --- src/gui_2.py | 144 +++++++++++++++++++++++++-------------------------- 1 file changed, 70 insertions(+), 74 deletions(-) diff --git a/src/gui_2.py b/src/gui_2.py index 958dcb40..69df72b8 100644 --- a/src/gui_2.py +++ b/src/gui_2.py @@ -76,10 +76,6 @@ def hide_tk_root() -> Tk: root.wm_attributes("-topmost", True) return root -# Standard Color Constants (normalized to 0-1) -def vec4(r: float, g: float, b: float, a: float = 1.0) -> imgui.ImVec4: - return imgui.ImVec4(r/255.0, g/255.0, b/255.0, a) - # Standard Color Constants (now bound to the theming system) def C_OUT() -> imgui.ImVec4: return theme.get_color("status_info") def C_IN() -> imgui.ImVec4: return theme.get_color("status_success") @@ -885,7 +881,7 @@ class App: win32gui.ReleaseCapture() win32gui.SendMessage(hwnd, win32con.WM_NCLBUTTONDOWN, win32con.HTCAPTION, 0) - imgui.push_style_color(imgui.Col_.button, vec4(0, 0, 0, 0)) + imgui.push_style_color(imgui.Col_.button, imgui.ImVec4(0, 0, 0, 0)) try: is_max = win32gui.GetWindowPlacement(hwnd)[1] == win32con.SW_SHOWMAXIMIZED @@ -902,7 +898,7 @@ class App: win32gui.ShowWindow(hwnd, win32con.SW_RESTORE if is_max else win32con.SW_MAXIMIZE) imgui.set_cursor_pos((right_x + btn_w * 2, 0)) - imgui.push_style_color(imgui.Col_.button_hovered, vec4(200, 50, 50, 255)) + imgui.push_style_color(imgui.Col_.button_hovered, theme.get_color("status_error")) if imgui.button("X", (btn_w, bar_h)): win32gui.PostMessage(hwnd, win32con.WM_CLOSE, 0, 0) imgui.pop_style_color() @@ -1499,7 +1495,7 @@ def render_cache_panel(app: App) -> None: if app.current_provider != "gemini": if app.perf_profiling_enabled: app.perf_monitor.end_component("_render_cache_panel") return - imgui.text_colored(C_LBL, 'Cache Analytics') + imgui.text_colored(C_LBL(), 'Cache Analytics') stats = getattr(app.controller, '_cached_cache_stats', {}) if not stats.get("cache_exists"): imgui.text_disabled("No active cache") @@ -1528,7 +1524,7 @@ def render_cache_panel(app: App) -> None: def render_tool_analytics_panel(app: App) -> None: if app.perf_profiling_enabled: app.perf_monitor.start_component("_render_tool_analytics_panel") - imgui.text_colored(C_LBL, 'Tool Usage') + imgui.text_colored(C_LBL(), 'Tool Usage') imgui.separator() now = time.time() if not hasattr(app, '_tool_stats_cache_time') or now - app._tool_stats_cache_time > 1.0: @@ -1566,14 +1562,14 @@ def render_tool_analytics_panel(app: App) -> None: def render_token_budget_panel(app: App) -> None: if app.perf_profiling_enabled: app.perf_monitor.start_component("_render_token_budget_panel") - imgui.text_colored(C_LBL, 'Prompt Utilization') + imgui.text_colored(C_LBL(), 'Prompt Utilization') usage = app.session_usage total = usage["input_tokens"] + usage["output_tokens"] if total == 0 and usage.get("total_tokens", 0) > 0: total = usage["total_tokens"] - render_selectable_label(app, "session_telemetry_tokens", f"Tokens: {total:,} (In: {usage['input_tokens']:,} Out: {usage['output_tokens']:,})", width=-1, color=C_RES) - if usage.get("last_latency", 0.0) > 0: imgui.text_colored(C_LBL, f" Last Latency: {usage['last_latency']:.2f}s") - if usage["cache_read_input_tokens"]: imgui.text_colored(C_LBL, f" Cache Read: {usage['cache_read_input_tokens']:,} Creation: {usage['cache_creation_input_tokens']:,}") - if app._gemini_cache_text: imgui.text_colored(C_SUB, app._gemini_cache_text) + render_selectable_label(app, "session_telemetry_tokens", f"Tokens: {total:,} (In: {usage['input_tokens']:,} Out: {usage['output_tokens']:,})", width=-1, color=C_RES()) + if usage.get("last_latency", 0.0) > 0: imgui.text_colored(C_LBL(), f" Last Latency: {usage['last_latency']:.2f}s") + if usage["cache_read_input_tokens"]: imgui.text_colored(C_LBL(), f" Cache Read: {usage['cache_read_input_tokens']:,} Creation: {usage['cache_creation_input_tokens']:,}") + if app._gemini_cache_text: imgui.text_colored(C_SUB(), app._gemini_cache_text) imgui.separator() if app._token_stats_dirty: @@ -1655,7 +1651,7 @@ def render_token_budget_panel(app: App) -> None: if cache_stats.get("cache_exists"): age = cache_stats.get("cache_age_seconds", 0) ttl = cache_stats.get("ttl_seconds", 3600) - imgui.text_colored(C_LBL, f"Cache Usage: ACTIVE | Age: {age:.0f}s / {ttl}s | Renews at: {ttl * 0.9:.0f}s") + imgui.text_colored(C_LBL(), f"Cache Usage: ACTIVE | Age: {age:.0f}s / {ttl}s | Renews at: {ttl * 0.9:.0f}s") else: imgui.text_disabled("Cache Usage: INACTIVE") if app.perf_profiling_enabled: app.perf_monitor.end_component("_render_token_budget_panel") @@ -1757,7 +1753,7 @@ def render_project_settings_hub(app: App) -> None: def render_projects_panel(app: App) -> None: if app.perf_profiling_enabled: app.perf_monitor.start_component("_render_projects_panel") proj_name = app.project.get("project", {}).get("name", Path(app.active_project_path).stem) - imgui.text_colored(C_IN, f"Active: {proj_name}") + imgui.text_colored(C_IN(), f"Active: {proj_name}") imgui.separator() imgui.text("Execution Mode") modes = ["native", "beads"] @@ -1802,11 +1798,11 @@ def render_projects_panel(app: App) -> None: break imgui.same_line() marker = " *" if is_active else "" - if is_active: imgui.push_style_color(imgui.Col_.text, C_IN) + if is_active: imgui.push_style_color(imgui.Col_.text, C_IN()) if imgui.button(f"{Path(pp).stem}{marker}##ps{i}"): app._switch_project(pp) if is_active: imgui.pop_style_color() imgui.same_line() - imgui.text_colored(C_LBL, pp) + imgui.text_colored(C_LBL(), pp) imgui.end_child() if imgui.button("Add Project"): r = hide_tk_root() @@ -1843,7 +1839,7 @@ def render_paths_panel(app: App) -> None: if app.perf_profiling_enabled: app.perf_monitor.start_component("_render_paths_panel") path_info = paths.get_full_path_info() - imgui.text_colored(C_IN, "System Path Configuration") + imgui.text_colored(C_IN(), "System Path Configuration") imgui.separator() def render_path_field(label: str, attr: str, key: str, tooltip: str): @@ -2186,7 +2182,7 @@ def render_base_prompt_diff_modal(app: App) -> None: return imgui.open_popup("Base Prompt Diff") if imgui.begin_popup_modal("Base Prompt Diff", True, imgui.WindowFlags_.always_auto_resize)[0]: - imgui.text_colored(C_IN, "Difference between Default and Custom Base System Prompt") + imgui.text_colored(C_IN(), "Difference between Default and Custom Base System Prompt") imgui.separator() default_lines = ai_client._SYSTEM_PROMPT.splitlines(keepends=True) @@ -2269,7 +2265,7 @@ def render_preset_manager_content(app: App, is_embedded: bool = False) -> None: imgui.begin_child("prompt_edit_pane", imgui.ImVec2(0, avail_r.y - 45), False) if True: p_disp = app._editing_preset_name or "(New Preset)" - imgui.text_colored(C_IN, f"Editing Prompt Preset: {p_disp}") + imgui.text_colored(C_IN(), f"Editing Prompt Preset: {p_disp}") imgui.separator() if imgui.begin_table("p_meta", 2): @@ -2369,7 +2365,7 @@ def render_tool_preset_manager_content(app: App, is_embedded: bool = False) -> N imgui.begin_child("tp_editor_content", imgui.ImVec2(0, avail_r.y - 45), False) if True: p_name = app._editing_tool_preset_name or "(New Tool Preset)" - imgui.text_colored(C_IN, f"Editing Tool Preset: {p_name}"); imgui.separator() + imgui.text_colored(C_IN(), f"Editing Tool Preset: {p_name}"); imgui.separator() if imgui.begin_table("tp_meta", 2): imgui.table_setup_column("L", imgui.TableColumnFlags_.width_fixed, 80); imgui.table_setup_column("F", imgui.TableColumnFlags_.width_stretch) @@ -2564,7 +2560,7 @@ def render_persona_editor_window(app: App, is_embedded: bool = False) -> None: imgui.begin_child("persona_editor_content", imgui.ImVec2(0, avail.y - 45), False) if True: header_text = "New Persona" if getattr(app, '_editing_persona_is_new', True) else f"Editing Persona: {app._editing_persona_name}" - imgui.text_colored(C_IN, header_text); imgui.separator() + imgui.text_colored(C_IN(), header_text); imgui.separator() if imgui.begin_table("p_meta", 2): imgui.table_setup_column("L", imgui.TableColumnFlags_.width_fixed, 60); imgui.table_setup_column("F", imgui.TableColumnFlags_.width_stretch) @@ -2595,10 +2591,10 @@ def render_persona_editor_window(app: App, is_embedded: bool = False) -> None: imgui.push_id(f"pref_model_{i}") prov, mod, is_expanded = entry.get("provider", "Unknown"), entry.get("model", "Unknown"), app._persona_pref_models_expanded.get(i, False) if imgui.button("-" if is_expanded else "+"): app._persona_pref_models_expanded[i] = not is_expanded - imgui.same_line(); imgui.text(f"{i+1}."); imgui.same_line(); imgui.text_colored(C_LBL, f"{prov}"); imgui.same_line(); imgui.text("-"); imgui.same_line(); imgui.text_colored(C_IN, f"{mod}") + imgui.same_line(); imgui.text(f"{i+1}."); imgui.same_line(); imgui.text_colored(C_LBL(), f"{prov}"); imgui.same_line(); imgui.text("-"); imgui.same_line(); imgui.text_colored(C_IN(), f"{mod}") if not is_expanded: imgui.same_line(); summary = f" (T:{entry.get('temperature', 0.7):.1f}, P:{entry.get('top_p', 1.0):.2f}, M:{entry.get('max_output_tokens', 0)})" - imgui.text_colored(C_SUB, summary) + imgui.text_colored(C_SUB(), summary) imgui.same_line(imgui.get_content_region_avail().x - 30); if imgui.button("x"): to_remove.append(i) if is_expanded: @@ -2994,7 +2990,7 @@ def render_ast_inspector_modal(app: App) -> None: imgui.separator() if imgui.collapsing_header("Custom Slices", imgui.TreeNodeFlags_.default_open): if not hasattr(f_item, 'custom_slices'): f_item.custom_slices = [] - imgui.text_colored(C_IN, "Highlight lines in right pane to add slices.") + imgui.text_colored(C_IN(), "Highlight lines in right pane to add slices.") if imgui.button("Add Selection as Slice"): if getattr(app, '_slice_sel_start', -1) != -1 and getattr(app, '_slice_sel_end', -1) != -1: s_line = min(app._slice_sel_start, app._slice_sel_end) @@ -3112,7 +3108,7 @@ def render_save_workspace_profile_modal(app: App) -> None: imgui.end_popup() def render_context_presets_panel(app: App) -> None: - imgui.text_colored(C_IN, "Context Presets") + imgui.text_colored(C_IN(), "Context Presets") imgui.separator() changed, new_name = imgui.input_text("Preset Name##new_ctx", app.ui_new_context_preset_name) if changed: app.ui_new_context_preset_name = new_name @@ -3402,14 +3398,14 @@ def render_thinking_trace(app: App, entry: dict, segments: list[dict], entry_ind 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(C_TC, "Selectable toggle") + imgui.text_colored(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(C_TC, f"[{marker}]") + imgui.text_colored(C_TC(), f"[{marker}]") if thinking_read_mode: if app.ui_word_wrap: with imscope.text_wrap(imgui.get_content_region_avail().x): @@ -3455,7 +3451,7 @@ def render_discussion_entry(app: App, entry: dict, index: int) -> None: usage = entry.get("usage", {}) if ts_str or usage: imgui.same_line() - if ts_str: imgui.text_colored(C_SUB, str(ts_str)) + if ts_str: imgui.text_colored(C_SUB(), str(ts_str)) 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 "") @@ -3474,7 +3470,7 @@ 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(C_SUB, preview) + imgui.text_colored(C_SUB(), preview) else: # Body content - FORCE START ON NEW LINE to prevent horizontal squashing imgui.new_line() @@ -3575,7 +3571,7 @@ def render_history_window(app: App) -> None: def render_session_insights_panel(app: App) -> None: if app.perf_profiling_enabled: app.perf_monitor.start_component("_render_session_insights_panel") - imgui.text_colored(C_LBL, 'Session Insights') + imgui.text_colored(C_LBL(), 'Session Insights') imgui.separator() insights = app.controller.get_session_insights() imgui.text(f"Total Tokens: {insights.get('total_tokens', 0):,}") @@ -3597,7 +3593,7 @@ def render_prior_session_view(app: App) -> None: collapsed = entry.get("collapsed", False) if imgui.button("+" if collapsed else "-"): entry["collapsed"] = not collapsed imgui.same_line(); role, ts = entry.get("role", "??"), entry.get("ts", "") - imgui.text_colored(C_LBL, f"[{role}]") + imgui.text_colored(C_LBL(), f"[{role}]") if ts: imgui.same_line(); imgui.text_colored(theme.get_color("text_disabled"), str(ts)) content = entry.get("content", "") if collapsed: @@ -3613,7 +3609,7 @@ def render_thinking_indicator(app: App) -> None: if is_thinking: val = math.sin(time.time() * 10 * math.pi) alpha = 1.0 if val > 0 else 0.0 - c = vec4(255, 50, 50, alpha) if theme.is_nerv_active() else vec4(255, 100, 100, alpha) + c = theme.get_color("status_error", alpha=alpha) imgui.text_colored(c, "THINKING..."); imgui.same_line() def render_synthesis_panel(app: App) -> None: @@ -3665,13 +3661,13 @@ def render_comms_history_panel(app: App) -> None: app._comms_log_dirty = True imgui.separator() - imgui.text_colored(C_OUT, "OUT"); imgui.same_line() - imgui.text_colored(C_REQ, "request"); imgui.same_line() - imgui.text_colored(C_TC, "tool_call"); imgui.same_line() + imgui.text_colored(C_OUT(), "OUT"); imgui.same_line() + imgui.text_colored(C_REQ(), "request"); imgui.same_line() + imgui.text_colored(C_TC(), "tool_call"); imgui.same_line() imgui.text(" "); imgui.same_line() - imgui.text_colored(C_IN, "IN"); imgui.same_line() - imgui.text_colored(C_RES, "response"); imgui.same_line() - imgui.text_colored(C_TR, "tool_result") + imgui.text_colored(C_IN(), "IN"); imgui.same_line() + imgui.text_colored(C_RES(), "response"); imgui.same_line() + imgui.text_colored(C_TR(), "tool_result") imgui.separator() avail = imgui.get_content_region_avail() @@ -3693,25 +3689,25 @@ def render_comms_history_panel(app: App) -> None: payload = entry # legacy # Row 1: #Idx TS DIR KIND Provider/Model [Tier] - imgui.text_colored(C_LBL, f"#{i_display}"); imgui.same_line() + imgui.text_colored(C_LBL(), f"#{i_display}"); imgui.same_line() imgui.text_colored(theme.get_color("text_disabled"), ts) latency = entry.get("latency") or entry.get("metadata", {}).get("latency") if latency: imgui.same_line() - imgui.text_colored(C_SUB, f" ({latency:.2f}s)") + imgui.text_colored(C_SUB(), f" ({latency:.2f}s)") ticket_id = entry.get("mma_ticket_id") if ticket_id: imgui.same_line() imgui.text_colored(theme.get_color("status_error"), f"[{ticket_id}]") imgui.same_line() - d_col = DIR_COLORS.get(direction, C_VAL) + d_col = DIR_COLORS.get(direction, C_VAL()) imgui.text_colored(d_col, direction); imgui.same_line() - k_col = KIND_COLORS.get(kind, C_VAL) + k_col = KIND_COLORS.get(kind, C_VAL()) imgui.text_colored(k_col, kind); imgui.same_line() - imgui.text_colored(C_LBL, f"{provider}/{model}"); imgui.same_line() - imgui.text_colored(C_SUB, f"[{tier}]") + imgui.text_colored(C_LBL(), f"{provider}/{model}"); imgui.same_line() + imgui.text_colored(C_SUB(), f"[{tier}]") # Optimized content rendering using _render_heavy_text logic idx_str = str(i) @@ -3719,7 +3715,7 @@ def render_comms_history_panel(app: App) -> None: usage = payload.get("usage", {}) if usage: inp = usage.get("input_tokens", 0) - imgui.text_colored(C_LBL, f" tokens in:{inp}") + imgui.text_colored(C_LBL(), f" tokens in:{inp}") render_heavy_text(app, "message", payload.get("message", ""), idx_str) if payload.get("system"): render_heavy_text(app, "system", payload.get("system", ""), idx_str) @@ -3734,7 +3730,7 @@ def render_comms_history_panel(app: App) -> None: cache = usage.get("cache_read_input_tokens", 0) usage_str = f" in:{inp} out:{out}" if cache: usage_str += f" cache:{cache}" - imgui.text_colored(C_LBL, f"round: {r} stop_reason: {sr}{usage_str}") + imgui.text_colored(C_LBL(), f"round: {r} stop_reason: {sr}{usage_str}") text_content = payload.get("text", "") segments, parsed_response = thinking_parser.parse_thinking_trace(text_content) @@ -3774,7 +3770,7 @@ def render_takes_panel(app: App) -> None: imgui.table_set_column_index(0) is_active = name == app.active_discussion if is_active: - imgui.text_colored(C_IN, name) + imgui.text_colored(C_IN(), name) else: imgui.text(name) imgui.table_set_column_index(1) @@ -3861,14 +3857,14 @@ def render_discussion_metadata(app: App) -> None: imgui.text_colored(theme.get_color("status_info"), f"Discussion Tokens: {total_in} In | {total_out} Out | {total_cache} Cache") imgui.separator() - imgui.text_colored(C_LBL, "commit:"); imgui.same_line() - render_selectable_label(app, 'git_commit_val', git_commit[:12] if git_commit else '(none)', width=100, color=(C_IN if git_commit else C_LBL)) + imgui.text_colored(C_LBL(), "commit:"); imgui.same_line() + render_selectable_label(app, 'git_commit_val', git_commit[:12] if git_commit else '(none)', width=100, color=(C_IN() if git_commit else C_LBL())) imgui.same_line() if imgui.button("Update Commit"): if app.ui_project_git_dir: cmt = project_manager.get_git_commit(app.ui_project_git_dir) if cmt: disc_data["git_commit"], disc_data["last_updated"], app.ai_status = cmt, project_manager.now_ts(), f"commit: {cmt[:12]}" - imgui.text_colored(C_LBL, "updated:"); imgui.same_line(); imgui.text_colored(C_SUB, last_updated if last_updated else "(never)") + imgui.text_colored(C_LBL(), "updated:"); imgui.same_line(); imgui.text_colored(C_SUB(), last_updated if last_updated else "(never)") ch, app.ui_disc_new_name_input = imgui.input_text("##new_disc", app.ui_disc_new_name_input); imgui.same_line() if imgui.button("Create"): nm = app.ui_disc_new_name_input.strip() @@ -4028,7 +4024,7 @@ def render_operations_hub(app: App) -> None: render_external_tools_panel(app) imgui.separator(); imgui.text("") try: render_external_editor_panel(app) - except Exception as e: imgui.text_colored(vec4(1, 0.3, 0.3, 1), f"Error: {str(e)}") + except Exception as e: imgui.text_colored(theme.get_color("status_error"), f"Error: {str(e)}") with imscope.tab_item("Workspace Layouts") as (exp, _): if exp: imgui.text("Experimental: Auto-switch layout by Tier") @@ -4114,7 +4110,7 @@ def render_response_panel(app: App) -> None: except: pass is_blinking = False - blink_color = vec4(0, 0, 0, 0) + blink_color = imgui.ImVec4(0, 0, 0, 0) if app._is_blinking: elapsed = time.time() - app._blink_start_time if elapsed > 1.5: @@ -4123,7 +4119,7 @@ def render_response_panel(app: App) -> None: is_blinking = True val = math.sin(elapsed * 8 * math.pi) alpha = 50/255 if val > 0 else 0 - blink_color = vec4(0, 255, 0, alpha) + blink_color = theme.get_color("status_success", alpha=alpha) with imscope.style_color(imgui.Col_.frame_bg, blink_color) if is_blinking else nullcontext(): with imscope.style_color(imgui.Col_.child_bg, blink_color) if is_blinking else nullcontext(): @@ -4180,7 +4176,7 @@ def render_tool_calls_panel(app: App) -> None: app.show_windows["Text Viewer"] = True imgui.table_next_column() - imgui.text_colored(C_SUB, f"[{entry.get('source_tier', 'main')}]") + imgui.text_colored(C_SUB(), f"[{entry.get('source_tier', 'main')}]") imgui.table_next_column() script_preview = script.replace("\n", " ")[:150] @@ -4256,7 +4252,7 @@ def render_text_viewer_window(app: App) -> None: app._slice_sel_end = -1 if expanded: if app.ui_editing_slices_file is not None: - imgui.text_colored(C_IN, "Slice Management (Click-drag lines to select range)") + imgui.text_colored(C_IN(), "Slice Management (Click-drag lines to select range)") if imgui.button("Add Selection as Slice"): if app._slice_sel_start != -1 and app._slice_sel_end != -1: s_line = min(app._slice_sel_start, app._slice_sel_end) @@ -4401,7 +4397,7 @@ def render_external_editor_panel(app: App) -> None: editors = launcher.config.editors default_name = launcher.config.default_editor if not editors: - imgui.text_colored(C_REQ, " No editors configured") + imgui.text_colored(C_REQ(), " No editors configured") imgui.text("") imgui.text("Add editors in config.toml:") imgui.text(" [tools.text_editors.vscode]") @@ -4428,7 +4424,7 @@ def render_external_editor_panel(app: App) -> None: if not editor: continue is_default = name == default_name marker = " (default)" if is_default else "" - if is_default: imgui.text_colored(C_IN, f" {name}{marker}") + if is_default: imgui.text_colored(C_IN(), f" {name}{marker}") else: imgui.text(f" {name}{marker}") imgui.text(f" {editor.path}") if editor.diff_args: imgui.textDisabled(f" diff: {editor.diff_args}") @@ -4436,7 +4432,7 @@ def render_external_editor_panel(app: App) -> None: imgui.text("Config: config.toml [tools.text_editors]") imgui.text("Override: manual_slop.toml default_editor") except Exception as e: - imgui.text_colored(C_TC, f"Error: {str(e)}") + imgui.text_colored(C_TC(), f"Error: {str(e)}") def render_approve_script_modal(app: App) -> None: """Renders the modal dialog for approving AI-generated PowerShell scripts.""" @@ -4670,8 +4666,8 @@ def render_heavy_text(app: App, label: str, content: str, id_suffix: str = "") - app.text_viewer_content = content app.show_windows["Text Viewer"] = True imgui.same_line() - imgui.text_colored(C_LBL, f"{label}:"); imgui.same_line() - render_selectable_label(app, f"heavy_label_{label}_{id_suffix}", content[:60].replace("\n", " ") + ("..." if len(content)>60 else ""), color=C_VAL) + imgui.text_colored(C_LBL(), f"{label}:"); imgui.same_line() + render_selectable_label(app, f"heavy_label_{label}_{id_suffix}", content[:60].replace("\n", " ") + ("..." if len(content)>60 else ""), color=C_VAL()) if content: ctx_id = f"{label}_{id_suffix}" @@ -4810,7 +4806,7 @@ def render_mma_track_summary(app: App) -> None: if getattr(app, "ui_project_execution_mode", "native") == "beads": track_name = "Beads Graph" track_stats = project_manager.calculate_track_progress(app.active_track.tickets if app.active_track else app.active_tickets) total_cost = sum(cost_tracker.estimate_cost(u.get('model','unknown'), u.get('input',0), u.get('output',0)) for u in app.mma_tier_usage.values()) - imgui.text("Track:"); imgui.same_line(); imgui.text_colored(C_VAL, track_name); imgui.same_line(); imgui.text(" | Status:"); imgui.same_line() + imgui.text("Track:"); imgui.same_line(); imgui.text_colored(C_VAL(), track_name); imgui.same_line(); imgui.text(" | Status:"); imgui.same_line() if app.mma_status == "paused": imgui.text_colored(theme.get_color("status_warning") if is_nerv else theme.get_color("status_warning"), "PIPELINE PAUSED"); imgui.same_line() status_col = imgui.ImVec4(1, 1, 1, 1) @@ -4825,18 +4821,18 @@ def render_mma_track_summary(app: App) -> None: imgui.push_style_color(imgui.Col_.plot_histogram, p_color); imgui.progress_bar(perc, imgui.ImVec2(-1, 0), f"{track_stats['percentage']:.1f}%"); imgui.pop_style_color() if imgui.begin_table("ticket_stats_breakdown", 4): for lbl, val in [("Completed:", track_stats["completed"]), ("In Progress:", track_stats["in_progress"]), ("Blocked:", track_stats["blocked"]), ("Todo:", track_stats["todo"])]: - imgui.table_next_column(); imgui.text_colored(C_LBL, lbl); imgui.same_line(); imgui.text_colored(C_VAL, str(val)) + imgui.table_next_column(); imgui.text_colored(C_LBL(), lbl); imgui.same_line(); imgui.text_colored(C_VAL(), str(val)) imgui.end_table() if app.active_track: remaining = track_stats["total"] - track_stats["completed"] eta_mins = (app._avg_ticket_time * remaining) / 60.0 - imgui.text_colored(C_LBL, "ETA:"); imgui.same_line(); imgui.text_colored(C_VAL, f"~{int(eta_mins)}m ({remaining} tickets remaining)") + imgui.text_colored(C_LBL(), "ETA:"); imgui.same_line(); imgui.text_colored(C_VAL(), f"~{int(eta_mins)}m ({remaining} tickets remaining)") def render_mma_epic_planner(app: App) -> None: """ [C: tests/test_gui_progress.py:test_render_mma_dashboard_progress] """ - imgui.text_colored(C_LBL, 'Epic Planning (Tier 1)') + imgui.text_colored(C_LBL(), 'Epic Planning (Tier 1)') _, app.ui_epic_input = imgui.input_text_multiline('##epic_input', app.ui_epic_input, imgui.ImVec2(-1, 80)) if imgui.button('Plan Epic (Tier 1)', imgui.ImVec2(-1, 0)): app._cb_plan_epic() @@ -4889,11 +4885,11 @@ def render_mma_global_controls(app: App) -> None: if is_paused: app.controller.engine.resume() else: app.controller.engine.pause() if app.active_tier: - imgui.same_line(); imgui.text_colored(C_VAL, f"| Active: {app.active_tier}") + imgui.same_line(); imgui.text_colored(C_VAL(), f"| Active: {app.active_tier}") any_pending = len(app._pending_mma_spawns) > 0 or len(app._pending_mma_approvals) > 0 or app._pending_ask_dialog if any_pending: alpha = abs(math.sin(time.time() * 5)) - c = vec4(255, 72, 64, alpha) if theme.is_nerv_active() else imgui.ImVec4(1, 0.3, 0.3, alpha) + c = theme.get_color("status_error", alpha=alpha) imgui.same_line(); imgui.text_colored(c, " APPROVAL PENDING"); imgui.same_line() if imgui.button("Go to Approval"): pass imgui.separator() @@ -4954,7 +4950,7 @@ def render_mma_usage_section(app: App) -> None: imgui.pop_item_width() def render_mma_ticket_editor(app: App) -> None: - imgui.separator(); imgui.text_colored(C_VAL, f"Editing: {app.ui_selected_ticket_id}") + imgui.separator(); imgui.text_colored(C_VAL(), f"Editing: {app.ui_selected_ticket_id}") ticket = next((t for t in app.active_tickets if str(t.get('id', '')) == app.ui_selected_ticket_id), None) if ticket: imgui.text(f"Status: {ticket.get('status', 'todo')}"); prio = ticket.get('priority', 'medium') @@ -5054,7 +5050,7 @@ def render_track_proposal_modal(app: App) -> None: shaders.draw_soft_shadow(imgui.get_background_draw_list(), p_min, p_max, imgui.ImVec4(0, 0, 0, 0.6), 25.0, 6.0) if app._show_track_proposal_modal: - imgui.text_colored(C_IN, "Proposed Implementation Tracks") + imgui.text_colored(C_IN(), "Proposed Implementation Tracks") imgui.separator() if not app.proposed_tracks: imgui.text("No tracks generated.") @@ -5225,11 +5221,11 @@ def render_task_dag_panel(app: App) -> None: # 4. Task DAG Visualizer if getattr(app, "ui_project_execution_mode", "native") == "beads": imgui.text_colored(theme.get_color("status_info"), "[B] ") imgui.same_line() - imgui.text_colored(C_KEY, f"Ticket: {tid}") + imgui.text_colored(C_KEY(), f"Ticket: {tid}") status = t.get('status', 'todo') - s_col = C_VAL - if status == 'done' or status == 'complete': s_col = C_IN - elif status == 'in_progress' or status == 'running': s_col = C_OUT + s_col = C_VAL() + if status == 'done' or status == 'complete': s_col = C_IN() + elif status == 'in_progress' or status == 'running': s_col = C_OUT() elif status == 'error': s_col = theme.get_color("status_error") imgui.text("Status: ") imgui.same_line() @@ -5315,7 +5311,7 @@ def render_task_dag_panel(app: App) -> None: # 4. Task DAG Visualizer app.ui_new_ticket_deps = "" if app._show_add_ticket_form: imgui.begin_child("add_ticket_form", imgui.ImVec2(-1, 220), True) - imgui.text_colored(C_VAL, "New Ticket Details") + imgui.text_colored(C_VAL(), "New Ticket Details") _, app.ui_new_ticket_id = imgui.input_text("ID##new_ticket", app.ui_new_ticket_id) _, app.ui_new_ticket_desc = imgui.input_text_multiline("Description##new_ticket", app.ui_new_ticket_desc, imgui.ImVec2(-1, 60)) _, app.ui_new_ticket_target = imgui.input_text("Target File##new_ticket", app.ui_new_ticket_target)