Add Dispatch_V0.1.1
This commit is contained in:
187
Dispatch_V0.1.1/gui/containers/stack_container.py
Normal file
187
Dispatch_V0.1.1/gui/containers/stack_container.py
Normal file
@@ -0,0 +1,187 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# gui/containers/stack_container.py
|
||||
|
||||
from PySide6.QtCore import Qt
|
||||
from PySide6.QtWidgets import QStackedWidget, QGridLayout, QLayout, QWidget
|
||||
from .percent_sized_widget import PercentSizedWidget
|
||||
from .content_host import ContentHost
|
||||
|
||||
|
||||
class StackContainer(PercentSizedWidget):
|
||||
"""Контейнер-обёртка над QStackedWidget с размерами в процентах от родителя."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
width_percent: int | float | None = None,
|
||||
height_percent: int | float | None = None,
|
||||
margin: int | tuple[int, int, int, int] = 0,
|
||||
content_margins: int | tuple[int, int, int, int] | None = None,
|
||||
spacing: int = 0,
|
||||
content_width_percent: int | None = None,
|
||||
content_height_percent: int | None = None,
|
||||
content_width: int | None = None,
|
||||
content_height: int | None = None,
|
||||
content_fit: bool = True,
|
||||
parent: QWidget | None = None,
|
||||
style: str | None = None,
|
||||
active_style: str | None = None,
|
||||
is_active: bool | None = None,
|
||||
):
|
||||
super().__init__(width_percent, height_percent, parent)
|
||||
self._init_stylable()
|
||||
self._auto_add_children = True
|
||||
|
||||
self._stack = QStackedWidget(self)
|
||||
self._content_host = ContentHost(
|
||||
width_percent=content_width_percent,
|
||||
height_percent=content_height_percent,
|
||||
orientation="v",
|
||||
margin=0,
|
||||
spacing=spacing,
|
||||
parent=self,
|
||||
)
|
||||
self._content_host.set_content_fit(content_fit)
|
||||
self._content_host.add_widget(self._stack)
|
||||
self._outer_layout = QGridLayout(self)
|
||||
self._outer_layout.setSpacing(0)
|
||||
|
||||
applied_margins = content_margins if content_margins is not None else margin
|
||||
if isinstance(applied_margins, (list, tuple)) and len(applied_margins) == 4:
|
||||
self._outer_layout.setContentsMargins(*applied_margins)
|
||||
else:
|
||||
self._outer_layout.setContentsMargins(applied_margins, applied_margins, applied_margins, applied_margins)
|
||||
|
||||
if content_width is not None or content_height is not None:
|
||||
w = content_width if content_width is not None else self._content_host.sizeHint().width()
|
||||
h = content_height if content_height is not None else self._content_host.sizeHint().height()
|
||||
self._content_host.set_fixed_size(w, h)
|
||||
|
||||
self._outer_layout.addWidget(self._content_host, 0, 0)
|
||||
self._outer_layout.setRowStretch(0, 1)
|
||||
self._outer_layout.setColumnStretch(0, 1)
|
||||
|
||||
if spacing:
|
||||
self._outer_layout.setSpacing(spacing)
|
||||
|
||||
if style is not None or active_style is not None or is_active is not None:
|
||||
self._apply_style(style_key=style, active_key=active_style, is_active=is_active)
|
||||
|
||||
# Методы работы со страницами (интерфейс похож на QStackedWidget)
|
||||
def add_widget(self, widget: QWidget) -> int:
|
||||
index = self._stack.addWidget(widget)
|
||||
if isinstance(widget, PercentSizedWidget):
|
||||
widget.schedule_percent_update()
|
||||
return index
|
||||
|
||||
def set_current_index(self, index: int) -> None:
|
||||
self._stack.setCurrentIndex(index)
|
||||
|
||||
def set_current_widget(self, widget: QWidget) -> None:
|
||||
self._stack.setCurrentWidget(widget)
|
||||
|
||||
def current_index(self) -> int:
|
||||
return self._stack.currentIndex()
|
||||
|
||||
def current_widget(self) -> QWidget | None:
|
||||
return self._stack.currentWidget()
|
||||
|
||||
def count(self) -> int:
|
||||
return self._stack.count()
|
||||
|
||||
def widget(self, index: int) -> QWidget | None:
|
||||
return self._stack.widget(index)
|
||||
|
||||
def remove_widget(self, widget: QWidget) -> None:
|
||||
self._stack.removeWidget(widget)
|
||||
|
||||
def get_available_size_for_content(self) -> tuple[int, int]:
|
||||
"""Полезная внутренняя область (без учёта margin)."""
|
||||
margins = self._outer_layout.contentsMargins()
|
||||
w = self.width() - margins.left() - margins.right()
|
||||
h = self.height() - margins.top() - margins.bottom()
|
||||
return max(0, w), max(0, h)
|
||||
|
||||
def get_layout(self) -> QLayout:
|
||||
return self._outer_layout
|
||||
|
||||
def set_margins(self, margin: int | tuple[int, int, int, int]) -> None:
|
||||
if isinstance(margin, (list, tuple)) and len(margin) == 4:
|
||||
self._outer_layout.setContentsMargins(*margin)
|
||||
else:
|
||||
self._outer_layout.setContentsMargins(margin, margin, margin, margin)
|
||||
|
||||
def set_spacing(self, spacing: int) -> None:
|
||||
self._outer_layout.setSpacing(spacing)
|
||||
|
||||
def set_alignment(self, alignment: str) -> None:
|
||||
raise NotImplementedError("Qt alignment for containers is disabled; use content springs.")
|
||||
|
||||
@property
|
||||
def stacked_widget(self) -> QStackedWidget:
|
||||
return self._stack
|
||||
|
||||
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Module workflow notes
|
||||
# ---------------------------------------------------------------------------
|
||||
#
|
||||
# 1) Назначение модуля:
|
||||
# Контейнер-обёртка над QStackedWidget с процентным sizing.
|
||||
# Реализует переключение «страниц» (одна видна
|
||||
# в каждый момент). Используется для панели плагинов, табов и т.п.
|
||||
#
|
||||
# 2) Зависимости модуля:
|
||||
# Импорты: Qt, QStackedWidget, QGridLayout, QLayout, QWidget (PySide6)
|
||||
# Хост/базовый класс: StylableMixin + PercentSizedWidget (MRO)
|
||||
# Внутренние: ContentHost (content_host.py), StylableMixin (stylable_mixin.py)
|
||||
# Внешние библиотеки: PySide6
|
||||
#
|
||||
# 3) Экспорт:
|
||||
# Класс StackContainer — стековый контейнер.
|
||||
# Методы: add_widget(), set_current_index(), set_current_widget(),
|
||||
# current_index(), current_widget(), count(), widget(),
|
||||
# remove_widget(), get_available_size_for_content(),
|
||||
# get_layout(), set_margins(), set_spacing(), set_alignment()
|
||||
# Свойство: stacked_widget (доступ к QStackedWidget).
|
||||
#
|
||||
# 4) Состояние (поля):
|
||||
# _stack : QStackedWidget — Qt stacked widget.
|
||||
# _content_host : ContentHost — промежуточный хост.
|
||||
# _outer_layout : QGridLayout — внешний layout (spring-based).
|
||||
# _auto_add_children : bool = True — авто-добавление потомков.
|
||||
#
|
||||
# 5) Последовательность действий и вызовов:
|
||||
# __init__(params) -> super().__init__(w%, h%, parent)
|
||||
# -> _init_stylable() -> создание QStackedWidget
|
||||
# -> создание ContentHost -> _content_host.add_widget(_stack)
|
||||
# -> создание _outer_layout (QGridLayout)
|
||||
# -> setContentsMargins(applied_margins)
|
||||
# -> _apply_style() если style задан
|
||||
# add_widget(w) -> _stack.addWidget(w) → возвращает int index
|
||||
# set_current_index(i) -> _stack.setCurrentIndex(i)
|
||||
#
|
||||
# 6) Побочные эффекты:
|
||||
# QStackedWidget скрывает все страницы, кроме текущей.
|
||||
# _auto_add_children = True — дочерние виджеты авто-добавляются.
|
||||
# set_alignment() бросает NotImplementedError.
|
||||
# _apply_style() применяет stylesheet.
|
||||
#
|
||||
# 7) Границы ответственности:
|
||||
# НЕ управляет навигацией между страницами — только хранит и показывает.
|
||||
# НЕ создаёт кнопок/табов для переключения — это делает вызывающий код.
|
||||
# НЕ поддерживает Qt alignment (только springs).
|
||||
#
|
||||
# 8) Обработка ошибок:
|
||||
# set_alignment() → NotImplementedError.
|
||||
# Защита от нетипичных значений alignment — параметр удалён.
|
||||
#
|
||||
# 9) Инварианты и контракты:
|
||||
# - add_widget возвращает index добавленной страницы.
|
||||
# - content_margins приоритетнее margin.
|
||||
#
|
||||
# 10) Правило сопровождения:
|
||||
# Интерфейс CRUD-страниц (add/remove/set_current) повторяет
|
||||
# QStackedWidget — при обновлении Qt API проверять совместимость.
|
||||
# Не добавлять alignment в конструктор — запрещено правилами.
|
||||
Reference in New Issue
Block a user