diff --git a/CMakeLists.txt b/CMakeLists.txt index b4a84aecf..797c6da79 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,197 +1,198 @@ cmake_minimum_required(VERSION 3.0) project(plasma-workspace) + set(PROJECT_VERSION "5.17.80") set(PROJECT_VERSION_MAJOR 5) set(QT_MIN_VERSION "5.12.0") set(KF5_MIN_VERSION "5.62.0") set(INSTALL_SDDM_THEME TRUE) find_package(Qt5 ${QT_MIN_VERSION} CONFIG REQUIRED COMPONENTS Widgets Quick QuickWidgets Concurrent Test Network) find_package(ECM ${KF5_MIN_VERSION} REQUIRED NO_MODULE) set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH}) include(KDEInstallDirs) include(KDECMakeSettings) include(KDECompilerSettings NO_POLICY_SCOPE) include(ECMMarkNonGuiExecutable) include(CMakePackageConfigHelpers) include(WriteBasicConfigVersionFile) include(CheckIncludeFiles) include(FeatureSummary) include(ECMOptionalAddSubdirectory) include(ECMQtDeclareLoggingCategory) include(KDEPackageAppTemplates) find_package(KF5 ${KF5_MIN_VERSION} REQUIRED COMPONENTS Plasma DocTools Runner NotifyConfig Su NewStuff Wallet IdleTime Declarative I18n KCMUtils TextWidgets KDELibs4Support Crash GlobalAccel DBusAddons Wayland CoreAddons People ActivitiesStats) find_package(KDED CONFIG REQUIRED) find_package(KF5NetworkManagerQt ${KF5_MIN_VERSION}) set_package_properties(KF5NetworkManagerQt PROPERTIES DESCRIPTION "Qt wrapper for NetworkManager API" TYPE OPTIONAL PURPOSE "Needed by geolocation data engine." ) find_package(KF5Kirigami2 ${KF5_MIN_VERSION} CONFIG) set_package_properties(KF5Kirigami2 PROPERTIES DESCRIPTION "A QtQuick based components set" TYPE RUNTIME ) # WARNING PlasmaQuick provides unversioned CMake config find_package(KUserFeedback) find_package(KF5 REQUIRED COMPONENTS PlasmaQuick) find_package(KF5 REQUIRED COMPONENTS SysGuard) find_package(KF5 REQUIRED COMPONENTS Package) find_package(KF5Baloo) set_package_properties(KF5Baloo PROPERTIES DESCRIPTION "File Searching" TYPE RECOMMENDED PURPOSE "Needed for the File Search runner." ) find_package(KF5TextEditor) find_package(KWinDBusInterface CONFIG REQUIRED) find_package(KF5Screen CONFIG REQUIRED) find_package(KScreenLocker 5.13.80 REQUIRED) find_package(ScreenSaverDBusInterface CONFIG REQUIRED) find_package(KF5Holidays) set_package_properties(KF5Holidays PROPERTIES DESCRIPTION "Holidays provider for Plasma calendar" TYPE OPTIONAL PURPOSE "Needed to for holidays plugin for Plasma Calendar." ) find_package(Phonon4Qt5 4.6.60 REQUIRED NO_MODULE) set_package_properties(Phonon4Qt5 PROPERTIES DESCRIPTION "Qt-based audio library" TYPE REQUIRED) find_package(KF5Activities ${KF5_MIN_VERSION}) set_package_properties(KF5Activities PROPERTIES DESCRIPTION "management of Plasma activities" TYPE OPTIONAL PURPOSE "Needed by activity related plasmoids." ) find_package(ZLIB) set_package_properties(ZLIB PROPERTIES DESCRIPTION "Support for gzip compressed files and data streams" URL "http://www.zlib.net" TYPE REQUIRED ) find_package(X11) set_package_properties(X11 PROPERTIES DESCRIPTION "X11 libraries" URL "http://www.x.org" TYPE OPTIONAL PURPOSE "Required for building the X11 based workspace") if(X11_FOUND) find_package(XCB MODULE REQUIRED COMPONENTS XCB RANDR) set_package_properties(XCB PROPERTIES TYPE REQUIRED) if(NOT X11_SM_FOUND) message(FATAL_ERROR "\nThe X11 Session Management (SM) development package could not be found.\nPlease install libSM.\n") endif(NOT X11_SM_FOUND) find_package(Qt5 ${QT_MIN_VERSION} CONFIG REQUIRED COMPONENTS X11Extras) endif() if(X11_FOUND AND XCB_XCB_FOUND) set(HAVE_X11 1) endif() find_package(AppStreamQt 0.10.6) set_package_properties(AppStreamQt PROPERTIES DESCRIPTION "Access metadata for listing available software" URL "https://www.freedesktop.org/wiki/Distributions/AppStream/" TYPE OPTIONAL ) if(${AppStreamQt_FOUND}) set(HAVE_APPSTREAMQT true) endif() include(ConfigureChecks.cmake) include_directories("${CMAKE_CURRENT_BINARY_DIR}") configure_file(config-workspace.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-workspace.h) configure_file(config-unix.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-unix.h ) configure_file(config-X11.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-X11.h) configure_file(config-appstream.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-appstream.h ) add_subdirectory(login-sessions) plasma_install_package(lookandfeel org.kde.breeze.desktop look-and-feel lookandfeel) if (INSTALL_SDDM_THEME) configure_file(sddm-theme/theme.conf.cmake ${CMAKE_CURRENT_BINARY_DIR}/sddm-theme/theme.conf) # Install the login theme into the SDDM directory # Longer term we need to look at making SDDM load from look and feel somehow.. and allow copying at runtime #NOTE this trailing slash is important to rename the directory install(DIRECTORY sddm-theme/ DESTINATION ${KDE_INSTALL_FULL_DATADIR}/sddm/themes/breeze PATTERN "README.txt" EXCLUDE PATTERN "components" EXCLUDE PATTERN "dummydata" EXCLUDE PATTERN "theme.conf.cmake" EXCLUDE) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/sddm-theme/theme.conf DESTINATION ${KDE_INSTALL_FULL_DATADIR}/sddm/themes/breeze) install(DIRECTORY lookandfeel/contents/components DESTINATION ${KDE_INSTALL_FULL_DATADIR}/sddm/themes/breeze PATTERN "README.txt" EXCLUDE) endif() add_definitions(-DQT_NO_URL_CAST_FROM_STRING) add_subdirectory(doc) add_subdirectory(libkworkspace) add_subdirectory(libdbusmenuqt) add_subdirectory(appmenu) add_subdirectory(libtaskmanager) add_subdirectory(libnotificationmanager) add_subdirectory(libcolorcorrect) add_subdirectory(components) add_subdirectory(plasma-windowed) add_subdirectory(shell) add_subdirectory(freespacenotifier) add_subdirectory(klipper) add_subdirectory(krunner) add_subdirectory(ksmserver) add_subdirectory(logout-greeter) add_subdirectory(ksplash) add_subdirectory(systemmonitor) add_subdirectory(statusnotifierwatcher) add_subdirectory(startkde) add_subdirectory(themes) add_subdirectory(kcms) add_subdirectory(containmentactions) add_subdirectory(runners) add_subdirectory(applets) add_subdirectory(dataengines) add_subdirectory(wallpapers) add_subdirectory(kioslave) add_subdirectory(ktimezoned) add_subdirectory(menu) add_subdirectory(phonon) # This ensures pressing the eject button on a CD drive ejects the disc # It listens to the Solid::OpticalDrive::ejectPressed signal that is only # supported by Solid in the HAL backend and does nothing with UDev if(CMAKE_SYSTEM_NAME MATCHES FreeBSD) add_subdirectory(solidautoeject) endif() ecm_optional_add_subdirectory(xembed-sni-proxy) ecm_optional_add_subdirectory(gmenu-dbusmenu-proxy) add_subdirectory(soliduiserver) if(KF5Holidays_FOUND) add_subdirectory(plasmacalendarintegration) endif() add_subdirectory(templates) install(FILES plasma-workspace.categories DESTINATION ${KDE_INSTALL_LOGGINGCATEGORIESDIR}) feature_summary(WHAT ALL INCLUDE_QUIET_PACKAGES FATAL_ON_MISSING_REQUIRED_PACKAGES) diff --git a/components/containmentlayoutmanager/gridlayoutmanager.cpp b/components/containmentlayoutmanager/gridlayoutmanager.cpp index 739694714..491db2247 100644 --- a/components/containmentlayoutmanager/gridlayoutmanager.cpp +++ b/components/containmentlayoutmanager/gridlayoutmanager.cpp @@ -1,594 +1,596 @@ /* * Copyright 2019 by Marco Martin * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Library General Public License for more details * * You should have received a copy of the GNU Library General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "gridlayoutmanager.h" #include "appletslayout.h" #include GridLayoutManager::GridLayoutManager(AppletsLayout *layout) : AbstractLayoutManager(layout) { } GridLayoutManager::~GridLayoutManager() { } QString GridLayoutManager::serializeLayout() const { QString result; for (auto *item : layout()->childItems()) { ItemContainer *itemCont = qobject_cast(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(); 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].toInt(), itemGeom[1].toInt(), itemGeom[2].toInt(), itemGeom[3].toInt(), itemGeom[4].toInt()}; } } 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(item); if (itemCont && itemCont != layout()->placeHolder()) { maintainItemEdgeAlignment(itemCont, newGeometry, oldGeometry); // NOTE: do not use positionItemAndAssign here, because we do not want to 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(item); if (itemCont && itemCont != layout()->placeHolder()) { // NOTE: do not use positionItemAndAssign here, because we do not want to emit layoutNeedsSaving, to not save after resize positionItem(itemCont); assignSpaceImpl(itemCont); } } } void GridLayoutManager::resetLayoutFromConfig() { m_grid.clear(); m_pointsForItem.clear(); QList missingItems; for (auto *item : layout()->childItems()) { ItemContainer *itemCont = qobject_cast(item); if (itemCont && itemCont != layout()->placeHolder()) { if (!restoreItem(itemCont)) { missingItems << itemCont; } } } for (auto *item : missingItems) { // NOTE: do not use positionItemAndAssign here, because we do not want to 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 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(row, column))) { return false; } } } return true; } bool GridLayoutManager::assignSpaceImpl(ItemContainer *item) { // Don't emit extra layoutneedssaving signals releaseSpaceImpl(item); if (!isRectAvailable(itemGeometry(item))) { qWarning()<<"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 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(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); } } 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 &cell) const { return cell.first < 0 || cell.second < 0 || cell.first >= rows() || cell.second >= columns(); } bool GridLayoutManager::isCellAvailable(const QPair &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 GridLayoutManager::nextCell(const QPair &cell, AppletsLayout::PreferredLayoutDirection direction) const { QPair 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 GridLayoutManager::nextAvailableCell(const QPair &cell, AppletsLayout::PreferredLayoutDirection direction) const { QPair 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(-1, -1); } QPair GridLayoutManager::nextTakenCell(const QPair &cell, AppletsLayout::PreferredLayoutDirection direction) const { QPair 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(-1, -1); } int GridLayoutManager::freeSpaceInDirection(const QPair &cell, AppletsLayout::PreferredLayoutDirection direction) const { QPair 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 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(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(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"