# -*- coding: utf-8 -*- # gui/components/dialog.py """Каноническая dialog-обёртка проекта.""" from __future__ import annotations from PySide6.QtCore import Slot from PySide6.QtWidgets import QDialog, QVBoxLayout from gui.containers import VContainer from gui.containers._widget_style_service import WidgetStyleService from gui.theme_bus import theme_bus class Dialog(QDialog): """Базовая stylable-обёртка над QDialog с корневым VContainer.""" def __init__( self, title: str = "", width: int | None = None, height: int | None = None, modal: bool = True, content_margin: int | tuple[int, int, int, int] = 0, content_spacing: int = 0, style: str = "DIALOG", parent=None, ): super().__init__(parent) # Зависимости self._style_service = WidgetStyleService(self) # Ссылки на ключевые виджеты self._content_container: VContainer | None = None # Визуальная настройка self.setModal(bool(modal)) if title: self.setWindowTitle(title) if width is not None and height is not None: self.resize(width, height) # Сборка и подключение self._build_root(content_margin, content_spacing) self._connect_base_signals() # Первичная синхронизация стиля self.style(style) # ── Сборка интерфейса ──────────────────────────────────────── def _build_root( self, content_margin: int | tuple[int, int, int, int], content_spacing: int, ) -> None: self._content_container = VContainer( margin=content_margin, spacing=content_spacing, ) root_layout = QVBoxLayout(self) root_layout.setContentsMargins(0, 0, 0, 0) root_layout.setSpacing(0) root_layout.addWidget(self._content_container) # ── Подключение сигналов ───────────────────────────────────── def _connect_base_signals(self) -> None: theme_bus.theme_changed.connect(self.set_theme) # ── Публичный API ──────────────────────────────────────────── @property def content_container(self) -> VContainer: return self._content_container def add_widget(self, widget) -> None: self._content_container.add_widget(widget) def add_stretch(self, stretch: int = 1) -> None: self._content_container.add_stretch(stretch) def style( self, style_key: str | None = None, active_key: str | None = None, is_active: bool | None = None, ) -> None: self._style_service.apply( style_key=style_key, active_key=active_key, is_active=is_active, ) # ── Обработчики событий ────────────────────────────────────── @Slot(str) def set_theme(self, theme: str) -> None: self._style_service.handle_theme_changed(theme)