aboutsummaryrefslogtreecommitdiffstats
path: root/src/quicklayouts
diff options
context:
space:
mode:
Diffstat (limited to 'src/quicklayouts')
-rw-r--r--src/quicklayouts/CMakeLists.txt28
-rw-r--r--src/quicklayouts/qquickgridlayoutengine.cpp51
-rw-r--r--src/quicklayouts/qquickgridlayoutengine_p.h49
-rw-r--r--src/quicklayouts/qquicklayout.cpp275
-rw-r--r--src/quicklayouts/qquicklayout_p.h170
-rw-r--r--src/quicklayouts/qquicklayoutglobal_p.h60
-rw-r--r--src/quicklayouts/qquicklayoutitemproxy.cpp532
-rw-r--r--src/quicklayouts/qquicklayoutitemproxy_p.h147
-rw-r--r--src/quicklayouts/qquicklayoutstyleinfo.cpp42
-rw-r--r--src/quicklayouts/qquicklayoutstyleinfo_p.h40
-rw-r--r--src/quicklayouts/qquicklinearlayout.cpp292
-rw-r--r--src/quicklayouts/qquicklinearlayout_p.h90
-rw-r--r--src/quicklayouts/qquickstacklayout.cpp145
-rw-r--r--src/quicklayouts/qquickstacklayout_p.h75
14 files changed, 1313 insertions, 683 deletions
diff --git a/src/quicklayouts/CMakeLists.txt b/src/quicklayouts/CMakeLists.txt
index 3524f5e4ba..4eeb697461 100644
--- a/src/quicklayouts/CMakeLists.txt
+++ b/src/quicklayouts/CMakeLists.txt
@@ -1,11 +1,21 @@
- qt_internal_add_module(QuickLayouts
- GENERATE_METATYPES
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+qt_internal_add_qml_module(QuickLayouts
+ URI "QtQuick.Layouts"
+ VERSION "${PROJECT_VERSION}"
+ DESIGNER_SUPPORTED
+ PLUGIN_TARGET qquicklayoutsplugin
+ CLASS_NAME QtQuickLayoutsPlugin
+ DEPENDENCIES
+ QtQuick/auto
SOURCES
qquickgridlayoutengine.cpp qquickgridlayoutengine_p.h
qquicklayout.cpp qquicklayout_p.h
qquicklayoutstyleinfo.cpp qquicklayoutstyleinfo_p.h
qquicklinearlayout.cpp qquicklinearlayout_p.h
qquickstacklayout.cpp qquickstacklayout_p.h
+ qquicklayoutitemproxy.cpp qquicklayoutitemproxy_p.h
qquicklayoutglobal_p.h
DEFINES
QT_BUILD_QUICKLAYOUTS_LIB
@@ -14,15 +24,5 @@
Qt::GuiPrivate
Qt::QuickPrivate
Qt::Qml
-)
-
-
-set_target_properties(QuickLayouts PROPERTIES
- QT_QML_MODULE_INSTALL_QMLTYPES TRUE
- QT_QML_MODULE_VERSION ${CMAKE_PROJECT_VERSION}
- QT_QML_MODULE_URI QtQuick.Layouts
- QT_QMLTYPES_FILENAME plugins.qmltypes
- QT_QML_MODULE_INSTALL_DIR "${INSTALL_QMLDIR}/QtQuick/Layouts"
-)
-
-qt6_qml_type_registration(QuickLayouts)
+ GENERATE_CPP_EXPORTS
+ )
diff --git a/src/quicklayouts/qquickgridlayoutengine.cpp b/src/quicklayouts/qquickgridlayoutengine.cpp
index 5275d70c39..82d229befb 100644
--- a/src/quicklayouts/qquickgridlayoutengine.cpp
+++ b/src/quicklayouts/qquickgridlayoutengine.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 "qquickitem.h"
#include "qquickgridlayoutengine_p.h"
@@ -51,11 +15,14 @@ void QQuickGridLayoutEngine::setAlignment(QQuickItem *quickItem, Qt::Alignment a
}
}
-Qt::Alignment QQuickGridLayoutEngine::alignment(QQuickItem *quickItem) const
+void QQuickGridLayoutEngine::setStretchFactor(QQuickItem *quickItem, int stretch,
+ Qt::Orientation orientation)
{
- if (QGridLayoutItem *item = findLayoutItem(quickItem))
- return item->alignment();
- return {};
+ Q_ASSERT(stretch >= -1); // -1 is reset
+ if (QGridLayoutItem *item = findLayoutItem(quickItem)) {
+ item->setStretchFactor(stretch, orientation);
+ invalidate();
+ }
}
QT_END_NAMESPACE
diff --git a/src/quicklayouts/qquickgridlayoutengine_p.h b/src/quicklayouts/qquickgridlayoutengine_p.h
index ff42fa4d43..047d214655 100644
--- a/src/quicklayouts/qquickgridlayoutengine_p.h
+++ b/src/quicklayouts/qquickgridlayoutengine_p.h
@@ -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
#ifndef QQUICKGRIDLAYOUTENGINE_P_H
#define QQUICKGRIDLAYOUTENGINE_P_H
@@ -78,7 +42,7 @@ public:
if (!sizeHintCacheDirty)
return cachedSizeHints;
- QQuickLayout::effectiveSizeHints_helper(m_item, cachedSizeHints, 0, useFallbackToWidthOrHeight);
+ QQuickLayout::effectiveSizeHints_helper(m_item, cachedSizeHints, nullptr, useFallbackToWidthOrHeight);
useFallbackToWidthOrHeight = false;
sizeHintCacheDirty = false;
@@ -122,6 +86,8 @@ public:
}
}
+ inline virtual QString toString() const override { return QDebug::toString(m_item); }
+
QQuickItem *layoutItem() const { return m_item; }
QQuickItem *m_item;
@@ -145,7 +111,7 @@ public:
QQuickGridLayoutItem *findLayoutItem(QQuickItem *layoutItem) const
{
- for (int i = q_items.count() - 1; i >= 0; --i) {
+ for (int i = q_items.size() - 1; i >= 0; --i) {
QQuickGridLayoutItem *item = static_cast<QQuickGridLayoutItem*>(q_items.at(i));
if (item->layoutItem() == layoutItem)
return item;
@@ -154,7 +120,8 @@ public:
}
void setAlignment(QQuickItem *quickItem, Qt::Alignment alignment);
- Qt::Alignment alignment(QQuickItem *quickItem) const;
+
+ void setStretchFactor(QQuickItem *quickItem, int stretch, Qt::Orientation orientation);
};
diff --git a/src/quicklayouts/qquicklayout.cpp b/src/quicklayouts/qquicklayout.cpp
index 7af6bd86af..f38bdfd396 100644
--- a/src/quicklayouts/qquicklayout.cpp
+++ b/src/quicklayouts/qquicklayout.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 "qquicklayout_p.h"
#include <QEvent>
@@ -48,7 +12,7 @@
/*!
\qmltype Layout
- \instantiates QQuickLayoutAttached
+ //! \instantiates QQuickLayoutAttached
\inqmlmodule QtQuick.Layouts
\ingroup layouts
\brief Provides attached properties for items pushed onto a \l GridLayout,
@@ -73,7 +37,11 @@
The \l fillWidth and \l fillHeight properties can either be \c true or \c false. If they are \c
false, the item's size will be fixed to its preferred size. Otherwise, it will grow or shrink
- between its minimum and maximum size as the layout is resized.
+ between its minimum and maximum size as the layout is resized. If there are multiple items
+ with \l fillWidth (or \l fillHeight) set to \c true, the layout will grow or shrink the items
+ relative to the ratio of their preferred size.
+
+ For more details on the layout algorithm, see also the \l {Qt Quick Layouts Overview}.
\note Do not bind to the x, y, width, or height properties of items in a layout,
as this would conflict with the goals of Layout, and can also cause binding loops.
@@ -117,10 +85,14 @@ QQuickLayoutAttached::QQuickLayoutAttached(QObject *parent)
m_isMaximumWidthSet(false),
m_isMaximumHeightSet(false),
m_changesNotificationEnabled(true),
+ m_isMarginsSet(false),
m_isLeftMarginSet(false),
m_isTopMarginSet(false),
m_isRightMarginSet(false),
- m_isBottomMarginSet(false)
+ m_isBottomMarginSet(false),
+ m_isAlignmentSet(false),
+ m_horizontalStretch(-1),
+ m_verticalStretch(-1)
{
}
@@ -331,15 +303,16 @@ void QQuickLayoutAttached::setMaximumImplicitSize(const QSizeF &sz)
If this property is \c true, the item will be as wide as possible while respecting
the given constraints. If the property is \c false, the item will have a fixed width
set to the preferred width.
- The default is \c false, except for layouts themselves, which default to \c true.
+ The default depends on implicit (built-in) size policy of item.
\sa fillHeight
*/
void QQuickLayoutAttached::setFillWidth(bool fill)
{
+ bool oldFillWidth = fillWidth();
m_isFillWidthSet = true;
- if (m_fillWidth != fill) {
- m_fillWidth = fill;
+ m_fillWidth = fill;
+ if (oldFillWidth != fill) {
invalidateItem();
emit fillWidthChanged();
}
@@ -351,15 +324,16 @@ void QQuickLayoutAttached::setFillWidth(bool fill)
If this property is \c true, the item will be as tall as possible while respecting
the given constraints. If the property is \c false, the item will have a fixed height
set to the preferred height.
- The default is \c false, except for layouts themselves, which default to \c true.
+ The default depends on implicit (built-in) size policy of the item.
\sa fillWidth
*/
void QQuickLayoutAttached::setFillHeight(bool fill)
{
+ bool oldFillHeight = fillHeight();
m_isFillHeightSet = true;
- if (m_fillHeight != fill) {
- m_fillHeight = fill;
+ m_fillHeight = fill;
+ if (oldFillHeight != fill) {
invalidateItem();
emit fillHeightChanged();
}
@@ -433,6 +407,7 @@ void QQuickLayoutAttached::setColumn(int column)
*/
void QQuickLayoutAttached::setAlignment(Qt::Alignment align)
{
+ m_isAlignmentSet = true;
if (align != m_alignment) {
m_alignment = align;
if (QQuickLayout *layout = parentLayout()) {
@@ -444,6 +419,80 @@ void QQuickLayoutAttached::setAlignment(Qt::Alignment align)
}
/*!
+ \qmlattachedproperty int Layout::horizontalStretchFactor
+
+ This property allows you to specify the horizontal stretch factor. By default, two identical
+ items arranged in a linear layout will have the same size, but if the first item has a
+ stretch factor of 1 and the second item has a stretch factor of 2, the first item will \e
+ aim to get 1/3 of the available space, and the second will \e aim to get 2/3 of the available
+ space. Note that, whether they become exactly 1/3 and 2/3 of the available space depends on
+ their size hints. This is because when e.g a horizontal layout is shown in its minimum width
+ all its child items will consequently also have their minimum width.
+
+ Likewise, when a horizontal layout has its preferred width, all child items will have their
+ preferred widths, and when a horizontal layout has its maximum width, all child items will have
+ their maximum widths. This strategy is applied regardless of what the individual stretch
+ factors are. As a consequence of this, stretch factors will only determine the growth rate of
+ child items \e between the preferredWidth and maximumWidth range.
+
+ The default value is \c -1, which means that no stretch factor is applied.
+
+ \note This requires that Layout::fillWidth is set to true
+
+ \since Qt 6.5
+
+ \sa verticalStretchFactor
+*/
+void QQuickLayoutAttached::setHorizontalStretchFactor(int factor)
+{
+ if (factor != m_horizontalStretch) {
+ m_horizontalStretch = factor;
+ if (QQuickLayout *layout = parentLayout()) {
+ layout->setStretchFactor(item(), factor, Qt::Horizontal);
+ invalidateItem();
+ }
+ emit horizontalStretchFactorChanged();
+ }
+}
+
+/*!
+ \qmlattachedproperty int Layout::verticalStretchFactor
+
+ This property allows you to specify the vertical stretch factor. By default, two identical
+ items arranged in a linear layout will have the same size, but if the first item has a
+ stretch factor of 1 and the second item has a stretch factor of 2, the first item will \e
+ aim to get 1/3 of the available space, and the second will \e aim to get 2/3 of the available
+ space. Note that, whether they become exactly 1/3 and 2/3 of the available space depends on
+ their size hints. This is because when e.g a vertical layout is shown in its minimum height
+ all its child items will consequently also have their minimum height.
+
+ Likewise, when a vertical layout has its preferred height, all child items will have their
+ preferred heights, and when a vertical layout has its maximum height, all child items will have
+ their maximum heights. This strategy is applied regardless of what the individual stretch
+ factors are. As a consequence of this, stretch factors will only determine the growth rate of
+ child items \e between the preferredHeight and maximumHeight range.
+
+ The default value is \c -1, which means that no stretch factor is applied.
+
+ \note This requires that Layout::fillHeight is set to true
+
+ \since Qt 6.5
+
+ \sa horizontalStretchFactor
+*/
+void QQuickLayoutAttached::setVerticalStretchFactor(int factor)
+{
+ if (factor != m_verticalStretch) {
+ m_verticalStretch = factor;
+ if (QQuickLayout *layout = parentLayout()) {
+ layout->setStretchFactor(item(), factor, Qt::Vertical);
+ invalidateItem();
+ }
+ emit verticalStretchFactorChanged();
+ }
+}
+
+/*!
\qmlattachedproperty real Layout::margins
Sets the margins outside of an item to all have the same value. The item
@@ -474,6 +523,7 @@ void QQuickLayoutAttached::setAlignment(Qt::Alignment align)
*/
void QQuickLayoutAttached::setMargins(qreal m)
{
+ m_isMarginsSet = true;
if (m == m_defaultMargins)
return;
@@ -693,28 +743,10 @@ QQuickItem *QQuickLayoutAttached::item() const
return qobject_cast<QQuickItem *>(parent());
}
-qreal QQuickLayoutPrivate::getImplicitWidth() const
+void QQuickLayoutPrivate::applySizeHints() const
{
Q_Q(const QQuickLayout);
- if (q->invalidated()) {
- QQuickLayoutPrivate *that = const_cast<QQuickLayoutPrivate*>(this);
- that->implicitWidth = q->sizeHint(Qt::PreferredSize).width();
- }
- return implicitWidth;
-}
-qreal QQuickLayoutPrivate::getImplicitHeight() const
-{
- Q_Q(const QQuickLayout);
- if (q->invalidated()) {
- QQuickLayoutPrivate *that = const_cast<QQuickLayoutPrivate*>(this);
- that->implicitHeight = q->sizeHint(Qt::PreferredSize).height();
- }
- return implicitHeight;
-}
-
-void QQuickLayoutPrivate::applySizeHints() const {
- Q_Q(const QQuickLayout);
QQuickLayout *that = const_cast<QQuickLayout*>(q);
QQuickLayoutAttached *info = attachedLayoutObject(that, true);
@@ -762,16 +794,10 @@ void QQuickLayout::updatePolish()
// Might have become "undirty" before we reach this updatePolish()
// (e.g. if somebody queried for implicitWidth it will immediately
// calculate size hints)
- if (invalidated()) {
- // Ensure that all invalidated layouts are synced and valid again. Since
- // ensureLayoutItemsUpdated() will also call applySizeHints(), and sizeHint() will call its
- // childrens sizeHint(), and sizeHint() will call ensureLayoutItemsUpdated(), this will be done
- // recursive as we want.
- // Note that we need to call ensureLayoutItemsUpdated() *before* we query width() and height(),
- // because width()/height() might return their implicitWidth/implicitHeight (e.g. for a layout
- // with no explicitly specified size, (nor anchors.fill: parent))
- ensureLayoutItemsUpdated();
- }
+ // Note that we need to call ensureLayoutItemsUpdated() *before* we query width() and height(),
+ // because width()/height() might return their implicitWidth/implicitHeight (e.g. for a layout
+ // with no explicitly specified size, (nor anchors.fill: parent))
+ ensureLayoutItemsUpdated(QQuickLayout::ApplySizeHints | QQuickLayout::Recursive);
rearrange(QSizeF(width(), height()));
m_inUpdatePolish = false;
qCDebug(lcQuickLayouts) << "updatePolish() LEAVING" << this;
@@ -786,6 +812,18 @@ void QQuickLayout::componentComplete()
d->m_isReady = true;
}
+void QQuickLayout::maybeSubscribeToBaseLineOffsetChanges(QQuickItem *item)
+{
+ QQuickLayoutAttached *info = attachedLayoutObject(item, false);
+ if (info) {
+ if (info->alignment() == Qt::AlignBaseline && static_cast<QQuickLayout*>(item->parentItem()) == this) {
+ qmlobject_connect(item, QQuickItem, SIGNAL(baselineOffsetChanged(qreal)), this, QQuickLayout, SLOT(invalidateSenderItem()));
+ } else {
+ qmlobject_disconnect(item, QQuickItem, SIGNAL(baselineOffsetChanged(qreal)), this, QQuickLayout, SLOT(invalidateSenderItem()));
+ }
+ }
+}
+
void QQuickLayout::invalidate(QQuickItem * /*childItem*/)
{
Q_D(QQuickLayout);
@@ -797,43 +835,26 @@ void QQuickLayout::invalidate(QQuickItem * /*childItem*/)
d->m_dirtyArrangement = true;
if (!qobject_cast<QQuickLayout *>(parentItem())) {
-
- if (m_inUpdatePolish)
- ++m_polishInsideUpdatePolish;
- else
- m_polishInsideUpdatePolish = 0;
-
- if (m_polishInsideUpdatePolish <= 2) {
- // allow at most two consecutive loops in order to respond to height-for-width
- // (e.g QQuickText changes implicitHeight when its width gets changed)
- qCDebug(lcQuickLayouts) << "QQuickLayout::invalidate(), polish()";
- polish();
+ polish();
+
+ if (m_inUpdatePolish) {
+ if (++m_polishInsideUpdatePolish > 2)
+ // allow at most two consecutive loops in order to respond to height-for-width
+ // (e.g QQuickText changes implicitHeight when its width gets changed)
+ qCDebug(lcQuickLayouts) << "Layout polish loop detected for " << this
+ << ". The polish request will still be scheduled.";
} else {
- qWarning() << "Qt Quick Layouts: Polish loop detected. Aborting after two iterations.";
+ m_polishInsideUpdatePolish = 0;
}
}
}
-bool QQuickLayout::shouldIgnoreItem(QQuickItem *child, QQuickLayoutAttached *&info, QSizeF *sizeHints) const
+bool QQuickLayout::shouldIgnoreItem(QQuickItem *child) const
{
- bool ignoreItem = true;
QQuickItemPrivate *childPrivate = QQuickItemPrivate::get(child);
- if (childPrivate->explicitVisible) {
- effectiveSizeHints_helper(child, sizeHints, &info, true);
- QSizeF effectiveMaxSize = sizeHints[Qt::MaximumSize];
- if (!effectiveMaxSize.isNull()) {
- QSizeF &prefS = sizeHints[Qt::PreferredSize];
- if (effectiveSizePolicy_helper(child, Qt::Horizontal, info) == QLayoutPolicy::Fixed)
- effectiveMaxSize.setWidth(prefS.width());
- if (effectiveSizePolicy_helper(child, Qt::Vertical, info) == QLayoutPolicy::Fixed)
- effectiveMaxSize.setHeight(prefS.height());
- }
- ignoreItem = effectiveMaxSize.isNull();
- }
-
+ bool ignoreItem = !childPrivate->explicitVisible;
if (!ignoreItem && childPrivate->isTransparentForPositioner())
ignoreItem = true;
-
return ignoreItem;
}
@@ -844,14 +865,35 @@ void QQuickLayout::checkAnchors(QQuickItem *item) const
qmlWarning(item) << "Detected anchors on an item that is managed by a layout. This is undefined behavior; use Layout.alignment instead.";
}
-void QQuickLayout::ensureLayoutItemsUpdated() const
+void QQuickLayout::ensureLayoutItemsUpdated(EnsureLayoutItemsUpdatedOptions options) const
{
Q_D(const QQuickLayout);
if (!invalidated())
return;
+ qCDebug(lcQuickLayouts) << "ENTER QQuickLayout::ensureLayoutItemsUpdated()" << this << options;
+ QQuickLayoutPrivate *priv = const_cast<QQuickLayoutPrivate*>(d);
+
+ // breadth-first
+ // must update the root first, and continue towards the leaf nodes.
+ // Otherwise, we wouldn't know which children to traverse to
const_cast<QQuickLayout*>(this)->updateLayoutItems();
+
+ // make invalidate() return true
d->m_dirty = false;
- d->applySizeHints();
+
+ if (options & Recursive) {
+ for (int i = 0; i < itemCount(); ++i) {
+ QQuickItem *itm = itemAt(i);
+ if (QQuickLayout *lay = qobject_cast<QQuickLayout*>(itm)) {
+ lay->ensureLayoutItemsUpdated(options);
+ }
+ }
+ }
+
+ // size hints are updated depth-first (parent size hints depends on their childrens size hints)
+ if (options & ApplySizeHints)
+ priv->applySizeHints();
+ qCDebug(lcQuickLayouts) << "LEAVE QQuickLayout::ensureLayoutItemsUpdated()" << this;
}
@@ -860,7 +902,7 @@ void QQuickLayout::itemChange(ItemChange change, const ItemChangeData &value)
if (change == ItemChildAddedChange) {
Q_D(QQuickLayout);
QQuickItem *item = value.item;
- qmlobject_connect(item, QQuickItem, SIGNAL(baselineOffsetChanged(qreal)), this, QQuickLayout, SLOT(invalidateSenderItem()));
+ maybeSubscribeToBaseLineOffsetChanges(item);
QQuickItemPrivate::get(item)->addItemChangeListener(this, changeTypes);
d->m_hasItemChangeListeners = true;
qCDebug(lcQuickLayouts) << "ChildAdded" << item;
@@ -868,7 +910,7 @@ void QQuickLayout::itemChange(ItemChange change, const ItemChangeData &value)
invalidate();
} else if (change == ItemChildRemovedChange) {
QQuickItem *item = value.item;
- qmlobject_disconnect(item, QQuickItem, SIGNAL(baselineOffsetChanged(qreal)), this, QQuickLayout, SLOT(invalidateSenderItem()));
+ maybeSubscribeToBaseLineOffsetChanges(item);
QQuickItemPrivate::get(item)->removeItemChangeListener(this, changeTypes);
qCDebug(lcQuickLayouts) << "ChildRemoved" << item;
if (isReady())
@@ -881,7 +923,7 @@ void QQuickLayout::geometryChange(const QRectF &newGeometry, const QRectF &oldGe
{
Q_D(QQuickLayout);
QQuickItem::geometryChange(newGeometry, oldGeometry);
- if (d->m_disableRearrange || !isReady() || !newGeometry.isValid())
+ if (invalidated() || d->m_disableRearrange || !isReady())
return;
qCDebug(lcQuickLayouts) << "QQuickLayout::geometryChange" << newGeometry << oldGeometry;
@@ -913,6 +955,7 @@ bool QQuickLayout::isReady() const
void QQuickLayout::deactivateRecur()
{
if (d_func()->m_hasItemChangeListeners) {
+ ensureLayoutItemsUpdated();
for (int i = 0; i < itemCount(); ++i) {
QQuickItem *item = itemAt(i);
// When deleting a layout with children, there is no reason for the children to inform the layout that their
@@ -1210,7 +1253,15 @@ void QQuickLayout::effectiveSizeHints_helper(QQuickItem *item, QSizeF *cachedSiz
*/
QLayoutPolicy::Policy QQuickLayout::effectiveSizePolicy_helper(QQuickItem *item, Qt::Orientation orientation, QQuickLayoutAttached *info)
{
- bool fillExtent = false;
+ bool fillExtent([&]{
+ QLayoutPolicy::Policy policy{QLayoutPolicy::Fixed};
+ if (item && QGuiApplication::testAttribute(Qt::AA_QtQuickUseDefaultSizePolicy)) {
+ QLayoutPolicy sizePolicy = QQuickItemPrivate::get(item)->sizePolicy();
+ policy = (orientation == Qt::Horizontal) ? sizePolicy.horizontalPolicy() : sizePolicy.verticalPolicy();
+ }
+ return (policy == QLayoutPolicy::Preferred);
+ }());
+
bool isSet = false;
if (info) {
if (orientation == Qt::Horizontal) {
@@ -1223,8 +1274,8 @@ QLayoutPolicy::Policy QQuickLayout::effectiveSizePolicy_helper(QQuickItem *item,
}
if (!isSet && qobject_cast<QQuickLayout*>(item))
fillExtent = true;
- return fillExtent ? QLayoutPolicy::Preferred : QLayoutPolicy::Fixed;
+ return fillExtent ? QLayoutPolicy::Preferred : QLayoutPolicy::Fixed;
}
void QQuickLayout::_q_dumpLayoutTree() const
@@ -1306,3 +1357,5 @@ void QQuickLayout::dumpLayoutTreeRecursive(int level, QString &buf) const
}
QT_END_NAMESPACE
+
+#include "moc_qquicklayout_p.cpp"
diff --git a/src/quicklayouts/qquicklayout_p.h b/src/quicklayouts/qquicklayout_p.h
index 74eb348928..f0ccc6dbf5 100644
--- a/src/quicklayouts/qquicklayout_p.h
+++ b/src/quicklayouts/qquicklayout_p.h
@@ -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
#ifndef QQUICKLAYOUT_P_H
#define QQUICKLAYOUT_P_H
@@ -53,10 +17,13 @@
#include <QPointer>
#include <QQuickItem>
+#include <QtCore/qflags.h>
+
#include <QtQuickLayouts/private/qquicklayoutglobal_p.h>
#include <private/qquickitem_p.h>
#include <QtQuick/private/qquickitemchangelistener_p.h>
#include <QtGui/private/qlayoutpolicy_p.h>
+#include <QtGui/qguiapplication.h>
QT_BEGIN_NAMESPACE
@@ -64,7 +31,7 @@ class QQuickLayoutAttached;
Q_DECLARE_LOGGING_CATEGORY(lcQuickLayouts)
class QQuickLayoutPrivate;
-class Q_QUICKLAYOUT_PRIVATE_EXPORT QQuickLayout : public QQuickItem, public QQuickItemChangeListener
+class Q_QUICKLAYOUTS_EXPORT QQuickLayout : public QQuickItem, public QQuickItemChangeListener
{
Q_OBJECT
@@ -81,7 +48,14 @@ public:
NSizes
};
- explicit QQuickLayout(QQuickLayoutPrivate &dd, QQuickItem *parent = 0);
+ enum EnsureLayoutItemsUpdatedOption {
+ Recursive = 0b001,
+ ApplySizeHints = 0b010
+ };
+
+ Q_DECLARE_FLAGS(EnsureLayoutItemsUpdatedOptions, EnsureLayoutItemsUpdatedOption)
+
+ explicit QQuickLayout(QQuickLayoutPrivate &dd, QQuickItem *parent = nullptr);
~QQuickLayout();
static QQuickLayoutAttached *qmlAttachedProperties(QObject *object);
@@ -90,9 +64,12 @@ public:
void componentComplete() override;
virtual QSizeF sizeHint(Qt::SizeHint whichSizeHint) const = 0;
virtual void setAlignment(QQuickItem *item, Qt::Alignment align) = 0;
- virtual void invalidate(QQuickItem * childItem = 0);
+ virtual void setStretchFactor(QQuickItem *item, int stretchFactor, Qt::Orientation orient) = 0;
+
+ virtual void invalidate(QQuickItem * childItem = nullptr);
virtual void updateLayoutItems() = 0;
- void ensureLayoutItemsUpdated() const;
+
+ void ensureLayoutItemsUpdated(EnsureLayoutItemsUpdatedOptions options = {}) const;
// iterator
virtual QQuickItem *itemAt(int index) const = 0;
@@ -102,7 +79,7 @@ public:
static void effectiveSizeHints_helper(QQuickItem *item, QSizeF *cachedSizeHints, QQuickLayoutAttached **info, bool useFallbackToWidthOrHeight);
static QLayoutPolicy::Policy effectiveSizePolicy_helper(QQuickItem *item, Qt::Orientation orientation, QQuickLayoutAttached *info);
- bool shouldIgnoreItem(QQuickItem *child, QQuickLayoutAttached *&info, QSizeF *sizeHints) const;
+ bool shouldIgnoreItem(QQuickItem *child) const;
void checkAnchors(QQuickItem *item) const;
void itemChange(ItemChange change, const ItemChangeData &value) override;
@@ -121,6 +98,8 @@ public:
void itemDestroyed(QQuickItem *item) override;
void itemVisibilityChanged(QQuickItem *item) override;
+ void maybeSubscribeToBaseLineOffsetChanges(QQuickItem *item);
+
Q_INVOKABLE void _q_dumpLayoutTree() const;
void dumpLayoutTreeRecursive(int level, QString &buf) const;
@@ -133,7 +112,7 @@ protected:
NOrientations
};
-protected slots:
+protected Q_SLOTS:
void invalidateSenderItem();
private:
@@ -145,15 +124,17 @@ private:
friend class QQuickLayoutAttached;
};
+Q_DECLARE_OPERATORS_FOR_FLAGS(QQuickLayout::EnsureLayoutItemsUpdatedOptions)
class QQuickLayoutPrivate : public QQuickItemPrivate
{
Q_DECLARE_PUBLIC(QQuickLayout)
public:
- QQuickLayoutPrivate() : m_dirty(true), m_dirtyArrangement(true), m_isReady(false), m_disableRearrange(true), m_hasItemChangeListeners(false) {}
-
- qreal getImplicitWidth() const override;
- qreal getImplicitHeight() const override;
+ QQuickLayoutPrivate() : m_dirty(true)
+ , m_dirtyArrangement(true)
+ , m_isReady(false)
+ , m_disableRearrange(true)
+ , m_hasItemChangeListeners(false) {}
void applySizeHints() const;
@@ -173,62 +154,77 @@ protected:
unsigned m_isReady : 1;
unsigned m_disableRearrange : 1;
unsigned m_hasItemChangeListeners : 1; // if false, we don't need to remove its item change listeners...
- mutable QSet<QQuickItem *> m_ignoredItems;
};
-class QQuickLayoutAttached : public QObject
+class Q_QUICKLAYOUTS_EXPORT QQuickLayoutAttached : public QObject
{
Q_OBJECT
- Q_PROPERTY(qreal minimumWidth READ minimumWidth WRITE setMinimumWidth NOTIFY minimumWidthChanged)
- Q_PROPERTY(qreal minimumHeight READ minimumHeight WRITE setMinimumHeight NOTIFY minimumHeightChanged)
- Q_PROPERTY(qreal preferredWidth READ preferredWidth WRITE setPreferredWidth NOTIFY preferredWidthChanged)
- Q_PROPERTY(qreal preferredHeight READ preferredHeight WRITE setPreferredHeight NOTIFY preferredHeightChanged)
- Q_PROPERTY(qreal maximumWidth READ maximumWidth WRITE setMaximumWidth NOTIFY maximumWidthChanged)
- Q_PROPERTY(qreal maximumHeight READ maximumHeight WRITE setMaximumHeight NOTIFY maximumHeightChanged)
- Q_PROPERTY(bool fillHeight READ fillHeight WRITE setFillHeight NOTIFY fillHeightChanged)
- Q_PROPERTY(bool fillWidth READ fillWidth WRITE setFillWidth NOTIFY fillWidthChanged)
- Q_PROPERTY(int row READ row WRITE setRow NOTIFY rowChanged)
- Q_PROPERTY(int column READ column WRITE setColumn NOTIFY columnChanged)
- Q_PROPERTY(int rowSpan READ rowSpan WRITE setRowSpan NOTIFY rowSpanChanged)
- Q_PROPERTY(int columnSpan READ columnSpan WRITE setColumnSpan NOTIFY columnSpanChanged)
- Q_PROPERTY(Qt::Alignment alignment READ alignment WRITE setAlignment NOTIFY alignmentChanged)
-
- Q_PROPERTY(qreal margins READ margins WRITE setMargins NOTIFY marginsChanged)
- Q_PROPERTY(qreal leftMargin READ leftMargin WRITE setLeftMargin RESET resetLeftMargin NOTIFY leftMarginChanged)
- Q_PROPERTY(qreal topMargin READ topMargin WRITE setTopMargin RESET resetTopMargin NOTIFY topMarginChanged)
- Q_PROPERTY(qreal rightMargin READ rightMargin WRITE setRightMargin RESET resetRightMargin NOTIFY rightMarginChanged)
- Q_PROPERTY(qreal bottomMargin READ bottomMargin WRITE setBottomMargin RESET resetBottomMargin NOTIFY bottomMarginChanged)
+ Q_PROPERTY(qreal minimumWidth READ minimumWidth WRITE setMinimumWidth NOTIFY minimumWidthChanged FINAL)
+ Q_PROPERTY(qreal minimumHeight READ minimumHeight WRITE setMinimumHeight NOTIFY minimumHeightChanged FINAL)
+ Q_PROPERTY(qreal preferredWidth READ preferredWidth WRITE setPreferredWidth NOTIFY preferredWidthChanged FINAL)
+ Q_PROPERTY(qreal preferredHeight READ preferredHeight WRITE setPreferredHeight NOTIFY preferredHeightChanged FINAL)
+ Q_PROPERTY(qreal maximumWidth READ maximumWidth WRITE setMaximumWidth NOTIFY maximumWidthChanged FINAL)
+ Q_PROPERTY(qreal maximumHeight READ maximumHeight WRITE setMaximumHeight NOTIFY maximumHeightChanged FINAL)
+ Q_PROPERTY(bool fillHeight READ fillHeight WRITE setFillHeight NOTIFY fillHeightChanged FINAL)
+ Q_PROPERTY(bool fillWidth READ fillWidth WRITE setFillWidth NOTIFY fillWidthChanged FINAL)
+ Q_PROPERTY(int row READ row WRITE setRow NOTIFY rowChanged FINAL)
+ Q_PROPERTY(int column READ column WRITE setColumn NOTIFY columnChanged FINAL)
+ Q_PROPERTY(int rowSpan READ rowSpan WRITE setRowSpan NOTIFY rowSpanChanged FINAL)
+ Q_PROPERTY(int columnSpan READ columnSpan WRITE setColumnSpan NOTIFY columnSpanChanged FINAL)
+ Q_PROPERTY(Qt::Alignment alignment READ alignment WRITE setAlignment NOTIFY alignmentChanged FINAL)
+ Q_PROPERTY(int horizontalStretchFactor READ horizontalStretchFactor WRITE setHorizontalStretchFactor NOTIFY horizontalStretchFactorChanged FINAL)
+ Q_PROPERTY(int verticalStretchFactor READ verticalStretchFactor WRITE setVerticalStretchFactor NOTIFY verticalStretchFactorChanged FINAL)
+
+ Q_PROPERTY(qreal margins READ margins WRITE setMargins NOTIFY marginsChanged FINAL)
+ Q_PROPERTY(qreal leftMargin READ leftMargin WRITE setLeftMargin RESET resetLeftMargin NOTIFY leftMarginChanged FINAL)
+ Q_PROPERTY(qreal topMargin READ topMargin WRITE setTopMargin RESET resetTopMargin NOTIFY topMarginChanged FINAL)
+ Q_PROPERTY(qreal rightMargin READ rightMargin WRITE setRightMargin RESET resetRightMargin NOTIFY rightMarginChanged FINAL)
+ Q_PROPERTY(qreal bottomMargin READ bottomMargin WRITE setBottomMargin RESET resetBottomMargin NOTIFY bottomMarginChanged FINAL)
public:
QQuickLayoutAttached(QObject *object);
qreal minimumWidth() const { return !m_isMinimumWidthSet ? sizeHint(Qt::MinimumSize, Qt::Horizontal) : m_minimumWidth; }
void setMinimumWidth(qreal width);
+ bool isMinimumWidthSet() const {return m_isMinimumWidthSet; }
qreal minimumHeight() const { return !m_isMinimumHeightSet ? sizeHint(Qt::MinimumSize, Qt::Vertical) : m_minimumHeight; }
void setMinimumHeight(qreal height);
+ bool isMinimumHeightSet() const {return m_isMinimumHeightSet; }
qreal preferredWidth() const { return m_preferredWidth; }
void setPreferredWidth(qreal width);
+ bool isPreferredWidthSet() const {return m_preferredWidth > -1; }
qreal preferredHeight() const { return m_preferredHeight; }
void setPreferredHeight(qreal width);
+ bool isPreferredHeightSet() const {return m_preferredHeight > -1; }
qreal maximumWidth() const { return !m_isMaximumWidthSet ? sizeHint(Qt::MaximumSize, Qt::Horizontal) : m_maximumWidth; }
void setMaximumWidth(qreal width);
+ bool isMaximumWidthSet() const {return m_isMaximumWidthSet; }
qreal maximumHeight() const { return !m_isMaximumHeightSet ? sizeHint(Qt::MaximumSize, Qt::Vertical) : m_maximumHeight; }
void setMaximumHeight(qreal height);
+ bool isMaximumHeightSet() const {return m_isMaximumHeightSet; }
void setMinimumImplicitSize(const QSizeF &sz);
void setMaximumImplicitSize(const QSizeF &sz);
- bool fillWidth() const { return m_fillWidth; }
+ bool fillWidth() const {
+ if (auto *itemPriv = itemForSizePolicy(m_isFillWidthSet))
+ return (itemPriv->sizePolicy().horizontalPolicy() == QLayoutPolicy::Preferred);
+ return m_fillWidth;
+ }
void setFillWidth(bool fill);
bool isFillWidthSet() const { return m_isFillWidthSet; }
- bool fillHeight() const { return m_fillHeight; }
+ bool fillHeight() const {
+ if (auto *itemPriv = itemForSizePolicy(m_isFillHeightSet))
+ return (itemPriv->sizePolicy().verticalPolicy() == QLayoutPolicy::Preferred);
+ return m_fillHeight;
+ }
void setFillHeight(bool fill);
bool isFillHeightSet() const { return m_isFillHeightSet; }
@@ -246,25 +242,38 @@ public:
Qt::Alignment alignment() const { return m_alignment; }
void setAlignment(Qt::Alignment align);
+ bool isAlignmentSet() const {return m_isAlignmentSet; }
+
+ int horizontalStretchFactor() const { return m_horizontalStretch; }
+ void setHorizontalStretchFactor(int stretchFactor);
+ bool isHorizontalStretchFactorSet() const { return m_horizontalStretch > -1; }
+ int verticalStretchFactor() const { return m_verticalStretch; }
+ void setVerticalStretchFactor(int stretchFactor);
+ bool isVerticalStretchFactorSet() const { return m_verticalStretch > -1; }
qreal margins() const { return m_defaultMargins; }
void setMargins(qreal m);
+ bool isMarginsSet() const { return m_isMarginsSet; }
qreal leftMargin() const { return m_isLeftMarginSet ? m_margins.left() : m_defaultMargins; }
void setLeftMargin(qreal m);
void resetLeftMargin();
+ bool isLeftMarginSet() const { return m_isLeftMarginSet; }
qreal topMargin() const { return m_isTopMarginSet ? m_margins.top() : m_defaultMargins; }
void setTopMargin(qreal m);
void resetTopMargin();
+ bool isTopMarginSet() const {return m_isTopMarginSet; }
qreal rightMargin() const { return m_isRightMarginSet ? m_margins.right() : m_defaultMargins; }
void setRightMargin(qreal m);
void resetRightMargin();
+ bool isRightMarginSet() const { return m_isRightMarginSet; }
qreal bottomMargin() const { return m_isBottomMarginSet ? m_margins.bottom() : m_defaultMargins; }
void setBottomMargin(qreal m);
void resetBottomMargin();
+ bool isBottomMarginSet() const { return m_isBottomMarginSet; }
QMarginsF qMargins() const {
return QMarginsF(leftMargin(), topMargin(), rightMargin(), bottomMargin());
@@ -303,7 +312,16 @@ public:
return false;
}
-signals:
+ QQuickItemPrivate *itemForSizePolicy(bool isFillSet) const
+ {
+ QQuickItemPrivate *itemPriv = nullptr;
+ if (!isFillSet && qobject_cast<QQuickItem *>(item()) &&
+ QGuiApplication::testAttribute(Qt::AA_QtQuickUseDefaultSizePolicy))
+ itemPriv = QQuickItemPrivate::get(item());
+ return itemPriv;
+ }
+
+Q_SIGNALS:
void minimumWidthChanged();
void minimumHeightChanged();
void preferredWidthChanged();
@@ -322,6 +340,8 @@ signals:
void rowSpanChanged();
void columnSpanChanged();
void alignmentChanged();
+ void horizontalStretchFactorChanged();
+ void verticalStretchFactorChanged();
private:
void invalidateItem();
@@ -358,11 +378,15 @@ private:
unsigned m_isMaximumWidthSet : 1;
unsigned m_isMaximumHeightSet : 1;
unsigned m_changesNotificationEnabled : 1;
+ unsigned m_isMarginsSet : 1;
unsigned m_isLeftMarginSet : 1;
unsigned m_isTopMarginSet : 1;
unsigned m_isRightMarginSet : 1;
unsigned m_isBottomMarginSet : 1;
+ unsigned m_isAlignmentSet : 1;
Qt::Alignment m_alignment;
+ int m_horizontalStretch;
+ int m_verticalStretch;
friend class QQuickLayout;
};
@@ -373,6 +397,4 @@ inline QQuickLayoutAttached *attachedLayoutObject(QQuickItem *item, bool create
QT_END_NAMESPACE
-QML_DECLARE_TYPE(QQuickLayout)
-
#endif // QQUICKLAYOUT_P_H
diff --git a/src/quicklayouts/qquicklayoutglobal_p.h b/src/quicklayouts/qquicklayoutglobal_p.h
index c63169bd93..8537aac835 100644
--- a/src/quicklayouts/qquicklayoutglobal_p.h
+++ b/src/quicklayouts/qquicklayoutglobal_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQuick 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) 2021 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
#ifndef QQUICKLAYOUTGLOBAL_P_H
#define QQUICKLAYOUTGLOBAL_P_H
@@ -52,24 +16,6 @@
//
#include <QtCore/qglobal.h>
-
-QT_BEGIN_NAMESPACE
-
-#if !defined(QT_STATIC)
-# if defined(QT_BUILD_QUICKLAYOUTS_LIB)
-# define Q_QUICKLAYOUT_EXPORT Q_DECL_EXPORT
-# else
-# define Q_QUICKLAYOUT_EXPORT Q_DECL_IMPORT
-# endif
-#else
-# define Q_QUICKLAYOUT_EXPORT
-#endif
-
-
-#define Q_QUICKLAYOUT_PRIVATE_EXPORT Q_QUICKLAYOUT_EXPORT
-
-QT_END_NAMESPACE
-
-void Q_QUICKLAYOUT_PRIVATE_EXPORT qml_register_types_QtQuick_Layouts();
+#include <QtQuickLayouts/qtquicklayoutsexports.h>
#endif // QQUICKLAYOUTGLOBAL_P_H
diff --git a/src/quicklayouts/qquicklayoutitemproxy.cpp b/src/quicklayouts/qquicklayoutitemproxy.cpp
new file mode 100644
index 0000000000..f690a2eae8
--- /dev/null
+++ b/src/quicklayouts/qquicklayoutitemproxy.cpp
@@ -0,0 +1,532 @@
+// Copyright (C) 2023 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 "qquicklayoutitemproxy_p.h"
+#include "qquicklayout_p.h"
+
+/*!
+ \qmltype LayoutItemProxy
+ \instantiates QQuickLayoutItemProxy
+ \inherits Item
+ \inqmlmodule QtQuick.Layouts
+ \ingroup layouts
+ \since QtQuick.Layouts 6.6
+ \brief The LayoutItemProxy class provides a placeholder for \l{QQuickItem}s
+ in layouts.
+
+ Some responsive layouts require different layout hierarchies for different
+ screen sizes, but the layout hierarchy is the same as the QML structure and
+ can therefore not be changed at runtime. LayoutItemProxy overcomes this
+ limitation by representing a \l{target} item within the layout. The
+ \l{target} item itself can be defined anywhere in the QML hierarchy. This
+ allows declaration of multiple layouts with the same content items. The
+ layouts can be shown and hidden to switch between them.
+
+ The LayoutItemProxy will try to take control of the \l{target} item if it
+ is \l [QML] {Item::}{visible}. Taking control will position and resize the
+ \l{target} item to match the position and size of the LayoutItemProxy.
+ Further, the LayoutItemProxy will set itself as the parent of the
+ \l{target} (to ensure event delivery and useful drawing order) and set the
+ visibility to \c true. Multiple LayoutItemProxies can \l{target} the same
+ item, but only one LayoutItemProxy can control an item at a time. Therefore
+ only one of the proxies targeting the same item should be visible at a
+ time. If multiple proxies target the same item but \e visible is set to
+ false for each proxy, the item will also be invisible.
+
+ All \l{Layout} attached properties of the \l {target}, as well as the
+ \l{QQuickItem::implicitWidth} and \l{QQuickItem::implicitHeight} of the
+ \l{target} are forwarded by the LayoutItemProxy. The LayoutItemProxy will
+ mimic the \l{target} as closely as possible in terms of \l{Layout}
+ properties and size. \l{Layout} attached properties can also be set
+ explicitly on the LayoutItemProxy which will stop the forwarding of the
+ \l {target} properties.
+
+ \section1 Example Usage
+
+ This is a minimalistic example, changing between two layouts using proxies
+ to use the same items in both layouts. The items that populate the layouts
+ can be defined at an arbitrary point in the QML structure.
+
+ \snippet layouts/simpleProxy.qml item definition
+
+ Then we can define the Layouts with LayoutItemProxys
+
+ \snippet layouts/simpleProxy.qml layout definition
+
+ We can switch now between the layouts, depending on a criterion of our
+ choice by toggling the visibility of the layouts on and off.
+
+ \snippet layouts/simpleProxy.qml layout choice
+
+ The two resulting layouts look like this:
+
+ \div {class="float-right"}
+ \inlineimage simpleProxy.png
+ \enddiv
+
+ The LayoutItemProxy can also be used without layouts, e.g. by anchoring it
+ to different items. A mix of real \l {Item}{Items} and proxy items is
+ equally possible, as well as nested structures of layouts and items.
+
+ \warning The LayoutItemProxy will set the parent of its target to itself.
+ Keep this in mind when referring to the parent of the target item.
+
+ \sa Item, GridLayout, RowLayout, ColumnLayout
+*/
+
+Q_LOGGING_CATEGORY(lcLayouts, "qt.quick.layouts")
+
+
+QQuickLayoutItemProxy::QQuickLayoutItemProxy(QQuickItem *parent)
+ : QQuickItem(*new QQuickLayoutItemProxyPrivate, parent)
+{
+
+}
+
+QQuickLayoutItemProxy::~QQuickLayoutItemProxy()
+{
+ Q_D(QQuickLayoutItemProxy);
+
+ if (!d->target)
+ return;
+
+ QQuickLayoutItemProxyAttachedData * attachedData = d->target->property("QQuickLayoutItemProxyAttachedData").value<QQuickLayoutItemProxyAttachedData*>();
+ // De-register this proxy from the proxies controlling the target
+ if (attachedData) {
+ if (attachedData->getControllingProxy() == this) {
+ attachedData->releaseControl(this);
+ d->target->setParentItem(nullptr);
+ }
+ attachedData->releaseProxy(this);
+ }
+ // The target item still has a QObject parent that takes care of its destrctuion.
+ // No need to invoke destruction of the target tiem from here.
+}
+
+/*! \internal
+ \brief QQuickLayoutItemProxy::geometryChange Reimplementation of
+ QQuickItem::geometryChange to update the target geometry too.
+*/
+void QQuickLayoutItemProxy::geometryChange(const QRectF &newGeom, const QRectF &oldGeom)
+{
+ QQuickItem::geometryChange(newGeom, oldGeom);
+ if (!isVisible())
+ return;
+
+ const QSizeF sz = newGeom.size();
+ QPointF pos(0., 0.);
+
+ if (QQuickItem *t = effectiveTarget()) {
+ if (QQuickLayoutItemProxyAttachedData * attachedData = target()->property("QQuickLayoutItemProxyAttachedData").value<QQuickLayoutItemProxyAttachedData*>()) {
+ if (attachedData->getControllingProxy() != this)
+ return;
+ }
+
+ // Should normally not be the case, except the user resets the parent
+ // This is a failsave for this case and positions the item correctly
+ if (t->parentItem() != this)
+ pos = t->parentItem()->mapFromGlobal(mapToGlobal(0, 0));
+
+ if (t->size() == sz && t->position() == pos && newGeom == oldGeom)
+ return;
+
+ t->setSize(sz);
+ t->setPosition(pos);
+ }
+}
+
+/*! \internal
+ \brief QQuickLayoutItemProxy::itemChange is a reimplementation of
+ QQuickItem::itemChange to react to changes in visibility.
+*/
+void QQuickLayoutItemProxy::itemChange(ItemChange c, const ItemChangeData &d)
+{
+ if (c == QQuickItem::ItemVisibleHasChanged)
+ {
+ maybeTakeControl();
+ }
+ QQuickItem::itemChange(c, d);
+}
+
+// Implementation of the slots to react to changes of the Layout attached properties.
+// If the target Layout propertie change, we change the proxy Layout properties accordingly
+// If the proxy Layout properties have been changed externally, we want to remove this binding.
+// The member variables m_expectProxy##Property##Change help us keep track about who invokes
+// the change of the parameter. If it is invoked by the target we expect a proxy property
+// change and will not remove the connection.
+#define propertyForwarding(property, Property) \
+ void QQuickLayoutItemProxy::target##Property##Changed() { \
+ Q_D(QQuickLayoutItemProxy); \
+ QQuickLayoutAttached *attTarget = attachedLayoutObject(target(), false); \
+ QQuickLayoutAttached *attProxy = attachedLayoutObject(this, false); \
+ if (!attTarget) return; \
+ if (attProxy->property() == attTarget->property()) \
+ return; \
+ d->m_expectProxy##Property##Change = true; \
+ attProxy->set##Property(attTarget->property()); \
+ } \
+ void QQuickLayoutItemProxy::proxy##Property##Changed() { \
+ Q_D(QQuickLayoutItemProxy); \
+ if (d->m_expectProxy##Property##Change) { \
+ d->m_expectProxy##Property##Change = false; \
+ return; \
+ } \
+ QQuickLayoutAttached *attTarget = attachedLayoutObject(target(), false); \
+ if (!attTarget) return; \
+ disconnect(attTarget, &QQuickLayoutAttached::property##Changed, this, &QQuickLayoutItemProxy::target##Property##Changed); \
+ }
+
+propertyForwarding(minimumWidth, MinimumWidth)
+propertyForwarding(minimumHeight, MinimumHeight)
+propertyForwarding(preferredWidth, PreferredWidth)
+propertyForwarding(preferredHeight, PreferredHeight)
+propertyForwarding(maximumWidth, MaximumWidth)
+propertyForwarding(maximumHeight, MaximumHeight)
+propertyForwarding(fillWidth, FillWidth)
+propertyForwarding(fillHeight, FillHeight)
+propertyForwarding(alignment, Alignment)
+propertyForwarding(horizontalStretchFactor, HorizontalStretchFactor)
+propertyForwarding(verticalStretchFactor, VerticalStretchFactor)
+propertyForwarding(margins, Margins)
+propertyForwarding(leftMargin, LeftMargin)
+propertyForwarding(topMargin, TopMargin)
+propertyForwarding(rightMargin, RightMargin)
+propertyForwarding(bottomMargin, BottomMargin)
+
+#undef propertyForwarding
+
+/*!
+ \qmlproperty Item LayoutItemProxy::target
+
+ This property holds the \l Item that the proxy should represent in a
+ \l {Layout} hierarchy.
+*/
+
+/*! \internal
+ \brief QQuickLayoutItemProxy::target
+ \return The target item of the proxy
+*/
+QQuickItem *QQuickLayoutItemProxy::target() const
+{
+ Q_D(const QQuickLayoutItemProxy);
+ return d->target;
+}
+
+/*! \internal
+ \brief QQuickLayoutItemProxy::setTarget sets the target
+ \param newTarget The item that the proxy stands in place for.
+
+ All layout properties of the target are connected to the layout properties
+ of the LayoutItemProxy. It the LayoutItemProxy is visible, it will try to
+ take control of the target.
+*/
+void QQuickLayoutItemProxy::setTarget(QQuickItem *newTarget)
+{
+ Q_D(QQuickLayoutItemProxy);
+
+ if (newTarget == d->target)
+ return;
+
+ d->target = newTarget;
+
+ if (newTarget) {
+
+ QQuickLayoutItemProxyAttachedData *attachedData;
+ if (newTarget->property("QQuickLayoutItemProxyAttachedData").isValid()) {
+ attachedData = newTarget->property("QQuickLayoutItemProxyAttachedData").value<QQuickLayoutItemProxyAttachedData*>();
+ } else {
+ attachedData = new QQuickLayoutItemProxyAttachedData(newTarget);
+ QVariant v;
+ v.setValue(attachedData);
+ newTarget->setProperty("QQuickLayoutItemProxyAttachedData", v);
+ }
+ attachedData->registerProxy(this);
+
+ // If there is no other controlling proxy, we will hide the target
+ if (!attachedData->proxyHasControl())
+ newTarget->setVisible(false);
+ // We are calling maybeTakeControl at the end to eventually take
+ // responsibility of showing the target.
+
+ if (QQuickLayoutAttached *attTarget = attachedLayoutObject(newTarget)) {
+ QQuickLayoutAttached *attProxy = attachedLayoutObject(this, true);
+
+ disconnect(attTarget, nullptr, attProxy, nullptr);
+
+ // bind item-specific layout properties:
+
+#define connectPropertyForwarding(property, Property) \
+ if (!attProxy->is##Property##Set()) { \
+ connect(attTarget, &QQuickLayoutAttached::property##Changed, this, &QQuickLayoutItemProxy::target##Property##Changed); \
+ connect(attProxy, &QQuickLayoutAttached::property##Changed, this, &QQuickLayoutItemProxy::proxy##Property##Changed); \
+ target##Property##Changed(); \
+ }
+ connectPropertyForwarding(minimumWidth, MinimumWidth)
+ connectPropertyForwarding(minimumHeight, MinimumHeight)
+ connectPropertyForwarding(preferredWidth, PreferredWidth)
+ connectPropertyForwarding(preferredHeight, PreferredHeight)
+ connectPropertyForwarding(maximumWidth, MaximumWidth)
+ connectPropertyForwarding(maximumHeight, MaximumHeight)
+ connectPropertyForwarding(fillWidth, FillWidth)
+ connectPropertyForwarding(fillHeight, FillHeight)
+ connectPropertyForwarding(alignment, Alignment)
+ connectPropertyForwarding(horizontalStretchFactor, HorizontalStretchFactor)
+ connectPropertyForwarding(verticalStretchFactor, VerticalStretchFactor)
+ connectPropertyForwarding(margins, Margins)
+ connectPropertyForwarding(leftMargin, LeftMargin)
+ connectPropertyForwarding(topMargin, TopMargin)
+ connectPropertyForwarding(rightMargin, RightMargin)
+ connectPropertyForwarding(bottomMargin, BottomMargin)
+#undef connectPropertyForwarding
+
+ // proxy.implicitWidth: target.implicitWidth
+ auto fnBindImplW = [newTarget, this](){ this->setImplicitWidth(newTarget->implicitWidth()); };
+ fnBindImplW();
+ connect(newTarget, &QQuickItem::implicitWidthChanged, fnBindImplW);
+
+ // proxy.implicitHeight: target.implicitHeight
+ auto fnBindImplH = [newTarget, this](){ this->setImplicitHeight(newTarget->implicitHeight()); };
+ fnBindImplH();
+ connect(newTarget, &QQuickItem::implicitHeightChanged, fnBindImplH);
+ }
+ }
+
+ if (isVisible())
+ maybeTakeControl();
+
+ emit targetChanged();
+}
+
+/*! \internal
+ \brief QQuickLayoutItemProxy::effectiveTarget
+ \return The target item of the proxy if it is in control, \c null otherwise.
+*/
+QQuickItem *QQuickLayoutItemProxy::effectiveTarget() const
+{
+ if (target() == nullptr)
+ return nullptr;
+
+ QQuickLayoutItemProxyAttachedData * attachedData = target()->property("QQuickLayoutItemProxyAttachedData").value<QQuickLayoutItemProxyAttachedData*>();
+ return (attachedData->getControllingProxy() == this) ? target() : nullptr;
+}
+
+/*! \internal
+ \brief QQuickLayoutItemProxy::clearTarget sets the target to null.
+
+ This function is called if the target is destroyed to make sure we do not
+ try to access a non-existing object.
+*/
+void QQuickLayoutItemProxy::clearTarget()
+{
+ setTarget(nullptr);
+}
+
+/*! \internal
+ \brief QQuickLayoutItemProxy::maybeTakeControl checks and takes over control
+ of the item.
+
+ If the proxy is visible it will try to take control over the target and set
+ its visibility to true. If the proxy is hidden it will also hide the target
+ and another LayoutItemProxy has to set the visibility to \c true or the
+ target will stay invisible.
+*/
+void QQuickLayoutItemProxy::maybeTakeControl()
+{
+ Q_D(QQuickLayoutItemProxy);
+ if (!d->target)
+ return;
+
+ QQuickLayoutItemProxyAttachedData * attachedData = d->target->property("QQuickLayoutItemProxyAttachedData").value<QQuickLayoutItemProxyAttachedData*>();
+ if (isVisible() && attachedData->getControllingProxy() != this) {
+ if (attachedData->takeControl(this)) {
+ d->target->setVisible(true);
+ d->target->setParentItem(this);
+ updatePos();
+ }
+ }
+ if (!isVisible() && attachedData->getControllingProxy() == this){
+ if (d->target->parentItem() == this) {
+ d->target->setParentItem(nullptr);
+ } else
+ qCDebug(lcLayouts) << "Parent was changed to" << d->target->parentItem() << "while an ItemProxy had control";
+ d->target->setVisible(false);
+ attachedData->releaseControl(this);
+ }
+}
+
+/*! \internal
+ \brief QQuickLayoutItemProxy::updatePos sets the geometry of the target to
+ the geometry of the proxy
+*/
+void QQuickLayoutItemProxy::updatePos()
+{
+ if (!isVisible())
+ return;
+ if (target()) {
+ if (QQuickLayoutItemProxyAttachedData * attachedData = target()->property("QQuickLayoutItemProxyAttachedData").value<QQuickLayoutItemProxyAttachedData*>()) {
+ if (attachedData->getControllingProxy() == this)
+ geometryChange(boundingRect(), boundingRect());
+ }
+ }
+}
+
+QQuickLayoutItemProxyPrivate::QQuickLayoutItemProxyPrivate()
+ : QQuickItemPrivate(),
+ m_expectProxyMinimumWidthChange(false),
+ m_expectProxyMinimumHeightChange(false),
+ m_expectProxyPreferredWidthChange(false),
+ m_expectProxyPreferredHeightChange(false),
+ m_expectProxyMaximumWidthChange(false),
+ m_expectProxyMaximumHeightChange(false),
+ m_expectProxyFillWidthChange(false),
+ m_expectProxyFillHeightChange(false),
+ m_expectProxyAlignmentChange(false),
+ m_expectProxyHorizontalStretchFactorChange(false),
+ m_expectProxyVerticalStretchFactorChange(false),
+ m_expectProxyMarginsChange(false),
+ m_expectProxyLeftMarginChange(false),
+ m_expectProxyTopMarginChange(false),
+ m_expectProxyRightMarginChange(false),
+ m_expectProxyBottomMarginChange(false)
+{
+
+}
+
+/*! \internal
+ \class QQuickLayoutItemProxyAttachedData
+ \brief Provides attached properties for items that are managed by one or
+ more LayoutItemProxy.
+
+ It stores all proxies that target the item, and will emit signals when the
+ proxies or the controlling proxy changes. Proxies can listen to the signal
+ and pick up control if they wish to.
+*/
+QQuickLayoutItemProxyAttachedData::QQuickLayoutItemProxyAttachedData(QObject *parent)
+ : QObject(parent), controllingProxy(nullptr)
+{
+
+}
+
+QQuickLayoutItemProxyAttachedData::~QQuickLayoutItemProxyAttachedData()
+{
+ // If this is destroyed, so is the target. Clear the target from the
+ // proxies so they do not try to access a destroyed object
+ for (auto &proxy: std::as_const(proxies))
+ proxy->clearTarget();
+}
+
+/*! \internal
+ \brief QQuickLayoutItemProxyAttachedData::registerProxy registers a proxy
+ that manages the item this data is attached to.
+
+ This is required to easily notify proxies when the target is destroyed or
+ when it is free to take over control.
+*/
+void QQuickLayoutItemProxyAttachedData::registerProxy(QQuickLayoutItemProxy *proxy)
+{
+ if (proxies.contains(proxy))
+ return;
+
+ proxies.append(proxy);
+ emit proxiesChanged();
+}
+
+/*! \internal
+ \brief QQuickLayoutItemProxyAttachedData::releaseProxy removes a proxy from
+ a list of known proxies that manage the item this data is attached to.
+*/
+void QQuickLayoutItemProxyAttachedData::releaseProxy(QQuickLayoutItemProxy *proxy)
+{
+ if (proxy == controllingProxy)
+ releaseControl(proxy);
+
+ proxies.removeAll(proxy);
+
+ if (proxies.isEmpty())
+ deleteLater();
+
+ emit proxiesChanged();
+}
+
+/*! \internal
+ \brief QQuickLayoutItemProxyAttachedData::takeControl is called by
+ LayoutItemProxies when they try to take control over the item this data is
+ attached to.
+ \return \c true if no other proxy controls the item and if control is
+ granted to the proxy, \c false otherwise.
+
+ \param proxy The proxy that tries to take control.
+*/
+bool QQuickLayoutItemProxyAttachedData::takeControl(QQuickLayoutItemProxy *proxy)
+{
+ if (controllingProxy || !proxies.contains(proxy))
+ return false;
+
+ qCDebug(lcLayouts) << proxy
+ << "takes control of"
+ << parent();
+
+ controllingProxy = proxy;
+ emit controlTaken();
+ emit controllingProxyChanged();
+ return true;
+}
+
+/*! \internal
+ \brief QQuickLayoutItemProxyAttachedData::releaseControl is called by
+ LayoutItemProxies when they try no longer control the item
+
+ \param proxy The proxy that gives up control.
+*/
+void QQuickLayoutItemProxyAttachedData::releaseControl(QQuickLayoutItemProxy *proxy)
+{
+ if (controllingProxy != proxy)
+ return;
+
+ qCDebug(lcLayouts) << proxy
+ << "no longer controls"
+ << parent();
+
+ controllingProxy = nullptr;
+ emit controlReleased();
+ emit controllingProxyChanged();
+
+ for (auto &otherProxy: std::as_const(proxies)) {
+ if (proxy != otherProxy)
+ otherProxy->maybeTakeControl();
+ }
+}
+
+/*! \internal
+ \brief QQuickLayoutItemProxyAttachedData::getControllingProxy
+ \return the proxy that currently controls the item this data is attached to.
+ Returns \c null if no proxy controls the item.
+*/
+QQuickLayoutItemProxy *QQuickLayoutItemProxyAttachedData::getControllingProxy() const
+{
+ return controllingProxy;
+}
+
+/*! \internal
+ \brief QQuickLayoutItemProxyAttachedData::getProxies
+ \return a list of all proxies that target the item this data is attached to.
+*/
+QQmlListProperty<QQuickLayoutItemProxy> QQuickLayoutItemProxyAttachedData::getProxies()
+{
+ using Type = QQuickLayoutItemProxy;
+ using Property = QQmlListProperty<Type>;
+
+ return Property(
+ this, &proxies,
+ [](Property *p) { return static_cast<QList<Type *> *>(p->data)->size(); },
+ [](Property *p, qsizetype i) { return static_cast<QList<Type *> *>(p->data)->at(i); }
+ );
+}
+
+/*! \internal
+ \brief QQuickLayoutItemProxyAttachedData::proxyHasControl
+ \return \c true if a proxy is controlling the item, \c false otherwise.
+*/
+bool QQuickLayoutItemProxyAttachedData::proxyHasControl() const
+{
+ return controllingProxy != nullptr;
+}
diff --git a/src/quicklayouts/qquicklayoutitemproxy_p.h b/src/quicklayouts/qquicklayoutitemproxy_p.h
new file mode 100644
index 0000000000..7d900bd2d6
--- /dev/null
+++ b/src/quicklayouts/qquicklayoutitemproxy_p.h
@@ -0,0 +1,147 @@
+// Copyright (C) 2023 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
+
+#ifndef QQUICKLAYOUTITEMPROXY_P_H
+#define QQUICKLAYOUTITEMPROXY_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qquickitem_p.h>
+#include <private/qquickrectangle_p.h>
+
+class QQuickLayoutItemProxyAttachedData;
+class QQuickLayoutItemProxyPrivate;
+class QQuickLayoutItemProxy : public QQuickItem
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QQuickItem *target READ target WRITE setTarget NOTIFY targetChanged)
+ QML_NAMED_ELEMENT(LayoutItemProxy)
+ QML_ADDED_IN_VERSION(6, 6)
+
+public:
+ QQuickLayoutItemProxy(QQuickItem *parent = nullptr);
+ ~QQuickLayoutItemProxy() override;
+
+ void geometryChange(const QRectF &newGeom, const QRectF &oldGeom) override;
+ void itemChange(ItemChange c, const ItemChangeData &d) override;
+
+ QQuickItem *target() const;
+ void setTarget(QQuickItem *newTarget);
+ Q_INVOKABLE QQuickItem *effectiveTarget() const;
+ void clearTarget();
+
+ void maybeTakeControl();
+public slots:
+ void updatePos();
+
+private slots:
+ // We define some slots to react to changes to the Layout attached properties.
+ // They are all named following the same scheme, which allows us to use a macro.
+#define propertyForwarding(Property) \
+ void target##Property##Changed(); \
+ void proxy##Property##Changed();
+
+ propertyForwarding(MinimumWidth)
+ propertyForwarding(MinimumHeight)
+ propertyForwarding(PreferredWidth)
+ propertyForwarding(PreferredHeight)
+ propertyForwarding(MaximumWidth)
+ propertyForwarding(MaximumHeight)
+ propertyForwarding(FillWidth)
+ propertyForwarding(FillHeight)
+ propertyForwarding(Alignment)
+ propertyForwarding(HorizontalStretchFactor)
+ propertyForwarding(VerticalStretchFactor)
+ propertyForwarding(Margins)
+ propertyForwarding(LeftMargin)
+ propertyForwarding(TopMargin)
+ propertyForwarding(RightMargin)
+ propertyForwarding(BottomMargin)
+#undef propertyForwarding
+
+signals:
+ void targetChanged();
+
+private:
+ Q_DECLARE_PRIVATE(QQuickLayoutItemProxy)
+};
+
+class QQuickLayoutItemProxyPrivate : public QQuickItemPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickLayoutItemProxy)
+
+public:
+ QQuickLayoutItemProxyPrivate();
+
+ // the target of the LayoutItem
+ QQuickItem *target = nullptr;
+
+ // These values are required to know why the Layout property of the proxy changed
+ // If it changed because the target changed we should keep the connection valid
+ // If a Layout property change is not invoked by the target, it was set
+ // explicitly by the application developer and we should disconnect the connection
+ // between target and proxy for this property.
+ unsigned m_expectProxyMinimumWidthChange : 1;
+ unsigned m_expectProxyMinimumHeightChange : 1;
+ unsigned m_expectProxyPreferredWidthChange : 1;
+ unsigned m_expectProxyPreferredHeightChange : 1;
+ unsigned m_expectProxyMaximumWidthChange : 1;
+ unsigned m_expectProxyMaximumHeightChange : 1;
+ unsigned m_expectProxyFillWidthChange : 1;
+ unsigned m_expectProxyFillHeightChange : 1;
+ unsigned m_expectProxyAlignmentChange : 1;
+ unsigned m_expectProxyHorizontalStretchFactorChange : 1;
+ unsigned m_expectProxyVerticalStretchFactorChange : 1;
+ unsigned m_expectProxyMarginsChange : 1;
+ unsigned m_expectProxyLeftMarginChange : 1;
+ unsigned m_expectProxyTopMarginChange : 1;
+ unsigned m_expectProxyRightMarginChange : 1;
+ unsigned m_expectProxyBottomMarginChange : 1;
+
+ friend class QQuickLayoutItemProxy;
+};
+
+class QQuickLayoutItemProxyAttachedData : public QObject
+{
+ Q_OBJECT
+
+ QML_ANONYMOUS
+ Q_PROPERTY(bool proxyHasControl READ proxyHasControl NOTIFY controllingProxyChanged)
+ Q_PROPERTY(QQuickLayoutItemProxy* controllingProxy READ getControllingProxy NOTIFY controllingProxyChanged)
+ Q_PROPERTY(QQmlListProperty<QQuickLayoutItemProxy> proxies READ getProxies NOTIFY proxiesChanged)
+
+public:
+ QQuickLayoutItemProxyAttachedData(QObject *parent);
+ ~QQuickLayoutItemProxyAttachedData() override;
+ void registerProxy(QQuickLayoutItemProxy *proxy);
+ void releaseProxy(QQuickLayoutItemProxy *proxy);
+ bool takeControl(QQuickLayoutItemProxy *proxy);
+ void releaseControl(QQuickLayoutItemProxy *proxy);
+ QQuickLayoutItemProxy *getControllingProxy() const;
+ QQmlListProperty<QQuickLayoutItemProxy> getProxies();
+ bool proxyHasControl() const;
+
+signals:
+ void controlTaken();
+ void controlReleased();
+ void controllingProxyChanged();
+ void proxiesChanged();
+
+private:
+ QList<QQuickLayoutItemProxy*> proxies;
+ QQuickLayoutItemProxy* controllingProxy;
+};
+
+Q_DECLARE_METATYPE(QQuickLayoutItemProxyAttachedData*);
+
+#endif // QQUICKLAYOUTITEMPROXY_P_H
diff --git a/src/quicklayouts/qquicklayoutstyleinfo.cpp b/src/quicklayouts/qquicklayoutstyleinfo.cpp
index 1632c1ce20..bfd3544b59 100644
--- a/src/quicklayouts/qquicklayoutstyleinfo.cpp
+++ b/src/quicklayouts/qquicklayoutstyleinfo.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 <QtGui/private/qfont_p.h>
@@ -57,7 +21,7 @@ qreal QQuickLayoutStyleInfo::spacing(Qt::Orientation /*orientation*/) const
qreal spacing = 5.0;
#endif
-#ifndef Q_OS_OSX
+#ifndef Q_OS_MACOS
// On OS X the DPI is always 72 so we should not scale it
spacing = qRound(spacing * (qreal(qt_defaultDpiX()) / 96.0));
#endif
diff --git a/src/quicklayouts/qquicklayoutstyleinfo_p.h b/src/quicklayouts/qquicklayoutstyleinfo_p.h
index cf22c8f21a..1be5d61109 100644
--- a/src/quicklayouts/qquicklayoutstyleinfo_p.h
+++ b/src/quicklayouts/qquicklayoutstyleinfo_p.h
@@ -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
#ifndef QQUICKLAYOUTSTYLEINFO_P_H
#define QQUICKLAYOUTSTYLEINFO_P_H
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);
}
}
diff --git a/src/quicklayouts/qquicklinearlayout_p.h b/src/quicklayouts/qquicklinearlayout_p.h
index bc9c395f0b..b3b692d13d 100644
--- a/src/quicklayouts/qquicklinearlayout_p.h
+++ b/src/quicklayouts/qquicklinearlayout_p.h
@@ -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
#ifndef QQUICKLINEARLAYOUT_P_H
#define QQUICKLINEARLAYOUT_P_H
@@ -64,7 +28,7 @@ QT_BEGIN_NAMESPACE
**/
class QQuickGridLayoutBasePrivate;
-class Q_QUICKLAYOUT_PRIVATE_EXPORT QQuickGridLayoutBase : public QQuickLayout
+class Q_QUICKLAYOUTS_EXPORT QQuickGridLayoutBase : public QQuickLayout
{
Q_OBJECT
@@ -79,11 +43,11 @@ public:
explicit QQuickGridLayoutBase(QQuickGridLayoutBasePrivate &dd,
Qt::Orientation orientation,
- QQuickItem *parent = 0);
+ QQuickItem *parent = nullptr);
~QQuickGridLayoutBase();
void componentComplete() override;
- void invalidate(QQuickItem *childItem = 0) override;
+ void invalidate(QQuickItem *childItem = nullptr) override;
Qt::Orientation orientation() const;
void setOrientation(Qt::Orientation orientation);
QSizeF sizeHint(Qt::SizeHint whichSizeHint) const override;
@@ -91,6 +55,7 @@ public:
void setLayoutDirection(Qt::LayoutDirection dir);
Qt::LayoutDirection effectiveLayoutDirection() const;
void setAlignment(QQuickItem *item, Qt::Alignment align) override;
+ void setStretchFactor(QQuickItem *item, int stretchFactor, Qt::Orientation orient) override;
/* QQuickItemChangeListener */
void itemDestroyed(QQuickItem *item) override;
@@ -104,7 +69,7 @@ protected:
void rearrange(const QSizeF &size) override;
virtual void insertLayoutItems() {}
-signals:
+Q_SIGNALS:
Q_REVISION(1, 1) void layoutDirectionChanged();
private:
@@ -121,7 +86,6 @@ class QQuickGridLayoutBasePrivate : public QQuickLayoutPrivate
public:
QQuickGridLayoutBasePrivate() : m_recurRearrangeCounter(0)
, m_rearranging(false)
- , m_updateAfterRearrange(false)
, m_layoutDirection(Qt::LeftToRight)
{}
@@ -135,7 +99,6 @@ public:
Qt::Orientation orientation;
unsigned m_recurRearrangeCounter : 2;
unsigned m_rearranging : 1;
- unsigned m_updateAfterRearrange : 1;
QVector<QQuickItem *> m_invalidateAfterRearrange;
Qt::LayoutDirection m_layoutDirection : 2;
@@ -148,7 +111,7 @@ public:
**
**/
class QQuickGridLayoutPrivate;
-class Q_QUICKLAYOUT_PRIVATE_EXPORT QQuickGridLayout : public QQuickGridLayoutBase
+class Q_QUICKLAYOUTS_EXPORT QQuickGridLayout : public QQuickGridLayoutBase
{
Q_OBJECT
@@ -157,10 +120,15 @@ class Q_QUICKLAYOUT_PRIVATE_EXPORT QQuickGridLayout : public QQuickGridLayoutBas
Q_PROPERTY(int columns READ columns WRITE setColumns NOTIFY columnsChanged)
Q_PROPERTY(int rows READ rows WRITE setRows NOTIFY rowsChanged)
Q_PROPERTY(Flow flow READ flow WRITE setFlow NOTIFY flowChanged)
+ Q_PROPERTY(bool uniformCellWidths READ uniformCellWidths WRITE setUniformCellWidths
+ NOTIFY uniformCellWidthsChanged REVISION(6, 6) FINAL)
+ Q_PROPERTY(bool uniformCellHeights READ uniformCellHeights WRITE setUniformCellHeights
+ NOTIFY uniformCellHeightsChanged REVISION(6, 6) FINAL)
+
QML_NAMED_ELEMENT(GridLayout)
QML_ADDED_IN_VERSION(1, 0)
public:
- explicit QQuickGridLayout(QQuickItem *parent = 0);
+ explicit QQuickGridLayout(QQuickItem *parent = nullptr);
qreal columnSpacing() const;
void setColumnSpacing(qreal spacing);
qreal rowSpacing() const;
@@ -176,9 +144,14 @@ public:
Flow flow() const;
void setFlow(Flow flow);
+ bool uniformCellWidths() const;
+ void setUniformCellWidths(bool uniformCellWidths);
+ bool uniformCellHeights() const;
+ void setUniformCellHeights(bool uniformCellHeights);
+
void insertLayoutItems() override;
-signals:
+Q_SIGNALS:
void columnSpacingChanged();
void rowSpacingChanged();
@@ -186,6 +159,9 @@ signals:
void rowsChanged();
void flowChanged();
+
+ Q_REVISION(6, 6) void uniformCellWidthsChanged();
+ Q_REVISION(6, 6) void uniformCellHeightsChanged();
private:
Q_DECLARE_PRIVATE(QQuickGridLayout)
};
@@ -207,21 +183,27 @@ public:
**
**/
class QQuickLinearLayoutPrivate;
-class QQuickLinearLayout : public QQuickGridLayoutBase
+class Q_QUICKLAYOUTS_EXPORT QQuickLinearLayout : public QQuickGridLayoutBase
{
Q_OBJECT
+ QML_ANONYMOUS
Q_PROPERTY(qreal spacing READ spacing WRITE setSpacing NOTIFY spacingChanged)
+ Q_PROPERTY(bool uniformCellSizes READ uniformCellSizes WRITE setUniformCellSizes
+ NOTIFY uniformCellSizesChanged REVISION(6, 6) FINAL)
public:
explicit QQuickLinearLayout(Qt::Orientation orientation,
- QQuickItem *parent = 0);
+ QQuickItem *parent = nullptr);
void insertLayoutItem(QQuickItem *item);
qreal spacing() const;
void setSpacing(qreal spacing);
+ bool uniformCellSizes() const;
+ void setUniformCellSizes(bool uniformCellSizes);
void insertLayoutItems() override;
-signals:
+Q_SIGNALS:
void spacingChanged();
+ Q_REVISION(6, 6) void uniformCellSizesChanged();
private:
Q_DECLARE_PRIVATE(QQuickLinearLayout)
};
@@ -239,14 +221,14 @@ public:
** QQuickRowLayout
**
**/
-class Q_QUICKLAYOUT_PRIVATE_EXPORT QQuickRowLayout : public QQuickLinearLayout
+class Q_QUICKLAYOUTS_EXPORT QQuickRowLayout : public QQuickLinearLayout
{
Q_OBJECT
QML_NAMED_ELEMENT(RowLayout)
QML_ADDED_IN_VERSION(1, 0)
public:
- explicit QQuickRowLayout(QQuickItem *parent = 0)
+ explicit QQuickRowLayout(QQuickItem *parent = nullptr)
: QQuickLinearLayout(Qt::Horizontal, parent) {}
};
@@ -256,14 +238,14 @@ public:
** QQuickColumnLayout
**
**/
-class Q_QUICKLAYOUT_PRIVATE_EXPORT QQuickColumnLayout : public QQuickLinearLayout
+class Q_QUICKLAYOUTS_EXPORT QQuickColumnLayout : public QQuickLinearLayout
{
Q_OBJECT
QML_NAMED_ELEMENT(ColumnLayout)
QML_ADDED_IN_VERSION(1, 0)
public:
- explicit QQuickColumnLayout(QQuickItem *parent = 0)
+ explicit QQuickColumnLayout(QQuickItem *parent = nullptr)
: QQuickLinearLayout(Qt::Vertical, parent) {}
};
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.
diff --git a/src/quicklayouts/qquickstacklayout_p.h b/src/quicklayouts/qquickstacklayout_p.h
index 07c2fc3727..0ace1e63a3 100644
--- a/src/quicklayouts/qquickstacklayout_p.h
+++ b/src/quicklayouts/qquickstacklayout_p.h
@@ -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
#ifndef QQUICKSTACKLAYOUT_H
#define QQUICKSTACKLAYOUT_H
@@ -59,7 +23,7 @@ QT_BEGIN_NAMESPACE
class QQuickStackLayoutPrivate;
class QQuickStackLayoutAttached;
-class Q_QUICKLAYOUT_PRIVATE_EXPORT QQuickStackLayout : public QQuickLayout
+class Q_QUICKLAYOUTS_EXPORT QQuickStackLayout : public QQuickLayout
{
Q_OBJECT
Q_PROPERTY(int count READ count NOTIFY countChanged)
@@ -69,7 +33,7 @@ class Q_QUICKLAYOUT_PRIVATE_EXPORT QQuickStackLayout : public QQuickLayout
QML_ATTACHED(QQuickStackLayoutAttached)
public:
- explicit QQuickStackLayout(QQuickItem *parent = 0);
+ explicit QQuickStackLayout(QQuickItem *parent = nullptr);
int count() const;
int currentIndex() const;
void setCurrentIndex(int index);
@@ -78,26 +42,34 @@ public:
void itemChange(ItemChange change, const ItemChangeData &value) override;
QSizeF sizeHint(Qt::SizeHint whichSizeHint) const override;
void setAlignment(QQuickItem *item, Qt::Alignment align) override;
- void invalidate(QQuickItem *childItem = 0) override;
- void updateLayoutItems() override;
+ void invalidate(QQuickItem *childItem = nullptr) override;
+ void updateLayoutItems() override { }
void rearrange(const QSizeF &) override;
+ void setStretchFactor(QQuickItem *item, int stretchFactor, Qt::Orientation orient) override;
// iterator
Q_INVOKABLE QQuickItem *itemAt(int index) const override;
int itemCount() const override;
int indexOf(QQuickItem *item) const;
+ /* QQuickItemChangeListener */
+ void itemSiblingOrderChanged(QQuickItem *item) override;
+
static QQuickStackLayoutAttached *qmlAttachedProperties(QObject *object);
-signals:
+Q_SIGNALS:
void currentIndexChanged();
void countChanged();
-public slots:
-
private:
+ enum AdjustCurrentIndexPolicy {
+ DontAdjustCurrentIndex,
+ AdjustCurrentIndex
+ };
+
static void collectItemSizeHints(QQuickItem *item, QSizeF *sizeHints);
bool shouldIgnoreItem(QQuickItem *item) const;
+ void childItemsChanged(AdjustCurrentIndexPolicy adjustCurrentIndexPolicy = DontAdjustCurrentIndex);
Q_DECLARE_PRIVATE(QQuickStackLayout)
friend class QQuickStackLayoutAttached;
@@ -111,8 +83,9 @@ private:
QSizeF array[Qt::NSizeHints];
};
- mutable QVector<SizeHints> m_cachedItemSizeHints;
+ mutable QHash<QQuickItem*, SizeHints> m_cachedItemSizeHints;
mutable QSizeF m_cachedSizeHints[Qt::NSizeHints];
+ SizeHints &cachedItemSizeHints(int index) const;
};
class QQuickStackLayoutPrivate : public QQuickLayoutPrivate
@@ -126,12 +99,12 @@ private:
bool explicitCurrentIndex;
};
-class QQuickStackLayoutAttached : public QObject
+class Q_QUICKLAYOUTS_EXPORT QQuickStackLayoutAttached : public QObject
{
Q_OBJECT
- Q_PROPERTY(int index READ index NOTIFY indexChanged)
- Q_PROPERTY(bool isCurrentItem READ isCurrentItem NOTIFY isCurrentItemChanged)
- Q_PROPERTY(QQuickStackLayout *layout READ layout NOTIFY layoutChanged)
+ Q_PROPERTY(int index READ index NOTIFY indexChanged FINAL)
+ Q_PROPERTY(bool isCurrentItem READ isCurrentItem NOTIFY isCurrentItemChanged FINAL)
+ Q_PROPERTY(QQuickStackLayout *layout READ layout NOTIFY layoutChanged FINAL)
public:
QQuickStackLayoutAttached(QObject *object);
@@ -145,7 +118,7 @@ public:
QQuickStackLayout *layout() const;
void setLayout(QQuickStackLayout *layout);
-signals:
+Q_SIGNALS:
void indexChanged();
void isCurrentItemChanged();
void layoutChanged();