handOver2/ui/components/flow_layout.py

108 lines
3.0 KiB
Python

# -*- coding: utf-8 -*-
"""
Flow Layout 모듈
칩이나 태그가 자동으로 줄바꿈되는 레이아웃입니다.
"""
from PySide6.QtWidgets import QLayout
from PySide6.QtCore import Qt, QRect, QPoint, QSize
from core.logger import get_logger
logger = get_logger(__name__)
class FlowLayout(QLayout):
"""
Flow Layout
가로 공간이 부족하면 자동으로 다음 줄로 넘어가는 레이아웃입니다.
칩이나 태그 UI에 사용됩니다.
"""
def __init__(self, parent=None, margin=0, h_spacing=10, v_spacing=10):
super().__init__(parent)
self.h_spacing = h_spacing
self.v_spacing = v_spacing
self.items = []
self.setContentsMargins(margin, margin, margin, margin)
def addItem(self, item):
"""아이템 추가"""
self.items.append(item)
def count(self):
"""아이템 개수"""
return len(self.items)
def itemAt(self, index):
"""인덱스로 아이템 가져오기"""
if 0 <= index < len(self.items):
return self.items[index]
return None
def takeAt(self, index):
"""인덱스로 아이템 제거"""
if 0 <= index < len(self.items):
return self.items.pop(index)
return None
def expandingDirections(self):
"""확장 방향"""
return Qt.Orientations(Qt.Orientation(0))
def hasHeightForWidth(self):
"""너비에 따른 높이 지원"""
return True
def heightForWidth(self, width):
"""너비에 따른 높이 계산"""
return self._do_layout(QRect(0, 0, width, 0), True)
def setGeometry(self, rect):
"""지오메트리 설정"""
super().setGeometry(rect)
self._do_layout(rect, False)
def sizeHint(self):
"""크기 힌트"""
return self.minimumSize()
def minimumSize(self):
"""최소 크기"""
size = QSize()
for item in self.items:
size = size.expandedTo(item.minimumSize())
size += QSize(2 * self.contentsMargins().top(), 2 * self.contentsMargins().top())
return size
def _do_layout(self, rect, test_only):
"""레이아웃 수행"""
x, y = rect.x(), rect.y()
line_height = 0
for item in self.items:
wid = item.widget()
space_x = self.h_spacing
space_y = self.v_spacing
next_x = x + item.sizeHint().width() + space_x
if next_x - space_x > rect.right() and line_height > 0:
x = rect.x()
y = y + line_height + space_y
next_x = x + item.sizeHint().width() + space_x
line_height = 0
if not test_only:
item.setGeometry(QRect(QPoint(x, y), item.sizeHint()))
x = next_x
line_height = max(line_height, item.sizeHint().height())
return y + line_height - rect.y()