File indexing completed on 2024-04-28 04:18:50

0001 /****************************************************************************
0002 **
0003 ** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
0004 ** Contact: Qt Software Information (qt-info@nokia.com)
0005 **
0006 ** This file is part of the example classes of the Qt Toolkit.
0007 **
0008 ** Commercial Usage
0009 ** Licensees holding valid Qt Commercial licenses may use this file in
0010 ** accordance with the Qt Commercial License Agreement provided with the
0011 ** Software or, alternatively, in accordance with the terms contained in
0012 ** a written agreement between you and Nokia.
0013 **
0014 **
0015 ** GNU General Public License Usage
0016 ** Alternatively, this file may be used under the terms of the GNU
0017 ** General Public License versions 2.0 or 3.0 as published by the Free
0018 ** Software Foundation and appearing in the file LICENSE.GPL included in
0019 ** the packaging of this file.  Please review the following information
0020 ** to ensure GNU General Public Licensing requirements will be met:
0021 ** https://www.fsf.org/licensing/licenses/info/GPLv2.html and
0022 ** https://www.gnu.org/copyleft/gpl.html.  In addition, as a special
0023 ** exception, Nokia gives you certain additional rights. These rights
0024 ** are described in the Nokia Qt GPL Exception version 1.3, included in
0025 ** the file GPL_EXCEPTION.txt in this package.
0026 **
0027 ** Qt for Windows(R) Licensees
0028 ** As a special exception, Nokia, as the sole copyright holder for Qt
0029 ** Designer, grants users of the Qt/Eclipse Integration plug-in the
0030 ** right for the Qt/Eclipse Integration to link to functionality
0031 ** provided by Qt Designer and its related libraries.
0032 **
0033 ** If you are unsure which license is appropriate for your use, please
0034 ** contact the sales department at qt-sales@nokia.com.
0035 **
0036 ****************************************************************************/
0037 
0038 // Self
0039 #include "flowlayout.h"
0040 
0041 // Qt
0042 #include <QHash>
0043 
0044 FlowLayout::FlowLayout(QWidget *parent, int margin, int spacing)
0045     : QLayout(parent)
0046 {
0047     setContentsMargins(margin, margin, margin, margin);
0048     setHorizontalSpacing(spacing);
0049     setVerticalSpacing(spacing);
0050 }
0051 
0052 FlowLayout::FlowLayout(int spacing)
0053 {
0054     setHorizontalSpacing(spacing);
0055     setVerticalSpacing(spacing);
0056 }
0057 
0058 FlowLayout::~FlowLayout()
0059 {
0060     QLayoutItem *item;
0061     while ((item = takeAt(0)))
0062         delete item;
0063 }
0064 
0065 int FlowLayout::horizontalSpacing() const
0066 {
0067     return mHorizontalSpacing;
0068 }
0069 
0070 void FlowLayout::setHorizontalSpacing(const int spacing)
0071 {
0072     mHorizontalSpacing = spacing;
0073 }
0074 
0075 int FlowLayout::verticalSpacing() const
0076 {
0077     return mVerticalSpacing;
0078 }
0079 
0080 void FlowLayout::setVerticalSpacing(const int spacing)
0081 {
0082     mVerticalSpacing = spacing;
0083 }
0084 
0085 void FlowLayout::addItem(QLayoutItem *item)
0086 {
0087     itemList.append(item);
0088 }
0089 
0090 int FlowLayout::count() const
0091 {
0092     return itemList.size();
0093 }
0094 
0095 QLayoutItem *FlowLayout::itemAt(int index) const
0096 {
0097     return itemList.value(index);
0098 }
0099 
0100 QLayoutItem *FlowLayout::takeAt(int index)
0101 {
0102     if (index >= 0 && index < itemList.size())
0103         return itemList.takeAt(index);
0104     else
0105         return nullptr;
0106 }
0107 
0108 Qt::Orientations FlowLayout::expandingDirections() const
0109 {
0110     return {};
0111 }
0112 
0113 bool FlowLayout::hasHeightForWidth() const
0114 {
0115     return true;
0116 }
0117 
0118 int FlowLayout::heightForWidth(int width) const
0119 {
0120     int height = doLayout(QRect(0, 0, width, 0), true);
0121     return height;
0122 }
0123 
0124 void FlowLayout::setGeometry(const QRect &rect)
0125 {
0126     QLayout::setGeometry(rect);
0127     doLayout(rect, false);
0128 }
0129 
0130 QSize FlowLayout::sizeHint() const
0131 {
0132     return minimumSize();
0133 }
0134 
0135 int FlowLayout::getMargin() const
0136 {
0137     int left, top, right, bottom;
0138     getContentsMargins(&left, &top, &right, &bottom);
0139     if (left == top && top == right && right == bottom) {
0140         return left;
0141     } else {
0142         return -1;
0143     }
0144 }
0145 
0146 QSize FlowLayout::minimumSize() const
0147 {
0148     QSize size;
0149     for (QLayoutItem *item : qAsConst(itemList))
0150         size = size.expandedTo(item->minimumSize());
0151 
0152     size += QSize(2 * getMargin(), 2 * getMargin());
0153     return size;
0154 }
0155 
0156 void FlowLayout::addSpacing(const int size)
0157 {
0158     addItem(new QSpacerItem(size, 0, QSizePolicy::Fixed, QSizePolicy::Minimum));
0159 }
0160 
0161 int FlowLayout::doLayout(const QRect &rect, bool testOnly) const
0162 {
0163     const int left = rect.x() + getMargin();
0164     int x = left;
0165     int y = rect.y() + getMargin();
0166     int lineHeight = 0;
0167     bool lastItemIsSpacer = false;
0168     QHash<int, int> widthForY;
0169 
0170     for (QLayoutItem *item : qAsConst(itemList)) {
0171         const bool itemIsSpacer = item->spacerItem() != nullptr;
0172         // Don't add invisible items or succeeding spacer items
0173         if (item->sizeHint().width() == 0 || (itemIsSpacer && lastItemIsSpacer)) {
0174             continue;
0175         }
0176 
0177         int nextX = x + item->sizeHint().width() + horizontalSpacing();
0178         if (nextX - horizontalSpacing() > rect.right() - getMargin() && lineHeight > 0) {
0179             x = left;
0180             y = y + lineHeight + verticalSpacing();
0181             nextX = x + item->sizeHint().width() + horizontalSpacing();
0182             lineHeight = 0;
0183         }
0184 
0185         // Don't place spacer items at start of line
0186         if (itemIsSpacer && x == left) {
0187             continue;
0188         }
0189 
0190         if (!testOnly)
0191             item->setGeometry(QRect(QPoint(x, y), item->sizeHint()));
0192 
0193         x = nextX;
0194         // Don't add spacer items at end of line
0195         if (!itemIsSpacer) {
0196             widthForY[y] = x - getMargin();
0197         }
0198         lineHeight = qMax(lineHeight, item->sizeHint().height());
0199         lastItemIsSpacer = itemIsSpacer;
0200     }
0201 
0202     if (!testOnly) {
0203         const int contentWidth = rect.width() - 2 * getMargin();
0204         for (auto item : itemList) {
0205             QRect itemRect = item->geometry();
0206             // Center lines horizontally if flag AlignHCenter is set
0207             if (alignment() & Qt::AlignHCenter) {
0208                 if (widthForY.contains(itemRect.y())) {
0209                     const int offset = (contentWidth - widthForY[itemRect.y()]) / 2;
0210                     itemRect.translate(offset, 0);
0211                 }
0212             }
0213             // Center items vertically if flag AlignVCenter is set
0214             if (alignment() & Qt::AlignVCenter) {
0215                 const int offset = (lineHeight - itemRect.height()) / 2;
0216                 itemRect.translate(0, offset);
0217             }
0218             item->setGeometry(itemRect);
0219         }
0220     }
0221 
0222     return y + lineHeight - rect.y() + getMargin();
0223 }
0224 
0225 #include "moc_flowlayout.cpp"