Private
Public Access
curation pass on gui_2.py
This commit is contained in:
+63
-163
@@ -41,6 +41,7 @@ import importlib as _importlib
|
|||||||
from typing import Any as _Any
|
from typing import Any as _Any
|
||||||
from typing import Optional as _Optional
|
from typing import Optional as _Optional
|
||||||
|
|
||||||
|
#TODO(Ed): Remove Excpetion based errors
|
||||||
class _LazyModule:
|
class _LazyModule:
|
||||||
"""Lazy proxy that defers an import until first attribute access or call.
|
"""Lazy proxy that defers an import until first attribute access or call.
|
||||||
|
|
||||||
@@ -89,7 +90,6 @@ class _FiledialogStub:
|
|||||||
def askdirectory(self, *args: _Any, **kwargs: _Any) -> str: return ""
|
def askdirectory(self, *args: _Any, **kwargs: _Any) -> str: return ""
|
||||||
def asksaveasfilename(self, *args: _Any, **kwargs: _Any) -> str: return ""
|
def asksaveasfilename(self, *args: _Any, **kwargs: _Any) -> str: return ""
|
||||||
|
|
||||||
|
|
||||||
# Heavy modules that were previously top-level imports (now lazy):
|
# Heavy modules that were previously top-level imports (now lazy):
|
||||||
np = _LazyModule("numpy") # was: import numpy as np
|
np = _LazyModule("numpy") # was: import numpy as np
|
||||||
filedialog = _LazyModule("tkinter", "filedialog") # was: from tkinter import filedialog
|
filedialog = _LazyModule("tkinter", "filedialog") # was: from tkinter import filedialog
|
||||||
@@ -186,6 +186,7 @@ def _detect_refresh_rate_win32() -> float:
|
|||||||
shelled out to PowerShell + WMI (Get-CimInstance Win32_VideoController), which
|
shelled out to PowerShell + WMI (Get-CimInstance Win32_VideoController), which
|
||||||
cost ~350ms on every startup and blocked the first frame.
|
cost ~350ms on every startup and blocked the first frame.
|
||||||
"""
|
"""
|
||||||
|
#Note(Ed): Exception(Thirdparty)
|
||||||
try:
|
try:
|
||||||
import ctypes
|
import ctypes
|
||||||
from ctypes import wintypes
|
from ctypes import wintypes
|
||||||
@@ -233,6 +234,7 @@ def _resolve_font_path(font_path: str, assets_dir: Path) -> str:
|
|||||||
p = Path(font_path)
|
p = Path(font_path)
|
||||||
if not p.is_absolute():
|
if not p.is_absolute():
|
||||||
return font_path # already relative; hello_imgui searches the assets folder
|
return font_path # already relative; hello_imgui searches the assets folder
|
||||||
|
#Note(Ed): Exception(Thirdparty)
|
||||||
try:
|
try:
|
||||||
if p.is_relative_to(assets_dir):
|
if p.is_relative_to(assets_dir):
|
||||||
return str(p.relative_to(assets_dir)).replace("\\", "/")
|
return str(p.relative_to(assets_dir)).replace("\\", "/")
|
||||||
@@ -297,16 +299,9 @@ class App:
|
|||||||
"""The main ImGui interface orchestrator for Manual Slop."""
|
"""The main ImGui interface orchestrator for Manual Slop."""
|
||||||
|
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
"""
|
"""Initializes core app dependencies (controller, history, performance monitor,
|
||||||
Initializes core app dependencies (controller, history, performance monitor,
|
|
||||||
command palette, workspace manager) and registers app callback handlers.
|
command palette, workspace manager) and registers app callback handlers.
|
||||||
|
SSDL Shape: `[I:init_controller] -> [I:init_workspace] -> [I:load_profiles]`
|
||||||
State Mutations:
|
|
||||||
self.controller, self.perf_monitor, self.history,
|
|
||||||
self.show_command_palette, self.workspace_manager.
|
|
||||||
|
|
||||||
SSDL Shape:
|
|
||||||
`[I:init_controller] -> [I:init_workspace] -> [I:load_profiles]`
|
|
||||||
"""
|
"""
|
||||||
#region: --- Core Dependencies & State ---
|
#region: --- Core Dependencies & State ---
|
||||||
from src.startup_profiler import startup_profiler
|
from src.startup_profiler import startup_profiler
|
||||||
@@ -564,18 +559,17 @@ class App:
|
|||||||
# is safe. The render_warmup_status_indicator() function reads
|
# is safe. The render_warmup_status_indicator() function reads
|
||||||
# the timestamp to show a brief "ready" tag for 3 seconds.
|
# the timestamp to show a brief "ready" tag for 3 seconds.
|
||||||
if hasattr(self.controller, "on_warmup_complete"):
|
if hasattr(self.controller, "on_warmup_complete"):
|
||||||
|
#Note(Ed): Exception(Thirdparty)
|
||||||
try:
|
try:
|
||||||
self.controller.on_warmup_complete(lambda status: _on_warmup_complete_callback(self, status))
|
self.controller.on_warmup_complete(lambda status: _on_warmup_complete_callback(self, status))
|
||||||
except Exception: pass
|
except Exception: pass
|
||||||
self._diag_layout_state()
|
self._diag_layout_state()
|
||||||
|
|
||||||
def _diag_layout_state(self) -> None:
|
def _diag_layout_state(self) -> None:
|
||||||
"""
|
"""One-shot startup diagnostic: log show_windows state and warn if the
|
||||||
One-shot startup diagnostic: log show_windows state and warn if the
|
|
||||||
on-disk manualslop_layout.ini references window names that no longer
|
on-disk manualslop_layout.ini references window names that no longer
|
||||||
exist in the current code. Helps users and test operators detect
|
exist in the current code. Helps users and test operators detect
|
||||||
stale layout state at a glance instead of debugging missing panels.
|
stale layout state at a glance instead of debugging missing panels.
|
||||||
[C: src/gui_2.py:App._post_init]
|
|
||||||
"""
|
"""
|
||||||
import os as _os
|
import os as _os
|
||||||
visible_by_default = [w for w, v in self.show_windows.items() if v]
|
visible_by_default = [w for w, v in self.show_windows.items() if v]
|
||||||
@@ -588,6 +582,7 @@ class App:
|
|||||||
return
|
return
|
||||||
ini_size = _os.path.getsize(ini_path)
|
ini_size = _os.path.getsize(ini_path)
|
||||||
sys.stderr.write(f"[GUI] layout file: {ini_path} ({ini_size} bytes)\n")
|
sys.stderr.write(f"[GUI] layout file: {ini_path} ({ini_size} bytes)\n")
|
||||||
|
#Note(Ed): Exception(Thirdparty)
|
||||||
try:
|
try:
|
||||||
with open(ini_path, encoding="utf-8") as _f:
|
with open(ini_path, encoding="utf-8") as _f:
|
||||||
_ini_text = _f.read()
|
_ini_text = _f.read()
|
||||||
@@ -611,14 +606,9 @@ class App:
|
|||||||
return result
|
return result
|
||||||
|
|
||||||
def run(self) -> None:
|
def run(self) -> None:
|
||||||
"""
|
"""Initializes the ImGui runner (HelloImGui) and starts the main application loop.
|
||||||
Initializes the ImGui runner (HelloImGui) and starts the main application loop.
|
|
||||||
Loads system themes, default styling metrics, fonts, and sets up window docking layouts.
|
Loads system themes, default styling metrics, fonts, and sets up window docking layouts.
|
||||||
|
SSDL: `[I:hello_imgui] -> o-> [I:main_loop]`
|
||||||
SSDL Shape:
|
|
||||||
`[I:hello_imgui] -> o-> [I:main_loop]`
|
|
||||||
|
|
||||||
[C: simulation/sim_base.py:run_sim, src/mcp_client.py:get_git_diff, src/project_manager.py:get_git_commit, src/rag_engine.py:RAGEngine._search_mcp, src/shell_runner.py:run_powershell, tests/conftest.py:kill_process_tree, tests/conftest.py:live_gui, tests/test_conductor_abort_event.py:test_conductor_abort_event_populated, tests/test_conductor_engine_v2.py:test_conductor_engine_dynamic_parsing_and_execution, tests/test_conductor_engine_v2.py:test_conductor_engine_run_executes_tickets_in_order, tests/test_extended_sims.py:test_ai_settings_sim_live, tests/test_extended_sims.py:test_context_sim_live, tests/test_extended_sims.py:test_execution_sim_live, tests/test_extended_sims.py:test_tools_sim_live, tests/test_external_editor_gui.py:get_vscode_processes, tests/test_external_editor_gui.py:test_vscode_launches_with_diff_view, tests/test_gui_custom_window.py:test_app_window_is_borderless, tests/test_headless_simulation.py:module, tests/test_headless_verification.py:test_headless_verification_error_and_qa_interceptor, tests/test_headless_verification.py:test_headless_verification_full_run, tests/test_mock_gemini_cli.py:run_mock, tests/test_orchestration_logic.py:test_conductor_engine_run, tests/test_parallel_execution.py:test_conductor_engine_pool_integration, tests/test_sim_ai_settings.py:test_ai_settings_simulation_run, tests/test_sim_context.py:test_context_simulation_run, tests/test_sim_execution.py:test_execution_simulation_run, tests/test_sim_tools.py:test_tools_simulation_run]
|
|
||||||
"""
|
"""
|
||||||
if "--headless" in sys.argv:
|
if "--headless" in sys.argv:
|
||||||
print("Headless mode active")
|
print("Headless mode active")
|
||||||
@@ -686,6 +676,7 @@ class App:
|
|||||||
self.runner_params.callbacks.post_init = _profiled_post_init
|
self.runner_params.callbacks.post_init = _profiled_post_init
|
||||||
self._fetch_models(self.current_provider)
|
self._fetch_models(self.current_provider)
|
||||||
md_options = markdown_helper.get_renderer().options
|
md_options = markdown_helper.get_renderer().options
|
||||||
|
#Note(Ed): Exception(Thirdparty)
|
||||||
try:
|
try:
|
||||||
immapp.run(self.runner_params, add_ons_params=immapp.AddOnsParams(with_markdown_options=md_options))
|
immapp.run(self.runner_params, add_ons_params=immapp.AddOnsParams(with_markdown_options=md_options))
|
||||||
except RuntimeError as _immapp_exc:
|
except RuntimeError as _immapp_exc:
|
||||||
@@ -730,6 +721,7 @@ class App:
|
|||||||
|
|
||||||
if font_path:
|
if font_path:
|
||||||
font_path = _resolve_font_path(font_path, assets_dir)
|
font_path = _resolve_font_path(font_path, assets_dir)
|
||||||
|
#Note(Ed): Exception(Thirdparty)
|
||||||
# Just try loading it directly; hello_imgui will look in the assets folder
|
# Just try loading it directly; hello_imgui will look in the assets folder
|
||||||
try:
|
try:
|
||||||
with startup_profiler.phase("load_fonts.main_with_fontawesome"):
|
with startup_profiler.phase("load_fonts.main_with_fontawesome"):
|
||||||
@@ -740,6 +732,7 @@ class App:
|
|||||||
else:
|
else:
|
||||||
self.main_font = None
|
self.main_font = None
|
||||||
|
|
||||||
|
#Note(Ed): Exception(Thirdparty)
|
||||||
try:
|
try:
|
||||||
with startup_profiler.phase("load_fonts.mono"):
|
with startup_profiler.phase("load_fonts.mono"):
|
||||||
params = hello_imgui.FontLoadingParams(font_config=config)
|
params = hello_imgui.FontLoadingParams(font_config=config)
|
||||||
@@ -756,6 +749,7 @@ class App:
|
|||||||
"""UI-level wrapper for approving a pending MMA sub-agent spawn."""
|
"""UI-level wrapper for approving a pending MMA sub-agent spawn."""
|
||||||
self._handle_mma_respond(approved=True)
|
self._handle_mma_respond(approved=True)
|
||||||
|
|
||||||
|
#TODO(Ed): Remove Exception based errors.
|
||||||
def __getattr__(self, name: str) -> Any:
|
def __getattr__(self, name: str) -> Any:
|
||||||
if name == 'controller':
|
if name == 'controller':
|
||||||
raise AttributeError(name)
|
raise AttributeError(name)
|
||||||
@@ -801,8 +795,10 @@ class App:
|
|||||||
def current_model(self, value: str) -> None:
|
def current_model(self, value: str) -> None:
|
||||||
self.controller.current_model = value
|
self.controller.current_model = value
|
||||||
|
|
||||||
|
#TODO(Ed): Remove Exception based errors.
|
||||||
def _get_active_capabilities(self) -> "VendorCapabilities":
|
def _get_active_capabilities(self) -> "VendorCapabilities":
|
||||||
from src.vendor_capabilities import VendorCapabilities, get_capabilities
|
from src.vendor_capabilities import VendorCapabilities, get_capabilities
|
||||||
|
#TODO(Ed): Remove Exception based errors.
|
||||||
try:
|
try:
|
||||||
caps = get_capabilities(self.current_provider, self.current_model)
|
caps = get_capabilities(self.current_provider, self.current_model)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
@@ -836,15 +832,9 @@ class App:
|
|||||||
}
|
}
|
||||||
|
|
||||||
def _take_snapshot(self) -> history.UISnapshot:
|
def _take_snapshot(self) -> history.UISnapshot:
|
||||||
"""
|
""" Captures the current state of UI input parameters, system prompts, active
|
||||||
Captures the current state of UI input parameters, system prompts, active
|
|
||||||
discussions, and files list, returning a UISnapshot for history management.
|
discussions, and files list, returning a UISnapshot for history management.
|
||||||
|
SSDL: `[Q:ui_state] -> [I:copy] -> [T:snapshot]`
|
||||||
State Mutations:
|
|
||||||
None (read-only state capture).
|
|
||||||
|
|
||||||
SSDL Shape:
|
|
||||||
`[Q:ui_state] -> [I:copy] -> [T:snapshot]`
|
|
||||||
"""
|
"""
|
||||||
from src import history
|
from src import history
|
||||||
import copy
|
import copy
|
||||||
@@ -865,16 +855,9 @@ class App:
|
|||||||
)
|
)
|
||||||
|
|
||||||
def _apply_snapshot(self, snapshot: history.UISnapshot) -> None:
|
def _apply_snapshot(self, snapshot: history.UISnapshot) -> None:
|
||||||
"""
|
"""Applies a previously captured UISnapshot back to the active UI state.
|
||||||
Applies a previously captured UISnapshot back to the active UI state.
|
|
||||||
Restores input fields, parameters, discussions, screenshots, and context files.
|
Restores input fields, parameters, discussions, screenshots, and context files.
|
||||||
|
SSDL Shape: `[I:lock_flag] -> [S:ui_state] -> [I:unlock]`
|
||||||
State Mutations:
|
|
||||||
Modifies active UI variables (self.ui_ai_input, self.temperature, self.files, self.context_files, etc.)
|
|
||||||
self._is_applying_snapshot (temporarily set to True)
|
|
||||||
|
|
||||||
SSDL Shape:
|
|
||||||
`[I:lock_flag] -> [S:ui_state] -> [I:unlock]`
|
|
||||||
"""
|
"""
|
||||||
self._is_applying_snapshot = True
|
self._is_applying_snapshot = True
|
||||||
try:
|
try:
|
||||||
@@ -893,42 +876,31 @@ class App:
|
|||||||
from src import models
|
from src import models
|
||||||
self.files = []
|
self.files = []
|
||||||
for f in snapshot.files:
|
for f in snapshot.files:
|
||||||
if isinstance(f, dict):
|
if isinstance(f, dict): self.files.append(models.FileItem.from_dict(f))
|
||||||
self.files.append(models.FileItem.from_dict(f))
|
else: self.files.append(models.FileItem(path=str(f)))
|
||||||
else:
|
|
||||||
self.files.append(models.FileItem(path=str(f)))
|
|
||||||
|
|
||||||
self.context_files = []
|
self.context_files = []
|
||||||
for f in snapshot.context_files:
|
for f in snapshot.context_files:
|
||||||
if isinstance(f, dict):
|
if isinstance(f, dict): self.context_files.append(models.FileItem.from_dict(f))
|
||||||
self.context_files.append(models.FileItem.from_dict(f))
|
else: self.context_files.append(models.FileItem(path=str(f)))
|
||||||
else:
|
|
||||||
self.context_files.append(models.FileItem(path=str(f)))
|
|
||||||
|
|
||||||
self.screenshots = list(snapshot.screenshots)
|
self.screenshots = list(snapshot.screenshots)
|
||||||
self._last_ui_snapshot = snapshot # Update last snapshot to avoid immediate re-push
|
self._last_ui_snapshot = snapshot # Update last snapshot to avoid immediate re-push
|
||||||
finally:
|
finally:
|
||||||
self._is_applying_snapshot = False
|
self._is_applying_snapshot = False # ?? TODO(Ed): Whats the point of this??
|
||||||
|
|
||||||
def _capture_workspace_profile(self, name: str) -> models.WorkspaceProfile:
|
def _capture_workspace_profile(self, name: str) -> models.WorkspaceProfile:
|
||||||
"""
|
"""Serializes the current window visibility states, popped-out panel layouts, and
|
||||||
Serializes the current window visibility states, popped-out panel layouts, and
|
|
||||||
ImGui INI configurations into a WorkspaceProfile object.
|
ImGui INI configurations into a WorkspaceProfile object.
|
||||||
|
SSDL Shape: `[Q:ui_states] -> [B:ini_ready] -> [T:profile]`
|
||||||
State Mutations:
|
|
||||||
self._ini_capture_ready (set to True on first invocation to bypass initial ImGui frame bugs).
|
|
||||||
|
|
||||||
SSDL Shape:
|
|
||||||
`[Q:ui_states] -> [B:ini_ready] -> [T:profile]`
|
|
||||||
"""
|
"""
|
||||||
if not getattr(self, "_ini_capture_ready", False):
|
if not getattr(self, "_ini_capture_ready", False):
|
||||||
self._ini_capture_ready = True
|
self._ini_capture_ready = True
|
||||||
ini = ""
|
ini = ""
|
||||||
else:
|
else:
|
||||||
try:
|
#Note(Ed): Thirdparty Exception
|
||||||
ini = str(imgui.save_ini_settings_to_memory() or "")
|
try: ini = str(imgui.save_ini_settings_to_memory() or "")
|
||||||
except Exception:
|
except Exception: ini = ""
|
||||||
ini = ""
|
|
||||||
panel_states = {
|
panel_states = {
|
||||||
"ui_separate_context_preview": getattr(self, "ui_separate_context_preview", False),
|
"ui_separate_context_preview": getattr(self, "ui_separate_context_preview", False),
|
||||||
"ui_separate_message_panel": getattr(self, "ui_separate_message_panel", False),
|
"ui_separate_message_panel": getattr(self, "ui_separate_message_panel", False),
|
||||||
@@ -951,66 +923,39 @@ class App:
|
|||||||
)
|
)
|
||||||
|
|
||||||
def _apply_workspace_profile(self, profile: models.WorkspaceProfile):
|
def _apply_workspace_profile(self, profile: models.WorkspaceProfile):
|
||||||
"""
|
"""Restores the window docking layout and popped-out panel visibility states
|
||||||
Restores the window docking layout and popped-out panel visibility states
|
|
||||||
from a saved WorkspaceProfile.
|
from a saved WorkspaceProfile.
|
||||||
|
SSDL Shape: `[I:load_ini] -> [S:ui_states]`
|
||||||
State Mutations:
|
|
||||||
Modifies window visibility and panel configuration state variables.
|
|
||||||
|
|
||||||
SSDL Shape:
|
|
||||||
`[I:load_ini] -> [S:ui_states]`
|
|
||||||
"""
|
"""
|
||||||
imgui.load_ini_settings_from_memory(profile.ini_content)
|
imgui.load_ini_settings_from_memory(profile.ini_content)
|
||||||
self.show_windows.update(profile.show_windows)
|
self.show_windows.update(profile.show_windows)
|
||||||
for k, v in profile.panel_states.items():
|
for k, v in profile.panel_states.items():
|
||||||
if hasattr(self, k):
|
if hasattr(self, k): setattr(self, k, v)
|
||||||
setattr(self, k, v)
|
|
||||||
|
|
||||||
def _handle_undo(self) -> None:
|
def _handle_undo(self) -> None:
|
||||||
"""
|
"""Reverts the application UI state to the previous snapshot in the history stack.
|
||||||
Reverts the application UI state to the previous snapshot in the history stack.
|
|
||||||
|
|
||||||
State Mutations:
|
|
||||||
self.history (mutated to record index changes)
|
|
||||||
Modifies active UI variables via _apply_snapshot()
|
|
||||||
|
|
||||||
DAG Render Context:
|
DAG Render Context:
|
||||||
Called by: _gui_func() (via hotkey Ctrl+Z) or undo button click.
|
Called by: _gui_func() (via hotkey Ctrl+Z) or undo button click.
|
||||||
Calls: _take_snapshot(), _apply_snapshot(), HistoryManager.undo()
|
Calls: _take_snapshot(), _apply_snapshot(), HistoryManager.undo()
|
||||||
|
|
||||||
Threading & Safety:
|
|
||||||
Must run synchronously on the Main Thread.
|
|
||||||
"""
|
"""
|
||||||
sys.stderr.write(f"[DEBUG History] _handle_undo called. can_undo={self.history.can_undo}\n")
|
sys.stderr.write(f"[DEBUG History] _handle_undo called. can_undo={self.history.can_undo}\n"); sys.stderr.flush()
|
||||||
sys.stderr.flush()
|
if not self.history.can_undo: return
|
||||||
if not self.history.can_undo:
|
|
||||||
return
|
|
||||||
current = self._take_snapshot()
|
current = self._take_snapshot()
|
||||||
entry = self.history.undo(current, "Undo Action")
|
entry = self.history.undo(current, "Undo Action")
|
||||||
if entry:
|
if entry:
|
||||||
sys.stderr.write(f"[DEBUG History] Undoing to: {entry.description}\n")
|
sys.stderr.write(f"[DEBUG History] Undoing to: {entry.description}\n"); sys.stderr.flush()
|
||||||
sys.stderr.flush()
|
|
||||||
self._apply_snapshot(entry.state)
|
self._apply_snapshot(entry.state)
|
||||||
|
|
||||||
def _handle_jump_to_history(self, index: int) -> None:
|
def _handle_jump_to_history(self, index: int) -> None:
|
||||||
sys.stderr.write(f"[DEBUG History] Jumping to index {index}\n")
|
sys.stderr.write(f"[DEBUG History] Jumping to index {index}\n"); sys.stderr.flush()
|
||||||
sys.stderr.flush()
|
|
||||||
current = self._take_snapshot()
|
current = self._take_snapshot()
|
||||||
entry = self.history.jump_to_undo(index, current, "Before Jump")
|
entry = self.history.jump_to_undo(index, current, "Before Jump")
|
||||||
if entry:
|
if entry:
|
||||||
self._apply_snapshot(entry.state)
|
self._apply_snapshot(entry.state)
|
||||||
|
|
||||||
def _handle_redo(self) -> None:
|
def _handle_redo(self) -> None:
|
||||||
"""
|
"""Re-applies the next snapshot in the history stack (forward navigation).
|
||||||
Re-applies the next snapshot in the history stack (forward navigation).
|
SSDL Shape: `[I:snapshot] -> [B:history] => [I:state]`
|
||||||
|
|
||||||
State Mutations:
|
|
||||||
self.history (mutated to record index changes)
|
|
||||||
Modifies active UI variables via _apply_snapshot()
|
|
||||||
|
|
||||||
SSDL Shape:
|
|
||||||
`[I:snapshot] -> [B:history] => [I:state]`
|
|
||||||
"""
|
"""
|
||||||
sys.stderr.write(f"[DEBUG History] _handle_redo called. can_redo={self.history.can_redo}\n")
|
sys.stderr.write(f"[DEBUG History] _handle_redo called. can_redo={self.history.can_redo}\n")
|
||||||
sys.stderr.flush()
|
sys.stderr.flush()
|
||||||
@@ -1024,17 +969,9 @@ class App:
|
|||||||
self._apply_snapshot(entry.state)
|
self._apply_snapshot(entry.state)
|
||||||
|
|
||||||
def shutdown(self) -> None:
|
def shutdown(self) -> None:
|
||||||
"""
|
"""Cleanly shuts down the app's background tasks, saves workspace layout configurations,
|
||||||
Cleanly shuts down the app's background tasks, saves workspace layout configurations,
|
|
||||||
forces a save of dirty registries/caches, and terminates the active thread pools.
|
forces a save of dirty registries/caches, and terminates the active thread pools.
|
||||||
|
SSDL Shape: `[I:save_ini] -> [I:controller_shutdown]`
|
||||||
State Mutations:
|
|
||||||
runner_params settings are flushed to disk (imgui.save_ini_settings_to_disk).
|
|
||||||
|
|
||||||
SSDL Shape:
|
|
||||||
`[I:save_ini] -> [I:controller_shutdown]`
|
|
||||||
|
|
||||||
[C: tests/conftest.py:app_instance, tests/conftest.py:mock_app]
|
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
if hasattr(self, 'runner_params') and self.runner_params.ini_filename:
|
if hasattr(self, 'runner_params') and self.runner_params.ini_filename:
|
||||||
@@ -1044,9 +981,6 @@ class App:
|
|||||||
self.controller.shutdown()
|
self.controller.shutdown()
|
||||||
|
|
||||||
def load_context_preset(self, name: str) -> None:
|
def load_context_preset(self, name: str) -> None:
|
||||||
"""
|
|
||||||
[C: tests/test_context_presets.py:test_load_context_preset, tests/test_context_presets.py:test_load_nonexistent_preset]
|
|
||||||
"""
|
|
||||||
preset = self.controller.load_context_preset(name)
|
preset = self.controller.load_context_preset(name)
|
||||||
from src import models
|
from src import models
|
||||||
import copy
|
import copy
|
||||||
@@ -1064,9 +998,6 @@ class App:
|
|||||||
self._update_context_file_stats()
|
self._update_context_file_stats()
|
||||||
|
|
||||||
def delete_context_preset(self, name: str) -> None:
|
def delete_context_preset(self, name: str) -> None:
|
||||||
"""
|
|
||||||
[C: tests/test_context_presets.py:test_delete_context_preset, tests/test_context_presets.py:test_delete_nonexistent_preset_no_error]
|
|
||||||
"""
|
|
||||||
self.controller.delete_context_preset(name)
|
self.controller.delete_context_preset(name)
|
||||||
if getattr(self, "ui_active_context_preset", "") == name:
|
if getattr(self, "ui_active_context_preset", "") == name:
|
||||||
self.ui_active_context_preset = ""
|
self.ui_active_context_preset = ""
|
||||||
@@ -1103,12 +1034,9 @@ class App:
|
|||||||
since the keyboard shortcut (Ctrl+Shift+P) cannot be simulated via the hook API."""
|
since the keyboard shortcut (Ctrl+Shift+P) cannot be simulated via the hook API."""
|
||||||
self.show_command_palette = not self.show_command_palette
|
self.show_command_palette = not self.show_command_palette
|
||||||
if self.show_command_palette:
|
if self.show_command_palette:
|
||||||
if hasattr(self, '_command_palette_query'):
|
if hasattr(self, '_command_palette_query'): self._command_palette_query = ""
|
||||||
self._command_palette_query = ""
|
if hasattr(self, '_command_palette_selected'): self._command_palette_selected = 0
|
||||||
if hasattr(self, '_command_palette_selected'):
|
if hasattr(self, '_command_palette_input_focused'): self._command_palette_input_focused = False
|
||||||
self._command_palette_selected = 0
|
|
||||||
if hasattr(self, '_command_palette_input_focused'):
|
|
||||||
self._command_palette_input_focused = False
|
|
||||||
|
|
||||||
def _test_callback_func_write_to_file(self, data: str) -> None:
|
def _test_callback_func_write_to_file(self, data: str) -> None:
|
||||||
"""A dummy function that a custom_callback would execute for testing."""
|
"""A dummy function that a custom_callback would execute for testing."""
|
||||||
@@ -1118,17 +1046,11 @@ class App:
|
|||||||
f.write(data)
|
f.write(data)
|
||||||
|
|
||||||
def _gui_func(self) -> None:
|
def _gui_func(self) -> None:
|
||||||
"""
|
"""Main immediate-mode render loop callback executed on every frame.
|
||||||
Main immediate-mode render loop callback executed on every frame.
|
|
||||||
Dispatches keyboard shortcuts, renders the background shader, custom title bar,
|
Dispatches keyboard shortcuts, renders the background shader, custom title bar,
|
||||||
main dockspace, and handles popups/modals.
|
main dockspace, and handles popups/modals.
|
||||||
|
|
||||||
State Mutations:
|
SSDL Shape: `o-> [I:hotkeys] -> [I:title_bar] -> [I:main_interface] -> [I:modals]`
|
||||||
self.show_command_palette (toggled via Ctrl+Shift+P)
|
|
||||||
self._hot_reload_error (updated on Ctrl+Alt+R)
|
|
||||||
|
|
||||||
SSDL Shape:
|
|
||||||
`o-> [I:hotkeys] -> [I:title_bar] -> [I:main_interface] -> [I:modals]`
|
|
||||||
|
|
||||||
ASCII Layout Map:
|
ASCII Layout Map:
|
||||||
+---------------------------------------------------------+
|
+---------------------------------------------------------+
|
||||||
@@ -1170,17 +1092,14 @@ class App:
|
|||||||
self._first_frame_painted = True
|
self._first_frame_painted = True
|
||||||
|
|
||||||
io = imgui.get_io()
|
io = imgui.get_io()
|
||||||
if io.key_ctrl and io.key_alt and imgui.is_key_down(imgui.Key.r):
|
if io.key_ctrl and io.key_alt and imgui.is_key_down(imgui.Key.r): self._trigger_hot_reload()
|
||||||
self._trigger_hot_reload()
|
|
||||||
if (io.key_ctrl and io.key_shift
|
if (io.key_ctrl and io.key_shift
|
||||||
and not io.key_alt and not io.key_super
|
and not io.key_alt and not io.key_super
|
||||||
and imgui.is_key_pressed(imgui.Key.p)):
|
and imgui.is_key_pressed(imgui.Key.p)):
|
||||||
self.show_command_palette = not self.show_command_palette
|
self.show_command_palette = not self.show_command_palette
|
||||||
if self.show_command_palette:
|
if self.show_command_palette:
|
||||||
if hasattr(self, '_command_palette_query'):
|
if hasattr(self, '_command_palette_query'): self._command_palette_query = ""
|
||||||
self._command_palette_query = ""
|
if hasattr(self, '_command_palette_selected'): self._command_palette_selected = 0
|
||||||
if hasattr(self, '_command_palette_selected'):
|
|
||||||
self._command_palette_selected = 0
|
|
||||||
|
|
||||||
render_custom_title_bar(self)
|
render_custom_title_bar(self)
|
||||||
render_shader_live_editor(self)
|
render_shader_live_editor(self)
|
||||||
@@ -1190,8 +1109,7 @@ class App:
|
|||||||
# Render background shader
|
# Render background shader
|
||||||
bg = bg_shader.get_bg()
|
bg = bg_shader.get_bg()
|
||||||
ws = imgui.get_io().display_size
|
ws = imgui.get_io().display_size
|
||||||
if bg.enabled:
|
if bg.enabled: bg.render(ws.x, ws.y)
|
||||||
bg.render(ws.x, ws.y)
|
|
||||||
|
|
||||||
theme.render_post_fx(ws.x, ws.y, self.ai_status, self.ui_crt_filter)
|
theme.render_post_fx(ws.x, ws.y, self.ai_status, self.ui_crt_filter)
|
||||||
|
|
||||||
@@ -1207,9 +1125,7 @@ class App:
|
|||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
|
|
||||||
self._handle_history_logic()
|
self._handle_history_logic()
|
||||||
|
if self.perf_profiling_enabled: self.perf_monitor.end_component("_gui_func")
|
||||||
if self.perf_profiling_enabled:
|
|
||||||
self.perf_monitor.end_component("_gui_func")
|
|
||||||
return
|
return
|
||||||
|
|
||||||
def _render_window_if_open(self, name: str, render_func: Callable[[], None], flag_condition: bool = True) -> None:
|
def _render_window_if_open(self, name: str, render_func: Callable[[], None], flag_condition: bool = True) -> None:
|
||||||
@@ -1220,9 +1136,6 @@ class App:
|
|||||||
if exp: render_func()
|
if exp: render_func()
|
||||||
|
|
||||||
def _show_menus(self) -> None:
|
def _show_menus(self) -> None:
|
||||||
"""
|
|
||||||
[C: tests/test_gui_window_controls.py:test_gui_window_controls_minimize_maximize_close]
|
|
||||||
"""
|
|
||||||
global win32gui, win32con
|
global win32gui, win32con
|
||||||
if win32gui is None:
|
if win32gui is None:
|
||||||
import win32con
|
import win32con
|
||||||
@@ -1231,8 +1144,7 @@ class App:
|
|||||||
win32gui = win32gui
|
win32gui = win32gui
|
||||||
|
|
||||||
with imscope.menu("manual slop") as (active):
|
with imscope.menu("manual slop") as (active):
|
||||||
if active and imgui.menu_item("Quit", "Ctrl+Q", False)[0]:
|
if active and imgui.menu_item("Quit", "Ctrl+Q", False)[0]: self.runner_params.app_shall_exit = True
|
||||||
self.runner_params.app_shall_exit = True
|
|
||||||
with imscope.menu("Windows") as (active):
|
with imscope.menu("Windows") as (active):
|
||||||
if (active):
|
if (active):
|
||||||
for w in self.show_windows.keys():
|
for w in self.show_windows.keys():
|
||||||
@@ -1306,33 +1218,22 @@ class App:
|
|||||||
win32gui.SendMessage(hwnd, win32con.WM_NCLBUTTONDOWN, win32con.HTCAPTION, 0)
|
win32gui.SendMessage(hwnd, win32con.WM_NCLBUTTONDOWN, win32con.HTCAPTION, 0)
|
||||||
|
|
||||||
imgui.push_style_color(imgui.Col_.button, imgui.ImVec4(0, 0, 0, 0))
|
imgui.push_style_color(imgui.Col_.button, imgui.ImVec4(0, 0, 0, 0))
|
||||||
|
#Note(Ed): Thirdparty Exception
|
||||||
try:
|
try: is_max = win32gui.GetWindowPlacement(hwnd)[1] == win32con.SW_SHOWMAXIMIZED
|
||||||
is_max = win32gui.GetWindowPlacement(hwnd)[1] == win32con.SW_SHOWMAXIMIZED
|
except Exception: is_max = False
|
||||||
except Exception:
|
|
||||||
is_max = False
|
|
||||||
|
|
||||||
# Explicitly set Y to 0 and match button height to bar height for perfect alignment
|
# Explicitly set Y to 0 and match button height to bar height for perfect alignment
|
||||||
imgui.set_cursor_pos((right_x, 0))
|
imgui.set_cursor_pos((right_x, 0))
|
||||||
if imgui.button("_", (btn_w, bar_h)):
|
if imgui.button("_", (btn_w, bar_h)): win32gui.ShowWindow(hwnd, win32con.SW_MINIMIZE)
|
||||||
win32gui.ShowWindow(hwnd, win32con.SW_MINIMIZE)
|
|
||||||
|
|
||||||
imgui.set_cursor_pos((right_x + btn_w, 0))
|
imgui.set_cursor_pos((right_x + btn_w, 0))
|
||||||
if imgui.button("[=]" if is_max else "[]", (btn_w, bar_h)):
|
if imgui.button("[=]" if is_max else "[]", (btn_w, bar_h)): win32gui.ShowWindow(hwnd, win32con.SW_RESTORE if is_max else win32con.SW_MAXIMIZE)
|
||||||
win32gui.ShowWindow(hwnd, win32con.SW_RESTORE if is_max else win32con.SW_MAXIMIZE)
|
|
||||||
|
|
||||||
imgui.set_cursor_pos((right_x + btn_w * 2, 0))
|
imgui.set_cursor_pos((right_x + btn_w * 2, 0))
|
||||||
imgui.push_style_color(imgui.Col_.button_hovered, theme.get_color("status_error"))
|
imgui.push_style_color(imgui.Col_.button_hovered, theme.get_color("status_error"))
|
||||||
if imgui.button("X", (btn_w, bar_h)):
|
if imgui.button("X", (btn_w, bar_h)): win32gui.PostMessage(hwnd, win32con.WM_CLOSE, 0, 0)
|
||||||
win32gui.PostMessage(hwnd, win32con.WM_CLOSE, 0, 0)
|
|
||||||
imgui.pop_style_color()
|
imgui.pop_style_color()
|
||||||
imgui.pop_style_color()
|
imgui.pop_style_color()
|
||||||
|
|
||||||
def _handle_history_logic(self) -> None:
|
def _handle_history_logic(self) -> None:
|
||||||
"""
|
"""Logic for capturing UI state for undo/redo."""
|
||||||
|
|
||||||
Logic for capturing UI state for undo/redo.
|
|
||||||
"""
|
|
||||||
if self._is_applying_snapshot:
|
if self._is_applying_snapshot:
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -2495,12 +2396,10 @@ def render_paths_panel(app: App) -> None:
|
|||||||
#region: AI Settings
|
#region: AI Settings
|
||||||
|
|
||||||
def render_ai_settings_hub(app: App) -> None:
|
def render_ai_settings_hub(app: App) -> None:
|
||||||
"""
|
"""Groups and renders all AI-related configuration panels in a unified hub sidebar.
|
||||||
Groups and renders all AI-related configuration panels in a unified hub sidebar.
|
|
||||||
Includes persona selection, LLM provider settings, system prompts, RAG config, and tools.
|
Includes persona selection, LLM provider settings, system prompts, RAG config, and tools.
|
||||||
|
|
||||||
SSDL Shape:
|
SSDL Shape: `[I:persona_selector] -> [B:provider_header] -> [B:system_prompts_header] -> [B:rag_header] -> [I:agent_tools]`
|
||||||
`[I:persona_selector] -> [B:provider_header] -> [B:system_prompts_header] -> [B:rag_header] -> [I:agent_tools]`
|
|
||||||
|
|
||||||
ASCII Layout Map:
|
ASCII Layout Map:
|
||||||
+---------------------------------------------------------+
|
+---------------------------------------------------------+
|
||||||
@@ -2669,6 +2568,7 @@ def render_agent_tools_panel(app: App) -> None:
|
|||||||
| Bias Profile: [None v] |
|
| Bias Profile: [None v] |
|
||||||
+---------------------------------------------------------+
|
+---------------------------------------------------------+
|
||||||
"""
|
"""
|
||||||
|
caps = app._get_active_capabilities()
|
||||||
if not caps.tool_calling:
|
if not caps.tool_calling:
|
||||||
if imgui.collapsing_header("Active Tool Presets & Biases", imgui.TreeNodeFlags_.default_open):
|
if imgui.collapsing_header("Active Tool Presets & Biases", imgui.TreeNodeFlags_.default_open):
|
||||||
imgui.text_disabled(f"(tools not supported by {app.current_provider}/{app.current_model})")
|
imgui.text_disabled(f"(tools not supported by {app.current_provider}/{app.current_model})")
|
||||||
|
|||||||
Reference in New Issue
Block a user