modularize gui_2.py and fix imgui scope leaks
This commit is contained in:
+66
-194
@@ -1625,197 +1625,78 @@ class App:
|
||||
with imscope.tab_item("Beads") as (exp, _):
|
||||
if exp: self._render_beads_tab()
|
||||
imgui.end_tab_bar()
|
||||
|
||||
if self._pending_ask_dialog:
|
||||
if not self._ask_dialog_open:
|
||||
imgui.open_popup("Approve Tool Execution")
|
||||
self._ask_dialog_open = True
|
||||
else:
|
||||
self._ask_dialog_open = False
|
||||
|
||||
if imgui.begin_popup_modal("Approve Tool Execution", None, imgui.WindowFlags_.always_auto_resize)[0]:
|
||||
if not self._pending_ask_dialog or self._ask_tool_data is None:
|
||||
imgui.close_current_popup()
|
||||
else:
|
||||
tool_name = self._ask_tool_data.get("tool", "unknown")
|
||||
tool_args = self._ask_tool_data.get("args", {})
|
||||
imgui.text("The AI wants to execute a tool:")
|
||||
imgui.text_colored(vec4(200, 200, 100), f"Tool: {tool_name}")
|
||||
imgui.separator()
|
||||
imgui.text("Arguments:")
|
||||
imgui.begin_child("ask_args_child", imgui.ImVec2(400, 200), True)
|
||||
imgui.text_unformatted(json.dumps(tool_args, indent=2))
|
||||
imgui.end_child()
|
||||
imgui.separator()
|
||||
if imgui.button("Approve", imgui.ImVec2(120, 0)):
|
||||
self._handle_approve_ask()
|
||||
imgui.close_current_popup()
|
||||
|
||||
def _render_text_viewer_window(self) -> None:
|
||||
"""Renders the standalone text/code/markdown viewer window."""
|
||||
if not self.show_text_viewer: return
|
||||
imgui.set_next_window_size(imgui.ImVec2(900, 700), imgui.Cond_.first_use_ever)
|
||||
expanded, opened = imgui.begin(f"Text Viewer - {self.text_viewer_title}", self.show_text_viewer)
|
||||
self.show_text_viewer = bool(opened)
|
||||
if not opened:
|
||||
self.ui_editing_slices_file = None
|
||||
self._slice_sel_start = -1
|
||||
self._slice_sel_end = -1
|
||||
if expanded:
|
||||
if self.ui_editing_slices_file is not None:
|
||||
imgui.text_colored(C_IN, "Slice Management (Click-drag lines to select range)")
|
||||
if imgui.button("Add Selection as Slice"):
|
||||
if self._slice_sel_start != -1 and self._slice_sel_end != -1:
|
||||
s_line = min(self._slice_sel_start, self._slice_sel_end)
|
||||
e_line = max(self._slice_sel_start, self._slice_sel_end)
|
||||
from src.fuzzy_anchor import FuzzyAnchor
|
||||
slice_data = FuzzyAnchor.create_slice(self.text_viewer_content, s_line, e_line)
|
||||
slice_data['tag'] = ""; slice_data['comment'] = ""
|
||||
self.ui_editing_slices_file.custom_slices.append(slice_data)
|
||||
self._slice_sel_start = -1; self._slice_sel_end = -1
|
||||
imgui.same_line()
|
||||
if imgui.button("Deny", imgui.ImVec2(120, 0)):
|
||||
self._handle_reject_ask()
|
||||
imgui.close_current_popup()
|
||||
imgui.end_popup()
|
||||
|
||||
#region: MMA Step Approval Modal
|
||||
if self._pending_mma_approvals:
|
||||
if not self._mma_approval_open:
|
||||
imgui.open_popup("MMA Step Approval")
|
||||
self._mma_approval_open = True
|
||||
self._mma_approval_edit_mode = False
|
||||
self._mma_approval_payload = self._pending_mma_approvals[0].get("payload", "")
|
||||
else:
|
||||
self._mma_approval_open = False
|
||||
if imgui.begin_popup_modal("MMA Step Approval", None, imgui.WindowFlags_.always_auto_resize)[0]:
|
||||
if not self._pending_mma_approvals:
|
||||
imgui.close_current_popup()
|
||||
else:
|
||||
ticket_id = self._pending_mma_approvals[0].get("ticket_id", "??")
|
||||
imgui.text(f"Ticket {ticket_id} is waiting for tool execution approval.")
|
||||
imgui.separator()
|
||||
if self._mma_approval_edit_mode:
|
||||
imgui.text("Edit Raw Payload (Manual Memory Mutation):")
|
||||
_, self._mma_approval_payload = imgui.input_text_multiline("##mma_payload", self._mma_approval_payload, imgui.ImVec2(600, 400))
|
||||
else:
|
||||
imgui.text("Proposed Tool Call:")
|
||||
imgui.begin_child("mma_preview", imgui.ImVec2(600, 300), True)
|
||||
imgui.text_unformatted(str(self._pending_mma_approvals[0].get("payload", "")))
|
||||
imgui.end_child()
|
||||
imgui.separator()
|
||||
if imgui.button("Approve", imgui.ImVec2(120, 0)):
|
||||
self._handle_mma_respond(approved=True, payload=self._mma_approval_payload)
|
||||
imgui.close_current_popup()
|
||||
imgui.same_line()
|
||||
if imgui.button("Edit Payload" if not self._mma_approval_edit_mode else "Show Original", imgui.ImVec2(120, 0)):
|
||||
self._mma_approval_edit_mode = not self._mma_approval_edit_mode
|
||||
if self._is_script_blinking:
|
||||
imgui.pop_style_color(2)
|
||||
imgui.end()
|
||||
if self.show_text_viewer:
|
||||
imgui.set_next_window_size(imgui.ImVec2(900, 700), imgui.Cond_.first_use_ever)
|
||||
expanded, opened = imgui.begin(f"Text Viewer - {self.text_viewer_title}", self.show_text_viewer)
|
||||
self.show_text_viewer = bool(opened)
|
||||
if not opened:
|
||||
self.ui_editing_slices_file = None
|
||||
self._slice_sel_start = -1
|
||||
self._slice_sel_end = -1
|
||||
|
||||
if expanded:
|
||||
if self.ui_editing_slices_file is not None:
|
||||
imgui.text_colored(C_IN, "Slice Management (Click-drag lines to select range)")
|
||||
if imgui.button("Add Selection as Slice"):
|
||||
if self._slice_sel_start != -1 and self._slice_sel_end != -1:
|
||||
s_line = min(self._slice_sel_start, self._slice_sel_end)
|
||||
e_line = max(self._slice_sel_start, self._slice_sel_end)
|
||||
from src.fuzzy_anchor import FuzzyAnchor
|
||||
slice_data = FuzzyAnchor.create_slice(self.text_viewer_content, s_line, e_line)
|
||||
slice_data['tag'] = ""
|
||||
slice_data['comment'] = ""
|
||||
self.ui_editing_slices_file.custom_slices.append(slice_data)
|
||||
self._slice_sel_start = -1
|
||||
self._slice_sel_end = -1
|
||||
if imgui.button("Clear Selection"): self._slice_sel_start = -1; self._slice_sel_end = -1
|
||||
to_remove = -1
|
||||
for idx, slc in enumerate(self.ui_editing_slices_file.custom_slices):
|
||||
imgui.push_id(f"slc_row_{idx}"); imgui.text(f"Slice {idx+1}: {slc['start_line']}-{slc['end_line']}"); imgui.same_line()
|
||||
imgui.set_next_item_width(100); changed_tag, new_tag = imgui.input_text("Tag", slc.get('tag', ''))
|
||||
if changed_tag: slc['tag'] = new_tag
|
||||
imgui.same_line(); imgui.set_next_item_width(200); changed_comm, new_comm = imgui.input_text("Comment", slc.get('comment', ''))
|
||||
if changed_comm: slc['comment'] = new_comm
|
||||
imgui.same_line()
|
||||
if imgui.button("Clear Selection"):
|
||||
self._slice_sel_start = -1
|
||||
self._slice_sel_end = -1
|
||||
|
||||
# Render existing slices (Tasks 3.4)
|
||||
to_remove = -1
|
||||
for idx, slc in enumerate(self.ui_editing_slices_file.custom_slices):
|
||||
imgui.push_id(f"slc_row_{idx}")
|
||||
imgui.text(f"Slice {idx+1}: {slc['start_line']}-{slc['end_line']}")
|
||||
imgui.same_line()
|
||||
|
||||
imgui.set_next_item_width(100)
|
||||
changed_tag, new_tag = imgui.input_text("Tag", slc.get('tag', ''))
|
||||
if changed_tag: slc['tag'] = new_tag
|
||||
|
||||
imgui.same_line()
|
||||
imgui.set_next_item_width(200)
|
||||
changed_comm, new_comm = imgui.input_text("Comment", slc.get('comment', ''))
|
||||
if changed_comm: slc['comment'] = new_comm
|
||||
|
||||
imgui.same_line()
|
||||
if imgui.button("Remove"):
|
||||
to_remove = idx
|
||||
imgui.pop_id()
|
||||
if to_remove != -1:
|
||||
self.ui_editing_slices_file.custom_slices.pop(to_remove)
|
||||
imgui.separator()
|
||||
|
||||
# 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)
|
||||
if imgui.button("Remove"): to_remove = idx
|
||||
imgui.pop_id()
|
||||
if to_remove != -1: self.ui_editing_slices_file.custom_slices.pop(to_remove)
|
||||
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 self.ui_editing_slices_file is not None:
|
||||
# Manual renderer for slice editing (Tasks 3.1, 3.2, 3.3)
|
||||
imgui.begin_child("slice_editor_content", imgui.ImVec2(-1, -1), True)
|
||||
lines = self.text_viewer_content.splitlines()
|
||||
draw_list = imgui.get_window_draw_list()
|
||||
|
||||
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':
|
||||
with imscope.child("tv_md_scroll", -1, -1, True): markdown_helper.render(self.text_viewer_content, context_id='text_viewer')
|
||||
elif self.ui_editing_slices_file is not None:
|
||||
with imscope.child("slice_editor_content", -1, -1, True):
|
||||
lines = self.text_viewer_content.splitlines(); draw_list = imgui.get_window_draw_list()
|
||||
for i, line_text in enumerate(lines):
|
||||
line_num = i + 1
|
||||
pos = imgui.get_cursor_screen_pos()
|
||||
line_height = imgui.get_text_line_height()
|
||||
|
||||
# Check if part of any slice (Task 3.2)
|
||||
is_sliced = False
|
||||
for slc in self.ui_editing_slices_file.custom_slices:
|
||||
if slc['start_line'] <= line_num <= slc['end_line']:
|
||||
is_sliced = True
|
||||
break
|
||||
|
||||
if is_sliced:
|
||||
# Orange alpha 0.2
|
||||
draw_list.add_rect_filled(pos, imgui.ImVec2(pos.x + imgui.get_content_region_avail().x, pos.y + line_height), imgui.get_color_u32(vec4(255, 165, 0, 0.2)))
|
||||
|
||||
# Selection highlight (Task 3.3)
|
||||
line_num = i + 1; pos = imgui.get_cursor_screen_pos(); line_height = imgui.get_text_line_height()
|
||||
is_sliced = any(slc['start_line'] <= line_num <= slc['end_line'] for slc in self.ui_editing_slices_file.custom_slices)
|
||||
if is_sliced: draw_list.add_rect_filled(pos, imgui.ImVec2(pos.x + imgui.get_content_region_avail().x, pos.y + line_height), imgui.get_color_u32(vec4(255, 165, 0, 0.2)))
|
||||
if self._slice_sel_start != -1 and self._slice_sel_end != -1:
|
||||
s = min(self._slice_sel_start, self._slice_sel_end)
|
||||
e = max(self._slice_sel_start, self._slice_sel_end)
|
||||
if s <= line_num <= e:
|
||||
draw_list.add_rect_filled(pos, imgui.ImVec2(pos.x + imgui.get_content_region_avail().x, pos.y + line_height), imgui.get_color_u32(vec4(100, 100, 255, 0.3)))
|
||||
|
||||
s, e = min(self._slice_sel_start, self._slice_sel_end), max(self._slice_sel_start, self._slice_sel_end)
|
||||
if s <= line_num <= e: draw_list.add_rect_filled(pos, imgui.ImVec2(pos.x + imgui.get_content_region_avail().x, pos.y + line_height), imgui.get_color_u32(vec4(100, 100, 255, 0.3)))
|
||||
imgui.selectable(f"{line_num:4} | {line_text}##ln{line_num}", False)
|
||||
if imgui.is_item_clicked():
|
||||
self._slice_sel_start = line_num
|
||||
self._slice_sel_end = line_num
|
||||
if imgui.is_item_hovered() and imgui.is_mouse_down(0):
|
||||
self._slice_sel_end = line_num
|
||||
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)
|
||||
|
||||
if imgui.is_item_clicked(): self._slice_sel_start = line_num; self._slice_sel_end = line_num
|
||||
if imgui.is_item_hovered() and imgui.is_mouse_down(0): self._slice_sel_end = line_num
|
||||
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)
|
||||
try:
|
||||
self._text_viewer_editor.set_text(self.text_viewer_content)
|
||||
if self.perf_profiling_enabled: self.perf_monitor.start_component("_render_text_viewer_ced")
|
||||
self._text_viewer_editor.render(f"##ced_{self.text_viewer_title}", imgui.ImVec2(-1, -1))
|
||||
if self.perf_profiling_enabled: self.perf_monitor.end_component("_render_text_viewer_ced")
|
||||
except Exception as e: imgui.text_colored(vec4(255, 100, 100), f"CED Error: {e}"); imgui.text_unformatted(self.text_viewer_content)
|
||||
else:
|
||||
with imscope.child("tv_scroll", -1, -1, True):
|
||||
if self.text_viewer_wrap: imgui.push_text_wrap_pos(imgui.get_content_region_avail().x)
|
||||
imgui.text_unformatted(self.text_viewer_content)
|
||||
if self.text_viewer_wrap: imgui.pop_text_wrap_pos()
|
||||
imgui.end()
|
||||
# Sync text and language
|
||||
lang_id = renderer._lang_map.get(tv_type, ced.TextEditor.LanguageDefinitionId.none)
|
||||
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.push_text_wrap_pos(imgui.get_content_region_avail().x)
|
||||
imgui.text(self.text_viewer_content)
|
||||
imgui.pop_text_wrap_pos()
|
||||
imgui.end_child()
|
||||
else:
|
||||
imgui.input_text_multiline("##tv_c", self.text_viewer_content, imgui.ImVec2(-1, -1), imgui.InputTextFlags_.read_only)
|
||||
imgui.end()
|
||||
#endregion: Cycle Detected Popup
|
||||
|
||||
#region: Inject File Modal
|
||||
if getattr(self, "show_inject_modal", False):
|
||||
@@ -5307,16 +5188,7 @@ def hello():
|
||||
imgui.end()
|
||||
if self.perf_profiling_enabled: self.perf_monitor.end_component("_render_theme_panel")
|
||||
|
||||
def _render_thinking_indicator(self) -> None:
|
||||
is_thinking = self.ai_status in ['sending...', 'streaming...', 'running powershell...']
|
||||
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)
|
||||
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))
|
||||
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"):
|
||||
|
||||
Reference in New Issue
Block a user