Warning, file /libraries/baloo-widgets/src/kblocklayout.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /*
0002     SPDX-FileCopyrightText: 2006-2007 Sebastian Trueg <trueg@kde.org>
0003 
0004     KBlockLayout is based on the FlowLayout example from QT4.
0005     SPDX-FileCopyrightText: 2004-2006 Trolltech ASA
0006     SPDX-FileCopyrightText: 2010 Nokia Corporation and /or its subsidiary(-ies) <qt-info@nokia.com>
0007 
0008     SPDX-License-Identifier: LGPL-2.0-or-later
0009 */
0010 
0011 #include "kblocklayout.h"
0012 
0013 #include <QList>
0014 #include <QStyle>
0015 #include <QWidget>
0016 
0017 class KBlockLayout::Private
0018 {
0019 public:
0020     Private()
0021         : alignment(Qt::AlignLeft | Qt::AlignTop)
0022     {
0023     }
0024 
0025     int smartSpacing(QStyle::PixelMetric pm) const
0026     {
0027         QObject *parent = q->parent();
0028         if (!parent) {
0029             return -1;
0030         } else if (parent->isWidgetType()) {
0031             auto pw = static_cast<QWidget *>(parent);
0032             return pw->style()->pixelMetric(pm, nullptr, pw);
0033         } else {
0034             return static_cast<QLayout *>(parent)->spacing();
0035         }
0036     }
0037 
0038     QList<QLayoutItem *> itemList;
0039 
0040     int m_hSpace;
0041     int m_vSpace;
0042 
0043     Qt::Alignment alignment;
0044 
0045     KBlockLayout *q = nullptr;
0046 };
0047 
0048 KBlockLayout::KBlockLayout(QWidget *parent, int margin, int hSpacing, int vSpacing)
0049     : QLayout(parent)
0050     , d(new Private())
0051 {
0052     d->q = this;
0053     setContentsMargins(margin, margin, margin, margin);
0054     setSpacing(hSpacing, vSpacing);
0055 }
0056 
0057 KBlockLayout::KBlockLayout(int margin, int hSpacing, int vSpacing)
0058     : d(new Private())
0059 {
0060     d->q = this;
0061     setContentsMargins(margin, margin, margin, margin);
0062     setSpacing(hSpacing, vSpacing);
0063 }
0064 
0065 KBlockLayout::~KBlockLayout()
0066 {
0067     QLayoutItem *item;
0068     while ((item = takeAt(0)))
0069         delete item;
0070     delete d;
0071 }
0072 
0073 void KBlockLayout::setAlignment(Qt::Alignment a)
0074 {
0075     d->alignment = a;
0076 }
0077 
0078 Qt::Alignment KBlockLayout::alignment() const
0079 {
0080     return d->alignment;
0081 }
0082 
0083 int KBlockLayout::horizontalSpacing() const
0084 {
0085     if (d->m_hSpace >= 0) {
0086         return d->m_hSpace;
0087     } else {
0088         return d->smartSpacing(QStyle::PM_LayoutHorizontalSpacing);
0089     }
0090 }
0091 
0092 int KBlockLayout::verticalSpacing() const
0093 {
0094     if (d->m_vSpace >= 0) {
0095         return d->m_vSpace;
0096     } else {
0097         return d->smartSpacing(QStyle::PM_LayoutVerticalSpacing);
0098     }
0099 }
0100 
0101 void KBlockLayout::setSpacing(int h, int v)
0102 {
0103     d->m_hSpace = h;
0104     d->m_vSpace = v;
0105     QLayout::setSpacing(h);
0106 }
0107 
0108 void KBlockLayout::addItem(QLayoutItem *item)
0109 {
0110     d->itemList.append(item);
0111 }
0112 
0113 int KBlockLayout::count() const
0114 {
0115     return d->itemList.size();
0116 }
0117 
0118 QLayoutItem *KBlockLayout::itemAt(int index) const
0119 {
0120     return d->itemList.value(index);
0121 }
0122 
0123 QLayoutItem *KBlockLayout::takeAt(int index)
0124 {
0125     if (index >= 0 && index < d->itemList.size())
0126         return d->itemList.takeAt(index);
0127     else
0128         return nullptr;
0129 }
0130 
0131 Qt::Orientations KBlockLayout::expandingDirections() const
0132 {
0133     return {};
0134 }
0135 
0136 bool KBlockLayout::hasHeightForWidth() const
0137 {
0138     return true;
0139 }
0140 
0141 int KBlockLayout::heightForWidth(int width) const
0142 {
0143     int height = doLayout(QRect(0, 0, width, 0), true);
0144     return height;
0145 }
0146 
0147 void KBlockLayout::setGeometry(const QRect &rect)
0148 {
0149     QLayout::setGeometry(rect);
0150     doLayout(rect, false);
0151 }
0152 
0153 int KBlockLayout::getMargin() const
0154 {
0155     int left, top, right, bottom;
0156     getContentsMargins(&left, &top, &right, &bottom);
0157     if (left == top && top == right && right == bottom) {
0158         return left;
0159     } else {
0160         return -1;
0161     }
0162 }
0163 
0164 QSize KBlockLayout::sizeHint() const
0165 {
0166     // TODO: try to get the items into a square
0167     QSize size;
0168     for (QLayoutItem *item : std::as_const(d->itemList)) {
0169         const QSize itemSize = item->minimumSize();
0170         size.rwidth() += itemSize.width();
0171         if (itemSize.height() > size.height()) {
0172             size.setHeight(itemSize.height());
0173         }
0174     }
0175 
0176     size.rwidth() += horizontalSpacing() * d->itemList.count();
0177     size += QSize(2 * getMargin(), 2 * getMargin());
0178     return size;
0179 }
0180 
0181 QSize KBlockLayout::minimumSize() const
0182 {
0183     QSize size;
0184     for (QLayoutItem *item : std::as_const(d->itemList)) {
0185         size = size.expandedTo(item->minimumSize());
0186     }
0187 
0188     size += QSize(2 * getMargin(), 2 * getMargin());
0189     return size;
0190 }
0191 
0192 struct Row {
0193     Row(const QList<QLayoutItem *> &i, int h, int w)
0194         : items(i)
0195         , height(h)
0196         , width(w)
0197     {
0198     }
0199 
0200     QList<QLayoutItem *> items;
0201     int height;
0202     int width;
0203 };
0204 
0205 int KBlockLayout::doLayout(const QRect &rect, bool testOnly) const
0206 {
0207     int x = rect.x();
0208     int y = rect.y();
0209     int lineHeight = 0;
0210 
0211     // 1. calculate lines
0212     QList<Row> rows;
0213     QList<QLayoutItem *> rowItems;
0214     for (int i = 0; i < d->itemList.count(); ++i) {
0215         QLayoutItem *item = d->itemList[i];
0216         int nextX = x + item->sizeHint().width() + horizontalSpacing();
0217         if (nextX - horizontalSpacing() > rect.right() && lineHeight > 0) {
0218             rows.append(Row(rowItems, lineHeight, x - horizontalSpacing()));
0219             rowItems.clear();
0220 
0221             x = rect.x();
0222             y = y + lineHeight + verticalSpacing();
0223             nextX = x + item->sizeHint().width() + horizontalSpacing();
0224             lineHeight = 0;
0225         }
0226 
0227         rowItems.append(item);
0228 
0229         x = nextX;
0230         lineHeight = qMax(lineHeight, item->sizeHint().height());
0231     }
0232     // append the last row
0233     rows.append(Row(rowItems, lineHeight, x - horizontalSpacing()));
0234 
0235     int finalHeight = y + lineHeight - rect.y();
0236     if (testOnly)
0237         return finalHeight;
0238 
0239     // 2. place the items
0240     y = rect.y();
0241     for (const Row &row : std::as_const(rows)) {
0242         x = rect.x();
0243         if (alignment() & Qt::AlignRight)
0244             x += (rect.width() - row.width);
0245         else if (alignment() & Qt::AlignHCenter)
0246             x += (rect.width() - row.width) / 2;
0247 
0248         for (QLayoutItem *item : std::as_const(row.items)) {
0249             int yy = y;
0250             if (alignment() & Qt::AlignBottom)
0251                 yy += (row.height - item->sizeHint().height());
0252             else if (alignment() & Qt::AlignVCenter)
0253                 yy += (row.height - item->sizeHint().height()) / 2;
0254             item->setGeometry(QRect(QPoint(x, yy), item->sizeHint()));
0255 
0256             x += item->sizeHint().width() + horizontalSpacing();
0257 
0258             if (alignment() & Qt::AlignJustify)
0259                 x += (rect.width() - row.width) / qMax(row.items.count() - 1, 1);
0260         }
0261 
0262         y = y + row.height + verticalSpacing();
0263     }
0264 
0265     return finalHeight;
0266 }