"""Configuration and layout persistence for AR Display Manager.""" from __future__ import annotations import json from dataclasses import dataclass, field from pathlib import Path REPO_ROOT = Path(__file__).resolve().parents[1] CONFIG_DIR = Path.home() / ".ar-autopilot" / "display_manager" CONFIG_FILE = CONFIG_DIR / "config.json" LAYOUT_FILE = CONFIG_DIR / "layout.json" @dataclass class AppExeConfig: """Path + launch args for one application.""" exe: str = "" args: list[str] = field(default_factory=list) title_hint: str = "" # substring to match window title when searching _DEFAULT_EXES: dict[str, AppExeConfig] = { "autopilot": AppExeConfig( exe=str( REPO_ROOT / "display" / "build" / "windows" / "x64" / "runner" / "Release" / "display.exe" ), title_hint="AR Autopilot", ), "ecdis": AppExeConfig(exe="", title_hint="AR-ECDIS"), "compass": AppExeConfig(exe="", title_hint="Compass"), "gps": AppExeConfig(exe="", title_hint="GPS Navigator"), } @dataclass class DisplayManagerConfig: apps: dict[str, AppExeConfig] = field(default_factory=dict) button_position: str = "top-right" # top-right | top-left | bottom-right | bottom-left button_margin: int = 12 # px from screen edge autolaunch: bool = False # launch all apps on startup (False = on-demand only) # ------------------------------------------------------------------ I/O @classmethod def load(cls) -> "DisplayManagerConfig": cfg = cls(apps=dict(_DEFAULT_EXES)) if not CONFIG_FILE.exists(): return cfg try: with open(CONFIG_FILE, encoding="utf-8") as f: data = json.load(f) cfg.button_position = data.get("button_position", cfg.button_position) cfg.button_margin = int(data.get("button_margin", cfg.button_margin)) cfg.autolaunch = bool(data.get("autolaunch", cfg.autolaunch)) for app_id, raw in data.get("apps", {}).items(): cfg.apps[app_id] = AppExeConfig( exe=raw.get("exe", ""), args=raw.get("args", []), title_hint=raw.get("title_hint", ""), ) except Exception: pass return cfg def save(self) -> None: CONFIG_DIR.mkdir(parents=True, exist_ok=True) with open(CONFIG_FILE, "w", encoding="utf-8") as f: json.dump( { "button_position": self.button_position, "button_margin": self.button_margin, "autolaunch": self.autolaunch, "apps": { k: {"exe": v.exe, "args": v.args, "title_hint": v.title_hint} for k, v in self.apps.items() }, }, f, indent=2, ) # --------------------------------------------------------------------------- Layout class LayoutStore: """Persists {screen_serial → app_id} so layout survives restarts.""" def __init__(self) -> None: self._data: dict[str, str] = {} self._load() def _load(self) -> None: if LAYOUT_FILE.exists(): try: with open(LAYOUT_FILE, encoding="utf-8") as f: self._data = json.load(f) except Exception: self._data = {} def get(self, screen_serial: str) -> str | None: return self._data.get(screen_serial) def set(self, screen_serial: str, app_id: str) -> None: self._data[screen_serial] = app_id self._save() def _save(self) -> None: CONFIG_DIR.mkdir(parents=True, exist_ok=True) with open(LAYOUT_FILE, "w", encoding="utf-8") as f: json.dump(self._data, f, indent=2)