88 lines
2.6 KiB
Python
88 lines
2.6 KiB
Python
from __future__ import annotations
|
|
|
|
from PySide6.QtCore import QPoint, QRect, QSize, Qt
|
|
from PySide6.QtWidgets import QLayout
|
|
|
|
|
|
class FlowLayout(QLayout):
|
|
def __init__(
|
|
self, parent=None, margin: int = 0, hspacing: int = 4, vspacing: int = 4
|
|
):
|
|
super().__init__(parent)
|
|
self._items = []
|
|
self._hspace = hspacing
|
|
self._vspace = vspacing
|
|
self.setContentsMargins(margin, margin, margin, margin)
|
|
|
|
def addItem(self, item):
|
|
self._items.append(item)
|
|
|
|
def itemAt(self, index):
|
|
if 0 <= index < len(self._items):
|
|
return self._items[index]
|
|
return None
|
|
|
|
def takeAt(self, index):
|
|
if 0 <= index < len(self._items):
|
|
return self._items.pop(index)
|
|
return None
|
|
|
|
def count(self):
|
|
return len(self._items)
|
|
|
|
def expandingDirections(self):
|
|
return Qt.Orientations(Qt.Orientation(0))
|
|
|
|
def hasHeightForWidth(self):
|
|
return True
|
|
|
|
def heightForWidth(self, width: int) -> int:
|
|
return self._do_layout(QRect(0, 0, width, 0), test_only=True)
|
|
|
|
def setGeometry(self, rect: QRect):
|
|
super().setGeometry(rect)
|
|
self._do_layout(rect, test_only=False)
|
|
|
|
def sizeHint(self) -> QSize:
|
|
return self.minimumSize()
|
|
|
|
def minimumSize(self) -> QSize:
|
|
size = QSize()
|
|
for item in self._items:
|
|
size = size.expandedTo(item.minimumSize())
|
|
left, top, right, bottom = self.getContentsMargins()
|
|
size += QSize(left + right, top + bottom)
|
|
return size
|
|
|
|
def _do_layout(self, rect: QRect, test_only: bool) -> int:
|
|
x = rect.x()
|
|
y = rect.y()
|
|
line_height = 0
|
|
|
|
left, top, right, bottom = self.getContentsMargins()
|
|
effective_rect = rect.adjusted(+left, +top, -right, -bottom)
|
|
x = effective_rect.x()
|
|
y = effective_rect.y()
|
|
max_right = effective_rect.right()
|
|
|
|
for item in self._items:
|
|
wid = item.widget()
|
|
if wid is None or not wid.isVisible():
|
|
continue
|
|
space_x = self._hspace
|
|
space_y = self._vspace
|
|
next_x = x + item.sizeHint().width() + space_x
|
|
if next_x - space_x > max_right and line_height > 0:
|
|
# Wrap
|
|
x = effective_rect.x()
|
|
y = y + line_height + space_y
|
|
next_x = x + item.sizeHint().width() + space_x
|
|
line_height = 0
|
|
|
|
if not test_only:
|
|
item.setGeometry(QRect(QPoint(x, y), item.sizeHint()))
|
|
|
|
x = next_x
|
|
line_height = max(line_height, item.sizeHint().height())
|
|
|
|
return y + line_height - rect.y() + bottom
|