File indexing completed on 2024-05-12 05:37:12

0001 /*
0002     SPDX-FileCopyrightText: 2019 Marco Martin <mart@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "abstractlayoutmanager.h"
0008 #include "itemcontainer.h"
0009 
0010 #include <cmath>
0011 
0012 AbstractLayoutManager::AbstractLayoutManager(AppletsLayout *layout)
0013     : QObject(layout)
0014     , m_layout(layout)
0015 {
0016 }
0017 
0018 AbstractLayoutManager::~AbstractLayoutManager()
0019 {
0020 }
0021 
0022 AppletsLayout *AbstractLayoutManager::layout() const
0023 {
0024     return m_layout;
0025 }
0026 
0027 QSizeF AbstractLayoutManager::cellSize() const
0028 {
0029     return m_cellSize;
0030 }
0031 
0032 QSizeF AbstractLayoutManager::cellAlignedContainingSize(const QSizeF &size) const
0033 {
0034     return QSizeF(m_cellSize.width() * ceil(size.width() / m_cellSize.width()), m_cellSize.height() * ceil(size.height() / m_cellSize.height()));
0035 }
0036 
0037 void AbstractLayoutManager::setCellSize(const QSizeF &size)
0038 {
0039     m_cellSize = size;
0040 }
0041 
0042 QRectF AbstractLayoutManager::candidateGeometry(ItemContainer *item) const
0043 {
0044     const QRectF originalItemRect = QRectF(item->x(), item->y(), item->width(), item->height());
0045 
0046     // TODO: a default minimum size
0047     QSizeF minimumSize = QSize(m_layout->minimumItemWidth(), m_layout->minimumItemHeight());
0048     if (item->layoutAttached()) {
0049         minimumSize = QSizeF(qMax(minimumSize.width(), item->layoutAttached()->property("minimumWidth").toReal()),
0050                              qMax(minimumSize.height(), item->layoutAttached()->property("minimumHeight").toReal()));
0051     }
0052 
0053     const QRectF ltrRect = nextAvailableSpace(item, minimumSize, AppletsLayout::LeftToRight);
0054     const QRectF rtlRect = nextAvailableSpace(item, minimumSize, AppletsLayout::RightToLeft);
0055     const QRectF ttbRect = nextAvailableSpace(item, minimumSize, AppletsLayout::TopToBottom);
0056     const QRectF bttRect = nextAvailableSpace(item, minimumSize, AppletsLayout::BottomToTop);
0057 
0058     // Take the closest rect, unless the item prefers a particular positioning strategy
0059     QMap<int, QRectF> distances;
0060     if (!ltrRect.isEmpty()) {
0061         const int dist =
0062             item->preferredLayoutDirection() == AppletsLayout::LeftToRight ? 0 : QPointF(originalItemRect.center() - ltrRect.center()).manhattanLength();
0063         distances[dist] = ltrRect;
0064     }
0065     if (!rtlRect.isEmpty()) {
0066         const int dist =
0067             item->preferredLayoutDirection() == AppletsLayout::RightToLeft ? 0 : QPointF(originalItemRect.center() - rtlRect.center()).manhattanLength();
0068         distances[dist] = rtlRect;
0069     }
0070     if (!ttbRect.isEmpty()) {
0071         const int dist =
0072             item->preferredLayoutDirection() == AppletsLayout::TopToBottom ? 0 : QPointF(originalItemRect.center() - ttbRect.center()).manhattanLength();
0073         distances[dist] = ttbRect;
0074     }
0075     if (!bttRect.isEmpty()) {
0076         const int dist =
0077             item->preferredLayoutDirection() == AppletsLayout::BottomToTop ? 0 : QPointF(originalItemRect.center() - bttRect.center()).manhattanLength();
0078         distances[dist] = bttRect;
0079     }
0080 
0081     if (distances.isEmpty()) {
0082         // Failure to layout, completely full
0083         return originalItemRect;
0084     } else {
0085         return distances.first();
0086     }
0087 }
0088 
0089 void AbstractLayoutManager::positionItem(ItemContainer *item)
0090 {
0091     // Give it a sane size if uninitialized: this may change size hints
0092     if (item->width() <= 0 || item->height() <= 0) {
0093         item->setSize(QSizeF(qMax(m_layout->minimumItemWidth(), m_layout->defaultItemWidth()), //
0094                              qMax(m_layout->minimumItemHeight(), m_layout->defaultItemHeight())));
0095     }
0096 
0097     QRectF candidate = candidateGeometry(item);
0098     // Use setProperty to allow Behavior on to take effect
0099     item->setProperty("x", candidate.topLeft().x());
0100     item->setProperty("y", candidate.topLeft().y());
0101     item->setSize(candidate.size());
0102 }
0103 
0104 void AbstractLayoutManager::positionItemAndAssign(ItemContainer *item)
0105 {
0106     releaseSpace(item);
0107     positionItem(item);
0108     assignSpace(item);
0109 }
0110 
0111 bool AbstractLayoutManager::assignSpace(ItemContainer *item)
0112 {
0113     if (assignSpaceImpl(item)) {
0114         Q_EMIT layoutNeedsSaving();
0115         return true;
0116     } else {
0117         return false;
0118     }
0119 }
0120 
0121 void AbstractLayoutManager::releaseSpace(ItemContainer *item)
0122 {
0123     releaseSpaceImpl(item);
0124     Q_EMIT layoutNeedsSaving();
0125 }
0126 
0127 void AbstractLayoutManager::layoutGeometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
0128 {
0129     Q_UNUSED(newGeometry);
0130     Q_UNUSED(oldGeometry);
0131     // NOTE: Empty base implementation, don't put anything here
0132 }
0133 
0134 #include "moc_abstractlayoutmanager.cpp"