From 0863559e595fc4c82577b9a40291b4ac4fb75027 Mon Sep 17 00:00:00 2001 From: Ed_ Date: Thu, 14 May 2026 20:19:44 -0400 Subject: [PATCH] fix(gui): Fix imgui.begin_child unbalanced EndChild() calls In ImGui, EndChild() MUST be called even if BeginChild() returns False (meaning the child is clipped). Using if imgui.begin_child(...): caused EndChild() to be skipped, unbalancing the stack and causing sloppy.py to crash when certain UI panels were off-screen or collapsed. --- src/gui_2.py | 54 +++++++++++++++++++++++++++++++++++----------------- 1 file changed, 37 insertions(+), 17 deletions(-) diff --git a/src/gui_2.py b/src/gui_2.py index 6c2f888..0a1134c 100644 --- a/src/gui_2.py +++ b/src/gui_2.py @@ -1983,7 +1983,8 @@ class App: # Left Sidebar imgui.table_next_column() - if imgui.begin_child("prompt_list_pane", imgui.ImVec2(0, 0), False): + imgui.begin_child("prompt_list_pane", imgui.ImVec2(0, 0), False) + if True: if imgui.button("New Preset", imgui.ImVec2(-1, 0)): self._editing_preset_name = "" self._editing_preset_system_prompt = "" @@ -2003,7 +2004,8 @@ class App: # Right Editor imgui.table_next_column() avail_r = imgui.get_content_region_avail() - if imgui.begin_child("prompt_edit_pane", imgui.ImVec2(0, avail_r.y - 45), False): + imgui.begin_child("prompt_edit_pane", imgui.ImVec2(0, avail_r.y - 45), False) + if True: p_disp = self._editing_preset_name or "(New Preset)" imgui.text_colored(C_IN, f"Editing Prompt Preset: {p_disp}") imgui.separator() @@ -2085,7 +2087,8 @@ class App: # Left Sidebar imgui.table_next_column() - if imgui.begin_child("tp_list_pane", imgui.ImVec2(0, 0), False): + imgui.begin_child("tp_list_pane", imgui.ImVec2(0, 0), False) + if True: if imgui.button("New Preset", imgui.ImVec2(-1, 0)): self._editing_tool_preset_name = ""; self._editing_tool_preset_categories = {cat: {} for cat in models.DEFAULT_TOOL_CATEGORIES} self._editing_tool_preset_scope = "project"; self._selected_tool_preset_idx = -1 @@ -2101,7 +2104,8 @@ class App: # Right Editor imgui.table_next_column() avail_r = imgui.get_content_region_avail() - if imgui.begin_child("tp_editor_content", imgui.ImVec2(0, avail_r.y - 45), False): + imgui.begin_child("tp_editor_content", imgui.ImVec2(0, avail_r.y - 45), False) + if True: p_name = self._editing_tool_preset_name or "(New Tool Preset)" imgui.text_colored(C_IN, f"Editing Tool Preset: {p_name}"); imgui.separator() @@ -2129,7 +2133,8 @@ class App: f_idx = cat_opts.index(self.ui_tool_filter_category) if self.ui_tool_filter_category in cat_opts else 0 imgui.set_next_item_width(200); ch_cat, next_f_idx = imgui.combo("##tp_filter", f_idx, cat_opts) if ch_cat: self.ui_tool_filter_category = cat_opts[next_f_idx] - if imgui.begin_child("tp_scroll", imgui.ImVec2(0, h1), True): + imgui.begin_child("tp_scroll", imgui.ImVec2(0, h1), True) + if True: for cat_name, default_tools in models.DEFAULT_TOOL_CATEGORIES.items(): if self.ui_tool_filter_category != "All" and self.ui_tool_filter_category != cat_name: continue if imgui.tree_node(cat_name): @@ -2162,11 +2167,13 @@ class App: opened_b = imgui.collapsing_header("Bias Profiles", imgui.TreeNodeFlags_.default_open) if opened_b != self._bias_list_open: self._bias_list_open = opened_b if self._bias_list_open: - if imgui.begin_child("bias_area", imgui.ImVec2(0, h2), True): + imgui.begin_child("bias_area", imgui.ImVec2(0, h2), True) + if True: if imgui.begin_table("bias_split", 2, imgui.TableFlags_.resizable | imgui.TableFlags_.borders_inner_v): imgui.table_setup_column("BList", imgui.TableColumnFlags_.width_fixed, 150); imgui.table_setup_column("BEdit", imgui.TableColumnFlags_.width_stretch) imgui.table_next_row(); imgui.table_next_column() - if imgui.begin_child("blist_pane", imgui.ImVec2(0, 0), False): + imgui.begin_child("blist_pane", imgui.ImVec2(0, 0), False) + if True: if imgui.button("New Profile", imgui.ImVec2(-1, 0)): self._editing_bias_profile_name = ""; self._editing_bias_profile_tool_weights = {} self._editing_bias_profile_category_multipliers = {}; self._selected_bias_profile_idx = -1 @@ -2178,7 +2185,8 @@ class App: imgui.end_child() imgui.table_next_column() - if imgui.begin_child("bedit_pane", imgui.ImVec2(0, 0), False): + imgui.begin_child("bedit_pane", imgui.ImVec2(0, 0), False) + if True: imgui.text("Name:"); imgui.same_line(); imgui.set_next_item_width(-1); _, self._editing_bias_profile_name = imgui.input_text("##bname", self._editing_bias_profile_name) rem_bias_y = imgui.get_content_region_avail().y - 45 if self._bias_weights_open and self._bias_cats_open: bh1, bh2 = rem_bias_y * self._bias_split_v, rem_bias_y - (rem_bias_y * self._bias_split_v) - 10 @@ -2189,7 +2197,8 @@ class App: opened_bw = imgui.collapsing_header("Tool Weights", imgui.TreeNodeFlags_.default_open) if opened_bw != self._bias_weights_open: self._bias_weights_open = opened_bw if self._bias_weights_open: - if imgui.begin_child("btool_scroll", imgui.ImVec2(0, bh1), True): + imgui.begin_child("btool_scroll", imgui.ImVec2(0, bh1), True) + if True: for cat_name, default_tools in models.DEFAULT_TOOL_CATEGORIES.items(): if imgui.tree_node(f"{cat_name}##b_list"): if imgui.begin_table(f"bt_{cat_name}", 2): @@ -2209,7 +2218,8 @@ class App: opened_bc = imgui.collapsing_header("Category Multipliers", imgui.TreeNodeFlags_.default_open) if opened_bc != self._bias_cats_open: self._bias_cats_open = opened_bc if self._bias_cats_open: - if imgui.begin_child("bcat_scroll", imgui.ImVec2(0, bh2), True): + imgui.begin_child("bcat_scroll", imgui.ImVec2(0, bh2), True) + if True: if imgui.begin_table("bcats", 2): imgui.table_setup_column("C", imgui.TableColumnFlags_.width_fixed, 220); imgui.table_setup_column("M", imgui.TableColumnFlags_.width_stretch) for cn in sorted(models.DEFAULT_TOOL_CATEGORIES.keys()): @@ -2267,7 +2277,8 @@ class App: imgui.table_next_row() imgui.table_next_column() - if imgui.begin_child("persona_list_pane", imgui.ImVec2(0, 0), False): + imgui.begin_child("persona_list_pane", imgui.ImVec2(0, 0), False) + if True: if imgui.button("New Persona", imgui.ImVec2(-1, 0)): self._editing_persona_name = ""; self._editing_persona_system_prompt = "" self._editing_persona_tool_preset_id = ""; self._editing_persona_bias_profile_id = "" @@ -2290,7 +2301,8 @@ class App: # --- Right Editor --- imgui.table_next_column() avail = imgui.get_content_region_avail() - if imgui.begin_child("persona_editor_content", imgui.ImVec2(0, avail.y - 45), False): + imgui.begin_child("persona_editor_content", imgui.ImVec2(0, avail.y - 45), False) + if True: header_text = "New Persona" if getattr(self, '_editing_persona_is_new', True) else f"Editing Persona: {self._editing_persona_name}" imgui.text_colored(C_IN, header_text); imgui.separator() @@ -2314,7 +2326,8 @@ class App: if opened_models != self._persona_models_open: self._persona_models_open = opened_models if self._persona_models_open: - if imgui.begin_child("pref_models_scroll", imgui.ImVec2(0, h1), True): + imgui.begin_child("pref_models_scroll", imgui.ImVec2(0, h1), True) + if True: to_remove = [] providers = models.PROVIDERS if not hasattr(self, '_persona_pref_models_expanded'): self._persona_pref_models_expanded = {} @@ -2384,7 +2397,8 @@ class App: if opened_prompt != self._persona_prompt_open: self._persona_prompt_open = opened_prompt if self._persona_prompt_open: - if imgui.begin_child("p_prompt_header_pane", imgui.ImVec2(0, 30), False): + imgui.begin_child("p_prompt_header_pane", imgui.ImVec2(0, 30), False) + if True: imgui.text("Template:"); imgui.same_line(); p_pre = ["Select..."] + sorted(self.controller.presets.keys()) if not hasattr(self, "_load_preset_idx"): self._load_preset_idx = 0 imgui.set_next_item_width(200); _, self._load_preset_idx = imgui.combo("##load_p", self._load_preset_idx, p_pre) @@ -2416,6 +2430,9 @@ 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_provider_panel(self) -> None: if self.perf_profiling_enabled: self.perf_monitor.start_component("_render_provider_panel") @@ -2870,7 +2887,8 @@ class App: imgui.table_next_column() #region: LEFT COLUMN (Tree) --- - if imgui.begin_child("ast_tree_scroll", imgui.ImVec2(0, 600), True): + imgui.begin_child("ast_tree_scroll", imgui.ImVec2(0, 600), True) + if True: if not self._cached_ast_nodes: imgui.text("No AST nodes found or error fetching outline.") else: for node in self._cached_ast_nodes: @@ -2899,7 +2917,8 @@ class App: imgui.table_next_column() #region: RIGHT COLUMN (Content) --- - if imgui.begin_child("ast_content_scroll", imgui.ImVec2(0, 600), True): + imgui.begin_child("ast_content_scroll", imgui.ImVec2(0, 600), True) + if True: if not hasattr(self, '_cached_ast_file_lines') or not self._cached_ast_file_lines: imgui.text("No file content loaded.") else: @@ -2950,7 +2969,8 @@ class App: """ if imgui.begin_popup_modal("Select Context Files", None, imgui.WindowFlags_.always_auto_resize)[0]: imgui.text("Select files from project to add to context:") - if imgui.begin_child("ctx_picker_list", imgui.ImVec2(600, 300), True): + imgui.begin_child("ctx_picker_list", imgui.ImVec2(600, 300), True) + if True: # Create a temporary selection set if not initialized if not hasattr(self, '_ui_picker_selected'): self._ui_picker_selected = set() for f in self.files: