72 lines
2.7 KiB
Python
72 lines
2.7 KiB
Python
"""Layout que coloca los widgets en fila y salta de línea cuando no caben.
|
|
|
|
Port mínimo del ejemplo FlowLayout de Qt: se usa para los 'pills' de cada fila,
|
|
que pueden ser muchos (topics) y deben envolver sin desbordar horizontalmente.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from PySide6.QtCore import QMargins, QPoint, QRect, QSize, Qt
|
|
from PySide6.QtWidgets import QLayout, QLayoutItem, QSizePolicy, QWidget
|
|
|
|
|
|
class FlowLayout(QLayout):
|
|
def __init__(self, parent: QWidget | None = None, spacing: int = 6) -> None:
|
|
super().__init__(parent)
|
|
self._items: list[QLayoutItem] = []
|
|
self._spacing = spacing
|
|
self.setContentsMargins(0, 0, 0, 0)
|
|
|
|
def addItem(self, item: QLayoutItem) -> None: # noqa: N802 - API Qt
|
|
self._items.append(item)
|
|
|
|
def count(self) -> int:
|
|
return len(self._items)
|
|
|
|
def itemAt(self, index: int) -> QLayoutItem | None: # noqa: N802 - API Qt
|
|
return self._items[index] if 0 <= index < len(self._items) else None
|
|
|
|
def takeAt(self, index: int) -> QLayoutItem | None: # noqa: N802 - API Qt
|
|
return self._items.pop(index) if 0 <= index < len(self._items) else None
|
|
|
|
def expandingDirections(self) -> Qt.Orientations: # noqa: N802 - API Qt
|
|
return Qt.Orientation(0)
|
|
|
|
def hasHeightForWidth(self) -> bool: # noqa: N802 - API Qt
|
|
return True
|
|
|
|
def heightForWidth(self, width: int) -> int: # noqa: N802 - API Qt
|
|
return self._layout(QRect(0, 0, width, 0), apply=False)
|
|
|
|
def setGeometry(self, rect: QRect) -> None: # noqa: N802 - API Qt
|
|
super().setGeometry(rect)
|
|
self._layout(rect, apply=True)
|
|
|
|
def sizeHint(self) -> QSize: # noqa: N802 - API Qt
|
|
return self.minimumSize()
|
|
|
|
def minimumSize(self) -> QSize: # noqa: N802 - API Qt
|
|
size = QSize()
|
|
for item in self._items:
|
|
size = size.expandedTo(item.minimumSize())
|
|
m: QMargins = self.contentsMargins()
|
|
return size + QSize(m.left() + m.right(), m.top() + m.bottom())
|
|
|
|
def _layout(self, rect: QRect, apply: bool) -> int:
|
|
m: QMargins = self.contentsMargins()
|
|
eff = rect.adjusted(m.left(), m.top(), -m.right(), -m.bottom())
|
|
x, y, line_h = eff.x(), eff.y(), 0
|
|
for item in self._items:
|
|
hint = item.sizeHint()
|
|
next_x = x + hint.width() + self._spacing
|
|
if next_x - self._spacing > eff.right() and line_h > 0:
|
|
x = eff.x()
|
|
y = y + line_h + self._spacing
|
|
next_x = x + hint.width() + self._spacing
|
|
line_h = 0
|
|
if apply:
|
|
item.setGeometry(QRect(QPoint(x, y), hint))
|
|
x = next_x
|
|
line_h = max(line_h, hint.height())
|
|
return y + line_h - rect.y() + m.bottom()
|