Warning, file /office/skrooge/skgbasegui/skgflowlayout.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: 2022 S. MANKOWSKI stephane@mankowski.fr
0003  * SPDX-FileCopyrightText: 2022 G. DE BURE support@mankowski.fr
0004  * SPDX-License-Identifier: GPL-3.0-or-later
0005  ***************************************************************************/
0006 /** @file
0007 * This file defines classes SKGFlowLayout.
0008 *
0009 * @author Stephane MANKOWSKI / Guillaume DE BURE
0010  */
0011 #include "skgflowlayout.h"
0012 #include "skgdefine.h"
0013 
0014 #include <qlayout.h>
0015 #include <qwidget.h>
0016 
0017 SKGFlowLayout::SKGFlowLayout(QWidget* iParent, int iMargin, int hSpacing, int vSpacing)
0018     : QLayout(iParent), m_hSpace(hSpacing), m_vSpace(vSpacing)
0019 {
0020     setContentsMargins(iMargin, iMargin, iMargin, iMargin);
0021 }
0022 
0023 SKGFlowLayout::SKGFlowLayout(int iMargin, int hSpacing, int vSpacing)
0024     :  m_hSpace(hSpacing), m_vSpace(vSpacing)
0025 {
0026     setContentsMargins(iMargin, iMargin, iMargin, iMargin);
0027 }
0028 
0029 SKGFlowLayout::~SKGFlowLayout()
0030 {
0031     while (count() != 0) {
0032         QLayoutItem* child = takeAt(0);
0033         if (child != nullptr) {
0034             QWidget* w = child->widget();
0035             delete w;
0036             delete child;
0037         }
0038     }
0039 }
0040 
0041 void SKGFlowLayout::addItem(QLayoutItem* item)
0042 {
0043     m_itemList.append(item);
0044 }
0045 
0046 void SKGFlowLayout::setSpacing(int space)
0047 {
0048     m_hSpace = space;
0049     m_vSpace = space;
0050 }
0051 
0052 int SKGFlowLayout::horizontalSpacing() const
0053 {
0054     if (m_hSpace >= 0) {
0055         return m_hSpace;
0056     }
0057     return smartSpacing(QStyle::PM_LayoutHorizontalSpacing);
0058 }
0059 
0060 int SKGFlowLayout::verticalSpacing() const
0061 {
0062     if (m_vSpace >= 0) {
0063         return m_vSpace;
0064     }
0065     return smartSpacing(QStyle::PM_LayoutVerticalSpacing);
0066 }
0067 
0068 int SKGFlowLayout::count() const
0069 {
0070     return m_itemList.size();
0071 }
0072 
0073 QLayoutItem* SKGFlowLayout::itemAt(int index) const
0074 {
0075     return m_itemList.value(index);
0076 }
0077 
0078 QLayoutItem* SKGFlowLayout::takeAt(int index)
0079 {
0080     if (index >= 0 && index < m_itemList.size()) {
0081         return m_itemList.takeAt(index);
0082     }
0083     return nullptr;
0084 }
0085 
0086 Qt::Orientations SKGFlowLayout::expandingDirections() const
0087 {
0088     return Qt::Orientations();
0089 }
0090 
0091 bool SKGFlowLayout::hasHeightForWidth() const
0092 {
0093     return true;
0094 }
0095 
0096 int SKGFlowLayout::heightForWidth(int width) const
0097 {
0098     int height = doLayout(QRect(0, 0, width, 0), true);
0099     return height;
0100 }
0101 
0102 void SKGFlowLayout::setGeometry(const QRect& rect)  // clazy:exclude=function-args-by-value
0103 {
0104     QLayout::setGeometry(rect);
0105     doLayout(rect, false);
0106 }
0107 
0108 QSize SKGFlowLayout::sizeHint() const
0109 {
0110     return minimumSize();
0111 }
0112 
0113 QSize SKGFlowLayout::minimumSize() const
0114 {
0115     QSize size;
0116     for (auto item : qAsConst(m_itemList)) {
0117         size = size.expandedTo(item->minimumSize());
0118     }
0119 
0120     size += QSize(2 * margin(), 2 * margin());
0121     return size;
0122 }
0123 
0124 int SKGFlowLayout::doLayout(const QRect rect, bool testOnly) const
0125 {
0126     int left, top, right, bottom;
0127     getContentsMargins(&left, &top, &right, &bottom);
0128     QRect effectiveRect = rect.adjusted(+left, +top, -right, -bottom);
0129     int x = effectiveRect.x();
0130     int y = effectiveRect.y();
0131     int lineHeight = 0;
0132     int x1 = x;
0133     int y1 = y;
0134 
0135     for (auto item : qAsConst(m_itemList)) {
0136         QWidget* wid = item->widget();
0137         if (wid != nullptr) {
0138             // Get spaces
0139             int spaceX = horizontalSpacing();
0140             if (spaceX == -1) {
0141                 spaceX = wid->style()->layoutSpacing(QSizePolicy::PushButton, QSizePolicy::PushButton, Qt::Horizontal);
0142             }
0143 
0144             int spaceY = verticalSpacing();
0145             if (spaceY == -1) {
0146                 spaceY = wid->style()->layoutSpacing(QSizePolicy::PushButton, QSizePolicy::PushButton, Qt::Vertical);
0147             }
0148 
0149             // Try option
0150             bool optionUsed = false;
0151             if ((lineHeight != 0) && (x1 != 0)) {
0152                 int nextX = x1 + item->sizeHint().width() + spaceX;
0153                 if (nextX <= x && y1 - y + item->sizeHint().height() <= lineHeight) {
0154                     optionUsed = true;
0155 
0156                     // Position item
0157                     if (!testOnly) {
0158                         item->setGeometry(QRect(QPoint(x1, y1), item->sizeHint()));
0159                     }
0160 
0161                     x1 = nextX;
0162                 }
0163             }
0164 
0165             if (!optionUsed) {
0166                 int nextX = x + item->sizeHint().width() + spaceX;
0167                 if (nextX - spaceX > effectiveRect.right() && lineHeight > 0) {
0168                     x = effectiveRect.x();
0169                     y = y + lineHeight + spaceY;
0170                     nextX = x + item->sizeHint().width() + spaceX;
0171                     lineHeight = 0;
0172                 }
0173 
0174                 // Position item
0175                 if (!testOnly) {
0176                     item->setGeometry(QRect(QPoint(x, y), item->sizeHint()));
0177                 }
0178 
0179                 x1 = x;
0180                 y1 = y + item->sizeHint().height() + spaceY;
0181                 x = nextX;
0182                 lineHeight = qMax(lineHeight, item->sizeHint().height());
0183             }
0184         }
0185     }
0186     return y + lineHeight - rect.y() + bottom;
0187 }
0188 
0189 int SKGFlowLayout::smartSpacing(QStyle::PixelMetric pm) const
0190 {
0191     QObject* p = this->parent();
0192     if (p == nullptr) {
0193         return -1;
0194     }
0195     if (p->isWidgetType()) {
0196         auto* pw = qobject_cast<QWidget*>(p);
0197         return pw->style()->pixelMetric(pm, nullptr, pw);
0198     }
0199     return qobject_cast<QLayout*>(p)->spacing();
0200 }