116 lines
3.8 KiB
Python
Executable File
116 lines
3.8 KiB
Python
Executable File
"""
|
|
Flow layout to allow widgets to be moved based around the size of the layout
|
|
|
|
This should be fun to doc and write demos, I'll do it later
|
|
"""
|
|
|
|
__DoNotReload__ = True # Module is NOT safe to be dynamciy reloaded
|
|
|
|
from PySide import QtGui, QtCore
|
|
|
|
|
|
class FlowLayout(QtGui.QLayout):
|
|
|
|
def __init__(self, parent=None, margin=-1, hSpacing=-1, vSpacing=-1):
|
|
super(FlowLayout, self).__init__()
|
|
self.setContentsMargins(margin, margin, margin, margin)
|
|
|
|
if parent is not None:
|
|
self.setMargin(margin)
|
|
|
|
self._itemList = []
|
|
self._hSpace = hSpacing
|
|
self._mSpace = vSpacing
|
|
|
|
def addItem(self, item):
|
|
self._itemList.append(item)
|
|
|
|
def horizontalSpacing(self):
|
|
if self._hSpace >= 0:
|
|
return self._hSpace
|
|
return self.smartSpacing(QtGui.QStyle.PM_LayoutHorizontalSpacing)
|
|
|
|
def verticalSpacing(self):
|
|
if self.vSpace >= 0:
|
|
return self.vSpace
|
|
return self.smartSpacing(QtGui.QStyle.PM_LayoutVerticalSpacing)
|
|
|
|
def count(self):
|
|
return len(self._itemList)
|
|
|
|
def itemAt(self, index):
|
|
if index >= 0 and index < len(self._itemList):
|
|
return self._itemList[index]
|
|
return None
|
|
|
|
def takeAt(self, index):
|
|
if index >= 0 and index < len(self._itemList):
|
|
return self._itemList.pop(index)
|
|
return 0
|
|
|
|
def expandingDirections(self):
|
|
return 0
|
|
|
|
def hasHeightForWidth(self):
|
|
return True
|
|
|
|
def heightForWidth(self, width):
|
|
return self.doLayout(QtCore.QRect(0, 0, width, 0), True)
|
|
|
|
def setGeometry(self, rect):
|
|
super(FlowLayout, self).setGeometry(rect)
|
|
self.doLayout(rect, False)
|
|
|
|
def sizeHint(self):
|
|
return self.minimumSize()
|
|
|
|
def minimumSize(self):
|
|
size = QtCore.QSize()
|
|
for item in self._itemList:
|
|
size = size.expandedTo(item.minimumSize())
|
|
|
|
size += QtCore.QSize(2*self.spacing(), 2*self.spacing())
|
|
return size
|
|
|
|
def doLayout(self, rect, testOnly=False):
|
|
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(QtGui.QSizePolicy.ButtonBox, QtGui.QSizePolicy.PushButton, QtCore.Qt.Horizontal)
|
|
|
|
spaceY = self.horizontalSpacing()
|
|
if (spaceY == -1):
|
|
spaceY = wid.style().layoutSpacing(QtGui.QSizePolicy.ButtonBox, QtGui.QSizePolicy.PushButton, QtCore.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(QtCore.QRect(QtCore.QPoint(x, y), item.sizeHint()))
|
|
|
|
x = nextX
|
|
lineHeight = max([lineHeight, item.sizeHint().height()])
|
|
|
|
return y + lineHeight - rect.y() + bottom
|
|
|
|
def smartSpacing(self, pixelMetric):
|
|
parent = self.parent()
|
|
if not parent:
|
|
return -1
|
|
elif isinstance(parent, QtGui.QWidget):
|
|
return parent.style().pixelMetric(pixelMetric)
|
|
else:
|
|
return parent.spacing()
|