aboutsummaryrefslogtreecommitdiffstats
path: root/src/quicklayouts/qquicklayout.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/quicklayouts/qquicklayout.cpp')
-rw-r--r--src/quicklayouts/qquicklayout.cpp1392
1 files changed, 1392 insertions, 0 deletions
diff --git a/src/quicklayouts/qquicklayout.cpp b/src/quicklayouts/qquicklayout.cpp
new file mode 100644
index 0000000000..97da0a61c9
--- /dev/null
+++ b/src/quicklayouts/qquicklayout.cpp
@@ -0,0 +1,1392 @@
+// 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>
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/private/qnumeric_p.h>
+#include <QtCore/qstack.h>
+#include <QtCore/qmath.h>
+#include <QtQml/qqmlinfo.h>
+#include <limits>
+
+/*!
+ \qmltype Layout
+ //! \instantiates QQuickLayoutAttached
+ \inqmlmodule QtQuick.Layouts
+ \ingroup layouts
+ \brief Provides attached properties for items pushed onto a \l GridLayout,
+ \l RowLayout or \l ColumnLayout.
+
+ An object of type Layout is attached to children of the layout to provide layout specific
+ information about the item.
+ The properties of the attached object influence how the layout will arrange the items.
+
+ For instance, you can specify \l minimumWidth, \l preferredWidth, and
+ \l maximumWidth if the default values are not satisfactory.
+
+ When a layout is resized, items may grow or shrink. Due to this, items have a
+ \l{Layout::minimumWidth}{minimum size}, \l{Layout::preferredWidth}{preferred size} and a
+ \l{Layout::maximumWidth}{maximum size}.
+
+ If minimum size has not been explicitly specified on an item, the size is set to \c 0.
+ If maximum size has not been explicitly specified on an item, the size is set to
+ \c Number.POSITIVE_INFINITY.
+
+ For layouts, the implicit minimum and maximum sizes depend on the content of the layouts.
+
+ 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. 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.
+ The width and height properties are used by the layout engine to store the current
+ size of items as calculated from the minimum/preferred/maximum attached properties,
+ and can be ovewritten each time the items are laid out. Use
+ \l {Layout::preferredWidth}{Layout.preferredWidth} and
+ \l {Layout::preferredHeight}{Layout.preferredHeight}, or \l {Item::}{implicitWidth}
+ and \l {Item::}{implicitHeight} to specify the preferred size of items.
+
+ \sa GridLayout
+ \sa RowLayout
+ \sa ColumnLayout
+*/
+
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(lcQuickLayouts, "qt.quick.layouts")
+
+QQuickLayoutAttached::QQuickLayoutAttached(QObject *parent)
+ : QObject(parent),
+ m_minimumWidth(0),
+ m_minimumHeight(0),
+ m_preferredWidth(-1),
+ m_preferredHeight(-1),
+ m_maximumWidth(std::numeric_limits<qreal>::infinity()),
+ m_maximumHeight(std::numeric_limits<qreal>::infinity()),
+ m_defaultMargins(0),
+ m_fallbackWidth(-1),
+ m_fallbackHeight(-1),
+ m_row(-1),
+ m_column(-1),
+ m_rowSpan(1),
+ m_columnSpan(1),
+ m_fillWidth(false),
+ m_fillHeight(false),
+ m_isFillWidthSet(false),
+ m_isFillHeightSet(false),
+ m_isUseDefaultSizePolicySet(false),
+ m_useDefaultSizePolicy(QQuickLayout::SizePolicyExplicit),
+ m_isMinimumWidthSet(false),
+ m_isMinimumHeightSet(false),
+ 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_isAlignmentSet(false),
+ m_horizontalStretch(-1),
+ m_verticalStretch(-1)
+{
+
+}
+
+/*!
+ \qmlattachedproperty real Layout::minimumWidth
+
+ This property holds the minimum width of an item in a layout.
+ The default value is the item's implicit minimum width.
+
+ If the item is a layout, the implicit minimum width will be the minimum width the layout can
+ have without any of its items shrinking below their minimum width.
+ The implicit minimum width for any other item is \c 0.
+
+ Setting this value to -1 will reset the width back to its implicit minimum width.
+
+
+ \sa preferredWidth
+ \sa maximumWidth
+*/
+void QQuickLayoutAttached::setMinimumWidth(qreal width)
+{
+ if (qt_is_nan(width))
+ return;
+ m_isMinimumWidthSet = width >= 0;
+ if (m_minimumWidth == width)
+ return;
+
+ m_minimumWidth = width;
+ invalidateItem();
+ emit minimumWidthChanged();
+}
+
+/*!
+ \qmlattachedproperty real Layout::minimumHeight
+
+ This property holds the minimum height of an item in a layout.
+ The default value is the item's implicit minimum height.
+
+ If the item is a layout, the implicit minimum height will be the minimum height the layout can
+ have without any of its items shrinking below their minimum height.
+ The implicit minimum height for any other item is \c 0.
+
+ Setting this value to -1 will reset the height back to its implicit minimum height.
+
+ \sa preferredHeight
+ \sa maximumHeight
+*/
+void QQuickLayoutAttached::setMinimumHeight(qreal height)
+{
+ if (qt_is_nan(height))
+ return;
+ m_isMinimumHeightSet = height >= 0;
+ if (m_minimumHeight == height)
+ return;
+
+ m_minimumHeight = height;
+ invalidateItem();
+ emit minimumHeightChanged();
+}
+
+/*!
+ \qmlattachedproperty real Layout::preferredWidth
+
+ This property holds the preferred width of an item in a layout.
+ If the preferred width is \c -1 it will be ignored, and the layout
+ will use \l{Item::implicitWidth}{implicitWidth} instead.
+ The default is \c -1.
+
+ \sa minimumWidth
+ \sa maximumWidth
+*/
+void QQuickLayoutAttached::setPreferredWidth(qreal width)
+{
+ if (qt_is_nan(width) || m_preferredWidth == width)
+ return;
+
+ m_preferredWidth = width;
+ invalidateItem();
+ emit preferredWidthChanged();
+}
+
+/*!
+ \qmlattachedproperty real Layout::preferredHeight
+
+ This property holds the preferred height of an item in a layout.
+ If the preferred height is \c -1 it will be ignored, and the layout
+ will use \l{Item::implicitHeight}{implicitHeight} instead.
+ The default is \c -1.
+
+ \sa minimumHeight
+ \sa maximumHeight
+*/
+void QQuickLayoutAttached::setPreferredHeight(qreal height)
+{
+ if (qt_is_nan(height) || m_preferredHeight == height)
+ return;
+
+ m_preferredHeight = height;
+ invalidateItem();
+ emit preferredHeightChanged();
+}
+
+/*!
+ \qmlattachedproperty real Layout::maximumWidth
+
+ This property holds the maximum width of an item in a layout.
+ The default value is the item's implicit maximum width.
+
+ If the item is a layout, the implicit maximum width will be the maximum width the layout can
+ have without any of its items growing beyond their maximum width.
+ The implicit maximum width for any other item is \c Number.POSITIVE_INFINITY.
+
+ Setting this value to \c -1 will reset the width back to its implicit maximum width.
+
+ \sa minimumWidth
+ \sa preferredWidth
+*/
+void QQuickLayoutAttached::setMaximumWidth(qreal width)
+{
+ if (qt_is_nan(width))
+ return;
+ m_isMaximumWidthSet = width >= 0;
+ if (m_maximumWidth == width)
+ return;
+
+ m_maximumWidth = width;
+ invalidateItem();
+ emit maximumWidthChanged();
+}
+
+/*!
+ \qmlattachedproperty real Layout::maximumHeight
+
+ The default value is the item's implicit maximum height.
+
+ If the item is a layout, the implicit maximum height will be the maximum height the layout can
+ have without any of its items growing beyond their maximum height.
+ The implicit maximum height for any other item is \c Number.POSITIVE_INFINITY.
+
+ Setting this value to \c -1 will reset the height back to its implicit maximum height.
+
+ \sa minimumHeight
+ \sa preferredHeight
+*/
+void QQuickLayoutAttached::setMaximumHeight(qreal height)
+{
+ if (qt_is_nan(height))
+ return;
+ m_isMaximumHeightSet = height >= 0;
+ if (m_maximumHeight == height)
+ return;
+
+ m_maximumHeight = height;
+ invalidateItem();
+ emit maximumHeightChanged();
+}
+
+void QQuickLayoutAttached::setMinimumImplicitSize(const QSizeF &sz)
+{
+ bool emitWidthChanged = false;
+ bool emitHeightChanged = false;
+ if (!m_isMinimumWidthSet && m_minimumWidth != sz.width()) {
+ m_minimumWidth = sz.width();
+ emitWidthChanged = true;
+ }
+ if (!m_isMinimumHeightSet && m_minimumHeight != sz.height()) {
+ m_minimumHeight = sz.height();
+ emitHeightChanged = true;
+ }
+ // Only invalidate the item once, and make sure we emit signal changed after the call to
+ // invalidateItem()
+ if (emitWidthChanged || emitHeightChanged) {
+ invalidateItem();
+ if (emitWidthChanged)
+ emit minimumWidthChanged();
+ if (emitHeightChanged)
+ emit minimumHeightChanged();
+ }
+}
+
+void QQuickLayoutAttached::setMaximumImplicitSize(const QSizeF &sz)
+{
+ bool emitWidthChanged = false;
+ bool emitHeightChanged = false;
+ if (!m_isMaximumWidthSet && m_maximumWidth != sz.width()) {
+ m_maximumWidth = sz.width();
+ emitWidthChanged = true;
+ }
+ if (!m_isMaximumHeightSet && m_maximumHeight != sz.height()) {
+ m_maximumHeight = sz.height();
+ emitHeightChanged = true;
+ }
+ // Only invalidate the item once, and make sure we emit changed signal after the call to
+ // invalidateItem()
+ if (emitWidthChanged || emitHeightChanged) {
+ invalidateItem();
+ if (emitWidthChanged)
+ emit maximumWidthChanged();
+ if (emitHeightChanged)
+ emit maximumHeightChanged();
+ }
+}
+
+/*!
+ \qmlattachedproperty bool Layout::fillWidth
+
+ 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 depends on implicit (built-in) size policy of item.
+
+ \sa fillHeight
+*/
+void QQuickLayoutAttached::setFillWidth(bool fill)
+{
+ bool oldFillWidth = fillWidth();
+ m_isFillWidthSet = true;
+ m_fillWidth = fill;
+ if (oldFillWidth != fill) {
+ invalidateItem();
+ emit fillWidthChanged();
+ }
+}
+
+/*!
+ \qmlattachedproperty bool Layout::fillHeight
+
+ 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 depends on implicit (built-in) size policy of the item.
+
+ \sa fillWidth
+*/
+void QQuickLayoutAttached::setFillHeight(bool fill)
+{
+ bool oldFillHeight = fillHeight();
+ m_isFillHeightSet = true;
+ m_fillHeight = fill;
+ if (oldFillHeight != fill) {
+ invalidateItem();
+ emit fillHeightChanged();
+ }
+}
+
+/*!
+ \qmlattachedproperty enumeration Layout::useDefaultSizePolicy
+ \since 6.8
+
+ This property allows the user to configure the layout size policy at the component
+ level.
+
+ The default value will be inherited by querying the application attribute
+ \l Qt::AA_QtQuickUseDefaultSizePolicy. You can use this property to override that value.
+
+ \value Layout.SizePolicyImplicit
+ The item in the layout uses implicit or built-in size policy
+ \value Layout.SizePolicyExplicit
+ The item in the layout don't use implicit size policies.
+*/
+void QQuickLayoutAttached::setUseDefaultSizePolicy(QQuickLayout::SizePolicy sizePolicy)
+{
+ m_isUseDefaultSizePolicySet = true;
+ if (m_useDefaultSizePolicy != sizePolicy) {
+ m_useDefaultSizePolicy = sizePolicy;
+ emit useDefaultSizePolicyChanged();
+ }
+}
+
+/*!
+ \qmlattachedproperty int Layout::row
+
+ This property allows you to specify the row position of an item in a \l GridLayout.
+
+ If both \l column and this property are not set, it is up to the layout to assign a cell to the item.
+
+ The default value is \c 0.
+
+ \sa column
+ \sa rowSpan
+*/
+void QQuickLayoutAttached::setRow(int row)
+{
+ if (row >= 0 && row != m_row) {
+ m_row = row;
+ invalidateItem();
+ emit rowChanged();
+ }
+}
+
+/*!
+ \qmlattachedproperty int Layout::column
+
+ This property allows you to specify the column position of an item in a \l GridLayout.
+
+ If both \l row and this property are not set, it is up to the layout to assign a cell to the item.
+
+ The default value is \c 0.
+
+ \sa row
+ \sa columnSpan
+*/
+void QQuickLayoutAttached::setColumn(int column)
+{
+ if (column >= 0 && column != m_column) {
+ m_column = column;
+ invalidateItem();
+ emit columnChanged();
+ }
+}
+
+
+/*!
+ \qmlattachedproperty Qt.Alignment Layout::alignment
+
+ This property allows you to specify the alignment of an item within the cell(s) it occupies.
+
+ The default value is \c 0, which means it will be \c{Qt.AlignVCenter | Qt.AlignLeft}.
+ These defaults also apply if only a horizontal or vertical flag is specified:
+ if only a horizontal flag is specified, the default vertical flag will be
+ \c Qt.AlignVCenter, and if only a vertical flag is specified, the default
+ horizontal flag will be \c Qt.AlignLeft.
+
+ A valid alignment is a combination of the following flags:
+ \list
+ \li Qt::AlignLeft
+ \li Qt::AlignHCenter
+ \li Qt::AlignRight
+ \li Qt::AlignTop
+ \li Qt::AlignVCenter
+ \li Qt::AlignBottom
+ \li Qt::AlignBaseline
+ \endlist
+
+*/
+void QQuickLayoutAttached::setAlignment(Qt::Alignment align)
+{
+ m_isAlignmentSet = true;
+ if (align != m_alignment) {
+ m_alignment = align;
+ if (QQuickLayout *layout = parentLayout()) {
+ layout->setAlignment(item(), align);
+ invalidateItem();
+ }
+ emit alignmentChanged();
+ }
+}
+
+/*!
+ \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
+ itself does not evaluate its own margins. It is the parent's responsibility
+ to decide if it wants to evaluate the margins.
+
+ Specifically, margins are only evaluated by ColumnLayout, RowLayout,
+ GridLayout, and other layout-like containers, such as SplitView, where the
+ effective cell size of an item will be increased as the margins are
+ increased.
+
+ Therefore, if an item with margins is a child of another \c Item, its
+ position, size and implicit size will remain unchanged.
+
+ Combining margins with alignment will align the item \e including its
+ margins. For instance, a vertically-centered Item with a top margin of \c 1
+ and a bottom margin of \c 9 will cause the Items effective alignment within
+ the cell to be 4 pixels above the center.
+
+ The default value is \c 0.
+
+ \sa leftMargin
+ \sa topMargin
+ \sa rightMargin
+ \sa bottomMargin
+
+ \since QtQuick.Layouts 1.2
+*/
+void QQuickLayoutAttached::setMargins(qreal m)
+{
+ m_isMarginsSet = true;
+ if (m == m_defaultMargins)
+ return;
+
+ m_defaultMargins = m;
+ invalidateItem();
+ if (!m_isLeftMarginSet && m_margins.left() != m)
+ emit leftMarginChanged();
+ if (!m_isTopMarginSet && m_margins.top() != m)
+ emit topMarginChanged();
+ if (!m_isRightMarginSet && m_margins.right() != m)
+ emit rightMarginChanged();
+ if (!m_isBottomMarginSet && m_margins.bottom() != m)
+ emit bottomMarginChanged();
+ emit marginsChanged();
+}
+
+/*!
+ \qmlattachedproperty real Layout::leftMargin
+
+ Specifies the left margin outside of an item.
+ If the value is not set, it will use the value from \l margins.
+
+ \sa margins
+
+ \since QtQuick.Layouts 1.2
+*/
+void QQuickLayoutAttached::setLeftMargin(qreal m)
+{
+ const bool changed = leftMargin() != m;
+ m_margins.setLeft(m);
+ m_isLeftMarginSet = true;
+ if (changed) {
+ invalidateItem();
+ emit leftMarginChanged();
+ }
+}
+
+void QQuickLayoutAttached::resetLeftMargin()
+{
+ const bool changed = m_isLeftMarginSet && (m_defaultMargins != m_margins.left());
+ m_isLeftMarginSet = false;
+ if (changed) {
+ invalidateItem();
+ emit leftMarginChanged();
+ }
+}
+
+/*!
+ \qmlattachedproperty real Layout::topMargin
+
+ Specifies the top margin outside of an item.
+ If the value is not set, it will use the value from \l margins.
+
+ \sa margins
+
+ \since QtQuick.Layouts 1.2
+*/
+void QQuickLayoutAttached::setTopMargin(qreal m)
+{
+ const bool changed = topMargin() != m;
+ m_margins.setTop(m);
+ m_isTopMarginSet = true;
+ if (changed) {
+ invalidateItem();
+ emit topMarginChanged();
+ }
+}
+
+void QQuickLayoutAttached::resetTopMargin()
+{
+ const bool changed = m_isTopMarginSet && (m_defaultMargins != m_margins.top());
+ m_isTopMarginSet = false;
+ if (changed) {
+ invalidateItem();
+ emit topMarginChanged();
+ }
+}
+
+/*!
+ \qmlattachedproperty real Layout::rightMargin
+
+ Specifies the right margin outside of an item.
+ If the value is not set, it will use the value from \l margins.
+
+ \sa margins
+
+ \since QtQuick.Layouts 1.2
+*/
+void QQuickLayoutAttached::setRightMargin(qreal m)
+{
+ const bool changed = rightMargin() != m;
+ m_margins.setRight(m);
+ m_isRightMarginSet = true;
+ if (changed) {
+ invalidateItem();
+ emit rightMarginChanged();
+ }
+}
+
+void QQuickLayoutAttached::resetRightMargin()
+{
+ const bool changed = m_isRightMarginSet && (m_defaultMargins != m_margins.right());
+ m_isRightMarginSet = false;
+ if (changed) {
+ invalidateItem();
+ emit rightMarginChanged();
+ }
+}
+
+/*!
+ \qmlattachedproperty real Layout::bottomMargin
+
+ Specifies the bottom margin outside of an item.
+ If the value is not set, it will use the value from \l margins.
+
+ \sa margins
+
+ \since QtQuick.Layouts 1.2
+*/
+void QQuickLayoutAttached::setBottomMargin(qreal m)
+{
+ const bool changed = bottomMargin() != m;
+ m_margins.setBottom(m);
+ m_isBottomMarginSet = true;
+ if (changed) {
+ invalidateItem();
+ emit bottomMarginChanged();
+ }
+}
+
+void QQuickLayoutAttached::resetBottomMargin()
+{
+ const bool changed = m_isBottomMarginSet && (m_defaultMargins != m_margins.bottom());
+ m_isBottomMarginSet = false;
+ if (changed) {
+ invalidateItem();
+ emit bottomMarginChanged();
+ }
+}
+
+
+/*!
+ \qmlattachedproperty int Layout::rowSpan
+
+ This property allows you to specify the row span of an item in a \l GridLayout.
+
+ The default value is \c 1.
+
+ \sa columnSpan
+ \sa row
+*/
+void QQuickLayoutAttached::setRowSpan(int span)
+{
+ if (span != m_rowSpan) {
+ m_rowSpan = span;
+ invalidateItem();
+ emit rowSpanChanged();
+ }
+}
+
+
+/*!
+ \qmlattachedproperty int Layout::columnSpan
+
+ This property allows you to specify the column span of an item in a \l GridLayout.
+
+ The default value is \c 1.
+
+ \sa rowSpan
+ \sa column
+*/
+void QQuickLayoutAttached::setColumnSpan(int span)
+{
+ if (span != m_columnSpan) {
+ m_columnSpan = span;
+ invalidateItem();
+ emit columnSpanChanged();
+ }
+}
+
+
+qreal QQuickLayoutAttached::sizeHint(Qt::SizeHint which, Qt::Orientation orientation) const
+{
+ qreal result = 0;
+ if (QQuickLayout *layout = qobject_cast<QQuickLayout *>(item())) {
+ const QSizeF sz = layout->sizeHint(which);
+ result = (orientation == Qt::Horizontal ? sz.width() : sz.height());
+ } else {
+ if (which == Qt::MaximumSize)
+ result = std::numeric_limits<qreal>::infinity();
+ }
+ return result;
+}
+
+void QQuickLayoutAttached::invalidateItem()
+{
+ qCDebug(lcQuickLayouts) << "QQuickLayoutAttached::invalidateItem";
+ if (QQuickLayout *layout = parentLayout()) {
+ layout->invalidate(item());
+ }
+}
+
+QQuickLayout *QQuickLayoutAttached::parentLayout() const
+{
+ QQuickItem *parentItem = item();
+ if (parentItem) {
+ parentItem = parentItem->parentItem();
+ return qobject_cast<QQuickLayout *>(parentItem);
+ } else {
+ qmlWarning(parent()) << "Layout must be attached to Item elements";
+ }
+ return nullptr;
+}
+
+QQuickItem *QQuickLayoutAttached::item() const
+{
+ return qobject_cast<QQuickItem *>(parent());
+}
+
+void QQuickLayoutPrivate::applySizeHints() const
+{
+ Q_Q(const QQuickLayout);
+
+ QQuickLayout *that = const_cast<QQuickLayout*>(q);
+ QQuickLayoutAttached *info = attachedLayoutObject(that, true);
+
+ const QSizeF min = q->sizeHint(Qt::MinimumSize);
+ const QSizeF max = q->sizeHint(Qt::MaximumSize);
+ const QSizeF pref = q->sizeHint(Qt::PreferredSize);
+ info->setMinimumImplicitSize(min);
+ info->setMaximumImplicitSize(max);
+ that->setImplicitSize(pref.width(), pref.height());
+}
+
+QQuickLayout::QQuickLayout(QQuickLayoutPrivate &dd, QQuickItem *parent)
+ : QQuickItem(dd, parent)
+ , m_inUpdatePolish(false)
+ , m_polishInsideUpdatePolish(0)
+{
+}
+
+static QQuickItemPrivate::ChangeTypes changeTypes =
+ QQuickItemPrivate::SiblingOrder
+ | QQuickItemPrivate::ImplicitWidth
+ | QQuickItemPrivate::ImplicitHeight
+ | QQuickItemPrivate::Destroyed
+ | QQuickItemPrivate::Visibility;
+
+QQuickLayout::~QQuickLayout()
+{
+ d_func()->m_isReady = false;
+
+ const auto childItems = d_func()->childItems;
+ for (QQuickItem *child : childItems)
+ QQuickItemPrivate::get(child)->removeItemChangeListener(this, changeTypes);
+}
+
+QQuickLayoutAttached *QQuickLayout::qmlAttachedProperties(QObject *object)
+{
+ return new QQuickLayoutAttached(object);
+}
+
+void QQuickLayout::updatePolish()
+{
+ qCDebug(lcQuickLayouts) << "updatePolish() ENTERING" << this;
+ m_inUpdatePolish = true;
+
+ // Might have become "undirty" before we reach this updatePolish()
+ // (e.g. if somebody queried for implicitWidth it will immediately
+ // calculate size hints)
+ // 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;
+}
+
+void QQuickLayout::componentComplete()
+{
+ Q_D(QQuickLayout);
+ d->m_disableRearrange = true;
+ QQuickItem::componentComplete(); // will call our geometryChange(), (where isComponentComplete() == true)
+ d->m_disableRearrange = false;
+ 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);
+ if (invalidated())
+ return;
+
+ qCDebug(lcQuickLayouts) << "QQuickLayout::invalidate()" << this;
+ d->m_dirty = true;
+ d->m_dirtyArrangement = true;
+
+ if (!qobject_cast<QQuickLayout *>(parentItem())) {
+ 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 {
+ m_polishInsideUpdatePolish = 0;
+ }
+ }
+}
+
+bool QQuickLayout::shouldIgnoreItem(QQuickItem *child) const
+{
+ QQuickItemPrivate *childPrivate = QQuickItemPrivate::get(child);
+ bool ignoreItem = !childPrivate->explicitVisible;
+ if (!ignoreItem && childPrivate->isTransparentForPositioner())
+ ignoreItem = true;
+ return ignoreItem;
+}
+
+void QQuickLayout::checkAnchors(QQuickItem *item) const
+{
+ QQuickAnchors *anchors = QQuickItemPrivate::get(item)->_anchors;
+ if (anchors && anchors->activeDirections())
+ qmlWarning(item) << "Detected anchors on an item that is managed by a layout. This is undefined behavior; use Layout.alignment instead.";
+}
+
+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;
+
+ 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;
+}
+
+
+void QQuickLayout::itemChange(ItemChange change, const ItemChangeData &value)
+{
+ if (change == ItemChildAddedChange) {
+ Q_D(QQuickLayout);
+ QQuickItem *item = value.item;
+ maybeSubscribeToBaseLineOffsetChanges(item);
+ QQuickItemPrivate::get(item)->addItemChangeListener(this, changeTypes);
+ d->m_hasItemChangeListeners = true;
+ qCDebug(lcQuickLayouts) << "ChildAdded" << item;
+ if (isReady())
+ invalidate();
+ } else if (change == ItemChildRemovedChange) {
+ QQuickItem *item = value.item;
+ maybeSubscribeToBaseLineOffsetChanges(item);
+ QQuickItemPrivate::get(item)->removeItemChangeListener(this, changeTypes);
+ qCDebug(lcQuickLayouts) << "ChildRemoved" << item;
+ if (isReady())
+ invalidate();
+ }
+ QQuickItem::itemChange(change, value);
+}
+
+void QQuickLayout::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
+{
+ Q_D(QQuickLayout);
+ QQuickItem::geometryChange(newGeometry, oldGeometry);
+ if ((invalidated() && !qobject_cast<QQuickLayout *>(parentItem())) ||
+ d->m_disableRearrange || !isReady())
+ return;
+
+ qCDebug(lcQuickLayouts) << "QQuickLayout::geometryChange" << newGeometry << oldGeometry;
+ rearrange(newGeometry.size());
+}
+
+void QQuickLayout::invalidateSenderItem()
+{
+ if (!isReady())
+ return;
+ QQuickItem *item = static_cast<QQuickItem *>(sender());
+ Q_ASSERT(item);
+ invalidate(item);
+}
+
+bool QQuickLayout::isReady() const
+{
+ return d_func()->m_isReady;
+}
+
+/*!
+ * \brief QQuickLayout::deactivateRecur
+ * \internal
+ *
+ * Call this from the dtor of the top-level layout.
+ * Otherwise, it will trigger lots of unneeded item change listeners (itemVisibleChanged()) for all its descendants
+ * that will have its impact thrown away.
+ */
+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
+ // e.g. visibility got changed. The layout already knows that all its children will eventually become invisible, so
+ // we therefore remove its change listener.
+ QQuickItemPrivate::get(item)->removeItemChangeListener(this, changeTypes);
+ if (QQuickLayout *layout = qobject_cast<QQuickLayout*>(item))
+ layout->deactivateRecur();
+ }
+ d_func()->m_hasItemChangeListeners = false;
+ }
+}
+
+bool QQuickLayout::invalidated() const
+{
+ return d_func()->m_dirty;
+}
+
+bool QQuickLayout::invalidatedArrangement() const
+{
+ return d_func()->m_dirtyArrangement;
+}
+
+bool QQuickLayout::isMirrored() const
+{
+ return d_func()->isMirrored();
+}
+
+void QQuickLayout::itemSiblingOrderChanged(QQuickItem *item)
+{
+ Q_UNUSED(item);
+ invalidate();
+}
+
+void QQuickLayout::itemImplicitWidthChanged(QQuickItem *item)
+{
+ if (!isReady() || item->signalsBlocked())
+ return;
+ invalidate(item);
+}
+
+void QQuickLayout::itemImplicitHeightChanged(QQuickItem *item)
+{
+ if (!isReady() || item->signalsBlocked())
+ return;
+ invalidate(item);
+}
+
+void QQuickLayout::itemDestroyed(QQuickItem *item)
+{
+ Q_UNUSED(item);
+}
+
+void QQuickLayout::itemVisibilityChanged(QQuickItem *item)
+{
+ Q_UNUSED(item);
+}
+
+void QQuickLayout::rearrange(const QSizeF &/*size*/)
+{
+ d_func()->m_dirtyArrangement = false;
+}
+
+
+/*
+ The layout engine assumes:
+ 1. minimum <= preferred <= maximum
+ 2. descent is within minimum and maximum bounds (### verify)
+
+ This function helps to ensure that by the following rules (in the following order):
+ 1. If minimum > maximum, set minimum = maximum
+ 2. Clamp preferred to be between the [minimum,maximum] range.
+ 3. If descent > minimum, set descent = minimum (### verify if this is correct, it might
+ need some refinements to multiline texts)
+
+ If any values are "not set" (i.e. negative), they will be left untouched, so that we
+ know which values needs to be fetched from the implicit hints (not user hints).
+ */
+static void normalizeHints(qreal &minimum, qreal &preferred, qreal &maximum, qreal &descent)
+{
+ if (minimum >= 0 && maximum >= 0 && minimum > maximum)
+ minimum = maximum;
+
+ if (preferred >= 0) {
+ if (minimum >= 0 && preferred < minimum) {
+ preferred = minimum;
+ } else if (maximum >= 0 && preferred > maximum) {
+ preferred = maximum;
+ }
+ }
+
+ if (minimum >= 0 && descent > minimum)
+ descent = minimum;
+}
+
+static void boundSize(QSizeF &result, const QSizeF &size)
+{
+ if (size.width() >= 0 && size.width() < result.width())
+ result.setWidth(size.width());
+ if (size.height() >= 0 && size.height() < result.height())
+ result.setHeight(size.height());
+}
+
+static void expandSize(QSizeF &result, const QSizeF &size)
+{
+ if (size.width() >= 0 && size.width() > result.width())
+ result.setWidth(size.width());
+ if (size.height() >= 0 && size.height() > result.height())
+ result.setHeight(size.height());
+}
+
+static inline void combineHints(qreal &current, qreal fallbackHint)
+{
+ if (current < 0)
+ current = fallbackHint;
+}
+
+static inline void combineSize(QSizeF &result, const QSizeF &fallbackSize)
+{
+ combineHints(result.rwidth(), fallbackSize.width());
+ combineHints(result.rheight(), fallbackSize.height());
+}
+
+static inline void combineImplicitHints(QQuickLayoutAttached *info, Qt::SizeHint which, QSizeF *size)
+{
+ if (!info) return;
+
+ Q_ASSERT(which == Qt::MinimumSize || which == Qt::MaximumSize);
+
+ const QSizeF constraint(which == Qt::MinimumSize
+ ? QSizeF(info->minimumWidth(), info->minimumHeight())
+ : QSizeF(info->maximumWidth(), info->maximumHeight()));
+
+ if (!info->isExtentExplicitlySet(Qt::Horizontal, which))
+ combineHints(size->rwidth(), constraint.width());
+ if (!info->isExtentExplicitlySet(Qt::Vertical, which))
+ combineHints(size->rheight(), constraint.height());
+}
+
+typedef qreal (QQuickLayoutAttached::*SizeGetter)() const;
+
+/*!
+ \internal
+ Note: Can potentially return the attached QQuickLayoutAttached object through \a attachedInfo.
+
+ It is like this is because it enables it to be reused.
+
+ The goal of this function is to return the effective minimum, preferred and maximum size hints
+ that the layout will use for this item.
+ This function takes care of gathering all explicitly set size hints, normalizes them so
+ that min < pref < max.
+ Further, the hints _not_explicitly_ set will then be initialized with the implicit size hints,
+ which is usually derived from the content of the layouts (or items).
+
+ The following table illustrates the preference of the properties used for measuring layout
+ items. If present, the USER properties will be preferred. If USER properties are not present,
+ the HINT properties will be preferred. Finally, the FALLBACK properties will be used as an
+ ultimate fallback.
+
+ Note that one can query if the value of Layout.minimumWidth or Layout.maximumWidth has been
+ explicitly or implicitly set with QQuickLayoutAttached::isExtentExplicitlySet(). This
+ determines if it should be used as a USER or as a HINT value.
+
+ Fractional size hints will be ceiled to the closest integer. This is in order to give some
+ slack when the items are snapped to the pixel grid.
+
+ | *Minimum* | *Preferred* | *Maximum* |
++----------------+----------------------+-----------------------+--------------------------+
+|USER (explicit) | Layout.minimumWidth | Layout.preferredWidth | Layout.maximumWidth |
+|HINT (implicit) | Layout.minimumWidth | implicitWidth | Layout.maximumWidth |
+|FALLBACK | 0 | width | Number.POSITIVE_INFINITY |
++----------------+----------------------+-----------------------+--------------------------+
+ */
+void QQuickLayout::effectiveSizeHints_helper(QQuickItem *item, QSizeF *cachedSizeHints, QQuickLayoutAttached **attachedInfo, bool useFallbackToWidthOrHeight)
+{
+ for (int i = 0; i < Qt::NSizeHints; ++i)
+ cachedSizeHints[i] = QSizeF();
+ QQuickLayoutAttached *info = attachedLayoutObject(item, false);
+ // First, retrieve the user-specified hints from the attached "Layout." properties
+ if (info) {
+ struct Getters {
+ SizeGetter call[NSizes];
+ };
+
+ static Getters horGetters = {
+ {&QQuickLayoutAttached::minimumWidth, &QQuickLayoutAttached::preferredWidth, &QQuickLayoutAttached::maximumWidth},
+ };
+
+ static Getters verGetters = {
+ {&QQuickLayoutAttached::minimumHeight, &QQuickLayoutAttached::preferredHeight, &QQuickLayoutAttached::maximumHeight}
+ };
+ for (int i = 0; i < NSizes; ++i) {
+ SizeGetter getter = horGetters.call[i];
+ Q_ASSERT(getter);
+
+ if (info->isExtentExplicitlySet(Qt::Horizontal, (Qt::SizeHint)i))
+ cachedSizeHints[i].setWidth((info->*getter)());
+
+ getter = verGetters.call[i];
+ Q_ASSERT(getter);
+ if (info->isExtentExplicitlySet(Qt::Vertical, (Qt::SizeHint)i))
+ cachedSizeHints[i].setHeight((info->*getter)());
+ }
+ }
+
+ QSizeF &minS = cachedSizeHints[Qt::MinimumSize];
+ QSizeF &prefS = cachedSizeHints[Qt::PreferredSize];
+ QSizeF &maxS = cachedSizeHints[Qt::MaximumSize];
+ QSizeF &descentS = cachedSizeHints[Qt::MinimumDescent];
+
+ // For instance, will normalize the following user-set hints
+ // from: [10, 5, 60]
+ // to: [10, 10, 60]
+ normalizeHints(minS.rwidth(), prefS.rwidth(), maxS.rwidth(), descentS.rwidth());
+ normalizeHints(minS.rheight(), prefS.rheight(), maxS.rheight(), descentS.rheight());
+
+ // All explicit values gathered, now continue to gather the implicit sizes
+
+ //--- GATHER MAXIMUM SIZE HINTS ---
+ combineImplicitHints(info, Qt::MaximumSize, &maxS);
+ combineSize(maxS, QSizeF(std::numeric_limits<qreal>::infinity(), std::numeric_limits<qreal>::infinity()));
+ // implicit max or min sizes should not limit an explicitly set preferred size
+ expandSize(maxS, prefS);
+ expandSize(maxS, minS);
+
+ //--- GATHER MINIMUM SIZE HINTS ---
+ combineImplicitHints(info, Qt::MinimumSize, &minS);
+ expandSize(minS, QSizeF(0,0));
+ boundSize(minS, prefS);
+ boundSize(minS, maxS);
+
+ //--- GATHER PREFERRED SIZE HINTS ---
+ // First, from implicitWidth/Height
+ qreal &prefWidth = prefS.rwidth();
+ qreal &prefHeight = prefS.rheight();
+ if (prefWidth < 0 && item->implicitWidth() > 0)
+ prefWidth = qCeil(item->implicitWidth());
+ if (prefHeight < 0 && item->implicitHeight() > 0)
+ prefHeight = qCeil(item->implicitHeight());
+
+ // If that fails, make an ultimate fallback to width/height
+ if (useFallbackToWidthOrHeight && !prefS.isValid()) {
+ /* If we want to support using width/height as preferred size hints in
+ layouts, (which we think most people expect), we only want to use the
+ initial width.
+ This is because the width will change due to layout rearrangement,
+ and the preferred width should return the same value, regardless of
+ the current width.
+ We therefore store this initial width in the attached layout object
+ and reuse it if needed rather than querying the width another time.
+ That means we need to ensure that an Layout attached object is available
+ by creating one if necessary.
+ */
+ if (!info)
+ info = attachedLayoutObject(item);
+
+ auto updatePreferredSizes = [](qreal &cachedSize, qreal &attachedSize, qreal size) {
+ if (cachedSize < 0) {
+ if (attachedSize < 0)
+ attachedSize = size;
+
+ cachedSize = attachedSize;
+ }
+ };
+ updatePreferredSizes(prefWidth, info->m_fallbackWidth, item->width());
+ updatePreferredSizes(prefHeight, info->m_fallbackHeight, item->height());
+ }
+
+ // Normalize again after the implicit hints have been gathered
+ expandSize(prefS, minS);
+ boundSize(prefS, maxS);
+
+ //--- GATHER DESCENT
+ // Minimum descent is only applicable for the effective minimum height,
+ // so we gather the descent last.
+ const qreal minimumDescent = minS.height() - item->baselineOffset();
+ descentS.setHeight(minimumDescent);
+
+ if (info) {
+ QMarginsF margins = info->qMargins();
+ QSizeF extraMargins(margins.left() + margins.right(), margins.top() + margins.bottom());
+ minS += extraMargins;
+ prefS += extraMargins;
+ maxS += extraMargins;
+ descentS += extraMargins;
+ }
+ if (attachedInfo)
+ *attachedInfo = info;
+}
+
+/*!
+ \internal
+
+ Assumes \a info is set (if the object has an attached property)
+ */
+QLayoutPolicy::Policy QQuickLayout::effectiveSizePolicy_helper(QQuickItem *item, Qt::Orientation orientation, QQuickLayoutAttached *info)
+{
+ QLayoutPolicy::Policy pol{QLayoutPolicy::Fixed};
+ bool isSet = false;
+ if (info) {
+ if (orientation == Qt::Horizontal) {
+ isSet = info->isFillWidthSet();
+ if (isSet && info->fillWidth())
+ pol = QLayoutPolicy::Preferred;
+ } else {
+ isSet = info->isFillHeightSet();
+ if (isSet && info->fillHeight())
+ pol = QLayoutPolicy::Preferred;
+ }
+ }
+ if (!isSet && item) {
+ auto effectiveUseDefaultSizePolicy = [info]() {
+ return info ? info->useDefaultSizePolicy() == QQuickLayout::SizePolicyImplicit
+ : QGuiApplication::testAttribute(Qt::AA_QtQuickUseDefaultSizePolicy);
+ };
+ if (qobject_cast<QQuickLayout*>(item)) {
+ pol = QLayoutPolicy::Preferred;
+ } else if (effectiveUseDefaultSizePolicy()) {
+ QLayoutPolicy sizePolicy = QQuickItemPrivate::get(item)->sizePolicy();
+ pol = (orientation == Qt::Horizontal) ? sizePolicy.horizontalPolicy() : sizePolicy.verticalPolicy();
+ }
+ }
+
+ return pol;
+}
+
+void QQuickLayout::_q_dumpLayoutTree() const
+{
+ QString buf;
+ dumpLayoutTreeRecursive(0, buf);
+ qDebug("\n%s", qPrintable(buf));
+}
+
+void QQuickLayout::dumpLayoutTreeRecursive(int level, QString &buf) const
+{
+ auto formatLine = [&level](const char *fmt) -> QString {
+ QString ss(level *4, QLatin1Char(' '));
+ return ss + QLatin1String(fmt) + QLatin1Char('\n');
+ };
+
+ auto f2s = [](qreal f) {
+ return QString::number(f);
+ };
+ auto b2s = [](bool b) {
+ static const char *strBool[] = {"false", "true"};
+ return QLatin1String(strBool[int(b)]);
+ };
+
+ buf += formatLine("%1 {").arg(QQmlMetaType::prettyTypeName(this));
+ ++level;
+ buf += formatLine("// Effective calculated values:");
+ buf += formatLine("sizeHintDirty: %2").arg(invalidated());
+ QSizeF min = sizeHint(Qt::MinimumSize);
+ buf += formatLine("sizeHint.min : [%1, %2]").arg(f2s(min.width()), 5).arg(min.height(), 5);
+ QSizeF pref = sizeHint(Qt::PreferredSize);
+ buf += formatLine("sizeHint.pref: [%1, %2]").arg(pref.width(), 5).arg(pref.height(), 5);
+ QSizeF max = sizeHint(Qt::MaximumSize);
+ buf += formatLine("sizeHint.max : [%1, %2]").arg(f2s(max.width()), 5).arg(f2s(max.height()), 5);
+
+ for (QQuickItem *item : childItems()) {
+ buf += QLatin1Char('\n');
+ if (QQuickLayout *childLayout = qobject_cast<QQuickLayout*>(item)) {
+ childLayout->dumpLayoutTreeRecursive(level, buf);
+ } else {
+ buf += formatLine("%1 {").arg(QQmlMetaType::prettyTypeName(item));
+ ++level;
+ if (item->implicitWidth() > 0)
+ buf += formatLine("implicitWidth: %1").arg(f2s(item->implicitWidth()));
+ if (item->implicitHeight() > 0)
+ buf += formatLine("implicitHeight: %1").arg(f2s(item->implicitHeight()));
+ QSizeF min;
+ QSizeF pref;
+ QSizeF max;
+ QQuickLayoutAttached *info = attachedLayoutObject(item, false);
+ if (info) {
+ min = QSizeF(info->minimumWidth(), info->minimumHeight());
+ pref = QSizeF(info->preferredWidth(), info->preferredHeight());
+ max = QSizeF(info->maximumWidth(), info->maximumHeight());
+ if (info->isExtentExplicitlySet(Qt::Horizontal, Qt::MinimumSize))
+ buf += formatLine("Layout.minimumWidth: %1").arg(f2s(min.width()));
+ if (info->isExtentExplicitlySet(Qt::Vertical, Qt::MinimumSize))
+ buf += formatLine("Layout.minimumHeight: %1").arg(f2s(min.height()));
+ if (pref.width() >= 0)
+ buf += formatLine("Layout.preferredWidth: %1").arg(f2s(pref.width()));
+ if (pref.height() >= 0)
+ buf += formatLine("Layout.preferredHeight: %1").arg(f2s(pref.height()));
+ if (info->isExtentExplicitlySet(Qt::Horizontal, Qt::MaximumSize))
+ buf += formatLine("Layout.maximumWidth: %1").arg(f2s(max.width()));
+ if (info->isExtentExplicitlySet(Qt::Vertical, Qt::MaximumSize))
+ buf += formatLine("Layout.maximumHeight: %1").arg(f2s(max.height()));
+
+ if (info->isFillWidthSet())
+ buf += formatLine("Layout.fillWidth: %1").arg(b2s(info->fillWidth()));
+ if (info->isFillHeightSet())
+ buf += formatLine("Layout.fillHeight: %1").arg(b2s(info->fillHeight()));
+ }
+ --level;
+ buf += formatLine("}");
+ }
+ }
+ --level;
+ buf += formatLine("}");
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquicklayout_p.cpp"