forked from Qortal/Brooklyn
553 lines
19 KiB
C++
553 lines
19 KiB
C++
|
/*
|
||
|
SPDX-FileCopyrightText: 2019 Marco Martin <mart@kde.org>
|
||
|
|
||
|
SPDX-License-Identifier: LGPL-2.0-or-later
|
||
|
*/
|
||
|
|
||
|
#include "gridlayoutmanager.h"
|
||
|
#include "appletslayout.h"
|
||
|
#include "containmentlayoutmanager_debug.h"
|
||
|
|
||
|
#include <cmath>
|
||
|
|
||
|
GridLayoutManager::GridLayoutManager(AppletsLayout *layout)
|
||
|
: AbstractLayoutManager(layout)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
GridLayoutManager::~GridLayoutManager()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
QString GridLayoutManager::serializeLayout() const
|
||
|
{
|
||
|
QString result;
|
||
|
|
||
|
for (auto *item : layout()->childItems()) {
|
||
|
ItemContainer *itemCont = qobject_cast<ItemContainer *>(item);
|
||
|
if (itemCont && itemCont != layout()->placeHolder()) {
|
||
|
result += itemCont->key() + QLatin1Char(':') + QString::number(itemCont->x()) + QLatin1Char(',') + QString::number(itemCont->y()) + QLatin1Char(',')
|
||
|
+ QString::number(itemCont->width()) + QLatin1Char(',') + QString::number(itemCont->height()) + QLatin1Char(',')
|
||
|
+ QString::number(itemCont->rotation()) + QLatin1Char(';');
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
void GridLayoutManager::parseLayout(const QString &savedLayout)
|
||
|
{
|
||
|
m_parsedConfig.clear();
|
||
|
const QStringList itemsConfigs = savedLayout.split(QLatin1Char(';'));
|
||
|
|
||
|
for (const auto &itemString : itemsConfigs) {
|
||
|
QStringList itemConfig = itemString.split(QLatin1Char(':'));
|
||
|
if (itemConfig.count() != 2) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
QString id = itemConfig[0];
|
||
|
QStringList itemGeom = itemConfig[1].split(QLatin1Char(','));
|
||
|
if (itemGeom.count() != 5) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
m_parsedConfig[id] = {itemGeom[0].toDouble(), itemGeom[1].toDouble(), itemGeom[2].toDouble(), itemGeom[3].toDouble(), itemGeom[4].toDouble()};
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool GridLayoutManager::itemIsManaged(ItemContainer *item)
|
||
|
{
|
||
|
return m_pointsForItem.contains(item);
|
||
|
}
|
||
|
|
||
|
inline void maintainItemEdgeAlignment(ItemContainer *item, const QRectF &newRect, const QRectF &oldRect)
|
||
|
{
|
||
|
const qreal leftDist = item->x() - oldRect.x();
|
||
|
const qreal hCenterDist = item->x() + item->width() / 2 - oldRect.center().x();
|
||
|
const qreal rightDist = oldRect.right() - item->x() - item->width();
|
||
|
|
||
|
qreal hMin = qMin(qMin(qAbs(leftDist), qAbs(hCenterDist)), qAbs(rightDist));
|
||
|
if (qFuzzyCompare(hMin, qAbs(leftDist))) {
|
||
|
// Right alignment, do nothing
|
||
|
} else if (qFuzzyCompare(hMin, qAbs(hCenterDist))) {
|
||
|
item->setX(newRect.center().x() - item->width() / 2 + hCenterDist);
|
||
|
} else if (qFuzzyCompare(hMin, qAbs(rightDist))) {
|
||
|
item->setX(newRect.right() - item->width() - rightDist);
|
||
|
}
|
||
|
|
||
|
const qreal topDist = item->y() - oldRect.y();
|
||
|
const qreal vCenterDist = item->y() + item->height() / 2 - oldRect.center().y();
|
||
|
const qreal bottomDist = oldRect.bottom() - item->y() - item->height();
|
||
|
|
||
|
qreal vMin = qMin(qMin(qAbs(topDist), qAbs(vCenterDist)), qAbs(bottomDist));
|
||
|
|
||
|
if (qFuzzyCompare(vMin, qAbs(topDist))) {
|
||
|
// Top alignment, do nothing
|
||
|
} else if (qFuzzyCompare(vMin, qAbs(vCenterDist))) {
|
||
|
item->setY(newRect.center().y() - item->height() / 2 + vCenterDist);
|
||
|
} else if (qFuzzyCompare(vMin, qAbs(bottomDist))) {
|
||
|
item->setY(newRect.bottom() - item->height() - bottomDist);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void GridLayoutManager::layoutGeometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
|
||
|
{
|
||
|
m_grid.clear();
|
||
|
m_pointsForItem.clear();
|
||
|
for (auto *item : layout()->childItems()) {
|
||
|
// Stash the old config
|
||
|
// m_parsedConfig[item->key()] = {item->x(), item->y(), item->width(), item->height(), item->rotation()};
|
||
|
// Move the item to maintain the distance with the anchors point
|
||
|
auto *itemCont = qobject_cast<ItemContainer *>(item);
|
||
|
if (itemCont && itemCont != layout()->placeHolder()) {
|
||
|
maintainItemEdgeAlignment(itemCont, newGeometry, oldGeometry);
|
||
|
// NOTE: do not use positionItemAndAssign here, because we do not want to Q_EMIT layoutNeedsSaving, to not save after resize
|
||
|
positionItem(itemCont);
|
||
|
assignSpaceImpl(itemCont);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void GridLayoutManager::resetLayout()
|
||
|
{
|
||
|
m_grid.clear();
|
||
|
m_pointsForItem.clear();
|
||
|
for (auto *item : layout()->childItems()) {
|
||
|
ItemContainer *itemCont = qobject_cast<ItemContainer *>(item);
|
||
|
if (itemCont && itemCont != layout()->placeHolder()) {
|
||
|
// NOTE: do not use positionItemAndAssign here, because we do not want to Q_EMIT layoutNeedsSaving, to not save after resize
|
||
|
positionItem(itemCont);
|
||
|
assignSpaceImpl(itemCont);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void GridLayoutManager::resetLayoutFromConfig()
|
||
|
{
|
||
|
m_grid.clear();
|
||
|
m_pointsForItem.clear();
|
||
|
QList<ItemContainer *> missingItems;
|
||
|
|
||
|
for (auto *item : layout()->childItems()) {
|
||
|
ItemContainer *itemCont = qobject_cast<ItemContainer *>(item);
|
||
|
if (itemCont && itemCont != layout()->placeHolder()) {
|
||
|
if (!restoreItem(itemCont)) {
|
||
|
missingItems << itemCont;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
for (auto *item : qAsConst(missingItems)) {
|
||
|
// NOTE: do not use positionItemAndAssign here, because we do not want to Q_EMIT layoutNeedsSaving, to not save after resize
|
||
|
positionItem(item);
|
||
|
assignSpaceImpl(item);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool GridLayoutManager::restoreItem(ItemContainer *item)
|
||
|
{
|
||
|
auto it = m_parsedConfig.find(item->key());
|
||
|
|
||
|
if (it != m_parsedConfig.end()) {
|
||
|
// Actual restore
|
||
|
item->setPosition(QPointF(it.value().x, it.value().y));
|
||
|
item->setSize(QSizeF(it.value().width, it.value().height));
|
||
|
item->setRotation(it.value().rotation);
|
||
|
|
||
|
// NOTE: do not use positionItemAndAssign here, because we do not want to Q_EMIT layoutNeedsSaving, to not save after resize
|
||
|
// If size is empty the layout is not in a valid state and probably startup is not completed yet
|
||
|
if (!layout()->size().isEmpty()) {
|
||
|
releaseSpaceImpl(item);
|
||
|
positionItem(item);
|
||
|
assignSpaceImpl(item);
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
bool GridLayoutManager::isRectAvailable(const QRectF &rect)
|
||
|
{
|
||
|
// TODO: define directions in which it can grow
|
||
|
if (rect.x() < 0 || rect.y() < 0 || rect.x() + rect.width() > layout()->width() || rect.y() + rect.height() > layout()->height()) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
const QRect cellItemGeom = cellBasedGeometry(rect);
|
||
|
|
||
|
for (int row = cellItemGeom.top(); row <= cellItemGeom.bottom(); ++row) {
|
||
|
for (int column = cellItemGeom.left(); column <= cellItemGeom.right(); ++column) {
|
||
|
if (!isCellAvailable(QPair<int, int>(row, column))) {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool GridLayoutManager::assignSpaceImpl(ItemContainer *item)
|
||
|
{
|
||
|
// Don't Q_EMIT extra layoutneedssaving signals
|
||
|
releaseSpaceImpl(item);
|
||
|
if (!isRectAvailable(itemGeometry(item))) {
|
||
|
qCWarning(CONTAINMENTLAYOUTMANAGER_DEBUG) << "Trying to take space not available" << item;
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
const QRect cellItemGeom = cellBasedGeometry(itemGeometry(item));
|
||
|
|
||
|
for (int row = cellItemGeom.top(); row <= cellItemGeom.bottom(); ++row) {
|
||
|
for (int column = cellItemGeom.left(); column <= cellItemGeom.right(); ++column) {
|
||
|
QPair<int, int> cell(row, column);
|
||
|
m_grid.insert(cell, item);
|
||
|
m_pointsForItem[item].insert(cell);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Reorder items tab order
|
||
|
for (auto *i2 : layout()->childItems()) {
|
||
|
ItemContainer *item2 = qobject_cast<ItemContainer *>(i2);
|
||
|
if (item2 && item2->parentItem() == item->parentItem() && item != item2 && item2 != layout()->placeHolder() && item->y() < item2->y() + item2->height()
|
||
|
&& item->x() <= item2->x()) {
|
||
|
item->stackBefore(item2);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (item->layoutAttached()) {
|
||
|
connect(item, &ItemContainer::sizeHintsChanged, this, [this, item]() {
|
||
|
adjustToItemSizeHints(item);
|
||
|
});
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
void GridLayoutManager::releaseSpaceImpl(ItemContainer *item)
|
||
|
{
|
||
|
auto it = m_pointsForItem.find(item);
|
||
|
|
||
|
if (it == m_pointsForItem.end()) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
for (const auto &point : it.value()) {
|
||
|
m_grid.remove(point);
|
||
|
}
|
||
|
|
||
|
m_pointsForItem.erase(it);
|
||
|
|
||
|
disconnect(item, &ItemContainer::sizeHintsChanged, this, nullptr);
|
||
|
}
|
||
|
|
||
|
int GridLayoutManager::rows() const
|
||
|
{
|
||
|
return layout()->height() / cellSize().height();
|
||
|
}
|
||
|
|
||
|
int GridLayoutManager::columns() const
|
||
|
{
|
||
|
return layout()->width() / cellSize().width();
|
||
|
}
|
||
|
|
||
|
void GridLayoutManager::adjustToItemSizeHints(ItemContainer *item)
|
||
|
{
|
||
|
if (!item->layoutAttached() || item->editMode()) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
bool changed = false;
|
||
|
|
||
|
// Minimum
|
||
|
const qreal newMinimumHeight = item->layoutAttached()->property("minimumHeight").toReal();
|
||
|
const qreal newMinimumWidth = item->layoutAttached()->property("minimumWidth").toReal();
|
||
|
|
||
|
if (newMinimumHeight > item->height()) {
|
||
|
item->setHeight(newMinimumHeight);
|
||
|
changed = true;
|
||
|
}
|
||
|
if (newMinimumWidth > item->width()) {
|
||
|
item->setWidth(newMinimumWidth);
|
||
|
changed = true;
|
||
|
}
|
||
|
|
||
|
// Preferred
|
||
|
const qreal newPreferredHeight = item->layoutAttached()->property("preferredHeight").toReal();
|
||
|
const qreal newPreferredWidth = item->layoutAttached()->property("preferredWidth").toReal();
|
||
|
|
||
|
if (newPreferredHeight > item->height()) {
|
||
|
item->setHeight(layout()->cellHeight() * ceil(newPreferredHeight / layout()->cellHeight()));
|
||
|
changed = true;
|
||
|
}
|
||
|
if (newPreferredWidth > item->width()) {
|
||
|
item->setWidth(layout()->cellWidth() * ceil(newPreferredWidth / layout()->cellWidth()));
|
||
|
changed = true;
|
||
|
}
|
||
|
|
||
|
/*// Maximum : IGNORE?
|
||
|
const qreal newMaximumHeight = item->layoutAttached()->property("preferredHeight").toReal();
|
||
|
const qreal newMaximumWidth = item->layoutAttached()->property("preferredWidth").toReal();
|
||
|
|
||
|
if (newMaximumHeight > 0 && newMaximumHeight < height()) {
|
||
|
item->setHeight(newMaximumHeight);
|
||
|
changed = true;
|
||
|
}
|
||
|
if (newMaximumHeight > 0 && newMaximumWidth < width()) {
|
||
|
item->setWidth(newMaximumWidth);
|
||
|
changed = true;
|
||
|
}*/
|
||
|
|
||
|
// Relayout if anything changed
|
||
|
if (changed && itemIsManaged(item)) {
|
||
|
releaseSpace(item);
|
||
|
positionItem(item);
|
||
|
assignSpace(item);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
QRect GridLayoutManager::cellBasedGeometry(const QRectF &geom) const
|
||
|
{
|
||
|
return QRect(round(qBound(0.0, geom.x(), layout()->width() - geom.width()) / cellSize().width()),
|
||
|
round(qBound(0.0, geom.y(), layout()->height() - geom.height()) / cellSize().height()),
|
||
|
round((qreal)geom.width() / cellSize().width()),
|
||
|
round((qreal)geom.height() / cellSize().height()));
|
||
|
}
|
||
|
|
||
|
QRect GridLayoutManager::cellBasedBoundingGeometry(const QRectF &geom) const
|
||
|
{
|
||
|
return QRect(floor(qBound(0.0, geom.x(), layout()->width() - geom.width()) / cellSize().width()),
|
||
|
floor(qBound(0.0, geom.y(), layout()->height() - geom.height()) / cellSize().height()),
|
||
|
ceil((qreal)geom.width() / cellSize().width()),
|
||
|
ceil((qreal)geom.height() / cellSize().height()));
|
||
|
}
|
||
|
|
||
|
bool GridLayoutManager::isOutOfBounds(const QPair<int, int> &cell) const
|
||
|
{
|
||
|
return cell.first < 0 || cell.second < 0 || cell.first >= rows() || cell.second >= columns();
|
||
|
}
|
||
|
|
||
|
bool GridLayoutManager::isCellAvailable(const QPair<int, int> &cell) const
|
||
|
{
|
||
|
return !isOutOfBounds(cell) && !m_grid.contains(cell);
|
||
|
}
|
||
|
|
||
|
QRectF GridLayoutManager::itemGeometry(QQuickItem *item) const
|
||
|
{
|
||
|
return QRectF(item->x(), item->y(), item->width(), item->height());
|
||
|
}
|
||
|
|
||
|
QPair<int, int> GridLayoutManager::nextCell(const QPair<int, int> &cell, AppletsLayout::PreferredLayoutDirection direction) const
|
||
|
{
|
||
|
QPair<int, int> nCell = cell;
|
||
|
|
||
|
switch (direction) {
|
||
|
case AppletsLayout::AppletsLayout::BottomToTop:
|
||
|
--nCell.first;
|
||
|
break;
|
||
|
case AppletsLayout::AppletsLayout::TopToBottom:
|
||
|
++nCell.first;
|
||
|
break;
|
||
|
case AppletsLayout::AppletsLayout::RightToLeft:
|
||
|
--nCell.second;
|
||
|
break;
|
||
|
case AppletsLayout::AppletsLayout::LeftToRight:
|
||
|
default:
|
||
|
++nCell.second;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return nCell;
|
||
|
}
|
||
|
|
||
|
QPair<int, int> GridLayoutManager::nextAvailableCell(const QPair<int, int> &cell, AppletsLayout::PreferredLayoutDirection direction) const
|
||
|
{
|
||
|
QPair<int, int> nCell = cell;
|
||
|
while (!isOutOfBounds(nCell)) {
|
||
|
nCell = nextCell(nCell, direction);
|
||
|
|
||
|
if (isOutOfBounds(nCell)) {
|
||
|
switch (direction) {
|
||
|
case AppletsLayout::AppletsLayout::BottomToTop:
|
||
|
nCell.first = rows() - 1;
|
||
|
--nCell.second;
|
||
|
break;
|
||
|
case AppletsLayout::AppletsLayout::TopToBottom:
|
||
|
nCell.first = 0;
|
||
|
++nCell.second;
|
||
|
break;
|
||
|
case AppletsLayout::AppletsLayout::RightToLeft:
|
||
|
--nCell.first;
|
||
|
nCell.second = columns() - 1;
|
||
|
break;
|
||
|
case AppletsLayout::AppletsLayout::LeftToRight:
|
||
|
default:
|
||
|
++nCell.first;
|
||
|
nCell.second = 0;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (isCellAvailable(nCell)) {
|
||
|
return nCell;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return QPair<int, int>(-1, -1);
|
||
|
}
|
||
|
|
||
|
QPair<int, int> GridLayoutManager::nextTakenCell(const QPair<int, int> &cell, AppletsLayout::PreferredLayoutDirection direction) const
|
||
|
{
|
||
|
QPair<int, int> nCell = cell;
|
||
|
while (!isOutOfBounds(nCell)) {
|
||
|
nCell = nextCell(nCell, direction);
|
||
|
|
||
|
if (isOutOfBounds(nCell)) {
|
||
|
switch (direction) {
|
||
|
case AppletsLayout::AppletsLayout::BottomToTop:
|
||
|
nCell.first = rows() - 1;
|
||
|
--nCell.second;
|
||
|
break;
|
||
|
case AppletsLayout::AppletsLayout::TopToBottom:
|
||
|
nCell.first = 0;
|
||
|
++nCell.second;
|
||
|
break;
|
||
|
case AppletsLayout::AppletsLayout::RightToLeft:
|
||
|
--nCell.first;
|
||
|
nCell.second = columns() - 1;
|
||
|
break;
|
||
|
case AppletsLayout::AppletsLayout::LeftToRight:
|
||
|
default:
|
||
|
++nCell.first;
|
||
|
nCell.second = 0;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!isCellAvailable(nCell)) {
|
||
|
return nCell;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return QPair<int, int>(-1, -1);
|
||
|
}
|
||
|
|
||
|
int GridLayoutManager::freeSpaceInDirection(const QPair<int, int> &cell, AppletsLayout::PreferredLayoutDirection direction) const
|
||
|
{
|
||
|
QPair<int, int> nCell = cell;
|
||
|
|
||
|
int avail = 0;
|
||
|
|
||
|
while (isCellAvailable(nCell)) {
|
||
|
++avail;
|
||
|
nCell = nextCell(nCell, direction);
|
||
|
}
|
||
|
|
||
|
return avail;
|
||
|
}
|
||
|
|
||
|
QRectF GridLayoutManager::nextAvailableSpace(ItemContainer *item, const QSizeF &minimumSize, AppletsLayout::PreferredLayoutDirection direction) const
|
||
|
{
|
||
|
// The mionimum size in grid units
|
||
|
const QSize minimumGridSize(ceil((qreal)minimumSize.width() / cellSize().width()), ceil((qreal)minimumSize.height() / cellSize().height()));
|
||
|
|
||
|
QRect itemCellGeom = cellBasedGeometry(itemGeometry(item));
|
||
|
itemCellGeom.setWidth(qMax(itemCellGeom.width(), minimumGridSize.width()));
|
||
|
itemCellGeom.setHeight(qMax(itemCellGeom.height(), minimumGridSize.height()));
|
||
|
|
||
|
QSize partialSize;
|
||
|
|
||
|
QPair<int, int> cell(itemCellGeom.y(), itemCellGeom.x());
|
||
|
if (direction == AppletsLayout::AppletsLayout::RightToLeft) {
|
||
|
cell.second += itemCellGeom.width();
|
||
|
} else if (direction == AppletsLayout::AppletsLayout::BottomToTop) {
|
||
|
cell.first += itemCellGeom.height();
|
||
|
}
|
||
|
|
||
|
if (!isCellAvailable(cell)) {
|
||
|
cell = nextAvailableCell(cell, direction);
|
||
|
}
|
||
|
|
||
|
while (!isOutOfBounds(cell)) {
|
||
|
if (direction == AppletsLayout::LeftToRight || direction == AppletsLayout::RightToLeft) {
|
||
|
partialSize = QSize(INT_MAX, 0);
|
||
|
|
||
|
int currentRow = cell.first;
|
||
|
for (; currentRow < cell.first + itemCellGeom.height(); ++currentRow) {
|
||
|
const int freeRow = freeSpaceInDirection(QPair<int, int>(currentRow, cell.second), direction);
|
||
|
|
||
|
partialSize.setWidth(qMin(partialSize.width(), freeRow));
|
||
|
|
||
|
if (freeRow > 0) {
|
||
|
partialSize.setHeight(partialSize.height() + 1);
|
||
|
} else if (partialSize.height() < minimumGridSize.height()) {
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (partialSize.width() >= itemCellGeom.width() && partialSize.height() >= itemCellGeom.height()) {
|
||
|
break;
|
||
|
} else if (partialSize.width() < minimumGridSize.width()) {
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (partialSize.width() >= minimumGridSize.width() && partialSize.height() >= minimumGridSize.height()) {
|
||
|
const int width = qMin(itemCellGeom.width(), partialSize.width()) * cellSize().width();
|
||
|
const int height = qMin(itemCellGeom.height(), partialSize.height()) * cellSize().height();
|
||
|
|
||
|
if (direction == AppletsLayout::RightToLeft) {
|
||
|
return QRectF((cell.second + 1) * cellSize().width() - width, cell.first * cellSize().height(), width, height);
|
||
|
// AppletsLayout::LeftToRight
|
||
|
} else {
|
||
|
return QRectF(cell.second * cellSize().width(), cell.first * cellSize().height(), width, height);
|
||
|
}
|
||
|
} else {
|
||
|
cell = nextAvailableCell(nextTakenCell(cell, direction), direction);
|
||
|
}
|
||
|
|
||
|
} else if (direction == AppletsLayout::TopToBottom || direction == AppletsLayout::BottomToTop) {
|
||
|
partialSize = QSize(0, INT_MAX);
|
||
|
|
||
|
int currentColumn = cell.second;
|
||
|
for (; currentColumn < cell.second + itemCellGeom.width(); ++currentColumn) {
|
||
|
const int freeColumn = freeSpaceInDirection(QPair<int, int>(cell.first, currentColumn), direction);
|
||
|
|
||
|
partialSize.setHeight(qMin(partialSize.height(), freeColumn));
|
||
|
|
||
|
if (freeColumn > 0) {
|
||
|
partialSize.setWidth(partialSize.width() + 1);
|
||
|
} else if (partialSize.width() < minimumGridSize.width()) {
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (partialSize.width() >= itemCellGeom.width() && partialSize.height() >= itemCellGeom.height()) {
|
||
|
break;
|
||
|
} else if (partialSize.height() < minimumGridSize.height()) {
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (partialSize.width() >= minimumGridSize.width() && partialSize.height() >= minimumGridSize.height()) {
|
||
|
const int width = qMin(itemCellGeom.width(), partialSize.width()) * cellSize().width();
|
||
|
const int height = qMin(itemCellGeom.height(), partialSize.height()) * cellSize().height();
|
||
|
|
||
|
if (direction == AppletsLayout::BottomToTop) {
|
||
|
return QRectF(cell.second * cellSize().width(), (cell.first + 1) * cellSize().height() - height, width, height);
|
||
|
// AppletsLayout::TopToBottom:
|
||
|
} else {
|
||
|
return QRectF(cell.second * cellSize().width(), cell.first * cellSize().height(), width, height);
|
||
|
}
|
||
|
} else {
|
||
|
cell = nextAvailableCell(nextTakenCell(cell, direction), direction);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// We didn't manage to find layout space, return invalid geometry
|
||
|
return QRectF();
|
||
|
}
|
||
|
|
||
|
#include "moc_gridlayoutmanager.cpp"
|