File indexing completed on 2024-12-01 04:36:37
0001 /* 0002 SPDX-FileCopyrightText: 2020-2024 Laurent Montel <montel@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "flowlayout.h" 0008 0009 #include <QStyle> 0010 #include <QWidget> 0011 0012 static int smartSpacing(QObject *parent, QStyle::PixelMetric pm) 0013 { 0014 if (!parent) { 0015 return -1; 0016 } else if (parent->isWidgetType()) { 0017 auto pw = static_cast<QWidget *>(parent); 0018 return pw->style()->pixelMetric(pm, nullptr, pw); 0019 } else { 0020 return static_cast<QLayout *>(parent)->spacing(); 0021 } 0022 } 0023 0024 FlowLayout::FlowLayout(QWidget *parent) 0025 : QLayout(parent) 0026 { 0027 } 0028 0029 FlowLayout::~FlowLayout() 0030 { 0031 clear(); 0032 } 0033 0034 int FlowLayout::horizontalSpacing() const 0035 { 0036 if (mHorizontalSpacing >= 0) { 0037 return mHorizontalSpacing; 0038 } else { 0039 return smartSpacing(parent(), QStyle::PM_LayoutHorizontalSpacing); 0040 } 0041 } 0042 0043 void FlowLayout::setHorizontalSpacing(int horizontalSpacing) 0044 { 0045 if (mHorizontalSpacing != horizontalSpacing) { 0046 mHorizontalSpacing = horizontalSpacing; 0047 invalidate(); 0048 } 0049 } 0050 0051 int FlowLayout::verticalSpacing() const 0052 { 0053 if (mVerticalSpacing >= 0) { 0054 return mVerticalSpacing; 0055 } else { 0056 return smartSpacing(parent(), QStyle::PM_LayoutVerticalSpacing); 0057 } 0058 } 0059 0060 void FlowLayout::setVerticalSpacing(int verticalSpacing) 0061 { 0062 if (mVerticalSpacing != verticalSpacing) { 0063 mVerticalSpacing = verticalSpacing; 0064 invalidate(); 0065 } 0066 } 0067 0068 QSize FlowLayout::sizeHint() const 0069 { 0070 return minimumSize(); 0071 } 0072 0073 QSize FlowLayout::minimumSize() const 0074 { 0075 const QMargins margins = contentsMargins(); 0076 QSize size; 0077 0078 for (const QLayoutItem *item : mItems) { 0079 size = size.expandedTo(item->minimumSize()); 0080 } 0081 0082 size += QSize(margins.left() + margins.right(), margins.top() + margins.bottom()); 0083 return size; 0084 } 0085 0086 void FlowLayout::addItem(QLayoutItem *item) 0087 { 0088 Q_ASSERT(!mItems.contains(item)); 0089 mItems.append(item); 0090 invalidate(); 0091 } 0092 0093 QLayoutItem *FlowLayout::itemAt(int index) const 0094 { 0095 if (index >= 0 && index < mItems.count()) { 0096 return mItems[index]; 0097 } 0098 0099 return nullptr; 0100 } 0101 0102 QLayoutItem *FlowLayout::takeAt(int index) 0103 { 0104 if (index >= 0 && index < mItems.count()) { 0105 auto *it = mItems.takeAt(index); 0106 invalidate(); 0107 return it; 0108 } 0109 0110 return nullptr; 0111 } 0112 0113 int FlowLayout::count() const 0114 { 0115 return mItems.count(); 0116 } 0117 0118 Qt::Orientations FlowLayout::expandingDirections() const 0119 { 0120 return {}; 0121 } 0122 0123 bool FlowLayout::hasHeightForWidth() const 0124 { 0125 return true; 0126 } 0127 0128 int FlowLayout::heightForWidth(int width) const 0129 { 0130 return doFlow(QRect(0, 0, width, 0), false); 0131 } 0132 0133 void FlowLayout::setGeometry(const QRect &rect) 0134 { 0135 QLayout::setGeometry(rect); 0136 doFlow(rect, true); 0137 } 0138 0139 void FlowLayout::clear() 0140 { 0141 while (QLayoutItem *item = takeAt(0)) { 0142 delete item; 0143 } 0144 } 0145 0146 void FlowLayout::clearAndDeleteWidgets() 0147 { 0148 while (QLayoutItem *item = takeAt(0)) { 0149 item->widget()->deleteLater(); 0150 delete item; 0151 } 0152 } 0153 0154 int FlowLayout::doFlow(QRect rect, bool effective) const 0155 { 0156 const QMargins margins = contentsMargins(); 0157 const QRect effectiveRect = rect.adjusted(margins.left(), margins.top(), -margins.right(), -margins.bottom()); 0158 int x = effectiveRect.x(); 0159 int y = effectiveRect.y(); 0160 int highest = 0; 0161 0162 for (QLayoutItem *item : mItems) { 0163 const QWidget *widget = item->widget(); 0164 0165 if (!widget->isVisibleTo(parentWidget())) { 0166 continue; 0167 } 0168 0169 int hSpacing = horizontalSpacing(); 0170 int vSpacing = verticalSpacing(); 0171 0172 if (hSpacing == -1) { 0173 hSpacing = widget->style()->layoutSpacing(QSizePolicy::Frame, QSizePolicy::Frame, Qt::Horizontal); 0174 } 0175 0176 if (vSpacing == -1) { 0177 vSpacing = widget->style()->layoutSpacing(QSizePolicy::Frame, QSizePolicy::Frame, Qt::Vertical); 0178 } 0179 0180 int widgetXPos = x + item->sizeHint().width() + hSpacing; 0181 0182 if (widgetXPos - hSpacing > effectiveRect.right() && highest > 0) { 0183 x = effectiveRect.x(); 0184 y += highest + vSpacing; 0185 widgetXPos = x + item->sizeHint().width() + hSpacing; 0186 highest = 0; 0187 } 0188 0189 if (effective) { 0190 item->setGeometry(QRect(QPoint(x, y), item->sizeHint())); 0191 } 0192 0193 x = widgetXPos; 0194 highest = qMax(highest, item->sizeHint().height()); 0195 } 0196 0197 return y + highest - rect.y() + margins.bottom(); 0198 } 0199 0200 #include "moc_flowlayout.cpp"