Add Dispatch_V0.1.1
This commit is contained in:
145
Dispatch_V0.1.1/gui/containers/content_host.py
Normal file
145
Dispatch_V0.1.1/gui/containers/content_host.py
Normal file
@@ -0,0 +1,145 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# gui/containers/content_host.py
|
||||
|
||||
from PySide6.QtCore import Qt
|
||||
from PySide6.QtWidgets import QVBoxLayout, QHBoxLayout, QWidget, QSizePolicy
|
||||
from .percent_sized_widget import PercentSizedWidget
|
||||
|
||||
|
||||
class ContentHost(PercentSizedWidget):
|
||||
"""Внутренний хост контента с процентными размерами и базовым layout."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
width_percent: int | None = None,
|
||||
height_percent: int | None = None,
|
||||
orientation: str = "v",
|
||||
margin: int | tuple[int, int, int, int] = 0,
|
||||
spacing: int = 0,
|
||||
parent: QWidget | None = None,
|
||||
):
|
||||
super().__init__(width_percent, height_percent, parent)
|
||||
|
||||
if orientation == "h":
|
||||
self._layout = QHBoxLayout(self)
|
||||
else:
|
||||
self._layout = QVBoxLayout(self)
|
||||
|
||||
self._layout.setSpacing(spacing)
|
||||
|
||||
if isinstance(margin, (list, tuple)) and len(margin) == 4:
|
||||
self._layout.setContentsMargins(*margin)
|
||||
else:
|
||||
self._layout.setContentsMargins(margin, margin, margin, margin)
|
||||
|
||||
# Контент-хост по умолчанию растягивается внутри контейнера
|
||||
self.set_content_fit(True)
|
||||
|
||||
def set_content_fit(self, expand: bool) -> None:
|
||||
"""Управление растягиванием контента внутри контейнера."""
|
||||
if expand:
|
||||
self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
|
||||
else:
|
||||
self.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred)
|
||||
|
||||
def _auto_add_to_parent(self) -> None:
|
||||
"""Контент-хост добавляется вручную контейнером."""
|
||||
return
|
||||
|
||||
def add_widget(self, widget: QWidget, alignment=None) -> None:
|
||||
"""Добавляет виджет в layout контейнера."""
|
||||
self._layout.addWidget(widget)
|
||||
self._notify_children_layout_changed()
|
||||
|
||||
def insert_widget(self, index: int, widget: QWidget) -> None:
|
||||
"""Вставляет виджет в layout контейнера по индексу."""
|
||||
self._layout.insertWidget(index, widget)
|
||||
self._notify_children_layout_changed()
|
||||
|
||||
def remove_widget(self, widget: QWidget) -> None:
|
||||
"""Удаляет виджет из layout контейнера."""
|
||||
self._layout.removeWidget(widget)
|
||||
self._notify_children_layout_changed()
|
||||
|
||||
def add_widget_with_stretch(self, widget: QWidget, stretch: int, alignment=None) -> None:
|
||||
"""Добавляет виджет с stretch в layout контейнера."""
|
||||
self._layout.addWidget(widget, stretch)
|
||||
self._notify_children_layout_changed()
|
||||
|
||||
def add_stretch(self, stretch: int = 1) -> None:
|
||||
self._layout.addStretch(stretch)
|
||||
|
||||
def get_layout(self):
|
||||
return self._layout
|
||||
|
||||
def _notify_children_layout_changed(self) -> None:
|
||||
"""Канал «состав детей»: после изменения списка детей host'а просим
|
||||
каждого percent-sized потомка перепланировать свой пересчёт.
|
||||
Коалесцирование обеспечивается флагом _update_pending в каждом потомке —
|
||||
несколько add_widget(...) подряд дают только один singleShot(0) на потомка.
|
||||
"""
|
||||
for index in range(self._layout.count()):
|
||||
item = self._layout.itemAt(index)
|
||||
if item is None:
|
||||
continue
|
||||
child_widget = item.widget()
|
||||
if isinstance(child_widget, PercentSizedWidget):
|
||||
child_widget.schedule_percent_update()
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Module workflow notes
|
||||
# ---------------------------------------------------------------------------
|
||||
#
|
||||
# 1) Назначение модуля:
|
||||
# Внутренний хост контента — промежуточный виджет, который размещается
|
||||
# внутри контейнеров (SContainer, GridContainer, StackContainer и пр.)
|
||||
# и содержит реальные дочерние виджеты. Поддерживает процентные размеры,
|
||||
# вертикальную/горизонтальную ориентацию layout'а, отступы и spacing.
|
||||
# Является деталью реализации контейнеров, а не частью публичного API.
|
||||
#
|
||||
# 2) Зависимости модуля:
|
||||
# Импорты: Qt, QVBoxLayout, QHBoxLayout, QWidget, QSizePolicy (PySide6)
|
||||
# Хост/базовый класс: PercentSizedWidget (percent_sized_widget.py)
|
||||
# Внешние библиотеки: PySide6
|
||||
#
|
||||
# 3) Экспорт:
|
||||
# Класс ContentHost — внутренний хост контента с layout.
|
||||
# Методы: set_content_fit(), add_widget(), add_widget_with_stretch(),
|
||||
# add_stretch(), get_layout()
|
||||
#
|
||||
# 4) Состояние (поля):
|
||||
# _layout : QVBoxLayout | QHBoxLayout — layout для размещения потомков,
|
||||
# выбирается по параметру orientation ("v"/"h").
|
||||
#
|
||||
# 5) Последовательность действий и вызовов:
|
||||
# __init__(params) -> super().__init__(width_percent, height_percent)
|
||||
# -> создание QVBoxLayout/QHBoxLayout
|
||||
# -> setSpacing() -> setContentsMargins()
|
||||
# -> set_content_fit(True) — SizePolicy = Expanding по умолчанию
|
||||
# add_widget(widget) -> _layout.addWidget(widget)
|
||||
# add_widget_with_stretch(widget, stretch) -> _layout.addWidget(widget, stretch)
|
||||
#
|
||||
# 6) Побочные эффекты:
|
||||
# Устанавливает SizePolicy на self при вызове set_content_fit().
|
||||
# _auto_add_to_parent() переопределён как no-op — ContentHost добавляется
|
||||
# контейнером вручную, а не через механизм авто-добавления PercentSizedWidget.
|
||||
#
|
||||
# 7) Границы ответственности:
|
||||
# НЕ управляет собственными процентами — это делает PercentSizedWidget.
|
||||
# НЕ стилизуется (не наследует StylableMixin).
|
||||
# НЕ дублирует логику контейнера; лишь предоставляет layout.
|
||||
#
|
||||
# 8) Обработка ошибок:
|
||||
# Нет явной обработки; некорректные margin/spacing молча приведут
|
||||
# к ошибке Qt. Если margin — не tuple(4), воспринимается как int.
|
||||
#
|
||||
# 9) Инварианты и контракты:
|
||||
# - orientation ∈ {"v", "h"}, иначе умолчание — вертикальный.
|
||||
# - margin: int или tuple(4). Иной тип вызовет ошибку setContentsMargins.
|
||||
# - _auto_add_to_parent всегда возвращает None.
|
||||
#
|
||||
# 10) Правило сопровождения:
|
||||
# Не расширять публичный интерфейс ContentHost — он должен оставаться
|
||||
# тонкой обёрткой. Новые фичи (стилизация, alignment) добавлять
|
||||
# в контейнеры, использующие ContentHost, а не сюда.
|
||||
Reference in New Issue
Block a user