Skip to content

Commit

Permalink
Add CurvedFlowLayout
Browse files Browse the repository at this point in the history
  • Loading branch information
zkovari committed Mar 13, 2023
1 parent b516567 commit 313887a
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 17 deletions.
6 changes: 5 additions & 1 deletion demo.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from qtpy.QtWidgets import QLabel, QPushButton
from qtpy.QtWidgets import QMainWindow, QApplication, QWidget

from qthandy import underline, bold, vbox, flow, btn_popup
from qthandy import underline, bold, vbox, flow, btn_popup, curved_flow
from qthandy.filter import InstantTooltipEventFilter, DragEventFilter, DropEventFilter


Expand Down Expand Up @@ -37,13 +37,17 @@ def __init__(self, parent=None):

self.wdgFlow = QWidget()
flow(self.wdgFlow)
self.wdgCurvedFlow = QWidget()
curved_flow(self.wdgCurvedFlow)

for i in range(15):
self.wdgFlow.layout().addWidget(QLabel(f'Label {i + 1}'))
self.wdgCurvedFlow.layout().addWidget(QLabel(f'Label {i + 1}'))

self.widget.layout().addWidget(self.lbl)
self.widget.layout().addWidget(self.btnWithMenu)
self.widget.layout().addWidget(self.wdgFlow)
self.widget.layout().addWidget(self.wdgCurvedFlow)


if __name__ == '__main__':
Expand Down
11 changes: 10 additions & 1 deletion qthandy/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from qtpy.QtWidgets import QWidget, QApplication, QMessageBox, QSizePolicy, QFrame, QMenu, QLabel, QWidgetAction, \
QPushButton, QToolButton, QVBoxLayout, QHBoxLayout, QLayout, QGraphicsOpacityEffect, QGridLayout

from qthandy.layout import FlowLayout
from qthandy.layout import FlowLayout, CurvedFlowLayout


def ask_confirmation(message: str, parent=None) -> bool:
Expand Down Expand Up @@ -205,6 +205,15 @@ def flow(widget, margin: int = 2, spacing: int = 3) -> FlowLayout:
return _layout


def curved_flow(widget, margin: int = 2, spacing: int = 3) -> FlowLayout:
_layout = CurvedFlowLayout()
widget.setLayout(_layout)
widget.layout().setContentsMargins(margin, margin, margin, margin)
widget.layout().setSpacing(spacing)

return _layout


def margins(widget, left=None, top=None, right=None, bottom=None):
if widget.layout() is None:
raise ValueError('Widget does not have a layout. Set a layout first to change the margins.')
Expand Down
71 changes: 57 additions & 14 deletions qthandy/layout.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ def takeAt(self, index: int) -> Optional[QLayoutItem]:
def hasHeightForWidth(self) -> bool:
return True

def heightForWidth(self, width) -> int:
def heightForWidth(self, width: int) -> int:
return self._arrange(QRect(0, 0, width, 0), True)

def setGeometry(self, rect: QRect):
Expand Down Expand Up @@ -70,20 +70,16 @@ def _arrange(self, rect: QRect, testOnly: bool) -> int:

for item in self._items:
widget = item.widget()
spaceX = self.spacing()
if spaceX == -1:
spaceX = widget.style().layoutSpacing(QSizePolicy.PushButton, QSizePolicy.PushButton,
Qt.Horizontal)
spaceY = self.spacing()
if spaceY == -1:
spaceY = widget.style().layoutSpacing(QSizePolicy.PushButton, QSizePolicy.PushButton,
Qt.Vertical)

nextX = x + item.sizeHint().width() + spaceX
if nextX - spaceX > effectiveRect.right() and lineHeight > 0:
spacing = self.spacing()
if spacing == -1:
spacing = widget.style().layoutSpacing(QSizePolicy.PushButton, QSizePolicy.PushButton,
Qt.Horizontal)

nextX = x + item.sizeHint().width() + spacing
if nextX - spacing > effectiveRect.right() and lineHeight > 0:
x = effectiveRect.x()
y = y + lineHeight + spaceY
nextX = x + item.sizeHint().width() + spaceX
y = y + lineHeight + spacing
nextX = x + item.sizeHint().width() + spacing
lineHeight = 0

if not testOnly:
Expand All @@ -93,3 +89,50 @@ def _arrange(self, rect: QRect, testOnly: bool) -> int:
lineHeight = max(lineHeight, item.sizeHint().height())

return y + lineHeight - rect.y() + bottom


class CurvedFlowLayout(FlowLayout):

def _arrange(self, rect: QRect, testOnly: bool) -> int:
left, top, right, bottom = self.getContentsMargins()
effectiveRect: QRect = rect.adjusted(left, top, -right, -bottom)
x = effectiveRect.x()
y = effectiveRect.y()
lineHeight = 0

forward = True

for item in self._items:
widget = item.widget()
spacing = self.spacing()
if spacing == -1:
spacing = widget.style().layoutSpacing(QSizePolicy.PushButton, QSizePolicy.PushButton,
Qt.Horizontal)
if forward:
nextX = x + item.sizeHint().width() + spacing
if nextX - spacing > effectiveRect.right() and lineHeight > 0:
forward = False
x = nextX - spacing - item.sizeHint().width()
nextX = x - item.sizeHint().width() - spacing
y = y + lineHeight + spacing
lineHeight = 0
else:
nextX = x - item.sizeHint().width() - spacing
if nextX + spacing < effectiveRect.x() and lineHeight > 0:
forward = True
x = effectiveRect.x()
nextX = x + item.sizeHint().width() + spacing
y = y + lineHeight + spacing

lineHeight = 0

if not forward:
x = x - item.sizeHint().width()

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
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@

setup(
name='qt-handy',
version='0.1.0',
version='0.2.0',

author='Zsolt Kovari',
author_email='zsolt@kovaridev.com',
Expand Down

0 comments on commit 313887a

Please sign in to comment.