-
Notifications
You must be signed in to change notification settings - Fork 0
/
flowlayout.py
119 lines (92 loc) · 3.84 KB
/
flowlayout.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
import typing
from PyQt5.QtCore import Qt, QPoint, QRect, QSize
from PyQt5.QtWidgets import QWidget, QLayout, QLayoutItem, QStyle, QSizePolicy
class FlowLayout(QLayout):
def __init__(self, parent: QWidget=None, margin: int=-1, hSpacing: int=-1, vSpacing: int=-1):
super().__init__(parent)
self.itemList = list()
self.m_hSpace = hSpacing
self.m_vSpace = vSpacing
self.setAlignment(Qt.AlignTop)
self.setContentsMargins(margin, margin, margin, margin)
def __del__(self):
# copied for consistency, not sure this is needed or ever called
item = self.takeAt(0)
while item:
item = self.takeAt(0)
def addItem(self, item: QLayoutItem):
self.itemList.append(item)
def horizontalSpacing(self) -> int:
if self.m_hSpace >= 0:
return self.m_hSpace
else:
return self.smartSpacing(QStyle.PM_LayoutHorizontalSpacing)
def verticalSpacing(self) -> int:
if self.m_vSpace >= 0:
return self.m_vSpace
else:
return self.smartSpacing(QStyle.PM_LayoutVerticalSpacing)
def count(self) -> int:
return len(self.itemList)
def itemAt(self, index: int) -> typing.Union[QLayoutItem, None]:
if 0 <= index < len(self.itemList):
return self.itemList[index]
else:
return None
def takeAt(self, index: int) -> typing.Union[QLayoutItem, None]:
if 0 <= index < len(self.itemList):
return self.itemList.pop(index)
else:
return None
def expandingDirections(self) -> Qt.Orientations:
return Qt.Orientations(Qt.Orientation(0))
def hasHeightForWidth(self) -> bool:
return True
def heightForWidth(self, width: int) -> int:
height = self.doLayout(QRect(0, 0, width, 0), True)
return height
def setGeometry(self, rect: QRect) -> None:
super().setGeometry(rect)
self.doLayout(rect, False)
def sizeHint(self) -> QSize:
return self.minimumSize()
def minimumSize(self) -> QSize:
size = QSize()
for item in self.itemList:
size = size.expandedTo(item.minimumSize())
margins = self.contentsMargins()
size += QSize(margins.left() + margins.right(), margins.top() + margins.bottom())
return size
def smartSpacing(self, pm: QStyle.PixelMetric) -> int:
parent = self.parent()
if not parent:
return -1
elif parent.isWidgetType():
return parent.style().pixelMetric(pm, None, parent)
else:
return parent.spacing()
def doLayout(self, rect: QRect, testOnly: bool) -> int:
left, top, right, bottom = self.getContentsMargins()
effectiveRect = rect.adjusted(+left, +top, -right, -bottom)
x = effectiveRect.x()
y = effectiveRect.y()
lineHeight = 0
for item in self.itemList:
wid = item.widget()
spaceX = self.horizontalSpacing()
if spaceX == -1:
spaceX = wid.style().layoutSpacing(QSizePolicy.PushButton, QSizePolicy.PushButton, Qt.Horizontal)
spaceY = self.verticalSpacing()
if spaceY == -1:
spaceY = wid.style().layoutSpacing(QSizePolicy.PushButton, QSizePolicy.PushButton, Qt.Vertical)
nextX = x + item.sizeHint().width() + spaceX
if nextX - spaceX > effectiveRect.right() and lineHeight > 0:
x = effectiveRect.x()
y = y + lineHeight + spaceY
nextX = x + item.sizeHint().width() + spaceX
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