* Optimized zFlowLayout() for speed.
authorUrban Wallasch <urban.wallasch@freenet.de>
Tue, 22 Jun 2021 09:41:51 +0000 (11:41 +0200)
committerUrban Wallasch <urban.wallasch@freenet.de>
Tue, 22 Jun 2021 09:41:51 +0000 (11:41 +0200)
kanjidic.py

index 07bc156ccfa8dd12e1788643056d3b4192561e1f..27e7ebfbd9688e51f4e8e68eeb70835cfbefe747 100755 (executable)
@@ -320,13 +320,11 @@ class zQTextEdit(QTextEdit):
         self._restore_cursor()
 
 # adapted from Qt flow layout C++ example
+# stripped down and optimized for speed in our special use case
 class zFlowLayout(QLayout):
-    def __init__(self, parent: QWidget=None, margin: int=-1, hSpacing: int=-1, vSpacing: int=-1):
+    def __init__(self, parent=None):
         super().__init__(parent)
         self.itemList = list()
-        self.m_hSpace = hSpacing
-        self.m_vSpace = vSpacing
-        self.setContentsMargins(margin, margin, margin, margin)
 
     def addItem(self, item):
         self.itemList.append(item)
@@ -351,30 +349,6 @@ class zFlowLayout(QLayout):
         except:
             return None
 
-    def horizontalSpacing(self):
-        if self.m_hSpace >= 0:
-            return self.m_hSpace
-        else:
-            return self.smartSpacing(QStyle.PM_LayoutHorizontalSpacing)
-
-    def verticalSpacing(self):
-        if self.m_vSpace >= 0:
-            return self.m_vSpace
-        else:
-            return self.smartSpacing(QStyle.PM_LayoutVerticalSpacing)
-
-    def smartSpacing(self, pm):
-        parent = self.parent()
-        if not parent:
-            return -1
-        elif parent.isWidgetType():
-            return parent.style().pixelMetric(pm, None, parent)
-        else:
-            return parent.spacing()
-
-    def expandingDirections(self):
-        return Qt.Orientations(Qt.Orientation(0))
-
     def hasHeightForWidth(self):
         return True
 
@@ -383,45 +357,34 @@ class zFlowLayout(QLayout):
         return height
 
     def setGeometry(self, rect):
-        super().setGeometry(rect)
         self.doLayout(rect, False)
 
     def sizeHint(self):
-        return self.minimumSize()
-
-    def minimumSize(self):
-        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 doLayout(self, rect, testOnly):
-        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()))
+        return QSize()
+
+    def doLayout(self, rect, testonly):
+        if not self.count():
+            return 0
+        x = rect.x()
+        y = rect.y()
+        right = rect.right() + 1
+        iszhint = self.itemList[0].widget().sizeHint()
+        iwidth = iszhint.width()
+        iheight = iszhint.height()
+        ngaps = int(right / iwidth)
+        gap = 0 if ngaps < 1 else int((right % iwidth) / ngaps)
+        for i in range(self.count()):
+            nextX = x + iwidth
+            if nextX > right:
+                x = rect.x()
+                y = y + iheight
+                nextX = x + iwidth + gap
+            else:
+                nextX += gap
+            if not testonly:
+                self.itemList[i].setGeometry(QRect(QPoint(x, y), iszhint))
             x = nextX
-            lineHeight = max(lineHeight, item.sizeHint().height())
-        return y + lineHeight - rect.y() + bottom
+        return y + iheight - rect.y()
 
 
 class zFlowScrollArea(QScrollArea):
@@ -437,7 +400,7 @@ class zFlowScrollArea(QScrollArea):
         self.clear()
         pane = QWidget()
         self.setWidget(pane)
-        layout = zFlowLayout(pane, 0, 0, 0)
+        layout = zFlowLayout(pane)
         layout.setEnabled(False)
         for tl in tiles:
             layout.addWidget(tl)
@@ -451,7 +414,7 @@ class zFlowScrollArea(QScrollArea):
         else:
             pane = QWidget()
             self.setWidget(pane)
-            layout = zFlowLayout(pane, 0, 0, 0)
+            layout = zFlowLayout(pane)
         for idx in range(layout.count()):
             if layout.itemAt(idx).widget().text() == w.text():
                 layout.takeAt(idx)