Files
Vual/src/vual/window.py
T
2026-03-19 02:47:08 +10:00

129 lines
4.4 KiB
Python

"""Main application window — single-page tile grid."""
from __future__ import annotations
import gi
gi.require_version("Gtk", "4.0")
gi.require_version("Adw", "1")
from gi.repository import Adw, Gio, GLib, Gtk # noqa: E402
from vual import APP_NAME # noqa: E402
from vual.config import Config # noqa: E402
from vual.i18n import _ # noqa: E402
class VualWindow(Adw.ApplicationWindow):
def __init__(self, config: Config, **kwargs) -> None:
super().__init__(
default_width=config.window_width,
default_height=config.window_height,
title=APP_NAME,
**kwargs,
)
self.config = config
self._build_ui()
# ── UI construction ──────────────────────────────────────────
def _build_ui(self) -> None:
self.toast_overlay = Adw.ToastOverlay()
self.set_content(self.toast_overlay)
toolbar_view = Adw.ToolbarView()
self.toast_overlay.set_child(toolbar_view)
# Single main page
from vual.ui.main_page import MainPage
self.main_page = MainPage(config=self.config, window=self)
# Header bar
header = Adw.HeaderBar()
header.add_css_class("flat")
# Title widget: search + counter
title_box = Gtk.Box(spacing=8)
title_box.append(self.main_page._search)
self._counter = Gtk.Label(css_classes=["games-counter"])
title_box.append(self._counter)
header.set_title_widget(title_box)
b_refresh = Gtk.Button(
icon_name="view-refresh-symbolic",
css_classes=["flat", "header-btn"],
tooltip_text=_("Refresh"),
)
b_refresh.connect("clicked", lambda _: self.main_page._load())
header.pack_start(b_refresh)
b_on = Gtk.Button(
icon_name="object-select-symbolic",
css_classes=["flat", "header-btn"],
tooltip_text=_("Enable All"),
)
b_on.connect("clicked", self.main_page._on_enable_all)
header.pack_start(b_on)
b_off = Gtk.Button(
icon_name="edit-clear-all-symbolic",
css_classes=["flat", "header-btn"],
tooltip_text=_("Disable All"),
)
b_off.connect("clicked", self.main_page._on_disable_all)
header.pack_start(b_off)
# Sort menu
sort_menu = Gio.Menu()
sort_menu.append(_("By name"), "win.sort::name")
sort_menu.append(_("By status"), "win.sort::status")
sort_btn = Gtk.MenuButton(
icon_name="view-sort-descending-symbolic",
css_classes=["flat", "header-btn"],
menu_model=sort_menu,
tooltip_text=_("Sort"),
)
header.pack_end(sort_btn)
# Sort action
sort_action = Gio.SimpleAction.new("sort", GLib.VariantType.new("s"))
sort_action.connect("activate", self._on_sort_changed)
self.add_action(sort_action)
menu_button = Gtk.MenuButton(
icon_name="open-menu-symbolic",
css_classes=["flat", "header-btn"],
menu_model=self._build_menu(),
)
header.pack_end(menu_button)
toolbar_view.add_top_bar(header)
toolbar_view.set_content(self.main_page)
def _on_sort_changed(self, action: Gio.SimpleAction, param: GLib.Variant) -> None:
sort_by = param.get_string()
self.config.sort_by = sort_by
self.main_page._update_sort()
def update_counter(self, count: int) -> None:
"""Update the games counter label."""
self._counter.set_label(_("%d games") % count)
# ── App menu ─────────────────────────────────────────────────
def _build_menu(self) -> Gio.Menu:
menu = Gio.Menu()
menu.append(_("Preferences"), "app.preferences")
menu.append(_("About"), "app.about")
menu.append(_("Quit"), "app.quit")
return menu
# ── Toast helper ─────────────────────────────────────────────
def show_toast(self, message: str, timeout: int = 3) -> None:
toast = Adw.Toast(title=message, timeout=timeout)
self.toast_overlay.add_toast(toast)
return False