# -*- 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()