File indexing completed on 2025-03-09 03:57:04
0001 /* ============================================================ 0002 * 0003 * This file is a part of digiKam project 0004 * https://www.digikam.org 0005 * 0006 * Date : 2009-10-22 0007 * Description : a dynamic layout manager 0008 * 0009 * SPDX-FileCopyrightText: 2009-2012 by Andi Clemens <andi dot clemens at gmail dot com> 0010 * 0011 * SPDX-License-Identifier: GPL-2.0-or-later 0012 * 0013 * ============================================================ */ 0014 0015 #include "dynamiclayout.h" 0016 0017 // Qt includes 0018 0019 #include <QStyle> 0020 #include <QWidget> 0021 0022 namespace Digikam 0023 { 0024 0025 class Q_DECL_HIDDEN DynamicLayout::Private 0026 { 0027 public: 0028 0029 explicit Private(int hSpacing, int vSpacing) 0030 : hSpace (hSpacing), 0031 vSpace (vSpacing), 0032 spaceX (0), 0033 spaceY (0), 0034 minItemWidth(0), 0035 minColumns (2) 0036 { 0037 } 0038 0039 int hSpace; 0040 int vSpace; 0041 int spaceX; 0042 int spaceY; 0043 int minItemWidth; 0044 const int minColumns; 0045 0046 QList<QLayoutItem*> itemList; 0047 }; 0048 0049 // -------------------------------------------------------- 0050 0051 DynamicLayout::DynamicLayout(QWidget* const parent, int margin, int hSpacing, int vSpacing) 0052 : QLayout(parent), 0053 d (new Private(hSpacing, vSpacing)) 0054 { 0055 setContentsMargins(margin, margin, margin, margin); 0056 } 0057 0058 DynamicLayout::DynamicLayout(int margin, int hSpacing, int vSpacing) 0059 : d(new Private(hSpacing, vSpacing)) 0060 { 0061 setContentsMargins(margin, margin, margin, margin); 0062 } 0063 0064 DynamicLayout::~DynamicLayout() 0065 { 0066 QLayoutItem* item = nullptr; 0067 0068 while ((item = this->takeAt(0))) 0069 { 0070 delete item; 0071 } 0072 0073 delete d; 0074 } 0075 0076 void DynamicLayout::addItem(QLayoutItem* layItem) 0077 { 0078 d->minItemWidth = 0; 0079 d->itemList.append(layItem); 0080 0081 Q_FOREACH (QLayoutItem* const item, d->itemList) 0082 { 0083 QWidget* const wid = item->widget(); 0084 d->spaceX = qMax<int>(wid->style()->layoutSpacing(QSizePolicy::PushButton, QSizePolicy::PushButton, 0085 Qt::Horizontal), d->spaceX); 0086 d->spaceY = qMax<int>(wid->style()->layoutSpacing(QSizePolicy::PushButton, QSizePolicy::PushButton, 0087 Qt::Vertical), d->spaceY); 0088 d->minItemWidth = qMax<int>(wid->sizeHint().width(), d->minItemWidth); 0089 } 0090 0091 Q_FOREACH (QLayoutItem* const item, d->itemList) 0092 { 0093 QWidget* const wid = item->widget(); 0094 wid->setMinimumWidth(d->minItemWidth); 0095 } 0096 } 0097 0098 int DynamicLayout::horizontalSpacing() const 0099 { 0100 return d->hSpace; 0101 } 0102 0103 int DynamicLayout::verticalSpacing() const 0104 { 0105 return d->vSpace; 0106 } 0107 0108 int DynamicLayout::count() const 0109 { 0110 return d->itemList.size(); 0111 } 0112 0113 QLayoutItem* DynamicLayout::itemAt(int index) const 0114 { 0115 return d->itemList.value(index); 0116 } 0117 0118 QLayoutItem* DynamicLayout::takeAt(int index) 0119 { 0120 QLayoutItem* item = nullptr; 0121 0122 if ((index >= 0) && (index < d->itemList.size())) 0123 { 0124 item = d->itemList.takeAt(index); 0125 } 0126 0127 return item; 0128 } 0129 0130 Qt::Orientations DynamicLayout::expandingDirections() const 0131 { 0132 return Qt::Orientations(); 0133 } 0134 0135 bool DynamicLayout::hasHeightForWidth() const 0136 { 0137 return true; 0138 } 0139 0140 int DynamicLayout::heightForWidth(int width) const 0141 { 0142 int height = reLayout(QRect(0, 0, width, 0), true); 0143 0144 return height; 0145 } 0146 0147 void DynamicLayout::setGeometry(const QRect& rect) 0148 { 0149 QLayout::setGeometry(rect); 0150 reLayout(rect, false); 0151 } 0152 0153 QSize DynamicLayout::sizeHint() const 0154 { 0155 return minimumSize(); 0156 } 0157 0158 QSize DynamicLayout::minimumSize() const 0159 { 0160 QSize size; 0161 0162 Q_FOREACH (QLayoutItem* const item, d->itemList) 0163 { 0164 size = size.expandedTo(item->minimumSize()); 0165 } 0166 0167 size += QSize(2 * contentsMargins().left(), 2 * contentsMargins().top()); 0168 int w = (size.width() * d->minColumns) + (d->minColumns * d->spaceX); 0169 size.setWidth(w); 0170 0171 return size; 0172 } 0173 0174 int DynamicLayout::reLayout(const QRect& rect, bool testOnly) const 0175 { 0176 int left = 0; 0177 int top = 0; 0178 int right = 0; 0179 int bottom = 0; 0180 getContentsMargins(&left, &top, &right, &bottom); 0181 0182 QRect effectiveRect = rect.adjusted(+left, +top, -right, -bottom); 0183 int x = effectiveRect.x(); 0184 int y = effectiveRect.y(); 0185 int lineHeight = 0; 0186 0187 // -------------------------------------------------------- 0188 0189 int buttonWidth = d->minItemWidth + d->spaceX; 0190 0191 if (buttonWidth == 0) 0192 { 0193 buttonWidth = 1; 0194 } 0195 0196 int maxButtonsInRow = (effectiveRect.width() - d->spaceX) / buttonWidth; 0197 0198 if (maxButtonsInRow < d->minColumns) 0199 { 0200 maxButtonsInRow = d->minColumns; 0201 } 0202 0203 int maxButtonWidth = d->minItemWidth + ((effectiveRect.width() - (maxButtonsInRow * buttonWidth)) / maxButtonsInRow); 0204 0205 int currentBtnWidth = (maxButtonsInRow >= d->itemList.count()) ? buttonWidth : maxButtonWidth; 0206 0207 // -------------------------------------------------------- 0208 0209 Q_FOREACH (QLayoutItem* const item, d->itemList) 0210 { 0211 int nextX = x + currentBtnWidth + d->spaceX; 0212 0213 // cppcheck-suppress knownConditionTrueFalse 0214 if (((nextX - d->spaceX) > effectiveRect.right()) && (lineHeight > 0)) 0215 { 0216 x = effectiveRect.x(); 0217 y = y + lineHeight + d->spaceY; 0218 nextX = x + currentBtnWidth + d->spaceX; 0219 lineHeight = 0; 0220 } 0221 0222 if (!testOnly) 0223 { 0224 QSize s = item->sizeHint(); 0225 s.setWidth(currentBtnWidth); 0226 item->setGeometry(QRect(QPoint(x, y), s)); 0227 } 0228 0229 x = nextX; 0230 lineHeight = qMax(lineHeight, item->sizeHint().height()); 0231 } 0232 0233 return (y + lineHeight - rect.y() + bottom); 0234 } 0235 0236 } // namespace Digikam 0237 0238 #include "moc_dynamiclayout.cpp"