diff options
Diffstat (limited to 'src/quicklayouts/qquicklinearlayout.cpp')
-rw-r--r-- | src/quicklayouts/qquicklinearlayout.cpp | 292 |
1 files changed, 192 insertions, 100 deletions
diff --git a/src/quicklayouts/qquicklinearlayout.cpp b/src/quicklayouts/qquicklinearlayout.cpp index 2f97708b52..41f45259ea 100644 --- a/src/quicklayouts/qquicklinearlayout.cpp +++ b/src/quicklayouts/qquicklinearlayout.cpp @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Quick Layouts module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include "qquicklinearlayout_p.h" #include "qquickgridlayoutengine_p.h" @@ -53,6 +17,10 @@ \ingroup layouts \brief Identical to \l GridLayout, but having only one row. + To be able to use this type more efficiently, it is recommended that you + understand the general mechanism of the Qt Quick Layouts module. Refer to + \l{Qt Quick Layouts Overview} for more information. + It is available as a convenience for developers, as it offers a cleaner API. Items in a RowLayout support these attached properties: @@ -96,7 +64,9 @@ Read more about attached properties \l{QML Object Attributes}{here}. \sa ColumnLayout \sa GridLayout + \sa StackLayout \sa Row + \sa {Qt Quick Layouts Overview} */ /*! @@ -107,6 +77,10 @@ \ingroup layouts \brief Identical to \l GridLayout, but having only one column. + To be able to use this type more efficiently, it is recommended that you + understand the general mechanism of the Qt Quick Layouts module. Refer to + \l{Qt Quick Layouts Overview} for more information. + It is available as a convenience for developers, as it offers a cleaner API. Items in a ColumnLayout support these attached properties: @@ -148,7 +122,9 @@ \sa RowLayout \sa GridLayout + \sa StackLayout \sa Column + \sa {Qt Quick Layouts Overview} */ @@ -160,7 +136,9 @@ \ingroup layouts \brief Provides a way of dynamically arranging items in a grid. - + To be able to use this type more efficiently, it is recommended that you + understand the general mechanism of the Qt Quick Layouts module. Refer to + \l{Qt Quick Layouts Overview} for more information. If the GridLayout is resized, all items in the layout will be rearranged. It is similar to the widget-based QGridLayout. All visible children of the GridLayout element will belong to @@ -212,7 +190,9 @@ \sa RowLayout \sa ColumnLayout + \sa StackLayout \sa Grid + \sa {Qt Quick Layouts Overview} */ @@ -227,7 +207,7 @@ QQuickGridLayoutBase::QQuickGridLayoutBase() QQuickGridLayoutBase::QQuickGridLayoutBase(QQuickGridLayoutBasePrivate &dd, Qt::Orientation orientation, - QQuickItem *parent /*= 0*/) + QQuickItem *parent /*= nullptr */) : QQuickLayout(dd, parent) { Q_D(QQuickGridLayoutBase); @@ -254,7 +234,6 @@ void QQuickGridLayoutBase::setOrientation(Qt::Orientation orientation) QSizeF QQuickGridLayoutBase::sizeHint(Qt::SizeHint whichSizeHint) const { Q_D(const QQuickGridLayoutBase); - ensureLayoutItemsUpdated(); return d->engine.sizeHint(whichSizeHint, QSizeF(), d->styleInfo); } @@ -268,10 +247,8 @@ QSizeF QQuickGridLayoutBase::sizeHint(Qt::SizeHint whichSizeHint) const Possible values: - \list - \li Qt.LeftToRight (default) - Items are laid out from left to right. - \li Qt.RightToLeft - Items are laid out from right to left. - \endlist + \value Qt.LeftToRight (default) Items are laid out from left to right. + \value Qt.RightToLeft Items are laid out from right to left. \sa RowLayout::layoutDirection, ColumnLayout::layoutDirection */ @@ -302,6 +279,13 @@ void QQuickGridLayoutBase::setAlignment(QQuickItem *item, Qt::Alignment alignmen { Q_D(QQuickGridLayoutBase); d->engine.setAlignment(item, alignment); + maybeSubscribeToBaseLineOffsetChanges(item); +} + +void QQuickGridLayoutBase::setStretchFactor(QQuickItem *item, int stretchFactor, Qt::Orientation orient) +{ + Q_D(QQuickGridLayoutBase); + d->engine.setStretchFactor(item, stretchFactor, orient); } QQuickGridLayoutBase::~QQuickGridLayoutBase() @@ -330,7 +314,7 @@ void QQuickGridLayoutBase::componentComplete() need to call invalidate() in advance */ invalidate(); - ensureLayoutItemsUpdated(); + ensureLayoutItemsUpdated(QQuickLayout::ApplySizeHints); QQuickItem *par = parentItem(); if (qobject_cast<QQuickLayout*>(par)) @@ -377,26 +361,24 @@ void QQuickGridLayoutBase::invalidate(QQuickItem *childItem) if (!isReady()) return; qCDebug(lcQuickLayouts) << "QQuickGridLayoutBase::invalidate()" << this << ", invalidated:" << invalidated(); - if (invalidated()) { - return; - } - qCDebug(lcQuickLayouts) << "d->m_rearranging:" << d->m_rearranging; - if (d->m_rearranging) { - d->m_invalidateAfterRearrange << childItem; - return; - } - if (childItem) { - if (QQuickGridLayoutItem *layoutItem = d->engine.findLayoutItem(childItem)) + if (d->m_rearranging) { + if (!d->m_invalidateAfterRearrange.contains(childItem)) + d->m_invalidateAfterRearrange << childItem; + return; + } + if (QQuickGridLayoutItem *layoutItem = d->engine.findLayoutItem(childItem)) { layoutItem->invalidate(); + } } + // invalidate engine d->engine.invalidate(); qCDebug(lcQuickLayouts) << "calling QQuickLayout::invalidate();"; QQuickLayout::invalidate(); - if (QQuickLayout *parentLayout = qobject_cast<QQuickLayout *>(parentItem())) + if (auto *parentLayout = qobject_cast<QQuickLayout *>(parentItem())) parentLayout->invalidate(this); qCDebug(lcQuickLayouts) << "QQuickGridLayoutBase::invalidate() LEAVING" << this; } @@ -406,10 +388,6 @@ void QQuickGridLayoutBase::updateLayoutItems() Q_D(QQuickGridLayoutBase); if (!isReady()) return; - if (d->m_rearranging) { - d->m_updateAfterRearrange = true; - return; - } qCDebug(lcQuickLayouts) << "QQuickGridLayoutBase::updateLayoutItems ENTERING" << this; d->engine.deleteItems(); @@ -420,16 +398,12 @@ void QQuickGridLayoutBase::updateLayoutItems() QQuickItem *QQuickGridLayoutBase::itemAt(int index) const { Q_D(const QQuickGridLayoutBase); - qCDebug(lcQuickLayouts).nospace() << "QQuickGridLayoutBase::itemAt(" << index << ")"; - ensureLayoutItemsUpdated(); - qCDebug(lcQuickLayouts).nospace() << "QQuickGridLayoutBase::itemAt(" << index << ") LEAVING"; return static_cast<QQuickGridLayoutItem*>(d->engine.itemAt(index))->layoutItem(); } int QQuickGridLayoutBase::itemCount() const { Q_D(const QQuickGridLayoutBase); - ensureLayoutItemsUpdated(); return d->engine.itemCount(); } @@ -467,7 +441,7 @@ void QQuickGridLayoutBase::itemVisibilityChanged(QQuickItem *item) void QQuickGridLayoutBase::rearrange(const QSizeF &size) { Q_D(QQuickGridLayoutBase); - if (!isReady()) + if (!isReady() || !size.isValid()) return; qCDebug(lcQuickLayouts) << "QQuickGridLayoutBase::rearrange" << d->m_recurRearrangeCounter << this; @@ -481,7 +455,9 @@ void QQuickGridLayoutBase::rearrange(const QSizeF &size) return; } - ensureLayoutItemsUpdated(); + // Should normally not be needed, but there might be an incoming window resize event that we + // will process before we process updatePolish() + ensureLayoutItemsUpdated(QQuickLayout::ApplySizeHints | QQuickLayout::Recursive); d->m_rearranging = true; qCDebug(lcQuickLayouts) << objectName() << "QQuickGridLayoutBase::rearrange()" << size; @@ -501,14 +477,9 @@ void QQuickGridLayoutBase::rearrange(const QSizeF &size) d->engine.setGeometries(QRectF(QPointF(0,0), size), d->styleInfo); d->m_rearranging = false; - for (QQuickItem *invalid : qAsConst(d->m_invalidateAfterRearrange)) - invalidate(invalid); + for (auto childItem : std::as_const(d->m_invalidateAfterRearrange)) + invalidate(childItem); d->m_invalidateAfterRearrange.clear(); - - if (d->m_updateAfterRearrange) { - ensureLayoutItemsUpdated(); - d->m_updateAfterRearrange = false; - } } /********************************** @@ -516,7 +487,7 @@ void QQuickGridLayoutBase::rearrange(const QSizeF &size) ** QQuickGridLayout ** **/ -QQuickGridLayout::QQuickGridLayout(QQuickItem *parent /* = 0*/) +QQuickGridLayout::QQuickGridLayout(QQuickItem *parent /* = nullptr*/) : QQuickGridLayoutBase(*new QQuickGridLayoutPrivate, Qt::Horizontal, parent) { } @@ -624,12 +595,10 @@ void QQuickGridLayout::setRows(int rows) Possible values are: - \list - \li GridLayout.LeftToRight (default) - Items are positioned next to - each other, then wrapped to the next line. - \li GridLayout.TopToBottom - Items are positioned next to each - other from top to bottom, then wrapped to the next column. - \endlist + \value GridLayout.LeftToRight + (default) Items are positioned next to each other, then wrapped to the next line. + \value GridLayout.TopToBottom + Items are positioned next to each other from top to bottom, then wrapped to the next column. \sa rows \sa columns @@ -651,6 +620,69 @@ void QQuickGridLayout::setFlow(QQuickGridLayout::Flow flow) emit flowChanged(); } +/*! + \qmlproperty bool GridLayout::uniformCellWidths + \since QtQuick.Layouts 6.6 + + If this property is set to \c true, the layout will force all cells to have + a uniform width. The layout aims to respect + \l{Layout::minimumWidth}{Layout.minimumWidth}, + \l{Layout::preferredWidth}{Layout.preferredWidth} and + \l{Layout::maximumWidth}{Layout.maximumWidth} in this mode but might make + compromisses to fullfill the requirements of all items. + + Default value is \c false. + + \sa GridLayout::uniformCellHeights, RowLayout::uniformCellSizes, ColumnLayout::uniformCellSizes +*/ +bool QQuickGridLayout::uniformCellWidths() const +{ + Q_D(const QQuickGridLayout); + return d->engine.uniformCellWidths(); +} + +void QQuickGridLayout::setUniformCellWidths(bool uniformCellWidths) +{ + Q_D(QQuickGridLayout); + if (d->engine.uniformCellWidths() == uniformCellWidths) + return; + d->engine.setUniformCellWidths(uniformCellWidths); + invalidate(); + emit uniformCellWidthsChanged(); +} + +/*! + \qmlproperty bool GridLayout::uniformCellHeights + \since QtQuick.Layouts 6.6 + + If this property is set to \c true, the layout will force all cells to have an + uniform Height. The layout aims to respect + \l{Layout::minimumHeight}{Layout.minimumHeight}, + \l{Layout::preferredHeight}{Layout.preferredHeight} and + \l{Layout::maximumHeight}{Layout.maximumHeight} in this mode but might make + compromisses to fullfill the requirements of all items. + + Default value is \c false. + + \sa GridLayout::uniformCellWidths, RowLayout::uniformCellSizes, ColumnLayout::uniformCellSizes +*/ +bool QQuickGridLayout::uniformCellHeights() const +{ + Q_D(const QQuickGridLayout); + return d->engine.uniformCellHeights(); +} + +void QQuickGridLayout::setUniformCellHeights(bool uniformCellHeights) +{ + Q_D(QQuickGridLayout); + if (d->engine.uniformCellHeights() == uniformCellHeights) + return; + d->engine.setUniformCellHeights(uniformCellHeights); + invalidate(); + emit uniformCellHeightsChanged(); +} + + void QQuickGridLayout::insertLayoutItems() { Q_D(QQuickGridLayout); @@ -668,17 +700,17 @@ void QQuickGridLayout::insertLayoutItems() if (flowBound < 0) flowBound = std::numeric_limits<int>::max(); - QSizeF sizeHints[Qt::NSizeHints]; const auto items = childItems(); for (QQuickItem *child : items) { checkAnchors(child); - QQuickLayoutAttached *info = nullptr; - // Will skip all items with effective maximum width/height == 0 - if (shouldIgnoreItem(child, info, sizeHints)) + if (shouldIgnoreItem(child)) continue; + QQuickLayoutAttached *info = attachedLayoutObject(child, false); Qt::Alignment alignment; + int hStretch = -1; + int vStretch = -1; int row = -1; int column = -1; int span[2] = {1,1}; @@ -718,6 +750,12 @@ void QQuickGridLayout::insertLayoutItems() return; } alignment = info->alignment(); + hStretch = info->horizontalStretchFactor(); + if (hStretch >= 0 && !info->fillWidth()) + qmlWarning(child) << "horizontalStretchFactor requires fillWidth to also be set to true"; + vStretch = info->verticalStretchFactor(); + if (vStretch >= 0 && !info->fillHeight()) + qmlWarning(child) << "verticalStretchFactor requires fillHeight to also be set to true"; } Q_ASSERT(columnSpan >= 1); @@ -769,7 +807,10 @@ void QQuickGridLayout::insertLayoutItems() column = nextColumn; row = nextRow; QQuickGridLayoutItem *layoutItem = new QQuickGridLayoutItem(child, row, column, rowSpan, columnSpan, alignment); - layoutItem->setCachedSizeHints(sizeHints); + if (hStretch >= 0) + layoutItem->setStretchFactor(hStretch, Qt::Horizontal); + if (vStretch >= 0) + layoutItem->setStretchFactor(vStretch, Qt::Vertical); d->engine.insertItem(layoutItem, -1); } @@ -781,7 +822,7 @@ void QQuickGridLayout::insertLayoutItems() ** **/ QQuickLinearLayout::QQuickLinearLayout(Qt::Orientation orientation, - QQuickItem *parent /*= 0*/) + QQuickItem *parent /*= nullptr*/) : QQuickGridLayoutBase(*new QQuickLinearLayoutPrivate, orientation, parent) { } @@ -796,10 +837,8 @@ QQuickLinearLayout::QQuickLinearLayout(Qt::Orientation orientation, Possible values: - \list - \li Qt.LeftToRight (default) - Items are laid out from left to right. - \li Qt.RightToLeft - Items are laid out from right to left - \endlist + \value Qt.LeftToRight (default) Items are laid out from left to right. + \value Qt.RightToLeft Items are laid out from right to left \sa GridLayout::layoutDirection, ColumnLayout::layoutDirection */ @@ -813,14 +852,49 @@ QQuickLinearLayout::QQuickLinearLayout(Qt::Orientation orientation, Possible values: - \list - \li Qt.LeftToRight (default) - Items are laid out from left to right. - \li Qt.RightToLeft - Items are laid out from right to left - \endlist + \value Qt.LeftToRight (default) Items are laid out from left to right. + \value Qt.RightToLeft Items are laid out from right to left \sa GridLayout::layoutDirection, RowLayout::layoutDirection */ +/*! + \qmlproperty bool RowLayout::uniformCellSizes + \since QtQuick.Layouts 6.6 + + If this property is set to \c true, the layout will force all cells to have + a uniform size. + + \sa GridLayout::uniformCellWidths, GridLayout::uniformCellHeights, ColumnLayout::uniformCellSizes +*/ +/*! + \qmlproperty bool ColumnLayout::uniformCellSizes + \since QtQuick.Layouts 6.6 + + If this property is set to \c true, the layout will force all cells to have + a uniform size. + + \sa GridLayout::uniformCellWidths, GridLayout::uniformCellHeights, RowLayout::uniformCellSizes +*/ +bool QQuickLinearLayout::uniformCellSizes() const +{ + Q_D(const QQuickLinearLayout); + Q_ASSERT(d->engine.uniformCellWidths() == d->engine.uniformCellHeights()); + return d->engine.uniformCellWidths(); +} + +void QQuickLinearLayout::setUniformCellSizes(bool uniformCellSizes) +{ + Q_D(QQuickLinearLayout); + Q_ASSERT(d->engine.uniformCellWidths() == d->engine.uniformCellHeights()); + if (d->engine.uniformCellHeights() == uniformCellSizes) + return; + d->engine.setUniformCellWidths(uniformCellSizes); + d->engine.setUniformCellHeights(uniformCellSizes); + invalidate(); + emit uniformCellSizesChanged(); +} + /*! \qmlproperty real RowLayout::spacing @@ -855,20 +929,28 @@ void QQuickLinearLayout::setSpacing(qreal space) void QQuickLinearLayout::insertLayoutItems() { Q_D(QQuickLinearLayout); - QSizeF sizeHints[Qt::NSizeHints]; const auto items = childItems(); for (QQuickItem *child : items) { Q_ASSERT(child); checkAnchors(child); - QQuickLayoutAttached *info = nullptr; // Will skip all items with effective maximum width/height == 0 - if (shouldIgnoreItem(child, info, sizeHints)) + if (shouldIgnoreItem(child)) continue; + QQuickLayoutAttached *info = attachedLayoutObject(child, false); Qt::Alignment alignment; - if (info) + int hStretch = -1; + int vStretch = -1; + bool fillWidth = false; + bool fillHeight = false; + if (info) { alignment = info->alignment(); + hStretch = info->horizontalStretchFactor(); + vStretch = info->verticalStretchFactor(); + fillWidth = info->fillWidth(); + fillHeight = info->fillHeight(); + } const int index = d->engine.rowCount(d->orientation); d->engine.insertRow(index, d->orientation); @@ -878,7 +960,17 @@ void QQuickLinearLayout::insertLayoutItems() if (d->orientation == Qt::Vertical) qSwap(gridRow, gridColumn); QQuickGridLayoutItem *layoutItem = new QQuickGridLayoutItem(child, gridRow, gridColumn, 1, 1, alignment); - layoutItem->setCachedSizeHints(sizeHints); + + if (hStretch >= 0) { + if (!fillWidth) + qmlWarning(child) << "horizontalStretchFactor requires fillWidth to also be set to true"; + layoutItem->setStretchFactor(hStretch, Qt::Horizontal); + } + if (vStretch >= 0) { + if (!fillHeight) + qmlWarning(child) << "verticalStretchFactor requires fillHeight to also be set to true"; + layoutItem->setStretchFactor(vStretch, Qt::Vertical); + } d->engine.insertItem(layoutItem, index); } } |