aboutsummaryrefslogtreecommitdiffstats
path: root/src/quicklayouts/qquicklinearlayout.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/quicklayouts/qquicklinearlayout.cpp')
-rw-r--r--src/quicklayouts/qquicklinearlayout.cpp980
1 files changed, 980 insertions, 0 deletions
diff --git a/src/quicklayouts/qquicklinearlayout.cpp b/src/quicklayouts/qquicklinearlayout.cpp
new file mode 100644
index 0000000000..41f45259ea
--- /dev/null
+++ b/src/quicklayouts/qquicklinearlayout.cpp
@@ -0,0 +1,980 @@
+// 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"
+#include "qquicklayoutstyleinfo_p.h"
+#include <QtCore/private/qnumeric_p.h>
+#include <QtQml/qqmlinfo.h>
+#include "qdebug.h"
+#include <limits>
+
+/*!
+ \qmltype RowLayout
+ //! \instantiates QQuickRowLayout
+ \inherits Item
+ \inqmlmodule QtQuick.Layouts
+ \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:
+ \list
+ \input layout.qdocinc attached-properties
+ \endlist
+
+ \image rowlayout.png
+
+ \code
+ RowLayout {
+ id: layout
+ anchors.fill: parent
+ spacing: 6
+ Rectangle {
+ color: 'teal'
+ Layout.fillWidth: true
+ Layout.minimumWidth: 50
+ Layout.preferredWidth: 100
+ Layout.maximumWidth: 300
+ Layout.minimumHeight: 150
+ Text {
+ anchors.centerIn: parent
+ text: parent.width + 'x' + parent.height
+ }
+ }
+ Rectangle {
+ color: 'plum'
+ Layout.fillWidth: true
+ Layout.minimumWidth: 100
+ Layout.preferredWidth: 200
+ Layout.preferredHeight: 100
+ Text {
+ anchors.centerIn: parent
+ text: parent.width + 'x' + parent.height
+ }
+ }
+ }
+ \endcode
+
+ Read more about attached properties \l{QML Object Attributes}{here}.
+ \sa ColumnLayout
+ \sa GridLayout
+ \sa StackLayout
+ \sa Row
+ \sa {Qt Quick Layouts Overview}
+*/
+
+/*!
+ \qmltype ColumnLayout
+ //! \instantiates QQuickColumnLayout
+ \inherits Item
+ \inqmlmodule QtQuick.Layouts
+ \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:
+ \list
+ \input layout.qdocinc attached-properties
+ \endlist
+
+ \image columnlayout.png
+
+ \code
+ ColumnLayout{
+ spacing: 2
+
+ Rectangle {
+ Layout.alignment: Qt.AlignCenter
+ color: "red"
+ Layout.preferredWidth: 40
+ Layout.preferredHeight: 40
+ }
+
+ Rectangle {
+ Layout.alignment: Qt.AlignRight
+ color: "green"
+ Layout.preferredWidth: 40
+ Layout.preferredHeight: 70
+ }
+
+ Rectangle {
+ Layout.alignment: Qt.AlignBottom
+ Layout.fillHeight: true
+ color: "blue"
+ Layout.preferredWidth: 70
+ Layout.preferredHeight: 40
+ }
+ }
+ \endcode
+
+ Read more about attached properties \l{QML Object Attributes}{here}.
+
+ \sa RowLayout
+ \sa GridLayout
+ \sa StackLayout
+ \sa Column
+ \sa {Qt Quick Layouts Overview}
+*/
+
+
+/*!
+ \qmltype GridLayout
+ //! \instantiates QQuickGridLayout
+ \inherits Item
+ \inqmlmodule QtQuick.Layouts
+ \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
+ the layout. If you want a layout with just one row or one column, you can use the
+ \l RowLayout or \l ColumnLayout. These offer a bit more convenient API, and improve
+ readability.
+
+ By default items will be arranged according to the \l flow property. The default value of
+ the \l flow property is \c GridLayout.LeftToRight.
+
+ If the \l columns property is specified, it will be treated as a maximum limit of how many
+ columns the layout can have, before the auto-positioning wraps back to the beginning of the
+ next row. The \l columns property is only used when \l flow is \c GridLayout.LeftToRight.
+
+ \image gridlayout.png
+
+ \code
+ GridLayout {
+ id: grid
+ columns: 3
+
+ Text { text: "Three"; font.bold: true; }
+ Text { text: "words"; color: "red" }
+ Text { text: "in"; font.underline: true }
+ Text { text: "a"; font.pixelSize: 20 }
+ Text { text: "row"; font.strikeout: true }
+ }
+ \endcode
+
+ The \l rows property works in a similar way, but items are auto-positioned vertically. The \l
+ rows property is only used when \l flow is \c GridLayout.TopToBottom.
+
+ You can specify which cell you want an item to occupy by setting the
+ \l{Layout::row}{Layout.row} and \l{Layout::column}{Layout.column} properties. You can also
+ specify the row span or column span by setting the \l{Layout::rowSpan}{Layout.rowSpan} or
+ \l{Layout::columnSpan}{Layout.columnSpan} properties.
+
+
+ Items in a GridLayout support these attached properties:
+ \list
+ \li \l{Layout::row}{Layout.row}
+ \li \l{Layout::column}{Layout.column}
+ \li \l{Layout::rowSpan}{Layout.rowSpan}
+ \li \l{Layout::columnSpan}{Layout.columnSpan}
+ \input layout.qdocinc attached-properties
+ \endlist
+
+ Read more about attached properties \l{QML Object Attributes}{here}.
+
+ \sa RowLayout
+ \sa ColumnLayout
+ \sa StackLayout
+ \sa Grid
+ \sa {Qt Quick Layouts Overview}
+*/
+
+
+
+QT_BEGIN_NAMESPACE
+
+QQuickGridLayoutBase::QQuickGridLayoutBase()
+ : QQuickLayout(*new QQuickGridLayoutBasePrivate)
+{
+
+}
+
+QQuickGridLayoutBase::QQuickGridLayoutBase(QQuickGridLayoutBasePrivate &dd,
+ Qt::Orientation orientation,
+ QQuickItem *parent /*= nullptr */)
+ : QQuickLayout(dd, parent)
+{
+ Q_D(QQuickGridLayoutBase);
+ d->orientation = orientation;
+ d->styleInfo = new QQuickLayoutStyleInfo;
+}
+
+Qt::Orientation QQuickGridLayoutBase::orientation() const
+{
+ Q_D(const QQuickGridLayoutBase);
+ return d->orientation;
+}
+
+void QQuickGridLayoutBase::setOrientation(Qt::Orientation orientation)
+{
+ Q_D(QQuickGridLayoutBase);
+ if (d->orientation == orientation)
+ return;
+
+ d->orientation = orientation;
+ invalidate();
+}
+
+QSizeF QQuickGridLayoutBase::sizeHint(Qt::SizeHint whichSizeHint) const
+{
+ Q_D(const QQuickGridLayoutBase);
+ return d->engine.sizeHint(whichSizeHint, QSizeF(), d->styleInfo);
+}
+
+/*!
+ \qmlproperty enumeration GridLayout::layoutDirection
+ \since QtQuick.Layouts 1.1
+
+ This property holds the layout direction of the grid layout - it controls whether items are
+ laid out from left to right or right to left. If \c Qt.RightToLeft is specified,
+ left-aligned items will be right-aligned and right-aligned items will be left-aligned.
+
+ Possible values:
+
+ \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
+*/
+Qt::LayoutDirection QQuickGridLayoutBase::layoutDirection() const
+{
+ Q_D(const QQuickGridLayoutBase);
+ return d->m_layoutDirection;
+}
+
+void QQuickGridLayoutBase::setLayoutDirection(Qt::LayoutDirection dir)
+{
+ Q_D(QQuickGridLayoutBase);
+ if (d->m_layoutDirection == dir)
+ return;
+ d->m_layoutDirection = dir;
+ invalidate();
+ emit layoutDirectionChanged();
+}
+
+Qt::LayoutDirection QQuickGridLayoutBase::effectiveLayoutDirection() const
+{
+ Q_D(const QQuickGridLayoutBase);
+ return !d->effectiveLayoutMirror == (layoutDirection() == Qt::LeftToRight)
+ ? Qt::LeftToRight : Qt::RightToLeft;
+}
+
+void QQuickGridLayoutBase::setAlignment(QQuickItem *item, Qt::Alignment alignment)
+{
+ 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()
+{
+ Q_D(QQuickGridLayoutBase);
+
+ // Remove item listeners so we do not act on signalling unnecessarily
+ // (there is no point, as the layout will be torn down anyway).
+ deactivateRecur();
+ delete d->styleInfo;
+}
+
+void QQuickGridLayoutBase::componentComplete()
+{
+ qCDebug(lcQuickLayouts) << "QQuickGridLayoutBase::componentComplete()" << this << parent();
+ QQuickLayout::componentComplete();
+
+ /* The layout is invalid when it is constructed, but during construction of the layout and
+ its children (in the "static/from QML" case which this is trying to cover) things
+ change and as a consequence invalidate() and ensureLayoutItemsUpdated() might be called.
+ As soon as ensureLayoutItemsUpdated() is called it will set d->dirty = false.
+ However, a subsequent invalidate() will return early if the component is not completed
+ because it knows that componentComplete() will take care of doing the proper layouting
+ (so it won't set d->dirty = true). When we then call ensureLayoutItemsUpdated() again here
+ it sees that its not dirty and assumes everything up-to-date. For those cases we therefore
+ need to call invalidate() in advance
+ */
+ invalidate();
+ ensureLayoutItemsUpdated(QQuickLayout::ApplySizeHints);
+
+ QQuickItem *par = parentItem();
+ if (qobject_cast<QQuickLayout*>(par))
+ return;
+ rearrange(QSizeF(width(), height()));
+ qCDebug(lcQuickLayouts) << "QQuickGridLayoutBase::componentComplete(). COMPLETED" << this << parent();
+}
+
+/*
+ Invalidation happens like this as a reaction to that a size hint changes on an item "a":
+
+ Suppose we have the following Qml document:
+ RowLayout {
+ id: l1
+ RowLayout {
+ id: l2
+ Item {
+ id: a
+ }
+ Item {
+ id: b
+ }
+ }
+ }
+
+ 1. l2->invalidate(a) is called on l2, where item refers to "a".
+ (this will dirty the cached size hints of item "a")
+ 2. The layout engine will invalidate:
+ i) invalidate the layout engine
+ ii) dirty the cached size hints of item "l2" (by calling parentLayout()->invalidate(l2)
+ The recursion continues to the topmost layout
+ */
+/*!
+ \internal
+
+ Invalidates \a childItem and this layout.
+ After a call to invalidate, the next call to retrieve e.g. sizeHint will be up-to date.
+ This function will also call QQuickLayout::invalidate(0), to ensure that the parent layout
+ is invalidated.
+ */
+void QQuickGridLayoutBase::invalidate(QQuickItem *childItem)
+{
+ Q_D(QQuickGridLayoutBase);
+ if (!isReady())
+ return;
+ qCDebug(lcQuickLayouts) << "QQuickGridLayoutBase::invalidate()" << this << ", invalidated:" << invalidated();
+ if (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 (auto *parentLayout = qobject_cast<QQuickLayout *>(parentItem()))
+ parentLayout->invalidate(this);
+ qCDebug(lcQuickLayouts) << "QQuickGridLayoutBase::invalidate() LEAVING" << this;
+}
+
+void QQuickGridLayoutBase::updateLayoutItems()
+{
+ Q_D(QQuickGridLayoutBase);
+ if (!isReady())
+ return;
+
+ qCDebug(lcQuickLayouts) << "QQuickGridLayoutBase::updateLayoutItems ENTERING" << this;
+ d->engine.deleteItems();
+ insertLayoutItems();
+ qCDebug(lcQuickLayouts) << "QQuickGridLayoutBase::updateLayoutItems() LEAVING" << this;
+}
+
+QQuickItem *QQuickGridLayoutBase::itemAt(int index) const
+{
+ Q_D(const QQuickGridLayoutBase);
+ return static_cast<QQuickGridLayoutItem*>(d->engine.itemAt(index))->layoutItem();
+}
+
+int QQuickGridLayoutBase::itemCount() const
+{
+ Q_D(const QQuickGridLayoutBase);
+ return d->engine.itemCount();
+}
+
+void QQuickGridLayoutBase::removeGridItem(QGridLayoutItem *gridItem)
+{
+ Q_D(QQuickGridLayoutBase);
+ const int index = gridItem->firstRow(d->orientation);
+ d->engine.removeItem(gridItem);
+ d->engine.removeRows(index, 1, d->orientation);
+}
+
+void QQuickGridLayoutBase::itemDestroyed(QQuickItem *item)
+{
+ if (!isReady())
+ return;
+ Q_D(QQuickGridLayoutBase);
+ qCDebug(lcQuickLayouts) << "QQuickGridLayoutBase::itemDestroyed";
+ if (QQuickGridLayoutItem *gridItem = d->engine.findLayoutItem(item)) {
+ removeGridItem(gridItem);
+ delete gridItem;
+ invalidate();
+ }
+}
+
+void QQuickGridLayoutBase::itemVisibilityChanged(QQuickItem *item)
+{
+ Q_UNUSED(item);
+
+ if (!isReady())
+ return;
+ qCDebug(lcQuickLayouts) << "QQuickGridLayoutBase::itemVisibilityChanged()";
+ invalidate(item);
+}
+
+void QQuickGridLayoutBase::rearrange(const QSizeF &size)
+{
+ Q_D(QQuickGridLayoutBase);
+ if (!isReady() || !size.isValid())
+ return;
+
+ qCDebug(lcQuickLayouts) << "QQuickGridLayoutBase::rearrange" << d->m_recurRearrangeCounter << this;
+ const auto refCounter = qScopeGuard([&d] {
+ --(d->m_recurRearrangeCounter);
+ });
+ if (d->m_recurRearrangeCounter++ == 2) {
+ // allow a recursive depth of two in order to respond to height-for-width
+ // (e.g QQuickText changes implicitHeight when its width gets changed)
+ qWarning() << "Qt Quick Layouts: Detected recursive rearrange. Aborting after two iterations.";
+ return;
+ }
+
+ // 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;
+ Qt::LayoutDirection visualDir = effectiveLayoutDirection();
+ d->engine.setVisualDirection(visualDir);
+
+ /*
+ qreal left, top, right, bottom;
+ left = top = right = bottom = 0; // ### support for margins?
+ if (visualDir == Qt::RightToLeft)
+ qSwap(left, right);
+ */
+
+ // Set m_dirty to false in case size hint changes during arrangement.
+ // This could happen if there is a binding like implicitWidth: height
+ QQuickLayout::rearrange(size);
+ d->engine.setGeometries(QRectF(QPointF(0,0), size), d->styleInfo);
+ d->m_rearranging = false;
+
+ for (auto childItem : std::as_const(d->m_invalidateAfterRearrange))
+ invalidate(childItem);
+ d->m_invalidateAfterRearrange.clear();
+}
+
+/**********************************
+ **
+ ** QQuickGridLayout
+ **
+ **/
+QQuickGridLayout::QQuickGridLayout(QQuickItem *parent /* = nullptr*/)
+ : QQuickGridLayoutBase(*new QQuickGridLayoutPrivate, Qt::Horizontal, parent)
+{
+}
+
+/*!
+ \qmlproperty real GridLayout::columnSpacing
+
+ This property holds the spacing between each column.
+ The default value is \c 5.
+*/
+qreal QQuickGridLayout::columnSpacing() const
+{
+ Q_D(const QQuickGridLayout);
+ return d->engine.spacing(Qt::Horizontal, d->styleInfo);
+}
+
+void QQuickGridLayout::setColumnSpacing(qreal spacing)
+{
+ Q_D(QQuickGridLayout);
+ if (qt_is_nan(spacing) || columnSpacing() == spacing)
+ return;
+
+ d->engine.setSpacing(spacing, Qt::Horizontal);
+ invalidate();
+ emit columnSpacingChanged();
+}
+
+/*!
+ \qmlproperty real GridLayout::rowSpacing
+
+ This property holds the spacing between each row.
+ The default value is \c 5.
+*/
+qreal QQuickGridLayout::rowSpacing() const
+{
+ Q_D(const QQuickGridLayout);
+ return d->engine.spacing(Qt::Vertical, d->styleInfo);
+}
+
+void QQuickGridLayout::setRowSpacing(qreal spacing)
+{
+ Q_D(QQuickGridLayout);
+ if (qt_is_nan(spacing) || rowSpacing() == spacing)
+ return;
+
+ d->engine.setSpacing(spacing, Qt::Vertical);
+ invalidate();
+ emit rowSpacingChanged();
+}
+
+/*!
+ \qmlproperty int GridLayout::columns
+
+ This property holds the column limit for items positioned if \l flow is
+ \c GridLayout.LeftToRight.
+ The default value is that there is no limit.
+*/
+int QQuickGridLayout::columns() const
+{
+ Q_D(const QQuickGridLayout);
+ return d->columns;
+}
+
+void QQuickGridLayout::setColumns(int columns)
+{
+ Q_D(QQuickGridLayout);
+ if (d->columns == columns)
+ return;
+ d->columns = columns;
+ invalidate();
+ emit columnsChanged();
+}
+
+
+/*!
+ \qmlproperty int GridLayout::rows
+
+ This property holds the row limit for items positioned if \l flow is \c GridLayout.TopToBottom.
+ The default value is that there is no limit.
+*/
+int QQuickGridLayout::rows() const
+{
+ Q_D(const QQuickGridLayout);
+ return d->rows;
+}
+
+void QQuickGridLayout::setRows(int rows)
+{
+ Q_D(QQuickGridLayout);
+ if (d->rows == rows)
+ return;
+ d->rows = rows;
+ invalidate();
+ emit rowsChanged();
+}
+
+
+/*!
+ \qmlproperty enumeration GridLayout::flow
+
+ This property holds the flow direction of items that does not have an explicit cell
+ position set.
+ It is used together with the \l columns or \l rows property, where
+ they specify when flow is reset to the next row or column respectively.
+
+ Possible values are:
+
+ \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
+*/
+QQuickGridLayout::Flow QQuickGridLayout::flow() const
+{
+ Q_D(const QQuickGridLayout);
+ return d->flow;
+}
+
+void QQuickGridLayout::setFlow(QQuickGridLayout::Flow flow)
+{
+ Q_D(QQuickGridLayout);
+ if (d->flow == flow)
+ return;
+ d->flow = flow;
+ // If flow is changed, the layout needs to be repopulated
+ invalidate();
+ 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);
+
+ int nextCellPos[2] = {0,0};
+ int &nextColumn = nextCellPos[0];
+ int &nextRow = nextCellPos[1];
+
+ const QSize gridSize(columns(), rows());
+ const int flowOrientation = flow();
+ int &flowColumn = nextCellPos[flowOrientation];
+ int &flowRow = nextCellPos[1 - flowOrientation];
+ int flowBound = (flowOrientation == QQuickGridLayout::LeftToRight) ? columns() : rows();
+
+ if (flowBound < 0)
+ flowBound = std::numeric_limits<int>::max();
+
+ const auto items = childItems();
+ for (QQuickItem *child : items) {
+ checkAnchors(child);
+ // Will skip all items with effective maximum width/height == 0
+ 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};
+ int &columnSpan = span[0];
+ int &rowSpan = span[1];
+
+ if (info) {
+ if (info->isRowSet() || info->isColumnSet()) {
+ // If row is specified and column is not specified (or vice versa),
+ // the unspecified component of the cell position should default to 0
+ // The getters do this for us, as they will return 0 for an
+ // unset (or negative) value.
+ // In addition, if \a rows is less than Layout.row, treat Layout.row as if it was not set
+ // This will basically make it find the next available cell (potentially wrapping to
+ // the next line). Likewise for an invalid Layout.column
+
+ if (gridSize.height() >= 0 && row >= gridSize.height()) {
+ qmlWarning(child) << QString::fromLatin1("Layout: row (%1) should be less than the number of rows (%2)").arg(info->row()).arg(rows());
+ } else {
+ row = info->row();
+ }
+
+ if (gridSize.width() >= 0 && info->column() >= gridSize.width()) {
+ qmlWarning(child) << QString::fromLatin1("Layout: column (%1) should be less than the number of columns (%2)").arg(info->column()).arg(columns());
+ } else {
+ column = info->column();
+ }
+ }
+ rowSpan = info->rowSpan();
+ columnSpan = info->columnSpan();
+ if (columnSpan < 1) {
+ qmlWarning(child) << "Layout: invalid column span: " << columnSpan;
+ return;
+
+ } else if (rowSpan < 1) {
+ qmlWarning(child) << "Layout: invalid row span: " << rowSpan;
+ 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);
+ Q_ASSERT(rowSpan >= 1);
+ const int sp = span[flowOrientation];
+ if (sp > flowBound)
+ return;
+
+ if (row >= 0)
+ nextRow = row;
+ if (column >= 0)
+ nextColumn = column;
+
+ if (row < 0 || column < 0) {
+ /* if row or column is not specified, find next position by
+ advancing in the flow direction until there is a cell that
+ can accept the item.
+
+ The acceptance rules are pretty simple, but complexity arises
+ when an item requires several cells (due to spans):
+ 1. Check if the cells that the item will require
+ does not extend beyond columns (for LeftToRight) or
+ rows (for TopToBottom).
+ 2. Check if the cells that the item will require is not already
+ taken by another item.
+ */
+ bool cellAcceptsItem;
+ while (true) {
+ // Check if the item does not span beyond the layout bound
+ cellAcceptsItem = (flowColumn + sp) <= flowBound;
+
+ // Check if all the required cells are not taken
+ for (int rs = 0; cellAcceptsItem && rs < rowSpan; ++rs) {
+ for (int cs = 0; cellAcceptsItem && cs < columnSpan; ++cs) {
+ if (d->engine.itemAt(nextRow + rs, nextColumn + cs)) {
+ cellAcceptsItem = false;
+ }
+ }
+ }
+ if (cellAcceptsItem)
+ break;
+ ++flowColumn;
+ if (flowColumn == flowBound) {
+ flowColumn = 0;
+ ++flowRow;
+ }
+ }
+ }
+ column = nextColumn;
+ row = nextRow;
+ QQuickGridLayoutItem *layoutItem = new QQuickGridLayoutItem(child, row, column, rowSpan, columnSpan, alignment);
+ if (hStretch >= 0)
+ layoutItem->setStretchFactor(hStretch, Qt::Horizontal);
+ if (vStretch >= 0)
+ layoutItem->setStretchFactor(vStretch, Qt::Vertical);
+
+ d->engine.insertItem(layoutItem, -1);
+ }
+}
+
+/**********************************
+ **
+ ** QQuickLinearLayout
+ **
+ **/
+QQuickLinearLayout::QQuickLinearLayout(Qt::Orientation orientation,
+ QQuickItem *parent /*= nullptr*/)
+ : QQuickGridLayoutBase(*new QQuickLinearLayoutPrivate, orientation, parent)
+{
+}
+
+/*!
+ \qmlproperty enumeration RowLayout::layoutDirection
+ \since QtQuick.Layouts 1.1
+
+ This property holds the layout direction of the row layout - it controls whether items are laid
+ out from left to right or right to left. If \c Qt.RightToLeft is specified,
+ left-aligned items will be right-aligned and right-aligned items will be left-aligned.
+
+ Possible values:
+
+ \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
+*/
+/*!
+ \qmlproperty enumeration ColumnLayout::layoutDirection
+ \since QtQuick.Layouts 1.1
+
+ This property holds the layout direction of the column layout - it controls whether items are laid
+ out from left to right or right to left. If \c Qt.RightToLeft is specified,
+ left-aligned items will be right-aligned and right-aligned items will be left-aligned.
+
+ Possible values:
+
+ \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
+
+ This property holds the spacing between each cell.
+ The default value is \c 5.
+*/
+/*!
+ \qmlproperty real ColumnLayout::spacing
+
+ This property holds the spacing between each cell.
+ The default value is \c 5.
+*/
+
+qreal QQuickLinearLayout::spacing() const
+{
+ Q_D(const QQuickLinearLayout);
+ return d->engine.spacing(d->orientation, d->styleInfo);
+}
+
+void QQuickLinearLayout::setSpacing(qreal space)
+{
+ Q_D(QQuickLinearLayout);
+ if (qt_is_nan(space) || spacing() == space)
+ return;
+
+ d->engine.setSpacing(space, Qt::Horizontal | Qt::Vertical);
+ invalidate();
+ emit spacingChanged();
+}
+
+void QQuickLinearLayout::insertLayoutItems()
+{
+ Q_D(QQuickLinearLayout);
+ const auto items = childItems();
+ for (QQuickItem *child : items) {
+ Q_ASSERT(child);
+ checkAnchors(child);
+
+ // Will skip all items with effective maximum width/height == 0
+ if (shouldIgnoreItem(child))
+ continue;
+ QQuickLayoutAttached *info = attachedLayoutObject(child, false);
+
+ Qt::Alignment alignment;
+ 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);
+
+ int gridRow = 0;
+ int gridColumn = index;
+ if (d->orientation == Qt::Vertical)
+ qSwap(gridRow, gridColumn);
+ QQuickGridLayoutItem *layoutItem = new QQuickGridLayoutItem(child, gridRow, gridColumn, 1, 1, alignment);
+
+ 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);
+ }
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquicklinearlayout_p.cpp"