from __future__ import annotations from typing import TYPE_CHECKING import customtkinter as ctk from gui._constants import COLOR_ERROR from gui.views.base import BaseView if TYPE_CHECKING: from gui.app import ArmaModManagerApp class LogsView(BaseView): """ Monospace textbox showing captured stdout/stderr from pipeline and tools. The app's poll loop appends text by calling append() directly on this view. Log content persists across navigation — the textbox is built once in build() and never recreated. """ def build(self) -> None: self.grid_columnconfigure(0, weight=1) self.grid_rowconfigure(1, weight=1) # ── Header ──────────────────────────────────────────────────────────── hdr = ctk.CTkFrame(self, fg_color="transparent") hdr.grid(row=0, column=0, sticky="ew", padx=24, pady=(20, 8)) ctk.CTkLabel(hdr, text="Logs", font=ctk.CTkFont(size=22, weight="bold")).pack(side="left") btn_row = ctk.CTkFrame(hdr, fg_color="transparent") btn_row.pack(side="right") ctk.CTkButton(btn_row, text="Copy", width=72, command=self._copy).pack(side="left", padx=4) ctk.CTkButton(btn_row, text="Clear", width=72, fg_color=COLOR_ERROR, hover_color="#c62828", command=self._clear).pack(side="left") # ── Log textbox (persistent) ────────────────────────────────────────── self._log_box = ctk.CTkTextbox( self, state="disabled", font=ctk.CTkFont(family="Consolas", size=12)) self._log_box.grid(row=1, column=0, sticky="nsew", padx=24, pady=(0, 12)) def append(self, text: str) -> None: """Thread-safe-ish: called from the app's after() poll loop (main thread).""" try: self._log_box.configure(state="normal") self._log_box.insert("end", text) self._log_box.see("end") self._log_box.configure(state="disabled") except Exception: pass def _copy(self) -> None: self.clipboard_clear() self.clipboard_append(self._log_box.get("1.0", "end")) def _clear(self) -> None: self._log_box.configure(state="normal") self._log_box.delete("1.0", "end") self._log_box.configure(state="disabled")