74 lines
2.3 KiB
Python
74 lines
2.3 KiB
Python
"""The contract every quad module implements.
|
|
|
|
Adding a module = drop a file in modules/ that defines a top-level `SPEC`
|
|
(a ModuleSpec), then append its import to registry.py. Nothing else needs to
|
|
change: enable/disable, feature toggles, the card chrome, and the expand/collapse
|
|
plumbing are all provided generically.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass, field
|
|
from typing import Callable, Optional
|
|
|
|
import gi
|
|
|
|
gi.require_version("Gtk", "4.0")
|
|
from gi.repository import Gtk # noqa: E402
|
|
|
|
|
|
@dataclass
|
|
class Feature:
|
|
"""A per-quad on/off switch surfaced in the card's settings popover."""
|
|
id: str
|
|
label: str
|
|
default: bool = True
|
|
|
|
|
|
@dataclass
|
|
class ModuleInstance:
|
|
"""What a module's build() returns."""
|
|
compact: Gtk.Widget # shown in the 2x2 cell
|
|
expanded: Optional[Gtk.Widget] = None # shown when the quad is expanded
|
|
scroll_expanded: bool = True # wrap the expanded view in a scroller
|
|
on_show: Optional[Callable[[], None]] = None
|
|
on_hide: Optional[Callable[[], None]] = None
|
|
destroy: Optional[Callable[[], None]] = None
|
|
|
|
|
|
@dataclass
|
|
class ModuleSpec:
|
|
id: str
|
|
title: str
|
|
icon: str # nerd-font glyph
|
|
build: Callable[["ModuleContext"], ModuleInstance]
|
|
default_enabled: bool = True
|
|
features: list[Feature] = field(default_factory=list)
|
|
|
|
|
|
class ModuleContext:
|
|
"""Handed to a module's build(). Scopes settings to the module and exposes the
|
|
expand/collapse requests so a module can drive the layout without knowing it."""
|
|
|
|
def __init__(self, spec: ModuleSpec, settings, services,
|
|
request_expand: Callable[[str], None],
|
|
request_collapse: Callable[[], None]):
|
|
self.spec = spec
|
|
self.settings = settings
|
|
self.services = services
|
|
self._request_expand = request_expand
|
|
self._request_collapse = request_collapse
|
|
|
|
def expand(self) -> None:
|
|
self._request_expand(self.spec.id)
|
|
|
|
def collapse(self) -> None:
|
|
self._request_collapse()
|
|
|
|
# feature toggles, scoped to this module
|
|
def feature(self, feature_id: str, default: bool = True) -> bool:
|
|
return self.settings.feature(self.spec.id, feature_id, default)
|
|
|
|
def on_settings_changed(self, cb: Callable[[], None]) -> None:
|
|
self.settings.subscribe(cb)
|