Add Dispatch_V0.1.1

This commit is contained in:
2026-04-29 08:18:54 +04:00
commit a7ede6ded4
404 changed files with 39167 additions and 0 deletions

View 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, а не сюда.