1
0
Fork 0
mirror of synced 2024-05-19 12:02:54 +12:00
Rare/rare/widgets/flow_layout.py

155 lines
4.8 KiB
Python

from typing import Optional, List, overload
from PyQt5.QtCore import Qt, QRect, QSize, QPoint
from PyQt5.QtWidgets import QLayout, QStyle, QSizePolicy, QLayoutItem, QWidget
class FlowLayout(QLayout):
def __init__(self, parent=None):
super(FlowLayout, self).__init__(parent)
self.setObjectName(type(self).__name__)
self._hspacing = -1
self._vspacing = -1
self._items: List[QLayoutItem] = []
def __del__(self):
del self._items[:]
@overload
def indexOf(self, a0: QWidget) -> int:
try:
return next(idx for idx, item in enumerate(self._items) if item.widget() is a0)
except:
return -1
def indexOf(self, a0: QLayoutItem) -> int:
try:
return self._items.index(a0)
except:
return -1
def addItem(self, a0: QLayoutItem) -> None:
self._items.append(a0)
self.invalidate()
def removeItem(self, a0: QLayoutItem) -> None:
self._items.remove(a0)
self.invalidate()
def spacing(self) -> int:
hspacing = self.horizontalSpacing()
if hspacing == self.verticalSpacing():
return hspacing
else:
return -1
def setSpacing(self, a0: int) -> None:
self._hspacing = self._vspacing = a0
self.invalidate()
def setHorizontalSpacing(self, a0: int) -> None:
self._hspacing = a0
self.invalidate()
def horizontalSpacing(self):
if self._hspacing >= 0:
return self._hspacing
else:
return self.smartSpacing(QStyle.PM_LayoutHorizontalSpacing)
def setVerticalSpacing(self, a0: int) -> None:
self._vspacing = a0
self.invalidate()
def verticalSpacing(self):
if self._vspacing >= 0:
return self._vspacing
else:
return self.smartSpacing(QStyle.PM_LayoutVerticalSpacing)
def count(self) -> int:
return len(self._items)
def itemAt(self, index: int) -> Optional[QLayoutItem]:
if 0 <= index < len(self._items):
return self._items[index]
return None
def takeAt(self, index: int) -> Optional[QLayoutItem]:
if 0 <= index < len(self._items):
item = self._items.pop(index)
self.invalidate()
return item
return None
def expandingDirections(self) -> Qt.Orientations:
return Qt.Orientations(Qt.Orientation(0))
# return Qt.Horizontal | Qt.Vertical
def hasHeightForWidth(self) -> bool:
return True
def heightForWidth(self, a0: int) -> int:
return self.doLayout(QRect(0, 0, a0, 0), True)
def setGeometry(self, a0: QRect) -> None:
super(FlowLayout, self).setGeometry(a0)
self.doLayout(a0, False)
def sizeHint(self) -> QSize:
return QSize(
self.parent().contentsRect().size().width(),
self.minimumSize().height()
)
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 doLayout(self, rect, testonly):
left, top, right, bottom = self.getContentsMargins()
effective = rect.adjusted(+left, +top, -right, -bottom)
x = effective.x()
y = effective.y()
lineheight = 0
if not self._items:
return y + lineheight - rect.y() + bottom
for item in self._items:
if item.isEmpty():
continue
widget = item.widget()
hspace = self.horizontalSpacing()
if hspace == -1:
hspace = widget.style().layoutSpacing(
QSizePolicy.PushButton, QSizePolicy.PushButton, Qt.Horizontal
)
vspace = self.verticalSpacing()
if vspace == -1:
vspace = widget.style().layoutSpacing(
QSizePolicy.PushButton, QSizePolicy.PushButton, Qt.Vertical
)
nextX = x + item.sizeHint().width() + hspace
if nextX - hspace > effective.right() and lineheight > 0:
x = effective.x()
y = y + lineheight + vspace
nextX = x + item.sizeHint().width() + hspace
lineheight = 0
if not testonly:
item.setGeometry(QRect(QPoint(x, y), item.sizeHint()))
x = nextX
lineheight = max(lineheight, item.sizeHint().height())
return y + lineheight - rect.y() + bottom
def smartSpacing(self, pm):
parent = self.parent()
if parent is None:
return -1
elif parent.isWidgetType():
return parent.style().pixelMetric(pm, None, parent)
else:
return parent.spacing()