diff options
Diffstat (limited to 'src/quicklayouts/qquickstacklayout.cpp')
-rw-r--r-- | src/quicklayouts/qquickstacklayout.cpp | 145 |
1 files changed, 83 insertions, 62 deletions
diff --git a/src/quicklayouts/qquickstacklayout.cpp b/src/quicklayouts/qquickstacklayout.cpp index 19d0033e8b..0f745be9f9 100644 --- a/src/quicklayouts/qquickstacklayout.cpp +++ b/src/quicklayouts/qquickstacklayout.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 "qquickstacklayout_p.h" @@ -52,6 +16,10 @@ \brief The StackLayout class provides a stack of items where only one item is visible at a time. + 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. + The current visible item can be modified by setting the \l currentIndex property. The index corresponds to the order of the StackLayout's children. @@ -98,6 +66,7 @@ \sa GridLayout \sa RowLayout \sa {QtQuick.Controls::StackView}{StackView} + \sa {Qt Quick Layouts Overview} */ QT_BEGIN_NAMESPACE @@ -115,6 +84,7 @@ QQuickStackLayout::QQuickStackLayout(QQuickItem *parent) : /*! \qmlproperty int StackLayout::count + \readonly This property holds the number of items that belong to the layout. @@ -123,7 +93,6 @@ QQuickStackLayout::QQuickStackLayout(QQuickItem *parent) : int QQuickStackLayout::count() const { Q_D(const QQuickStackLayout); - ensureLayoutItemsUpdated(); return d->count; } @@ -132,18 +101,19 @@ int QQuickStackLayout::count() const This property holds the index of the child item that is currently visible in the StackLayout. By default it will be \c -1 for an empty layout, otherwise the default is \c 0 (referring to the first item). + + Since 6.5, inserting/removing a new Item at an index less than or equal to the current index + will increment/decrement the current index, but keep the current Item. */ int QQuickStackLayout::currentIndex() const { Q_D(const QQuickStackLayout); - ensureLayoutItemsUpdated(); return d->currentIndex; } void QQuickStackLayout::setCurrentIndex(int index) { Q_D(QQuickStackLayout); - ensureLayoutItemsUpdated(); if (index == d->currentIndex) return; @@ -179,7 +149,9 @@ void QQuickStackLayout::componentComplete() { QQuickLayout::componentComplete(); // will call our geometryChange(), (where isComponentComplete() == true) - ensureLayoutItemsUpdated(); + childItemsChanged(); + invalidate(); + ensureLayoutItemsUpdated(ApplySizeHints); QQuickItem *par = parentItem(); if (qobject_cast<QQuickLayout*>(par)) @@ -191,6 +163,8 @@ void QQuickStackLayout::componentComplete() void QQuickStackLayout::itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &value) { QQuickLayout::itemChange(change, value); + if (!isReady()) + return; if (change == ItemChildRemovedChange) { QQuickItem *item = value.item; @@ -200,8 +174,11 @@ void QQuickStackLayout::itemChange(QQuickItem::ItemChange change, const QQuickIt stackLayoutAttached->setIndex(-1); stackLayoutAttached->setIsCurrentItem(false); } + m_cachedItemSizeHints.remove(item); + childItemsChanged(AdjustCurrentIndex); // removal; might have to adjust currentIndex invalidate(); } else if (change == ItemChildAddedChange) { + childItemsChanged(); invalidate(); } } @@ -209,7 +186,6 @@ void QQuickStackLayout::itemChange(QQuickItem::ItemChange change, const QQuickIt QSizeF QQuickStackLayout::sizeHint(Qt::SizeHint whichSizeHint) const { Q_D(const QQuickStackLayout); - ensureLayoutItemsUpdated(); QSizeF &askingFor = m_cachedSizeHints[whichSizeHint]; if (!askingFor.isValid()) { QSizeF &minS = m_cachedSizeHints[Qt::MinimumSize]; @@ -221,10 +197,8 @@ QSizeF QQuickStackLayout::sizeHint(Qt::SizeHint whichSizeHint) const maxS = QSizeF(std::numeric_limits<qreal>::infinity(), std::numeric_limits<qreal>::infinity()); const int count = itemCount(); - m_cachedItemSizeHints.resize(count); for (int i = 0; i < count; ++i) { - SizeHints &hints = m_cachedItemSizeHints[i]; - QQuickStackLayout::collectItemSizeHints(itemAt(i), hints.array); + SizeHints &hints = cachedItemSizeHints(i); minS = minS.expandedTo(hints.min()); prefS = prefS.expandedTo(hints.pref()); //maxS = maxS.boundedTo(hints.max()); // Can be resized to be larger than any of its items. @@ -238,7 +212,6 @@ QSizeF QQuickStackLayout::sizeHint(Qt::SizeHint whichSizeHint) const int QQuickStackLayout::indexOf(QQuickItem *childItem) const { - ensureLayoutItemsUpdated(); if (childItem) { int indexOfItem = 0; const auto items = childItems(); @@ -290,11 +263,11 @@ void QQuickStackLayout::setAlignment(QQuickItem * /*item*/, Qt::Alignment /*alig void QQuickStackLayout::invalidate(QQuickItem *childItem) { - const int indexOfChild = indexOf(childItem); - if (indexOfChild >= 0 && indexOfChild < m_cachedItemSizeHints.count()) { - m_cachedItemSizeHints[indexOfChild].min() = QSizeF(); - m_cachedItemSizeHints[indexOfChild].pref() = QSizeF(); - m_cachedItemSizeHints[indexOfChild].max() = QSizeF(); + if (childItem) { + SizeHints &hints = m_cachedItemSizeHints[childItem]; + hints.min() = QSizeF(); + hints.pref() = QSizeF(); + hints.max() = QSizeF(); } for (int i = 0; i < Qt::NSizeHints; ++i) @@ -305,15 +278,36 @@ void QQuickStackLayout::invalidate(QQuickItem *childItem) parentLayout->invalidate(this); } -void QQuickStackLayout::updateLayoutItems() +void QQuickStackLayout::childItemsChanged(AdjustCurrentIndexPolicy adjustCurrentIndexPolicy) { Q_D(QQuickStackLayout); - d->m_ignoredItems.clear(); const int count = itemCount(); - int oldIndex = d->currentIndex; + const int oldIndex = d->currentIndex; if (!d->explicitCurrentIndex) d->currentIndex = (count > 0 ? 0 : -1); + if (adjustCurrentIndexPolicy == AdjustCurrentIndex) { + /* + * If an item is inserted or deleted at an index less than or equal to the current index it + * will affect the current index, but keep the current item. This is consistent with + * QStackedLayout, QStackedWidget and TabBar + * + * Unless the caller is componentComplete(), we can assume that only one of the children + * are visible, and we should keep that visible even if the stacking order has changed. + * This means that if the sibling order has changed (or an item stacked before the current + * item is added/removed), we must update the currentIndex so that it corresponds with the + * current visible item. + */ + if (d->currentIndex < d->count) { + for (int i = 0; i < count; ++i) { + QQuickItem *child = itemAt(i); + if (child->isVisible()) { + d->currentIndex = i; + break; + } + } + } + } if (d->currentIndex != oldIndex) emit currentIndexChanged(); @@ -335,6 +329,17 @@ void QQuickStackLayout::updateLayoutItems() } } +QQuickStackLayout::SizeHints &QQuickStackLayout::cachedItemSizeHints(int index) const +{ + QQuickItem *item = itemAt(index); + Q_ASSERT(item); + SizeHints &hints = m_cachedItemSizeHints[item]; // will create an entry if it doesn't exist + if (!hints.min().isValid()) + QQuickStackLayout::collectItemSizeHints(item, hints.array); + return hints; +} + + void QQuickStackLayout::rearrange(const QSizeF &newSize) { Q_D(QQuickStackLayout); @@ -342,11 +347,10 @@ void QQuickStackLayout::rearrange(const QSizeF &newSize) return; qCDebug(lcQuickLayouts) << "QQuickStackLayout::rearrange"; - ensureLayoutItemsUpdated(); - if (d->currentIndex == -1 || d->currentIndex >= m_cachedItemSizeHints.count()) + if (d->currentIndex == -1 || d->currentIndex >= m_cachedItemSizeHints.size()) return; - QQuickStackLayout::SizeHints &hints = m_cachedItemSizeHints[d->currentIndex]; + QQuickStackLayout::SizeHints &hints = cachedItemSizeHints(d->currentIndex); QQuickItem *item = itemAt(d->currentIndex); Q_ASSERT(item); item->setPosition(QPointF(0,0)); // ### respect alignment? @@ -358,6 +362,10 @@ void QQuickStackLayout::rearrange(const QSizeF &newSize) QQuickLayout::rearrange(newSize); } +void QQuickStackLayout::setStretchFactor(QQuickItem * /*item*/, int /*stretchFactor*/, Qt::Orientation /*orient*/) +{ +} + void QQuickStackLayout::collectItemSizeHints(QQuickItem *item, QSizeF *sizeHints) { QQuickLayoutAttached *info = nullptr; @@ -379,10 +387,15 @@ void QQuickStackLayout::collectItemSizeHints(QQuickItem *item, QSizeF *sizeHints bool QQuickStackLayout::shouldIgnoreItem(QQuickItem *item) const { - const bool ignored = QQuickItemPrivate::get(item)->isTransparentForPositioner(); - if (ignored) - d_func()->m_ignoredItems << item; - return ignored; + return QQuickItemPrivate::get(item)->isTransparentForPositioner(); +} + +void QQuickStackLayout::itemSiblingOrderChanged(QQuickItem *) +{ + if (!isReady()) + return; + childItemsChanged(AdjustCurrentIndex); + invalidate(); } QQuickStackLayoutAttached::QQuickStackLayoutAttached(QObject *object) @@ -410,10 +423,16 @@ QQuickStackLayoutAttached::QQuickStackLayoutAttached(QObject *object) setLayout(stackLayout); setIndex(index); setIsCurrentItem(stackLayout->currentIndex() == index); + + // In case of lazy loading in loader, attachedProperties are created and updated for the + // object after adding the child object to the stack layout, which leads to entries with + // same index. Triggering childItemsChanged() resets to right index in the stack layout. + stackLayout->childItemsChanged(); } /*! \qmlattachedproperty int StackLayout::index + \readonly This attached property holds the index of each child item in the \l StackLayout. @@ -438,6 +457,7 @@ void QQuickStackLayoutAttached::setIndex(int index) /*! \qmlattachedproperty bool StackLayout::isCurrentItem + \readonly This attached property is \c true if this child is the current item in the \l StackLayout. @@ -462,6 +482,7 @@ void QQuickStackLayoutAttached::setIsCurrentItem(bool isCurrentItem) /*! \qmlattachedproperty StackLayout StackLayout::layout + \readonly This attached property holds the \l StackLayout that manages this child item. |