gemini 3.1 fails
This commit is contained in:
+389
-438
@@ -15,7 +15,7 @@ import threading
|
||||
import time
|
||||
# from defer import defer
|
||||
import tomli_w
|
||||
# from contextlib import ExitStack
|
||||
# from contextlib import ExitStack, nullcontext
|
||||
import traceback
|
||||
import typing
|
||||
from pathlib import Path
|
||||
@@ -605,53 +605,53 @@ class App:
|
||||
def _render_thinking_trace(self, segments: list[dict], entry_index: int, is_standalone: bool = False) -> None:
|
||||
if not segments:
|
||||
return
|
||||
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()
|
||||
with imscope.style_color(imgui.Col_.child_bg, vec4(40, 35, 25, 180)), \
|
||||
imscope.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}"
|
||||
show_content = imgui.collapsing_header(header_label)
|
||||
show_content = True
|
||||
if not is_standalone:
|
||||
header_label = f"Monologue ({len(segments)} traces)###thinking_header_{entry_index}"
|
||||
show_content = imgui.collapsing_header(header_label)
|
||||
|
||||
if show_content:
|
||||
h = 150 if is_standalone else 100
|
||||
with 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")
|
||||
with imscope.id(f"think_{entry_index}_{idx}"):
|
||||
imgui.text_colored(vec4(180, 150, 80), f"[{marker}]")
|
||||
if self.ui_word_wrap:
|
||||
imscope.text_wrap(imgui.get_content_region_avail().x)
|
||||
imgui.text_colored(vec4(200, 200, 150), content)
|
||||
else:
|
||||
imgui.text_colored(vec4(200, 200, 150), content)
|
||||
imgui.separator()
|
||||
if show_content:
|
||||
h = 150 if is_standalone else 100
|
||||
with 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")
|
||||
with imscope.id(f"think_{entry_index}_{idx}"):
|
||||
imgui.text_colored(vec4(180, 150, 80), f"[{marker}]")
|
||||
if self.ui_word_wrap:
|
||||
with imscope.text_wrap(imgui.get_content_region_avail().x):
|
||||
imgui.text_colored(vec4(200, 200, 150), content)
|
||||
else:
|
||||
imgui.text_colored(vec4(200, 200, 150), content)
|
||||
imgui.separator()
|
||||
|
||||
imgui.unindent()
|
||||
imgui.pop_style_color(2)
|
||||
imgui.unindent()
|
||||
|
||||
def _render_selectable_label(self, label: str, value: str, width: float = 0.0, multiline: bool = False, height: float = 0.0, color: Optional[imgui.ImVec4] = None) -> None:
|
||||
imgui.push_id(label + str(hash(value)))
|
||||
pops = 4
|
||||
imgui.push_style_color(imgui.Col_.frame_bg, vec4(0, 0, 0, 0))
|
||||
imgui.push_style_color(imgui.Col_.frame_bg_hovered, vec4(0, 0, 0, 0))
|
||||
imgui.push_style_color(imgui.Col_.frame_bg_active, vec4(0, 0, 0, 0))
|
||||
imgui.push_style_color(imgui.Col_.border, vec4(0, 0, 0, 0))
|
||||
if color:
|
||||
imgui.push_style_color(imgui.Col_.text, color)
|
||||
pops += 1
|
||||
imgui.push_style_var(imgui.StyleVar_.frame_border_size, 0.0)
|
||||
imgui.push_style_var(imgui.StyleVar_.frame_padding, imgui.ImVec2(0, 0))
|
||||
if multiline:
|
||||
imgui.input_text_multiline("##" + label, value, imgui.ImVec2(width, height), imgui.InputTextFlags_.read_only)
|
||||
else:
|
||||
if width > 0: imgui.set_next_item_width(width)
|
||||
imgui.input_text("##" + label, value, imgui.InputTextFlags_.read_only)
|
||||
imgui.pop_style_color(pops)
|
||||
imgui.pop_style_var(2)
|
||||
imgui.pop_id()
|
||||
with imscope.id(label + str(hash(value))):
|
||||
with imscope.style_color(imgui.Col_.frame_bg, vec4(0, 0, 0, 0)), \
|
||||
imscope.style_color(imgui.Col_.frame_bg_hovered, vec4(0, 0, 0, 0)), \
|
||||
imscope.style_color(imgui.Col_.frame_bg_active, vec4(0, 0, 0, 0)), \
|
||||
imscope.style_color(imgui.Col_.border, vec4(0, 0, 0, 0)):
|
||||
with imscope.style_var(imgui.StyleVar_.frame_border_size, 0.0), \
|
||||
imscope.style_var(imgui.StyleVar_.frame_padding, imgui.ImVec2(0, 0)):
|
||||
if color:
|
||||
with imscope.style_color(imgui.Col_.text, color):
|
||||
if multiline:
|
||||
imgui.input_text_multiline("##" + label, value, imgui.ImVec2(width, height), imgui.InputTextFlags_.read_only)
|
||||
else:
|
||||
if width > 0: imgui.set_next_item_width(width)
|
||||
imgui.input_text("##" + label, value, imgui.InputTextFlags_.read_only)
|
||||
else:
|
||||
if multiline:
|
||||
imgui.input_text_multiline("##" + label, value, imgui.ImVec2(width, height), imgui.InputTextFlags_.read_only)
|
||||
else:
|
||||
if width > 0: imgui.set_next_item_width(width)
|
||||
imgui.input_text("##" + label, value, imgui.InputTextFlags_.read_only)
|
||||
|
||||
def _render_window_if_open(self, name: str, render_func: Callable[[], None], flag_condition: bool = True) -> None:
|
||||
"""Helper to render a window only if its toggle is active."""
|
||||
@@ -1220,34 +1220,30 @@ class App:
|
||||
imgui.text_colored(c, "THINKING..."); imgui.same_line()
|
||||
|
||||
def _render_prior_session_view(self) -> None:
|
||||
imgui.push_style_color(imgui.Col_.child_bg, vec4(50, 40, 20))
|
||||
if imgui.button("Exit Prior Session"): self.controller.cb_exit_prior_session(); self._comms_log_dirty = True
|
||||
imgui.separator()
|
||||
with imscope.child("prior_scroll"):
|
||||
clipper = imgui.ListClipper(); clipper.begin(len(self.prior_disc_entries))
|
||||
while clipper.step():
|
||||
for idx in range(clipper.display_start, clipper.display_end):
|
||||
entry = self.prior_disc_entries[idx];
|
||||
with imscope.id(f"prior_disc_{idx}"):
|
||||
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}]")
|
||||
if ts: imgui.same_line(); imgui.text_colored(vec4(160, 160, 160), str(ts))
|
||||
content = entry.get("content", "")
|
||||
if collapsed:
|
||||
imgui.same_line(); preview = content.replace("\n", " ")[:80]
|
||||
if len(content) > 80: preview += "..."
|
||||
imgui.text_colored(vec4(180, 180, 180), preview)
|
||||
else:
|
||||
is_nerv = theme.is_nerv_active()
|
||||
if is_nerv: imgui.push_style_color(imgui.Col_.text, vec4(80, 255, 80))
|
||||
markdown_helper.render(content, context_id=f'prior_disc_{idx}')
|
||||
if is_nerv: imgui.pop_style_color()
|
||||
imgui.separator()
|
||||
imgui.pop_style_color()
|
||||
|
||||
def _render_discussion_selector(self) -> None:
|
||||
with imscope.style_color(imgui.Col_.child_bg, vec4(50, 40, 20)):
|
||||
if imgui.button("Exit Prior Session"): self.controller.cb_exit_prior_session(); self._comms_log_dirty = True
|
||||
imgui.separator()
|
||||
with imscope.child("prior_scroll"):
|
||||
clipper = imgui.ListClipper(); clipper.begin(len(self.prior_disc_entries))
|
||||
while clipper.step():
|
||||
for idx in range(clipper.display_start, clipper.display_end):
|
||||
entry = self.prior_disc_entries[idx];
|
||||
with imscope.id(f"prior_disc_{idx}"):
|
||||
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}]")
|
||||
if ts: imgui.same_line(); imgui.text_colored(vec4(160, 160, 160), str(ts))
|
||||
content = entry.get("content", "")
|
||||
if collapsed:
|
||||
imgui.same_line(); preview = content.replace("\n", " ")[:80]
|
||||
if len(content) > 80: preview += "..."
|
||||
imgui.text_colored(vec4(180, 180, 180), preview)
|
||||
else:
|
||||
is_nerv = theme.is_nerv_active()
|
||||
with imscope.style_color(imgui.Col_.text, vec4(80, 255, 80)) if is_nerv else nullcontext():
|
||||
markdown_helper.render(content, context_id=f'prior_disc_{idx}')
|
||||
imgui.separator()
|
||||
if not imgui.collapsing_header("Discussions", imgui.TreeNodeFlags_.default_open): return
|
||||
names = self._get_discussion_names(); grouped = {}
|
||||
for name in names:
|
||||
@@ -2204,11 +2200,12 @@ class App:
|
||||
if not self.show_preset_manager_window and not is_embedded: return
|
||||
if not is_embedded:
|
||||
imgui.set_next_window_size(imgui.ImVec2(1000, 800), imgui.Cond_.first_use_ever)
|
||||
opened, self.show_preset_manager_window = imgui.begin("Prompt Presets Manager", self.show_preset_manager_window)
|
||||
if not opened:
|
||||
imgui.end(); return
|
||||
self._render_preset_manager_content(is_embedded=is_embedded)
|
||||
if not is_embedded: imgui.end()
|
||||
with imscope.window("Prompt Presets Manager", self.show_preset_manager_window) as (opened, visible):
|
||||
self.show_preset_manager_window = visible
|
||||
if opened:
|
||||
self._render_preset_manager_content(is_embedded=is_embedded)
|
||||
else:
|
||||
self._render_preset_manager_content(is_embedded=is_embedded)
|
||||
|
||||
def _render_tool_preset_manager_content(self, is_embedded: bool = False) -> None:
|
||||
avail = imgui.get_content_region_avail()
|
||||
@@ -2382,16 +2379,16 @@ class App:
|
||||
if not is_embedded:
|
||||
if imgui.button("Close##tp", imgui.ImVec2(100, 0)): self.show_tool_preset_manager_window = False
|
||||
imgui.end_table()
|
||||
|
||||
def _render_tool_preset_manager_window(self, is_embedded: bool = False) -> None:
|
||||
if not self.show_tool_preset_manager_window and not is_embedded: return
|
||||
if not is_embedded:
|
||||
imgui.set_next_window_size(imgui.ImVec2(1000, 800), imgui.Cond_.first_use_ever)
|
||||
opened, self.show_tool_preset_manager_window = imgui.begin("Tool Preset Manager", self.show_tool_preset_manager_window)
|
||||
if not opened:
|
||||
imgui.end(); return
|
||||
self._render_tool_preset_manager_content(is_embedded=is_embedded)
|
||||
if not is_embedded: imgui.end()
|
||||
with imscope.window("Tool Preset Manager", self.show_tool_preset_manager_window) as (opened, visible):
|
||||
self.show_tool_preset_manager_window = visible
|
||||
if opened:
|
||||
self._render_tool_preset_manager_content(is_embedded=is_embedded)
|
||||
else:
|
||||
self._render_preset_manager_content(is_embedded=is_embedded)
|
||||
|
||||
def _render_persona_editor_window(self, is_embedded: bool = False) -> None:
|
||||
if not self.show_persona_editor_window and not is_embedded: return
|
||||
@@ -2557,7 +2554,6 @@ class App:
|
||||
if imgui.button("Close##pers", imgui.ImVec2(100, 0)):
|
||||
self.show_persona_editor_window = False
|
||||
imgui.end_table()
|
||||
if not is_embedded: imgui.end()
|
||||
|
||||
def _render_projects_panel(self) -> None:
|
||||
if self.perf_profiling_enabled: self.perf_monitor.start_component("_render_projects_panel")
|
||||
@@ -2908,192 +2904,183 @@ class App:
|
||||
[C: tests/test_log_management_ui.py:test_render_log_management_logic]
|
||||
"""
|
||||
if self.perf_profiling_enabled: self.perf_monitor.start_component("_render_log_management")
|
||||
exp, opened = imgui.begin("Log Management", self.show_windows["Log Management"])
|
||||
self.show_windows["Log Management"] = bool(opened)
|
||||
if not exp:
|
||||
imgui.end()
|
||||
return
|
||||
|
||||
if self._log_registry is None:
|
||||
self._log_registry = log_registry.LogRegistry(str(paths.get_logs_dir() / "log_registry.toml"))
|
||||
else:
|
||||
if imgui.button("Refresh Registry"):
|
||||
self._log_registry = log_registry.LogRegistry(str(paths.get_logs_dir() / "log_registry.toml"))
|
||||
imgui.same_line()
|
||||
if imgui.button("Load Log"):
|
||||
self.cb_load_prior_log()
|
||||
imgui.same_line()
|
||||
if imgui.button("Force Prune Logs"):
|
||||
self.controller.event_queue.put("gui_task", {"action": "click", "item": "btn_prune_logs"})
|
||||
|
||||
registry = self._log_registry
|
||||
sessions = registry.data
|
||||
if imgui.begin_table("sessions_table", 7, imgui.TableFlags_.borders | imgui.TableFlags_.row_bg | imgui.TableFlags_.resizable):
|
||||
imgui.table_setup_column("Session ID")
|
||||
imgui.table_setup_column("Start Time")
|
||||
imgui.table_setup_column("Star")
|
||||
imgui.table_setup_column("Reason")
|
||||
imgui.table_setup_column("Size (KB)")
|
||||
imgui.table_setup_column("Msgs")
|
||||
imgui.table_setup_column("Actions")
|
||||
imgui.table_headers_row()
|
||||
for session_id, s_data in sessions.items():
|
||||
imgui.table_next_row()
|
||||
imgui.table_next_column()
|
||||
imgui.text(session_id)
|
||||
imgui.table_next_column()
|
||||
imgui.text(s_data.get("start_time", ""))
|
||||
imgui.table_next_column()
|
||||
whitelisted = s_data.get("whitelisted", False)
|
||||
if whitelisted:
|
||||
imgui.text_colored(vec4(255, 215, 0), "YES")
|
||||
with imscope.window("Log Management", self.show_windows["Log Management"]) as (exp, opened):
|
||||
self.show_windows["Log Management"] = bool(opened)
|
||||
if exp:
|
||||
if self._log_registry is None:
|
||||
self._log_registry = log_registry.LogRegistry(str(paths.get_logs_dir() / "log_registry.toml"))
|
||||
else:
|
||||
imgui.text("NO")
|
||||
metadata = s_data.get("metadata") or {}
|
||||
imgui.table_next_column()
|
||||
imgui.text(metadata.get("reason", ""))
|
||||
imgui.table_next_column()
|
||||
imgui.text(str(metadata.get("size_kb", "")))
|
||||
imgui.table_next_column()
|
||||
imgui.text(str(metadata.get("message_count", "")))
|
||||
imgui.table_next_column()
|
||||
if imgui.button(f"Load##{session_id}"):
|
||||
self.cb_load_prior_log(s_data.get("path"))
|
||||
if imgui.button("Refresh Registry"):
|
||||
self._log_registry = log_registry.LogRegistry(str(paths.get_logs_dir() / "log_registry.toml"))
|
||||
imgui.same_line()
|
||||
if imgui.button("Load Log"):
|
||||
self.cb_load_prior_log()
|
||||
imgui.same_line()
|
||||
if whitelisted:
|
||||
if imgui.button(f"Unstar##{session_id}"):
|
||||
registry.update_session_metadata(
|
||||
session_id,
|
||||
message_count=int(metadata.get("message_count") or 0),
|
||||
errors=int(metadata.get("errors") or 0),
|
||||
size_kb=int(metadata.get("size_kb") or 0),
|
||||
whitelisted=False,
|
||||
reason=str(metadata.get("reason") or "")
|
||||
)
|
||||
else:
|
||||
if imgui.button(f"Star##{session_id}"):
|
||||
registry.update_session_metadata(
|
||||
session_id,
|
||||
message_count=int(metadata.get("message_count") or 0),
|
||||
errors=int(metadata.get("errors") or 0),
|
||||
size_kb=int(metadata.get("size_kb") or 0),
|
||||
whitelisted=True,
|
||||
reason="Manually whitelisted"
|
||||
)
|
||||
imgui.end_table()
|
||||
if imgui.button("Force Prune Logs"):
|
||||
self.controller.event_queue.put("gui_task", {"action": "click", "item": "btn_prune_logs"})
|
||||
|
||||
registry = self._log_registry
|
||||
sessions = registry.data
|
||||
if imgui.begin_table("sessions_table", 7, imgui.TableFlags_.borders | imgui.TableFlags_.row_bg | imgui.TableFlags_.resizable):
|
||||
imgui.table_setup_column("Session ID")
|
||||
imgui.table_setup_column("Start Time")
|
||||
imgui.table_setup_column("Star")
|
||||
imgui.table_setup_column("Reason")
|
||||
imgui.table_setup_column("Size (KB)")
|
||||
imgui.table_setup_column("Msgs")
|
||||
imgui.table_setup_column("Actions")
|
||||
imgui.table_headers_row()
|
||||
for session_id, s_data in sessions.items():
|
||||
imgui.table_next_row()
|
||||
imgui.table_next_column()
|
||||
imgui.text(session_id)
|
||||
imgui.table_next_column()
|
||||
imgui.text(s_data.get("start_time", ""))
|
||||
imgui.table_next_column()
|
||||
whitelisted = s_data.get("whitelisted", False)
|
||||
if whitelisted:
|
||||
imgui.text_colored(vec4(255, 215, 0), "YES")
|
||||
else:
|
||||
imgui.text("NO")
|
||||
metadata = s_data.get("metadata") or {}
|
||||
imgui.table_next_column()
|
||||
imgui.text(metadata.get("reason", ""))
|
||||
imgui.table_next_column()
|
||||
imgui.text(str(metadata.get("size_kb", "")))
|
||||
imgui.table_next_column()
|
||||
imgui.text(str(metadata.get("message_count", "")))
|
||||
imgui.table_next_column()
|
||||
if imgui.button(f"Load##{session_id}"):
|
||||
self.cb_load_prior_log(s_data.get("path"))
|
||||
imgui.same_line()
|
||||
if whitelisted:
|
||||
if imgui.button(f"Unstar##{session_id}"):
|
||||
registry.update_session_metadata(
|
||||
session_id,
|
||||
message_count=int(metadata.get("message_count") or 0),
|
||||
errors=int(metadata.get("errors") or 0),
|
||||
size_kb=int(metadata.get("size_kb") or 0),
|
||||
whitelisted=False,
|
||||
reason=str(metadata.get("reason") or "")
|
||||
)
|
||||
else:
|
||||
if imgui.button(f"Star##{session_id}"):
|
||||
registry.update_session_metadata(
|
||||
session_id,
|
||||
message_count=int(metadata.get("message_count") or 0),
|
||||
errors=int(metadata.get("errors") or 0),
|
||||
size_kb=int(metadata.get("size_kb") or 0),
|
||||
whitelisted=True,
|
||||
reason="Manually whitelisted"
|
||||
)
|
||||
imgui.end_table()
|
||||
|
||||
if self.perf_profiling_enabled: self.perf_monitor.end_component("_render_log_management")
|
||||
imgui.end()
|
||||
|
||||
def _render_diagnostics_panel(self) -> None:
|
||||
if self.perf_profiling_enabled: self.perf_monitor.start_component("_render_diagnostics_panel")
|
||||
exp, opened = imgui.begin("Diagnostics", self.show_windows.get("Diagnostics", False))
|
||||
self.show_windows["Diagnostics"] = bool(opened)
|
||||
if not exp:
|
||||
imgui.end()
|
||||
if self.perf_profiling_enabled: self.perf_monitor.end_component("_render_diagnostics_panel")
|
||||
return
|
||||
|
||||
metrics = self.perf_monitor.get_metrics()
|
||||
imgui.text("Performance Telemetry")
|
||||
imgui.same_line()
|
||||
_, self.perf_profiling_enabled = imgui.checkbox("Enable Profiling", self.perf_profiling_enabled)
|
||||
imgui.separator()
|
||||
|
||||
if imgui.begin_table("perf_table", 3, imgui.TableFlags_.borders_inner_h):
|
||||
imgui.table_setup_column("Metric")
|
||||
imgui.table_setup_column("Value")
|
||||
imgui.table_setup_column("Graph")
|
||||
imgui.table_headers_row()
|
||||
|
||||
for label, key, format_str in [
|
||||
("FPS", "fps", "%.1f"),
|
||||
("Frame Time (ms)", "frame_time_ms", "%.2f"),
|
||||
("CPU %", "cpu_percent", "%.1f"),
|
||||
("Input Lag (ms)", "input_lag_ms", "%.1f")
|
||||
]:
|
||||
imgui.table_next_row()
|
||||
imgui.table_next_column()
|
||||
imgui.text(label)
|
||||
imgui.table_next_column()
|
||||
if key == "fps":
|
||||
avg_val = imgui.get_io().framerate
|
||||
else:
|
||||
avg_val = metrics.get(f"{key}_avg", metrics.get(key, 0.0))
|
||||
imgui.text(format_str % avg_val)
|
||||
imgui.table_next_column()
|
||||
self.perf_show_graphs.setdefault(key, False)
|
||||
_, self.perf_show_graphs[key] = imgui.checkbox(f"##g_{key}", self.perf_show_graphs[key])
|
||||
imgui.end_table()
|
||||
|
||||
if self.perf_profiling_enabled:
|
||||
imgui.separator()
|
||||
imgui.text("Detailed Component Timings (Moving Average)")
|
||||
if imgui.begin_table("comp_timings", 6, imgui.TableFlags_.borders):
|
||||
imgui.table_setup_column("Component")
|
||||
imgui.table_setup_column("Avg (ms)")
|
||||
imgui.table_setup_column("Count")
|
||||
imgui.table_setup_column("Max (ms)")
|
||||
imgui.table_setup_column("Min (ms)")
|
||||
imgui.table_setup_column("Graph")
|
||||
imgui.table_headers_row()
|
||||
for key, val in metrics.items():
|
||||
if key.startswith("time_") and key.endswith("_ms") and not key.endswith("_avg"):
|
||||
comp_name = key[5:-3]
|
||||
avg_val = metrics.get(f"{key}_avg", val)
|
||||
count = int(metrics.get(f"count_{comp_name}", 0))
|
||||
max_val = metrics.get(f"max_{comp_name}_ms", 0.0)
|
||||
min_val = metrics.get(f"min_{comp_name}_ms", 0.0)
|
||||
with imscope.window("Diagnostics", self.show_windows.get("Diagnostics", False)) as (exp, opened):
|
||||
self.show_windows["Diagnostics"] = bool(opened)
|
||||
if exp:
|
||||
metrics = self.perf_monitor.get_metrics()
|
||||
imgui.text("Performance Telemetry")
|
||||
imgui.same_line()
|
||||
_, self.perf_profiling_enabled = imgui.checkbox("Enable Profiling", self.perf_profiling_enabled)
|
||||
imgui.separator()
|
||||
|
||||
if imgui.begin_table("perf_table", 3, imgui.TableFlags_.borders_inner_h):
|
||||
imgui.table_setup_column("Metric")
|
||||
imgui.table_setup_column("Value")
|
||||
imgui.table_setup_column("Graph")
|
||||
imgui.table_headers_row()
|
||||
|
||||
for label, key, format_str in [
|
||||
("FPS", "fps", "%.1f"),
|
||||
("Frame Time (ms)", "frame_time_ms", "%.2f"),
|
||||
("CPU %", "cpu_percent", "%.1f"),
|
||||
("Input Lag (ms)", "input_lag_ms", "%.1f")
|
||||
]:
|
||||
imgui.table_next_row()
|
||||
imgui.table_next_column()
|
||||
imgui.text(comp_name)
|
||||
imgui.text(label)
|
||||
imgui.table_next_column()
|
||||
if avg_val > 10.0:
|
||||
imgui.text_colored(imgui.ImVec4(1.0, 0.2, 0.2, 1.0), f"{avg_val:.2f}")
|
||||
if key == "fps":
|
||||
avg_val = imgui.get_io().framerate
|
||||
else:
|
||||
imgui.text(f"{avg_val:.2f}")
|
||||
avg_val = metrics.get(f"{key}_avg", metrics.get(key, 0.0))
|
||||
imgui.text(format_str % avg_val)
|
||||
imgui.table_next_column()
|
||||
imgui.text(f"{count}")
|
||||
imgui.table_next_column()
|
||||
imgui.text(f"{max_val:.2f}")
|
||||
imgui.table_next_column()
|
||||
imgui.text(f"{min_val:.2f}")
|
||||
imgui.table_next_column()
|
||||
self.perf_show_graphs.setdefault(comp_name, False)
|
||||
_, self.perf_show_graphs[comp_name] = imgui.checkbox(f"##g_{comp_name}", self.perf_show_graphs[comp_name])
|
||||
imgui.end_table()
|
||||
self.perf_show_graphs.setdefault(key, False)
|
||||
_, self.perf_show_graphs[key] = imgui.checkbox(f"##g_{key}", self.perf_show_graphs[key])
|
||||
imgui.end_table()
|
||||
|
||||
imgui.separator()
|
||||
imgui.text("Performance Graphs")
|
||||
for key, show in self.perf_show_graphs.items():
|
||||
if show:
|
||||
imgui.text(f"History: {key}")
|
||||
hist_data = self.perf_monitor.get_history(key)
|
||||
if hist_data:
|
||||
import numpy as np
|
||||
imgui.plot_lines(f"##plot_{key}", np.array(hist_data, dtype=np.float32), graph_size=imgui.ImVec2(-1, 60))
|
||||
else:
|
||||
imgui.text_disabled(f"(no history data for {key})")
|
||||
if self.perf_profiling_enabled:
|
||||
imgui.separator()
|
||||
imgui.text("Detailed Component Timings (Moving Average)")
|
||||
if imgui.begin_table("comp_timings", 6, imgui.TableFlags_.borders):
|
||||
imgui.table_setup_column("Component")
|
||||
imgui.table_setup_column("Avg (ms)")
|
||||
imgui.table_setup_column("Count")
|
||||
imgui.table_setup_column("Max (ms)")
|
||||
imgui.table_setup_column("Min (ms)")
|
||||
imgui.table_setup_column("Graph")
|
||||
imgui.table_headers_row()
|
||||
for key, val in metrics.items():
|
||||
if key.startswith("time_") and key.endswith("_ms") and not key.endswith("_avg"):
|
||||
comp_name = key[5:-3]
|
||||
avg_val = metrics.get(f"{key}_avg", val)
|
||||
count = int(metrics.get(f"count_{comp_name}", 0))
|
||||
max_val = metrics.get(f"max_{comp_name}_ms", 0.0)
|
||||
min_val = metrics.get(f"min_{comp_name}_ms", 0.0)
|
||||
imgui.table_next_row()
|
||||
imgui.table_next_column()
|
||||
imgui.text(comp_name)
|
||||
imgui.table_next_column()
|
||||
if avg_val > 10.0:
|
||||
imgui.text_colored(imgui.ImVec4(1.0, 0.2, 0.2, 1.0), f"{avg_val:.2f}")
|
||||
else:
|
||||
imgui.text(f"{avg_val:.2f}")
|
||||
imgui.table_next_column()
|
||||
imgui.text(f"{count}")
|
||||
imgui.table_next_column()
|
||||
imgui.text(f"{max_val:.2f}")
|
||||
imgui.table_next_column()
|
||||
imgui.text(f"{min_val:.2f}")
|
||||
imgui.table_next_column()
|
||||
self.perf_show_graphs.setdefault(comp_name, False)
|
||||
_, self.perf_show_graphs[comp_name] = imgui.checkbox(f"##g_{comp_name}", self.perf_show_graphs[comp_name])
|
||||
imgui.end_table()
|
||||
|
||||
imgui.separator()
|
||||
imgui.text("Diagnostic Log")
|
||||
if imgui.begin_table("diag_log_table", 3, imgui.TableFlags_.borders | imgui.TableFlags_.row_bg | imgui.TableFlags_.resizable):
|
||||
imgui.table_setup_column("Timestamp", imgui.TableColumnFlags_.width_fixed, 150)
|
||||
imgui.table_setup_column("Type", imgui.TableColumnFlags_.width_fixed, 100)
|
||||
imgui.table_setup_column("Message")
|
||||
imgui.table_headers_row()
|
||||
for entry in reversed(self.controller.diagnostic_log):
|
||||
imgui.table_next_row()
|
||||
imgui.table_next_column()
|
||||
imgui.text(entry.get("ts", ""))
|
||||
imgui.table_next_column()
|
||||
imgui.text(entry.get("type", ""))
|
||||
imgui.table_next_column()
|
||||
imgui.text_wrapped(entry.get("message", ""))
|
||||
imgui.end_table()
|
||||
imgui.separator()
|
||||
imgui.text("Performance Graphs")
|
||||
for key, show in self.perf_show_graphs.items():
|
||||
if show:
|
||||
imgui.text(f"History: {key}")
|
||||
hist_data = self.perf_monitor.get_history(key)
|
||||
if hist_data:
|
||||
import numpy as np
|
||||
imgui.plot_lines(f"##plot_{key}", np.array(hist_data, dtype=np.float32), graph_size=imgui.ImVec2(-1, 60))
|
||||
else:
|
||||
imgui.text_disabled(f"(no history data for {key})")
|
||||
|
||||
imgui.separator()
|
||||
imgui.text("Diagnostic Log")
|
||||
if imgui.begin_table("diag_log_table", 3, imgui.TableFlags_.borders | imgui.TableFlags_.row_bg | imgui.TableFlags_.resizable):
|
||||
imgui.table_setup_column("Timestamp", imgui.TableColumnFlags_.width_fixed, 150)
|
||||
imgui.table_setup_column("Type", imgui.TableColumnFlags_.width_fixed, 100)
|
||||
imgui.table_setup_column("Message")
|
||||
imgui.table_headers_row()
|
||||
for entry in reversed(self.controller.diagnostic_log):
|
||||
imgui.table_next_row()
|
||||
imgui.table_next_column()
|
||||
imgui.text(entry.get("ts", ""))
|
||||
imgui.table_next_column()
|
||||
imgui.text(entry.get("type", ""))
|
||||
imgui.table_next_column()
|
||||
imgui.text_wrapped(entry.get("message", ""))
|
||||
imgui.end_table()
|
||||
|
||||
if self.perf_profiling_enabled: self.perf_monitor.end_component("_render_diagnostics_panel")
|
||||
imgui.end()
|
||||
|
||||
def _render_discussion_tab(self) -> None:
|
||||
imgui.begin_child("HistoryChild", size=(0, -self.ui_discussion_split_h))
|
||||
@@ -3215,118 +3202,116 @@ class App:
|
||||
|
||||
grouped_files = aggregate.group_files_by_dir(self.context_files)
|
||||
|
||||
if imgui.begin_table("ctx_comp_table", 2, imgui.TableFlags_.resizable | imgui.TableFlags_.borders):
|
||||
imgui.table_setup_column("File", imgui.TableColumnFlags_.width_stretch)
|
||||
imgui.table_setup_column("Flags", imgui.TableColumnFlags_.width_fixed, 200)
|
||||
imgui.table_headers_row()
|
||||
|
||||
file_indices = {id(f): idx for idx, f in enumerate(self.context_files)}
|
||||
|
||||
for dir_name, g_files in grouped_files.items():
|
||||
imgui.table_next_row()
|
||||
imgui.table_set_column_index(0)
|
||||
is_open = imgui.tree_node_ex(f"{dir_name}##dir_{dir_name}", imgui.TreeNodeFlags_.default_open)
|
||||
imgui.table_set_column_index(1)
|
||||
if is_open:
|
||||
for f_item in g_files:
|
||||
i = file_indices[id(f_item)]
|
||||
imgui.table_next_row()
|
||||
imgui.table_set_column_index(0)
|
||||
|
||||
# Checkbox for selection
|
||||
f_path = f_item.path if hasattr(f_item, "path") else str(f_item)
|
||||
is_sel = f_path in self.ui_selected_context_files
|
||||
changed_sel, is_sel = imgui.checkbox(f"##sel{i}", is_sel)
|
||||
if changed_sel:
|
||||
if imgui.get_io().key_shift and self._last_selected_context_index != -1:
|
||||
start = min(self._last_selected_context_index, i)
|
||||
end = max(self._last_selected_context_index, i)
|
||||
for idx in range(start, end + 1):
|
||||
item = self.context_files[idx]
|
||||
item_path = item.path if hasattr(item, "path") else str(item)
|
||||
if is_sel:
|
||||
self.ui_selected_context_files.add(item_path)
|
||||
else:
|
||||
self.ui_selected_context_files.discard(item_path)
|
||||
else:
|
||||
if is_sel:
|
||||
self.ui_selected_context_files.add(f_path)
|
||||
else:
|
||||
self.ui_selected_context_files.discard(f_path)
|
||||
self._last_selected_context_index = i
|
||||
imgui.same_line()
|
||||
|
||||
mtime = os.path.getmtime(f_path) if os.path.exists(f_path) else 0
|
||||
cache_key = f"{f_path}_{mtime}"
|
||||
stats = self._file_stats_cache.get(cache_key, {"lines": 0, "ast_elements": 0})
|
||||
f_name = os.path.basename(f_path)
|
||||
imgui.text(f"{f_name} (L: {stats.get('lines', 0)}, AST: {stats.get('ast_elements', 0)})")
|
||||
|
||||
if f_path.lower().endswith(('.c', '.cpp', '.h', '.hpp', '.cxx', '.cc')):
|
||||
imgui.same_line()
|
||||
if imgui.button(f"[Inspect]##{i}"):
|
||||
self.ui_inspecting_ast_file = f_item
|
||||
self._show_ast_inspector = True
|
||||
|
||||
imgui.same_line()
|
||||
if imgui.button(f"[Slices]##{i}"):
|
||||
self.ui_editing_slices_file = f_item
|
||||
f_path = f_item.path if hasattr(f_item, "path") else str(f_item)
|
||||
self.text_viewer_title = f"Slices: {f_path}"
|
||||
try:
|
||||
self.text_viewer_content = mcp_client.read_file(f_path)
|
||||
except Exception as e:
|
||||
self.text_viewer_content = f"Error reading file: {e}"
|
||||
self.text_viewer_type = 'cpp' if f_path.endswith(('.cpp', '.hpp', '.h')) else 'python' if f_path.endswith('.py') else 'text'
|
||||
self.show_text_viewer = True
|
||||
|
||||
with imscope.table("ctx_comp_table", 2, imgui.TableFlags_.resizable | imgui.TableFlags_.borders) as active:
|
||||
if active:
|
||||
imgui.table_setup_column("File", imgui.TableColumnFlags_.width_stretch)
|
||||
imgui.table_setup_column("Flags", imgui.TableColumnFlags_.width_fixed, 200)
|
||||
imgui.table_headers_row()
|
||||
|
||||
file_indices = {id(f): idx for idx, f in enumerate(self.context_files)}
|
||||
|
||||
for dir_name, g_files in grouped_files.items():
|
||||
imgui.table_next_row()
|
||||
imgui.table_set_column_index(0)
|
||||
with imscope.tree_node_ex(f"{dir_name}##dir_{dir_name}", imgui.TreeNodeFlags_.default_open) as is_open:
|
||||
imgui.table_set_column_index(1)
|
||||
if not hasattr(f_item, "view_mode"):
|
||||
f_item.view_mode = "summary"
|
||||
view_modes = ["full", "summary", "skeleton", "outline", "masked", "none"]
|
||||
try:
|
||||
current_idx = view_modes.index(f_item.view_mode)
|
||||
except ValueError:
|
||||
current_idx = 1
|
||||
f_item.view_mode = "summary"
|
||||
imgui.set_next_item_width(120)
|
||||
changed_vm, new_idx = imgui.combo(f"##vm{i}", current_idx, view_modes)
|
||||
if changed_vm:
|
||||
f_item.view_mode = view_modes[new_idx]
|
||||
|
||||
imgui.same_line()
|
||||
if imgui.button(f"[Save]##vpsave{i}"):
|
||||
imgui.open_popup(f"save_vp_popup{i}")
|
||||
|
||||
if imgui.begin_popup(f"save_vp_popup{i}"):
|
||||
imgui.text("Preset Name:")
|
||||
changed_pname, self.ui_new_vp_name = imgui.input_text(f"##pname{i}", self.ui_new_vp_name)
|
||||
if imgui.button("OK"):
|
||||
if self.ui_new_vp_name.strip():
|
||||
self.controller._cb_save_view_preset(self.ui_new_vp_name.strip(), f_item)
|
||||
self.ui_new_vp_name = ""
|
||||
imgui.close_current_popup()
|
||||
imgui.end_popup()
|
||||
if is_open:
|
||||
for f_item in g_files:
|
||||
i = file_indices[id(f_item)]
|
||||
imgui.table_next_row()
|
||||
imgui.table_set_column_index(0)
|
||||
|
||||
# Checkbox for selection
|
||||
f_path = f_item.path if hasattr(f_item, "path") else str(f_item)
|
||||
is_sel = f_path in self.ui_selected_context_files
|
||||
changed_sel, is_sel = imgui.checkbox(f"##sel{i}", is_sel)
|
||||
if changed_sel:
|
||||
if imgui.get_io().key_shift and self._last_selected_context_index != -1:
|
||||
start = min(self._last_selected_context_index, i)
|
||||
end = max(self._last_selected_context_index, i)
|
||||
for idx in range(start, end + 1):
|
||||
item = self.context_files[idx]
|
||||
item_path = item.path if hasattr(item, "path") else str(item)
|
||||
if is_sel:
|
||||
self.ui_selected_context_files.add(item_path)
|
||||
else:
|
||||
self.ui_selected_context_files.discard(item_path)
|
||||
else:
|
||||
if is_sel:
|
||||
self.ui_selected_context_files.add(f_path)
|
||||
else:
|
||||
self.ui_selected_context_files.discard(f_path)
|
||||
self._last_selected_context_index = i
|
||||
imgui.same_line()
|
||||
|
||||
mtime = os.path.getmtime(f_path) if os.path.exists(f_path) else 0
|
||||
cache_key = f"{f_path}_{mtime}"
|
||||
stats = self._file_stats_cache.get(cache_key, {"lines": 0, "ast_elements": 0})
|
||||
f_name = os.path.basename(f_path)
|
||||
imgui.text(f"{f_name} (L: {stats.get('lines', 0)}, AST: {stats.get('ast_elements', 0)})")
|
||||
|
||||
imgui.same_line()
|
||||
if imgui.button(f"[Load]##vpload{i}"):
|
||||
imgui.open_popup(f"load_vp_popup{i}")
|
||||
|
||||
if imgui.begin_popup(f"load_vp_popup{i}"):
|
||||
vp_names = sorted([vp.name for vp in self.controller.view_presets])
|
||||
if not vp_names:
|
||||
imgui.text("No presets saved.")
|
||||
for vp_name in vp_names:
|
||||
if imgui.selectable(vp_name):
|
||||
self.controller._cb_apply_view_preset(vp_name, f_item)
|
||||
imgui.close_current_popup()
|
||||
imgui.end_popup()
|
||||
if hasattr(f_item, "custom_slices") and f_item.custom_slices:
|
||||
imgui.same_line()
|
||||
imgui.text_colored(imgui.ImVec4(1.0, 0.5, 0.0, 1.0), "[Slices Active]")
|
||||
imgui.tree_pop()
|
||||
|
||||
imgui.end_table()
|
||||
if f_path.lower().endswith(('.c', '.cpp', '.h', '.hpp', '.cxx', '.cc')):
|
||||
imgui.same_line()
|
||||
if imgui.button(f"[Inspect]##{i}"):
|
||||
self.ui_inspecting_ast_file = f_item
|
||||
self._show_ast_inspector = True
|
||||
|
||||
imgui.same_line()
|
||||
if imgui.button(f"[Slices]##{i}"):
|
||||
self.ui_editing_slices_file = f_item
|
||||
f_path = f_item.path if hasattr(f_item, "path") else str(f_item)
|
||||
self.text_viewer_title = f"Slices: {f_path}"
|
||||
try:
|
||||
self.text_viewer_content = mcp_client.read_file(f_path)
|
||||
except Exception as e:
|
||||
self.text_viewer_content = f"Error reading file: {e}"
|
||||
self.text_viewer_type = 'cpp' if f_path.endswith(('.cpp', '.hpp', '.h')) else 'python' if f_path.endswith('.py') else 'text'
|
||||
self.show_text_viewer = True
|
||||
|
||||
imgui.table_set_column_index(1)
|
||||
if not hasattr(f_item, "view_mode"):
|
||||
f_item.view_mode = "summary"
|
||||
view_modes = ["full", "summary", "skeleton", "outline", "masked", "none"]
|
||||
try:
|
||||
current_idx = view_modes.index(f_item.view_mode)
|
||||
except ValueError:
|
||||
current_idx = 1
|
||||
f_item.view_mode = "summary"
|
||||
imgui.set_next_item_width(120)
|
||||
changed_vm, new_idx = imgui.combo(f"##vm{i}", current_idx, view_modes)
|
||||
if changed_vm:
|
||||
f_item.view_mode = view_modes[new_idx]
|
||||
|
||||
imgui.same_line()
|
||||
if imgui.button(f"[Save]##vpsave{i}"):
|
||||
imgui.open_popup(f"save_vp_popup{i}")
|
||||
|
||||
if imgui.begin_popup(f"save_vp_popup{i}"):
|
||||
imgui.text("Preset Name:")
|
||||
changed_pname, self.ui_new_vp_name = imgui.input_text(f"##pname{i}", self.ui_new_vp_name)
|
||||
if imgui.button("OK"):
|
||||
if self.ui_new_vp_name.strip():
|
||||
self.controller._cb_save_view_preset(self.ui_new_vp_name.strip(), f_item)
|
||||
self.ui_new_vp_name = ""
|
||||
imgui.close_current_popup()
|
||||
imgui.end_popup()
|
||||
|
||||
imgui.same_line()
|
||||
if imgui.button(f"[Load]##vpload{i}"):
|
||||
imgui.open_popup(f"load_vp_popup{i}")
|
||||
|
||||
if imgui.begin_popup(f"load_vp_popup{i}"):
|
||||
vp_names = sorted([vp.name for vp in self.controller.view_presets])
|
||||
if not vp_names:
|
||||
imgui.text("No presets saved.")
|
||||
for vp_name in vp_names:
|
||||
if imgui.selectable(vp_name):
|
||||
self.controller._cb_apply_view_preset(vp_name, f_item)
|
||||
imgui.close_current_popup()
|
||||
imgui.end_popup()
|
||||
if hasattr(f_item, "custom_slices") and f_item.custom_slices:
|
||||
imgui.same_line()
|
||||
imgui.text_colored(imgui.ImVec4(1.0, 0.5, 0.0, 1.0), "[Slices Active]")
|
||||
# Context Composition collasping header
|
||||
|
||||
imgui.separator()
|
||||
@@ -4078,53 +4063,47 @@ def hello():
|
||||
self._handle_reset_session()
|
||||
if self.perf_profiling_enabled: self.perf_monitor.end_component("_render_message_panel")
|
||||
|
||||
def _render_response_panel(self) -> None:
|
||||
if self.perf_profiling_enabled: self.perf_monitor.start_component("_render_response_panel")
|
||||
if self._trigger_blink:
|
||||
self._trigger_blink = False
|
||||
self._is_blinking = True
|
||||
self._blink_start_time = time.time()
|
||||
try:
|
||||
imgui.set_window_focus("Response") # type: ignore[call-arg]
|
||||
except:
|
||||
pass
|
||||
is_blinking = False
|
||||
if self._is_blinking:
|
||||
elapsed = time.time() - self._blink_start_time
|
||||
if elapsed > 1.5:
|
||||
self._is_blinking = False
|
||||
else:
|
||||
is_blinking = True
|
||||
val = math.sin(elapsed * 8 * math.pi)
|
||||
alpha = 50/255 if val > 0 else 0
|
||||
imgui.push_style_color(imgui.Col_.frame_bg, vec4(0, 255, 0, alpha))
|
||||
imgui.push_style_color(imgui.Col_.child_bg, vec4(0, 255, 0, alpha))
|
||||
# --- Always Render Content ---
|
||||
|
||||
imgui.begin_child("response_scroll_area", imgui.ImVec2(0, -40), True)
|
||||
is_nerv = theme.is_nerv_active()
|
||||
if is_nerv: imgui.push_style_color(imgui.Col_.text, vec4(80, 255, 80))
|
||||
|
||||
segments, parsed_response = thinking_parser.parse_thinking_trace(self.ai_response)
|
||||
if segments:
|
||||
self._render_thinking_trace([{"content": s.content, "marker": s.marker} for s in segments], 9999)
|
||||
|
||||
markdown_helper.render(parsed_response, context_id="response")
|
||||
|
||||
if is_nerv: imgui.pop_style_color()
|
||||
imgui.end_child()
|
||||
|
||||
imgui.separator()
|
||||
if imgui.button("-> History"):
|
||||
if self.ai_response:
|
||||
segments, response = thinking_parser.parse_thinking_trace(self.ai_response)
|
||||
entry = {"role": "AI", "content": response, "collapsed": True, "ts": project_manager.now_ts()}
|
||||
if segments:
|
||||
entry["thinking_segments"] = [{"content": s.content, "marker": s.marker} for s in segments]
|
||||
self.disc_entries.append(entry)
|
||||
if is_blinking:
|
||||
imgui.pop_style_color(2)
|
||||
if self.perf_profiling_enabled: self.perf_monitor.end_component("_render_response_panel")
|
||||
def _render_response_panel(self) -> None:
|
||||
if self.perf_profiling_enabled: self.perf_monitor.start_component("_render_response_panel")
|
||||
if self._trigger_blink:
|
||||
self._trigger_blink = False
|
||||
self._is_blinking = True
|
||||
self._blink_start_time = time.time()
|
||||
try:
|
||||
imgui.set_window_focus("Response") # type: ignore[call-arg]
|
||||
except:
|
||||
pass
|
||||
is_blinking = False
|
||||
blink_color = vec4(0, 0, 0, 0)
|
||||
if self._is_blinking:
|
||||
elapsed = time.time() - self._blink_start_time
|
||||
if elapsed > 1.5:
|
||||
self._is_blinking = False
|
||||
else:
|
||||
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)
|
||||
|
||||
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():
|
||||
with imscope.child("response_scroll_area", imgui.ImVec2(0, -40), True):
|
||||
is_nerv = theme.is_nerv_active()
|
||||
with imscope.style_color(imgui.Col_.text, vec4(80, 255, 80)) if is_nerv else nullcontext():
|
||||
segments, parsed_response = thinking_parser.parse_thinking_trace(self.ai_response)
|
||||
if segments:
|
||||
self._render_thinking_trace([{"content": s.content, "marker": s.marker} for s in segments], 9999)
|
||||
markdown_helper.render(parsed_response, context_id="response")
|
||||
|
||||
imgui.separator()
|
||||
if imgui.button("-> History"):
|
||||
if self.ai_response:
|
||||
segments, response = thinking_parser.parse_thinking_trace(self.ai_response)
|
||||
entry = {"role": "AI", "content": response, "collapsed": True, "ts": project_manager.now_ts()}
|
||||
if segments:
|
||||
entry["thinking_segments"] = [{"content": s.content, "marker": s.marker} for s in segments]
|
||||
self.disc_entries.append(entry)
|
||||
if self.perf_profiling_enabled: self.perf_monitor.end_component("_render_response_panel")
|
||||
|
||||
def _render_external_tools_panel(self) -> None:
|
||||
if self.perf_profiling_enabled: self.perf_monitor.start_component("_render_external_tools_panel")
|
||||
@@ -5188,34 +5167,6 @@ def hello():
|
||||
imgui.end()
|
||||
if self.perf_profiling_enabled: self.perf_monitor.end_component("_render_theme_panel")
|
||||
|
||||
def _render_prior_session_view(self) -> None: imgui.push_style_color(imgui.Col_.child_bg, vec4(50, 40, 20))
|
||||
if imgui.button("Exit Prior Session"): self.controller.cb_exit_prior_session(); self._comms_log_dirty = True
|
||||
imgui.separator()
|
||||
with imscope.child("prior_scroll"):
|
||||
clipper = imgui.ListClipper(); clipper.begin(len(self.prior_disc_entries))
|
||||
while clipper.step():
|
||||
for idx in range(clipper.display_start, clipper.display_end):
|
||||
entry = self.prior_disc_entries[idx];
|
||||
with imscope.id(f"prior_disc_{idx}"):
|
||||
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}]")
|
||||
if ts: imgui.same_line(); imgui.text_colored(vec4(160, 160, 160), str(ts))
|
||||
content = entry.get("content", "")
|
||||
if collapsed:
|
||||
imgui.same_line(); preview = content.replace("\n", " ")[:80]
|
||||
if len(content) > 80: preview += "..."
|
||||
imgui.text_colored(vec4(180, 180, 180), preview)
|
||||
else:
|
||||
is_nerv = theme.is_nerv_active()
|
||||
if is_nerv: imgui.push_style_color(imgui.Col_.text, vec4(80, 255, 80))
|
||||
markdown_helper.render(content, context_id=f'prior_disc_{idx}')
|
||||
if is_nerv: imgui.pop_style_color()
|
||||
imgui.separator()
|
||||
imgui.pop_style_color()
|
||||
|
||||
def _render_discussion_selector(self) -> None:
|
||||
if not imgui.collapsing_header("Discussions", imgui.TreeNodeFlags_.default_open): return
|
||||
names = self._get_discussion_names(); grouped = {}
|
||||
for name in names:
|
||||
|
||||
@@ -160,3 +160,39 @@ class _ScopeTabItem:
|
||||
if self._expanded:
|
||||
imgui.end_tab_item()
|
||||
return False
|
||||
|
||||
def style_color(col: int, val: Any): return _ScopeStyleColor(col, val)
|
||||
class _ScopeStyleColor:
|
||||
def __init__(self, col: int, val: Any):
|
||||
self._col = col
|
||||
self._val = val
|
||||
def __enter__(self):
|
||||
imgui.push_style_color(self._col, self._val)
|
||||
def __exit__(self, *args):
|
||||
imgui.pop_style_color()
|
||||
return False
|
||||
|
||||
def style_var(var: int, val: Any): return _ScopeStyleVar(var, val)
|
||||
class _ScopeStyleVar:
|
||||
def __init__(self, var: int, val: Any):
|
||||
self._var = var
|
||||
self._val = val
|
||||
def __enter__(self):
|
||||
imgui.push_style_var(self._var, self._val)
|
||||
def __exit__(self, *args):
|
||||
imgui.pop_style_var()
|
||||
return False
|
||||
|
||||
def tree_node_ex(label: str, flags: int = 0): return _ScopeTreeNodeEx(label, flags)
|
||||
class _ScopeTreeNodeEx:
|
||||
def __init__(self, label: str, flags: int):
|
||||
self._label = label
|
||||
self._flags = flags
|
||||
self._opened = False
|
||||
def __enter__(self):
|
||||
self._opened = imgui.tree_node_ex(self._label, self._flags)
|
||||
return self._opened
|
||||
def __exit__(self, *args):
|
||||
if self._opened:
|
||||
imgui.tree_pop()
|
||||
return False
|
||||
|
||||
Reference in New Issue
Block a user