103 lines
3.4 KiB
Python
103 lines
3.4 KiB
Python
# -*- 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)
|