Private
Public Access
0
0

feat(gui): Unified window state and fixed context preservation regressions

- Implement unified show_windows['Text Viewer'] state and fix docking conflict loops.
- Fix Tool Call row interactivity using spanned selectables.
- Fix context selection loss when switching/creating discussions.
- Implement 'Empty Context Warning' modal for safer generation.
- Correct IndentationError in app_controller.py.
- Remove legacy show_text_viewer attribute and update API hooks.
This commit is contained in:
2026-06-02 00:18:48 -04:00
parent b33a213697
commit 0f859d81d6
5 changed files with 39 additions and 63 deletions
+22 -44
View File
@@ -2229,7 +2229,7 @@ def render_preset_manager_content(app: App, is_embedded: bool = False) -> None:
app.text_viewer_title = f"Preset: {app._editing_preset_name}"
app.text_viewer_content = app._editing_preset_system_prompt
app.text_viewer_type = "markdown"
app.show_text_viewer = True
app.show_windows["Text Viewer"] = True
rem_y = imgui.get_content_region_avail().y
_, app._editing_preset_system_prompt = imgui.input_text_multiline("##pcont", app._editing_preset_system_prompt, imgui.ImVec2(-1, rem_y))
@@ -3242,7 +3242,7 @@ def render_context_files_table(app: App) -> None:
except Exception as e:
app.text_viewer_content = f"Error reading file: {e}"
app.text_viewer_type = 'cpp' if f_path.endswith(('.cpp', '.hpp', '.h')) else 'python' if f_path.endswith('.py') else 'text'
app.show_text_viewer = True
app.show_windows["Text Viewer"] = True
app.show_windows["Text Viewer"] = True
imgui.table_set_column_index(1)
@@ -3499,7 +3499,7 @@ def render_discussion_entry_read_mode(app: App, entry: dict, index: int) -> None
if imgui.collapsing_header(f'Chunk {idx}: {path}'):
if imgui.button(f'[Source]##rag_{index}_{idx}'):
res = mcp_client.read_file(path)
if res: app.text_viewer_title, app.text_viewer_content, app.text_viewer_type, app.show_text_viewer = path, res, (Path(path).suffix.lstrip('.') if Path(path).suffix else 'text'), True
if res: app.text_viewer_title, app.text_viewer_content, app.text_viewer_type = path, res, (Path(path).suffix.lstrip('.') if Path(path).suffix else 'text'); app.show_windows["Text Viewer"] = True
imgui.text_unformatted(chunk_content)
content = content[:rag_match.start()] + content[rag_match.end():]
pattern = re.compile(r"\[Definition: (.*?) from (.*?) \(line (\d+)\)\](\s+```[\s\S]*?```)?")
@@ -3520,7 +3520,7 @@ def render_discussion_entry_read_mode(app: App, entry: dict, index: int) -> None
if imgui.collapsing_header(header_text):
if imgui.button(f"[Source]##{index}_{match.start()}"):
res = mcp_client.read_file(path)
if res: app.text_viewer_title, app.text_viewer_content, app.text_viewer_type, app.show_text_viewer = path, res, (Path(path).suffix.lstrip('.') if Path(path).suffix else 'text'), True
if res: app.text_viewer_title, app.text_viewer_content, app.text_viewer_type = path, res, (Path(path).suffix.lstrip('.') if Path(path).suffix else 'text'); app.show_windows["Text Viewer"] = True
if code_block:
with theme.ai_text_style():
markdown_helper.render(code_block, context_id=f'disc_{index}_c_{m_idx}')
@@ -4127,36 +4127,31 @@ def render_tool_calls_panel(app: App) -> None:
entry = log_to_render[i]
imgui.table_next_row()
script = entry.get("script", "")
res = entry.get("result", "")
combined = f"**COMMAND:**\n```powershell\n{script}\n```\n\n---\n**OUTPUT:**\n```text\n{res}\n```"
imgui.table_next_column()
imgui.text_colored(C_LBL, f"#{i+1}")
# Use selectable for the entire row trigger
opened_details = imgui.selectable(f"#{i+1}##row_{i}", False, imgui.SelectableFlags_.span_all_columns)[0]
if opened_details:
app.text_viewer_title = f"Tool Call #{i+1} Details"
app.text_viewer_content = combined
app.text_viewer_type = 'markdown'
app.show_windows["Text Viewer"] = True
imgui.table_next_column()
imgui.text_colored(C_SUB, f"[{entry.get('source_tier', 'main')}]")
imgui.table_next_column()
script = entry.get("script", "")
res = entry.get("result", "")
# Use a clear, formatted combined view for the detail window
combined = f"**COMMAND:**\n```powershell\n{script}\n```\n\n---\n**OUTPUT:**\n```text\n{res}\n```"
script_preview = script.replace("\n", " ")[:150]
if len(script) > 150: script_preview += "..."
render_selectable_label(app, f'tc_script_{i}', script_preview, width=-1)
if imgui.is_item_clicked():
app.text_viewer_title = f"Tool Call #{i+1} Details"
app.text_viewer_content = combined
app.text_viewer_type = 'markdown'
app.show_text_viewer = True
imgui.table_next_column()
res_preview = res.replace("\n", " ")[:30]
if len(res) > 30: res_preview += "..."
render_selectable_label(app, f'tc_res_{i}', res_preview, width=-1)
if imgui.is_item_clicked():
app.text_viewer_title = f"Tool Call #{i+1} Details"
app.text_viewer_content = combined
app.text_viewer_type = 'markdown'
app.show_text_viewer = True
imgui.end_table()
@@ -4211,10 +4206,10 @@ def render_external_tools_panel(app: App) -> None:
def render_text_viewer_window(app: App) -> None:
"""Renders the standalone text/code/markdown viewer window."""
if not app.show_text_viewer: return
if not app.show_windows.get("Text Viewer", False): return
imgui.set_next_window_size(imgui.ImVec2(900, 700), imgui.Cond_.first_use_ever)
expanded, opened = imgui.begin(f"{app.text_viewer_title or 'Text Viewer'}###Text_Viewer", app.show_text_viewer)
app.show_text_viewer = bool(opened)
expanded, opened = imgui.begin(f"{app.text_viewer_title or 'Text Viewer'}###Text_Viewer", True, imgui.WindowFlags_.no_collapse)
app.show_windows["Text Viewer"] = bool(opened)
if not opened:
app.ui_editing_slices_file = None
app._slice_sel_start = -1
@@ -4470,8 +4465,8 @@ def render_approve_script_modal(app: App) -> None:
imgui.text_colored(vec4(200, 200, 100), f"base_dir: {dlg._base_dir}")
imgui.separator()
# Checkbox to toggle full preview inside modal
_, app.show_text_viewer = imgui.checkbox("Show Full Preview", app.show_text_viewer)
if app.show_text_viewer:
_, app.show_windows["Text Viewer"] = imgui.checkbox("Show Full Preview", app.show_windows.get("Text Viewer", False))
if app.show_windows.get("Text Viewer", False):
imgui.begin_child("preview_child", imgui.ImVec2(600, 300), True)
imgui.text_unformatted(dlg._script)
imgui.end_child()
@@ -4634,14 +4629,14 @@ def render_error_tint(app: App) -> None:
def render_text_viewer(app: App, label: str, content: str, text_type: str = 'text', force_open: bool = False, id_suffix: str = "") -> None:
if imgui.button(f"[+]##{id_suffix or str(id(content))}") or force_open:
app.text_viewer_type = text_type
app.show_text_viewer = True
app.show_windows["Text Viewer"] = True
app.text_viewer_title = label
app.text_viewer_content = content
app.show_windows["Text Viewer"] = True
def render_heavy_text(app: App, label: str, content: str, id_suffix: str = "") -> None:
if imgui.button(f"[+]##{label}{id_suffix}"):
app.show_text_viewer = True
app.show_windows["Text Viewer"] = True
app.show_windows["Text Viewer"] = True
app.text_viewer_type = 'markdown' if label in ('message', 'text', 'content', 'system') else 'json' if label in ('tool_calls', 'data') else 'powershell' if label == 'script' else 'text'
app.text_viewer_title = label
@@ -5458,23 +5453,6 @@ def render_empty_context_modal(app: App) -> None:
def render_context_modals(app: App) -> None:
render_empty_context_modal(app)
if app.show_empty_context_warning_modal:
imgui.open_popup("Empty Context Warning")
app.show_empty_context_warning_modal = False
if imgui.begin_popup_modal("Empty Context Warning", True, imgui.WindowFlags_.always_auto_resize)[0]:
imgui.text_colored(imgui.ImVec4(1.0, 1.0, 0.0, 1.0), "WARNING: Empty Context Composition")
imgui.text("You are attempting to generate a response without any files selected.")
imgui.text("This may result in poor AI performance or loss of project context.")
imgui.separator()
if imgui.button("Proceed Anyway", imgui.ImVec2(150, 0)):
if app._empty_context_target_action == 'generate': app.controller._handle_generate_send()
elif app._empty_context_target_action == 'md_only': app.controller._handle_md_only()
imgui.close_current_popup()
imgui.same_line()
if imgui.button("Cancel", imgui.ImVec2(120, 0)):
imgui.close_current_popup()
imgui.end_popup()
if app.show_missing_files_modal:
imgui.open_popup("Missing Files Warning")