Add GUI desktop application
- Add gui/ package: CustomTkinter app with dashboard, mods, tools, logs, and settings views; first-run SetupWizard for config.json generation - Add gui.py root entry point (calls gui.run_app()) - Add selection.json for GUI selection state persistence - Add customtkinter to requirements.txt - Fix link_mods.py minor issues surfaced during GUI integration - Add modlist_html/Test_Preset_A.html and Test_Preset_B.html as example inputs - Update README.md: add GUI prerequisites, gui.py script section, gui/ folder structure, customtkinter to prerequisites table - Update CLAUDE.md: add python gui.py to common commands, document GUI package architecture and views Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
64
gui/views/logs.py
Normal file
64
gui/views/logs.py
Normal file
@@ -0,0 +1,64 @@
|
||||
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")
|
||||
Reference in New Issue
Block a user