aboutsummaryrefslogtreecommitdiffstats
path: root/src/declarative/items/qquickpositioners.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/declarative/items/qquickpositioners.cpp')
-rw-r--r--src/declarative/items/qquickpositioners.cpp1533
1 files changed, 1533 insertions, 0 deletions
diff --git a/src/declarative/items/qquickpositioners.cpp b/src/declarative/items/qquickpositioners.cpp
new file mode 100644
index 0000000000..15cd35c2f0
--- /dev/null
+++ b/src/declarative/items/qquickpositioners.cpp
@@ -0,0 +1,1533 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickpositioners_p.h"
+#include "qquickpositioners_p_p.h"
+
+#include <QtDeclarative/qdeclarative.h>
+#include <QtDeclarative/qdeclarativeinfo.h>
+#include <QtCore/qmath.h>
+#include <QtCore/qcoreapplication.h>
+
+#include <private/qdeclarativestate_p.h>
+#include <private/qdeclarativestategroup_p.h>
+#include <private/qdeclarativestateoperations_p.h>
+#include <private/qdeclarativetransition_p.h>
+
+QT_BEGIN_NAMESPACE
+
+static const QQuickItemPrivate::ChangeTypes watchedChanges
+ = QQuickItemPrivate::Geometry
+ | QQuickItemPrivate::SiblingOrder
+ | QQuickItemPrivate::Visibility
+ | QQuickItemPrivate::Destroyed;
+
+void QQuickBasePositionerPrivate::watchChanges(QQuickItem *other)
+{
+ QQuickItemPrivate *otherPrivate = QQuickItemPrivate::get(other);
+ otherPrivate->addItemChangeListener(this, watchedChanges);
+}
+
+void QQuickBasePositionerPrivate::unwatchChanges(QQuickItem* other)
+{
+ QQuickItemPrivate *otherPrivate = QQuickItemPrivate::get(other);
+ otherPrivate->removeItemChangeListener(this, watchedChanges);
+}
+
+QQuickBasePositioner::QQuickBasePositioner(PositionerType at, QQuickItem *parent)
+ : QQuickImplicitSizeItem(*(new QQuickBasePositionerPrivate), parent)
+{
+ Q_D(QQuickBasePositioner);
+ d->init(at);
+}
+/*!
+ \internal
+ \class QQuickBasePositioner
+ \brief The QQuickBasePositioner class provides a base for QQuickGraphics layouts.
+
+ To create a QQuickGraphics Positioner, simply subclass QQuickBasePositioner and implement
+ doLayout(), which is automatically called when the layout might need
+ updating. In doLayout() use the setX and setY functions from QQuickBasePositioner, and the
+ base class will apply the positions along with the appropriate transitions. The items to
+ position are provided in order as the protected member positionedItems.
+
+ You also need to set a PositionerType, to declare whether you are positioning the x, y or both
+ for the child items. Depending on the chosen type, only x or y changes will be applied.
+
+ Note that the subclass is responsible for adding the spacing in between items.
+
+ Positioning is usually delayed until before a frame is rendered, to batch multiple repositioning
+ changes into one calculation.
+*/
+
+QQuickBasePositioner::QQuickBasePositioner(QQuickBasePositionerPrivate &dd, PositionerType at, QQuickItem *parent)
+ : QQuickImplicitSizeItem(dd, parent)
+{
+ Q_D(QQuickBasePositioner);
+ d->init(at);
+}
+
+QQuickBasePositioner::~QQuickBasePositioner()
+{
+ Q_D(QQuickBasePositioner);
+ for (int i = 0; i < positionedItems.count(); ++i)
+ d->unwatchChanges(positionedItems.at(i).item);
+ positionedItems.clear();
+}
+
+void QQuickBasePositioner::updatePolish()
+{
+ Q_D(QQuickBasePositioner);
+ if (d->positioningDirty)
+ prePositioning();
+}
+
+int QQuickBasePositioner::spacing() const
+{
+ Q_D(const QQuickBasePositioner);
+ return d->spacing;
+}
+
+void QQuickBasePositioner::setSpacing(int s)
+{
+ Q_D(QQuickBasePositioner);
+ if (s==d->spacing)
+ return;
+ d->spacing = s;
+ d->setPositioningDirty();
+ emit spacingChanged();
+}
+
+QDeclarativeTransition *QQuickBasePositioner::move() const
+{
+ Q_D(const QQuickBasePositioner);
+ return d->moveTransition;
+}
+
+void QQuickBasePositioner::setMove(QDeclarativeTransition *mt)
+{
+ Q_D(QQuickBasePositioner);
+ if (mt == d->moveTransition)
+ return;
+ d->moveTransition = mt;
+ emit moveChanged();
+}
+
+QDeclarativeTransition *QQuickBasePositioner::add() const
+{
+ Q_D(const QQuickBasePositioner);
+ return d->addTransition;
+}
+
+void QQuickBasePositioner::setAdd(QDeclarativeTransition *add)
+{
+ Q_D(QQuickBasePositioner);
+ if (add == d->addTransition)
+ return;
+
+ d->addTransition = add;
+ emit addChanged();
+}
+
+void QQuickBasePositioner::componentComplete()
+{
+ QQuickItem::componentComplete();
+ positionedItems.reserve(childItems().count());
+ prePositioning();
+ reportConflictingAnchors();
+}
+
+void QQuickBasePositioner::itemChange(ItemChange change, const ItemChangeData &value)
+{
+ Q_D(QQuickBasePositioner);
+ if (change == ItemChildAddedChange){
+ d->setPositioningDirty();
+ } else if (change == ItemChildRemovedChange) {
+ QQuickItem *child = value.item;
+ QQuickBasePositioner::PositionedItem posItem(child);
+ int idx = positionedItems.find(posItem);
+ if (idx >= 0) {
+ d->unwatchChanges(child);
+ positionedItems.remove(idx);
+ }
+ d->setPositioningDirty();
+ }
+
+ QQuickItem::itemChange(change, value);
+}
+
+void QQuickBasePositioner::prePositioning()
+{
+ Q_D(QQuickBasePositioner);
+ if (!isComponentComplete())
+ return;
+
+ if (d->doingPositioning)
+ return;
+
+ d->positioningDirty = false;
+ d->doingPositioning = true;
+ //Need to order children by creation order modified by stacking order
+ QList<QQuickItem *> children = childItems();
+
+ QPODVector<PositionedItem,8> oldItems;
+ positionedItems.copyAndClear(oldItems);
+ for (int ii = 0; ii < children.count(); ++ii) {
+ QQuickItem *child = children.at(ii);
+ QQuickItemPrivate *childPrivate = QQuickItemPrivate::get(child);
+ PositionedItem *item = 0;
+ PositionedItem posItem(child);
+ int wIdx = oldItems.find(posItem);
+ if (wIdx < 0) {
+ d->watchChanges(child);
+ positionedItems.append(posItem);
+ item = &positionedItems[positionedItems.count()-1];
+ item->isNew = true;
+ if (!childPrivate->explicitVisible || !child->width() || !child->height())
+ item->isVisible = false;
+ } else {
+ item = &oldItems[wIdx];
+ // Items are only omitted from positioning if they are explicitly hidden
+ // i.e. their positioning is not affected if an ancestor is hidden.
+ if (!childPrivate->explicitVisible || !child->width() || !child->height()) {
+ item->isVisible = false;
+ } else if (!item->isVisible) {
+ item->isVisible = true;
+ item->isNew = true;
+ } else {
+ item->isNew = false;
+ }
+ positionedItems.append(*item);
+ }
+ }
+ QSizeF contentSize(0,0);
+ doPositioning(&contentSize);
+ updateAttachedProperties();
+ if (!d->addActions.isEmpty() || !d->moveActions.isEmpty())
+ finishApplyTransitions();
+ d->doingPositioning = false;
+ //Set implicit size to the size of its children
+ setImplicitHeight(contentSize.height());
+ setImplicitWidth(contentSize.width());
+}
+
+void QQuickBasePositioner::positionX(int x, const PositionedItem &target)
+{
+ Q_D(QQuickBasePositioner);
+ if (d->type == Horizontal || d->type == Both) {
+ if (target.isNew) {
+ if (!d->addTransition || !d->addTransition->enabled())
+ target.item->setX(x);
+ else
+ d->addActions << QDeclarativeAction(target.item, QLatin1String("x"), QVariant(x));
+ } else if (x != target.item->x()) {
+ if (!d->moveTransition || !d->moveTransition->enabled())
+ target.item->setX(x);
+ else
+ d->moveActions << QDeclarativeAction(target.item, QLatin1String("x"), QVariant(x));
+ }
+ }
+}
+
+void QQuickBasePositioner::positionY(int y, const PositionedItem &target)
+{
+ Q_D(QQuickBasePositioner);
+ if (d->type == Vertical || d->type == Both) {
+ if (target.isNew) {
+ if (!d->addTransition || !d->addTransition->enabled())
+ target.item->setY(y);
+ else
+ d->addActions << QDeclarativeAction(target.item, QLatin1String("y"), QVariant(y));
+ } else if (y != target.item->y()) {
+ if (!d->moveTransition || !d->moveTransition->enabled())
+ target.item->setY(y);
+ else
+ d->moveActions << QDeclarativeAction(target.item, QLatin1String("y"), QVariant(y));
+ }
+ }
+}
+
+void QQuickBasePositioner::finishApplyTransitions()
+{
+ Q_D(QQuickBasePositioner);
+ // Note that if a transition is not set the transition manager will
+ // apply the changes directly, in the case add/move aren't set
+ d->addTransitionManager.transition(d->addActions, d->addTransition);
+ d->moveTransitionManager.transition(d->moveActions, d->moveTransition);
+ d->addActions.clear();
+ d->moveActions.clear();
+}
+
+QQuickPositionerAttached *QQuickBasePositioner::qmlAttachedProperties(QObject *obj)
+{
+ return new QQuickPositionerAttached(obj);
+}
+
+void QQuickBasePositioner::updateAttachedProperties(QQuickPositionerAttached *specificProperty, QQuickItem *specificPropertyOwner) const
+{
+ // If this function is deemed too expensive or shows up in profiles, it could
+ // be changed to run only when there are attached properties present. This
+ // could be a flag in the positioner that is set by the attached property
+ // constructor.
+ QQuickPositionerAttached *prevLastProperty = 0;
+ QQuickPositionerAttached *lastProperty = 0;
+
+ int visibleItemIndex = 0;
+ for (int ii = 0; ii < positionedItems.count(); ++ii) {
+ const PositionedItem &child = positionedItems.at(ii);
+ if (!child.item)
+ continue;
+
+ QQuickPositionerAttached *property = 0;
+
+ if (specificProperty) {
+ if (specificPropertyOwner == child.item) {
+ property = specificProperty;
+ }
+ } else {
+ property = static_cast<QQuickPositionerAttached *>(qmlAttachedPropertiesObject<QQuickBasePositioner>(child.item, false));
+ }
+
+ if (child.isVisible) {
+ if (property) {
+ property->setIndex(visibleItemIndex);
+ property->setIsFirstItem(visibleItemIndex == 0);
+
+ if (property->isLastItem())
+ prevLastProperty = property;
+ }
+
+ lastProperty = property;
+ ++visibleItemIndex;
+ } else if (property) {
+ property->setIndex(-1);
+ property->setIsFirstItem(false);
+ property->setIsLastItem(false);
+ }
+ }
+
+ if (prevLastProperty && prevLastProperty != lastProperty)
+ prevLastProperty->setIsLastItem(false);
+ if (lastProperty)
+ lastProperty->setIsLastItem(true);
+}
+
+/*!
+ \qmlclass Positioner QQuickPositionerAttached
+ \inqmlmodule QtQuick 2
+ \ingroup qml-positioning-elements
+ \brief The Positioner type provides attached properties that contain details on where an item exists in a positioner.
+
+ Positioner items (such as Column, Row, Flow and Grid) provide automatic layout
+ for child items. Attaching this property allows a child item to determine
+ where it exists within the positioner.
+*/
+
+QQuickPositionerAttached::QQuickPositionerAttached(QObject *parent) : QObject(parent), m_index(-1), m_isFirstItem(false), m_isLastItem(false)
+{
+ QQuickItem *attachedItem = qobject_cast<QQuickItem *>(parent);
+ if (attachedItem) {
+ QQuickBasePositioner *positioner = qobject_cast<QQuickBasePositioner *>(attachedItem->parent());
+ if (positioner) {
+ positioner->updateAttachedProperties(this, attachedItem);
+ }
+ }
+}
+
+/*!
+ \qmlattachedproperty Item QtQuick2::Positioner::index
+
+ This property allows the item to determine
+ its index within the positioner.
+*/
+void QQuickPositionerAttached::setIndex(int index)
+{
+ if (m_index == index)
+ return;
+ m_index = index;
+ emit indexChanged();
+}
+
+/*!
+ \qmlattachedproperty Item QtQuick2::Positioner::isFirstItem
+ \qmlattachedproperty Item QtQuick2::Positioner::isLastItem
+
+ These properties allow the item to determine if it
+ is the first or last item in the positioner, respectively.
+*/
+void QQuickPositionerAttached::setIsFirstItem(bool isFirstItem)
+{
+ if (m_isFirstItem == isFirstItem)
+ return;
+ m_isFirstItem = isFirstItem;
+ emit isFirstItemChanged();
+}
+
+void QQuickPositionerAttached::setIsLastItem(bool isLastItem)
+{
+ if (m_isLastItem == isLastItem)
+ return;
+ m_isLastItem = isLastItem;
+ emit isLastItemChanged();
+}
+
+/*!
+ \qmlclass Column QQuickColumn
+ \inqmlmodule QtQuick 2
+ \ingroup qml-positioning-elements
+ \brief The Column item arranges its children vertically.
+ \inherits Item
+
+ The Column item positions its child items so that they are vertically
+ aligned and not overlapping.
+
+ Spacing between items can be added using the \l spacing property.
+ Transitions can be used for cases where items managed by a Column are
+ added or moved. These are stored in the \l add and \l move properties
+ respectively.
+
+ See \l{Using QML Positioner and Repeater Items} for more details about this item and other
+ related items.
+
+ \section1 Example Usage
+
+ The following example positions differently shaped rectangles using a Column
+ item.
+
+ \image verticalpositioner_example.png
+
+ \snippet doc/src/snippets/declarative/column/vertical-positioner.qml document
+
+ \section1 Using Transitions
+
+ Transitions can be used to animate items that are added to, moved within,
+ or removed from a Column item. The \l add and \l move properties can be set to
+ the transitions that will be applied when items are added to, removed from,
+ or re-positioned within a Column item.
+
+ The use of transitions with positioners is described in more detail in the
+ \l{Using QML Positioner and Repeater Items#Using Transitions}{Using QML
+ Positioner and Repeater Items} document.
+
+ \image verticalpositioner_transition.gif
+
+ \qml
+ Column {
+ spacing: 2
+ add: Transition {
+ // Define an animation for adding a new item...
+ }
+ move: Transition {
+ // Define an animation for moving items within the column...
+ }
+ // ...
+ }
+ \endqml
+
+ \section1 Limitations
+
+ Note that the positioner assumes that the x and y positions of its children
+ will not change. If you manually change the x or y properties in script, bind
+ the x or y properties, use anchors on a child of a positioner, or have the
+ height of a child depend on the position of a child, then the
+ positioner may exhibit strange behavior. If you need to perform any of these
+ actions, consider positioning the items without the use of a Column.
+
+ Items with a width or height of 0 will not be positioned.
+
+ Positioning is batched and syncronized with painting to reduce the number of
+ calculations needed. This means that positioners may not reposition items immediately
+ when changes occur, but it will have moved by the next frame.
+
+ \sa Row, Grid, Flow, Positioner, {declarative/positioners}{Positioners example}
+*/
+/*!
+ \qmlproperty Transition QtQuick2::Column::add
+
+ This property holds the transition to be applied when adding an
+ item to the positioner. The transition will only be applied to the
+ added item(s). Positioner transitions will only affect the
+ position (x, y) of items.
+
+ For a positioner, adding an item can mean that either the object
+ has been created or reparented, and thus is now a child or the
+ positioner, or that the object has had its opacity increased from
+ zero, and thus is now visible.
+
+ \sa move
+*/
+/*!
+ \qmlproperty Transition QtQuick2::Column::move
+
+ This property holds the transition to apply when moving an item
+ within the positioner. Positioner transitions will only affect
+ the position (x, y) of items.
+
+ This transition can be performed when other items are added or removed
+ from the positioner, or when items resize themselves.
+
+ \image positioner-move.gif
+
+ \qml
+ Column {
+ move: Transition {
+ NumberAnimation {
+ properties: "y"
+ duration: 1000
+ }
+ }
+ }
+ \endqml
+
+ \sa add, {declarative/positioners}{Positioners example}
+*/
+/*!
+ \qmlproperty int QtQuick2::Column::spacing
+
+ The spacing is the amount in pixels left empty between adjacent
+ items. The default spacing is 0.
+
+ \sa Grid::spacing
+*/
+QQuickColumn::QQuickColumn(QQuickItem *parent)
+: QQuickBasePositioner(Vertical, parent)
+{
+}
+
+void QQuickColumn::doPositioning(QSizeF *contentSize)
+{
+ int voffset = 0;
+
+ for (int ii = 0; ii < positionedItems.count(); ++ii) {
+ const PositionedItem &child = positionedItems.at(ii);
+ if (!child.item || !child.isVisible)
+ continue;
+
+ if (child.item->y() != voffset)
+ positionY(voffset, child);
+
+ contentSize->setWidth(qMax(contentSize->width(), child.item->width()));
+
+ voffset += child.item->height();
+ voffset += spacing();
+ }
+
+ if (voffset != 0)//If we positioned any items, undo the spacing from the last item
+ voffset -= spacing();
+ contentSize->setHeight(voffset);
+}
+
+void QQuickColumn::reportConflictingAnchors()
+{
+ QQuickBasePositionerPrivate *d = static_cast<QQuickBasePositionerPrivate*>(QQuickBasePositionerPrivate::get(this));
+ for (int ii = 0; ii < positionedItems.count(); ++ii) {
+ const PositionedItem &child = positionedItems.at(ii);
+ if (child.item) {
+ QQuickAnchors *anchors = QQuickItemPrivate::get(static_cast<QQuickItem *>(child.item))->_anchors;
+ if (anchors) {
+ QQuickAnchors::Anchors usedAnchors = anchors->usedAnchors();
+ if (usedAnchors & QQuickAnchors::TopAnchor ||
+ usedAnchors & QQuickAnchors::BottomAnchor ||
+ usedAnchors & QQuickAnchors::VCenterAnchor ||
+ anchors->fill() || anchors->centerIn()) {
+ d->anchorConflict = true;
+ break;
+ }
+ }
+ }
+ }
+ if (d->anchorConflict) {
+ qmlInfo(this) << "Cannot specify top, bottom, verticalCenter, fill or centerIn anchors for items inside Column";
+ }
+}
+/*!
+ \qmlclass Row QQuickRow
+ \inqmlmodule QtQuick 2
+ \ingroup qml-positioning-elements
+ \brief The Row item arranges its children horizontally.
+ \inherits Item
+
+ The Row item positions its child items so that they are horizontally
+ aligned and not overlapping.
+
+ Use \l spacing to set the spacing between items in a Row, and use the
+ \l add and \l move properties to set the transitions that should be applied
+ when items are added to, removed from, or re-positioned within the Row.
+
+ See \l{Using QML Positioner and Repeater Items} for more details about this item and other
+ related items.
+
+ \section1 Example Usage
+
+ The following example lays out differently shaped rectangles using a Row.
+
+ \image horizontalpositioner_example.png
+
+ \snippet doc/src/snippets/declarative/row/row.qml document
+
+ \section1 Using Transitions
+
+ Transitions can be used to animate items that are added to, moved within,
+ or removed from a Grid item. The \l add and \l move properties can be set to
+ the transitions that will be applied when items are added to, removed from,
+ or re-positioned within a Row item.
+
+ \section1 Limitations
+
+ Note that the positioner assumes that the x and y positions of its children
+ will not change. If you manually change the x or y properties in script, bind
+ the x or y properties, use anchors on a child of a positioner, or have the
+ width of a child depend on the position of a child, then the
+ positioner may exhibit strange behaviour. If you need to perform any of these
+ actions, consider positioning the items without the use of a Row.
+
+ Items with a width or height of 0 will not be positioned.
+
+ Positioning is batched and syncronized with painting to reduce the number of
+ calculations needed. This means that positioners may not reposition items immediately
+ when changes occur, but it will have moved by the next frame.
+
+ \sa Column, Grid, Flow, Positioner, {declarative/positioners}{Positioners example}
+*/
+/*!
+ \qmlproperty Transition QtQuick2::Row::add
+
+ This property holds the transition to be applied when adding an
+ item to the positioner. The transition will only be applied to the
+ added item(s). Positioner transitions will only affect the
+ position (x, y) of items.
+
+ For a positioner, adding an item can mean that either the object
+ has been created or reparented, and thus is now a child or the
+ positioner, or that the object has had its opacity increased from
+ zero, and thus is now visible.
+
+ \sa move
+*/
+/*!
+ \qmlproperty Transition QtQuick2::Row::move
+
+ This property holds the transition to be applied when moving an
+ item within the positioner. Positioner transitions will only affect
+ the position (x, y) of items.
+
+ This transition can be performed when other items are added or removed
+ from the positioner, or when items resize themselves.
+
+ \qml
+ Row {
+ id: positioner
+ move: Transition {
+ NumberAnimation {
+ properties: "x"
+ duration: 1000
+ }
+ }
+ }
+ \endqml
+
+ \sa add, {declarative/positioners}{Positioners example}
+*/
+/*!
+ \qmlproperty int QtQuick2::Row::spacing
+
+ The spacing is the amount in pixels left empty between adjacent
+ items. The default spacing is 0.
+
+ \sa Grid::spacing
+*/
+
+QQuickRow::QQuickRow(QQuickItem *parent)
+: QQuickBasePositioner(Horizontal, parent)
+{
+}
+/*!
+ \qmlproperty enumeration QtQuick2::Row::layoutDirection
+
+ This property holds the layoutDirection of the row.
+
+ Possible values:
+
+ \list
+ \o Qt.LeftToRight (default) - Items are laid out from left to right. If the width of the row is explicitly set,
+ the left anchor remains to the left of the row.
+ \o Qt.RightToLeft - Items are laid out from right to left. If the width of the row is explicitly set,
+ the right anchor remains to the right of the row.
+ \endlist
+
+ \sa Grid::layoutDirection, Flow::layoutDirection, {declarative/righttoleft/layoutdirection}{Layout directions example}
+*/
+
+Qt::LayoutDirection QQuickRow::layoutDirection() const
+{
+ return QQuickBasePositionerPrivate::getLayoutDirection(this);
+}
+
+void QQuickRow::setLayoutDirection(Qt::LayoutDirection layoutDirection)
+{
+ QQuickBasePositionerPrivate *d = static_cast<QQuickBasePositionerPrivate* >(QQuickBasePositionerPrivate::get(this));
+ if (d->layoutDirection != layoutDirection) {
+ d->layoutDirection = layoutDirection;
+ // For RTL layout the positioning changes when the width changes.
+ if (d->layoutDirection == Qt::RightToLeft)
+ d->addItemChangeListener(d, QQuickItemPrivate::Geometry);
+ else
+ d->removeItemChangeListener(d, QQuickItemPrivate::Geometry);
+ prePositioning();
+ emit layoutDirectionChanged();
+ emit effectiveLayoutDirectionChanged();
+ }
+}
+/*!
+ \qmlproperty enumeration QtQuick2::Row::effectiveLayoutDirection
+ This property holds the effective layout direction of the row positioner.
+
+ When using the attached property \l {LayoutMirroring::enabled}{LayoutMirroring::enabled} for locale layouts,
+ the visual layout direction of the row positioner will be mirrored. However, the
+ property \l {Row::layoutDirection}{layoutDirection} will remain unchanged.
+
+ \sa Row::layoutDirection, {LayoutMirroring}{LayoutMirroring}
+*/
+
+Qt::LayoutDirection QQuickRow::effectiveLayoutDirection() const
+{
+ return QQuickBasePositionerPrivate::getEffectiveLayoutDirection(this);
+}
+
+void QQuickRow::doPositioning(QSizeF *contentSize)
+{
+ QQuickBasePositionerPrivate *d = static_cast<QQuickBasePositionerPrivate* >(QQuickBasePositionerPrivate::get(this));
+ int hoffset = 0;
+
+ QList<int> hoffsets;
+ for (int ii = 0; ii < positionedItems.count(); ++ii) {
+ const PositionedItem &child = positionedItems.at(ii);
+ if (!child.item || !child.isVisible)
+ continue;
+
+ if (d->isLeftToRight()) {
+ if (child.item->x() != hoffset)
+ positionX(hoffset, child);
+ } else {
+ hoffsets << hoffset;
+ }
+
+ contentSize->setHeight(qMax(contentSize->height(), child.item->height()));
+
+ hoffset += child.item->width();
+ hoffset += spacing();
+ }
+
+ if (hoffset != 0)//If we positioned any items, undo the extra spacing from the last item
+ hoffset -= spacing();
+ contentSize->setWidth(hoffset);
+
+ if (d->isLeftToRight())
+ return;
+
+ //Right to Left layout
+ int end = 0;
+ if (!widthValid())
+ end = contentSize->width();
+ else
+ end = width();
+
+ int acc = 0;
+ for (int ii = 0; ii < positionedItems.count(); ++ii) {
+ const PositionedItem &child = positionedItems.at(ii);
+ if (!child.item || !child.isVisible)
+ continue;
+ hoffset = end - hoffsets[acc++] - child.item->width();
+ if (child.item->x() != hoffset)
+ positionX(hoffset, child);
+ }
+}
+
+void QQuickRow::reportConflictingAnchors()
+{
+ QQuickBasePositionerPrivate *d = static_cast<QQuickBasePositionerPrivate*>(QQuickBasePositionerPrivate::get(this));
+ for (int ii = 0; ii < positionedItems.count(); ++ii) {
+ const PositionedItem &child = positionedItems.at(ii);
+ if (child.item) {
+ QQuickAnchors *anchors = QQuickItemPrivate::get(static_cast<QQuickItem *>(child.item))->_anchors;
+ if (anchors) {
+ QQuickAnchors::Anchors usedAnchors = anchors->usedAnchors();
+ if (usedAnchors & QQuickAnchors::LeftAnchor ||
+ usedAnchors & QQuickAnchors::RightAnchor ||
+ usedAnchors & QQuickAnchors::HCenterAnchor ||
+ anchors->fill() || anchors->centerIn()) {
+ d->anchorConflict = true;
+ break;
+ }
+ }
+ }
+ }
+ if (d->anchorConflict)
+ qmlInfo(this) << "Cannot specify left, right, horizontalCenter, fill or centerIn anchors for items inside Row";
+}
+
+/*!
+ \qmlclass Grid QQuickGrid
+ \inqmlmodule QtQuick 2
+ \ingroup qml-positioning-elements
+ \brief The Grid item positions its children in a grid.
+ \inherits Item
+
+ The Grid item positions its child items so that they are
+ aligned in a grid and are not overlapping.
+
+ The grid positioner calculates a grid of rectangular cells of sufficient
+ size to hold all items, placing the items in the cells, from left to right
+ and top to bottom. Each item is positioned in the top-left corner of its
+ cell with position (0, 0).
+
+ A Grid defaults to four columns, and as many rows as are necessary to
+ fit all child items. The number of rows and columns can be constrained
+ by setting the \l rows and \l columns properties.
+
+ Spacing can be added between child items by setting the \l spacing
+ property. The amount of spacing applied will be the same in the
+ horizontal and vertical directions.
+
+ See \l{Using QML Positioner and Repeater Items} for more details about this item and other
+ related items.
+
+ \section1 Example Usage
+
+ The following example demonstrates this.
+
+ \image gridLayout_example.png
+
+ \snippet doc/src/snippets/declarative/grid/grid.qml document
+
+ \section1 Using Transitions
+
+ Transitions can be used to animate items that are added to, moved within,
+ or removed from a Grid item. The \l add and \l move properties can be set to
+ the transitions that will be applied when items are added to, removed from,
+ or re-positioned within a Grid item.
+
+ \section1 Limitations
+
+ Note that the positioner assumes that the x and y positions of its children
+ will not change. If you manually change the x or y properties in script, bind
+ the x or y properties, use anchors on a child of a positioner, or have the
+ width or height of a child depend on the position of a child, then the
+ positioner may exhibit strange behaviour. If you need to perform any of these
+ actions, consider positioning the items without the use of a Grid.
+
+ Items with a width or height of 0 will not be positioned.
+
+ Positioning is batched and syncronized with painting to reduce the number of
+ calculations needed. This means that positioners may not reposition items immediately
+ when changes occur, but it will have moved by the next frame.
+
+ \sa Flow, Row, Column, Positioner, {declarative/positioners}{Positioners example}
+*/
+/*!
+ \qmlproperty Transition QtQuick2::Grid::add
+
+ This property holds the transition to be applied when adding an
+ item to the positioner. The transition will only be applied to the
+ added item(s). Positioner transitions will only affect the
+ position (x, y) of items.
+
+ For a positioner, adding an item can mean that either the object
+ has been created or reparented, and thus is now a child or the
+ positioner, or that the object has had its opacity increased from
+ zero, and thus is now visible.
+
+ \sa move
+*/
+/*!
+ \qmlproperty Transition QtQuick2::Grid::move
+
+ This property holds the transition to be applied when moving an
+ item within the positioner. Positioner transitions will only affect
+ the position (x, y) of items.
+
+ This transition can be performed when other items are added or removed
+ from the positioner, or when items resize themselves.
+
+ \qml
+ Grid {
+ move: Transition {
+ NumberAnimation {
+ properties: "x,y"
+ duration: 1000
+ }
+ }
+ }
+ \endqml
+
+ \sa add, {declarative/positioners}{Positioners example}
+*/
+/*!
+ \qmlproperty int QtQuick2::Grid::spacing
+
+ The spacing is the amount in pixels left empty between adjacent
+ items. The default spacing is 0.
+
+ The below example places a Grid containing a red, a blue and a
+ green rectangle on a gray background. The area the grid positioner
+ occupies is colored white. The positioner on the left has the
+ no spacing (the default), and the positioner on the right has
+ a spacing of 6.
+
+ \inlineimage qml-grid-no-spacing.png
+ \inlineimage qml-grid-spacing.png
+
+ \sa rows, columns
+*/
+QQuickGrid::QQuickGrid(QQuickItem *parent) :
+ QQuickBasePositioner(Both, parent), m_rows(-1), m_columns(-1), m_rowSpacing(-1), m_columnSpacing(-1), m_flow(LeftToRight)
+{
+}
+
+/*!
+ \qmlproperty int QtQuick2::Grid::columns
+
+ This property holds the number of columns in the grid. The default
+ number of columns is 4.
+
+ If the grid does not have enough items to fill the specified
+ number of columns, some columns will be of zero width.
+*/
+
+/*!
+ \qmlproperty int QtQuick2::Grid::rows
+ This property holds the number of rows in the grid.
+
+ If the grid does not have enough items to fill the specified
+ number of rows, some rows will be of zero width.
+*/
+
+void QQuickGrid::setColumns(const int columns)
+{
+ if (columns == m_columns)
+ return;
+ m_columns = columns;
+ prePositioning();
+ emit columnsChanged();
+}
+
+void QQuickGrid::setRows(const int rows)
+{
+ if (rows == m_rows)
+ return;
+ m_rows = rows;
+ prePositioning();
+ emit rowsChanged();
+}
+
+/*!
+ \qmlproperty enumeration QtQuick2::Grid::flow
+ This property holds the flow of the layout.
+
+ Possible values are:
+
+ \list
+ \o Grid.LeftToRight (default) - Items are positioned next to
+ each other in the \l layoutDirection, then wrapped to the next line.
+ \o Grid.TopToBottom - Items are positioned next to each
+ other from top to bottom, then wrapped to the next column.
+ \endlist
+*/
+QQuickGrid::Flow QQuickGrid::flow() const
+{
+ return m_flow;
+}
+
+void QQuickGrid::setFlow(Flow flow)
+{
+ if (m_flow != flow) {
+ m_flow = flow;
+ prePositioning();
+ emit flowChanged();
+ }
+}
+
+/*!
+ \qmlproperty int QtQuick2::Grid::rowSpacing
+
+ This property holds the spacing in pixels between rows.
+
+ \sa columnSpacing
+ \since QtQuick2.0
+*/
+void QQuickGrid::setRowSpacing(const int rowSpacing)
+{
+ if (rowSpacing == m_rowSpacing)
+ return;
+ m_rowSpacing = rowSpacing;
+ prePositioning();
+ emit rowSpacingChanged();
+}
+
+/*!
+ \qmlproperty int QtQuick2::Grid::columnSpacing
+
+ This property holds the spacing in pixels between columns.
+
+ \sa rowSpacing
+ \since QtQuick2.0
+*/
+void QQuickGrid::setColumnSpacing(const int columnSpacing)
+{
+ if (columnSpacing == m_columnSpacing)
+ return;
+ m_columnSpacing = columnSpacing;
+ prePositioning();
+ emit columnSpacingChanged();
+}
+
+/*!
+ \qmlproperty enumeration QtQuick2::Grid::layoutDirection
+
+ This property holds the layout direction of the layout.
+
+ Possible values are:
+
+ \list
+ \o Qt.LeftToRight (default) - Items are positioned from the top to bottom,
+ and left to right. The flow direction is dependent on the
+ \l Grid::flow property.
+ \o Qt.RightToLeft - Items are positioned from the top to bottom,
+ and right to left. The flow direction is dependent on the
+ \l Grid::flow property.
+ \endlist
+
+ \sa Flow::layoutDirection, Row::layoutDirection, {declarative/righttoleft/layoutdirection}{Layout directions example}
+*/
+Qt::LayoutDirection QQuickGrid::layoutDirection() const
+{
+ return QQuickBasePositionerPrivate::getLayoutDirection(this);
+}
+
+void QQuickGrid::setLayoutDirection(Qt::LayoutDirection layoutDirection)
+{
+ QQuickBasePositionerPrivate *d = static_cast<QQuickBasePositionerPrivate*>(QQuickBasePositionerPrivate::get(this));
+ if (d->layoutDirection != layoutDirection) {
+ d->layoutDirection = layoutDirection;
+ // For RTL layout the positioning changes when the width changes.
+ if (d->layoutDirection == Qt::RightToLeft)
+ d->addItemChangeListener(d, QQuickItemPrivate::Geometry);
+ else
+ d->removeItemChangeListener(d, QQuickItemPrivate::Geometry);
+ prePositioning();
+ emit layoutDirectionChanged();
+ emit effectiveLayoutDirectionChanged();
+ }
+}
+
+/*!
+ \qmlproperty enumeration QtQuick2::Grid::effectiveLayoutDirection
+ This property holds the effective layout direction of the grid positioner.
+
+ When using the attached property \l {LayoutMirroring::enabled}{LayoutMirroring::enabled} for locale layouts,
+ the visual layout direction of the grid positioner will be mirrored. However, the
+ property \l {Grid::layoutDirection}{layoutDirection} will remain unchanged.
+
+ \sa Grid::layoutDirection, {LayoutMirroring}{LayoutMirroring}
+*/
+Qt::LayoutDirection QQuickGrid::effectiveLayoutDirection() const
+{
+ return QQuickBasePositionerPrivate::getEffectiveLayoutDirection(this);
+}
+
+void QQuickGrid::doPositioning(QSizeF *contentSize)
+{
+ QQuickBasePositionerPrivate *d = static_cast<QQuickBasePositionerPrivate*>(QQuickBasePositionerPrivate::get(this));
+ int c = m_columns;
+ int r = m_rows;
+ //Is allocating the extra QPODVector too much overhead?
+ QPODVector<PositionedItem, 8> visibleItems;//we aren't concerned with invisible items
+ visibleItems.reserve(positionedItems.count());
+ for (int i=0; i<positionedItems.count(); i++)
+ if (positionedItems[i].item && positionedItems[i].isVisible)
+ visibleItems.append(positionedItems[i]);
+
+ int numVisible = visibleItems.count();
+ if (m_columns <= 0 && m_rows <= 0){
+ c = 4;
+ r = (numVisible+3)/4;
+ } else if (m_rows <= 0){
+ r = (numVisible+(m_columns-1))/m_columns;
+ } else if (m_columns <= 0){
+ c = (numVisible+(m_rows-1))/m_rows;
+ }
+
+ if (r==0 || c==0)
+ return; //Nothing to do
+
+ QList<int> maxColWidth;
+ QList<int> maxRowHeight;
+ int childIndex =0;
+ if (m_flow == LeftToRight) {
+ for (int i=0; i < r; i++){
+ for (int j=0; j < c; j++){
+ if (j==0)
+ maxRowHeight << 0;
+ if (i==0)
+ maxColWidth << 0;
+
+ if (childIndex == visibleItems.count())
+ break;
+
+ const PositionedItem &child = visibleItems.at(childIndex++);
+ if (child.item->width() > maxColWidth[j])
+ maxColWidth[j] = child.item->width();
+ if (child.item->height() > maxRowHeight[i])
+ maxRowHeight[i] = child.item->height();
+ }
+ }
+ } else {
+ for (int j=0; j < c; j++){
+ for (int i=0; i < r; i++){
+ if (j==0)
+ maxRowHeight << 0;
+ if (i==0)
+ maxColWidth << 0;
+
+ if (childIndex == visibleItems.count())
+ break;
+
+ const PositionedItem &child = visibleItems.at(childIndex++);
+ if (child.item->width() > maxColWidth[j])
+ maxColWidth[j] = child.item->width();
+ if (child.item->height() > maxRowHeight[i])
+ maxRowHeight[i] = child.item->height();
+ }
+ }
+ }
+
+ int columnSpacing = m_columnSpacing;
+ if (columnSpacing == -1)
+ columnSpacing = spacing();
+
+ int rowSpacing = m_rowSpacing;
+ if (rowSpacing == -1)
+ rowSpacing = spacing();
+
+ int widthSum = 0;
+ for (int j=0; j < maxColWidth.size(); j++){
+ if (j)
+ widthSum += columnSpacing;
+ widthSum += maxColWidth[j];
+ }
+
+ int heightSum = 0;
+ for (int i=0; i < maxRowHeight.size(); i++){
+ if (i)
+ heightSum += rowSpacing;
+ heightSum += maxRowHeight[i];
+ }
+
+ contentSize->setHeight(heightSum);
+ contentSize->setWidth(widthSum);
+
+ int end = 0;
+ if (widthValid())
+ end = width();
+ else
+ end = widthSum;
+
+ int xoffset=0;
+ if (!d->isLeftToRight())
+ xoffset = end;
+ int yoffset=0;
+ int curRow =0;
+ int curCol =0;
+ for (int i = 0; i < visibleItems.count(); ++i) {
+ const PositionedItem &child = visibleItems.at(i);
+ int childXOffset = xoffset;
+ if (!d->isLeftToRight())
+ childXOffset -= child.item->width();
+ if ((child.item->x() != childXOffset) || (child.item->y() != yoffset)){
+ positionX(childXOffset, child);
+ positionY(yoffset, child);
+ }
+
+ if (m_flow == LeftToRight) {
+ if (d->isLeftToRight())
+ xoffset += maxColWidth[curCol]+columnSpacing;
+ else
+ xoffset -= maxColWidth[curCol]+columnSpacing;
+ curCol++;
+ curCol%=c;
+ if (!curCol){
+ yoffset += maxRowHeight[curRow]+rowSpacing;
+ if (d->isLeftToRight())
+ xoffset = 0;
+ else
+ xoffset = end;
+ curRow++;
+ if (curRow>=r)
+ break;
+ }
+ } else {
+ yoffset+=maxRowHeight[curRow]+rowSpacing;
+ curRow++;
+ curRow%=r;
+ if (!curRow){
+ if (d->isLeftToRight())
+ xoffset += maxColWidth[curCol]+columnSpacing;
+ else
+ xoffset -= maxColWidth[curCol]+columnSpacing;
+ yoffset=0;
+ curCol++;
+ if (curCol>=c)
+ break;
+ }
+ }
+ }
+}
+
+void QQuickGrid::reportConflictingAnchors()
+{
+ QQuickBasePositionerPrivate *d = static_cast<QQuickBasePositionerPrivate*>(QQuickBasePositionerPrivate::get(this));
+ for (int ii = 0; ii < positionedItems.count(); ++ii) {
+ const PositionedItem &child = positionedItems.at(ii);
+ if (child.item) {
+ QQuickAnchors *anchors = QQuickItemPrivate::get(static_cast<QQuickItem *>(child.item))->_anchors;
+ if (anchors && (anchors->usedAnchors() || anchors->fill() || anchors->centerIn())) {
+ d->anchorConflict = true;
+ break;
+ }
+ }
+ }
+ if (d->anchorConflict)
+ qmlInfo(this) << "Cannot specify anchors for items inside Grid";
+}
+
+/*!
+ \qmlclass Flow QQuickFlow
+ \inqmlmodule QtQuick 2
+ \ingroup qml-positioning-elements
+ \brief The Flow item arranges its children side by side, wrapping as necessary.
+ \inherits Item
+
+ The Flow item positions its child items like words on a page, wrapping them
+ to create rows or columns of items that do not overlap.
+
+ Spacing between items can be added using the \l spacing property.
+ Transitions can be used for cases where items managed by a Column are
+ added or moved. These are stored in the \l add and \l move properties
+ respectively.
+
+ See \l{Using QML Positioner and Repeater Items} for more details about this item and other
+ related items.
+
+ \section1 Example Usage
+
+ The following example positions \l Text items within a parent item using
+ a Flow item.
+
+ \image qml-flow-snippet.png
+
+ \snippet doc/src/snippets/declarative/flow.qml flow item
+
+ \section1 Using Transitions
+
+ Transitions can be used to animate items that are added to, moved within,
+ or removed from a Flow item. The \l add and \l move properties can be set to
+ the transitions that will be applied when items are added to, removed from,
+ or re-positioned within a Flow item.
+
+ The use of transitions with positioners is described in more detail in the
+ \l{Using QML Positioner and Repeater Items#Using Transitions}{Using QML
+ Positioner and Repeater Items} document.
+
+ \section1 Limitations
+
+ Note that the positioner assumes that the x and y positions of its children
+ will not change. If you manually change the x or y properties in script, bind
+ the x or y properties, use anchors on a child of a positioner, or have the
+ width or height of a child depend on the position of a child, then the
+ positioner may exhibit strange behaviour. If you need to perform any of these
+ actions, consider positioning the items without the use of a Flow.
+
+ Items with a width or height of 0 will not be positioned.
+
+ Positioning is batched and syncronized with painting to reduce the number of
+ calculations needed. This means that positioners may not reposition items immediately
+ when changes occur, but it will have moved by the next frame.
+
+ \sa Column, Row, Grid, Positioner, {declarative/positioners}{Positioners example}
+*/
+/*!
+ \qmlproperty Transition QtQuick2::Flow::add
+
+ This property holds the transition to be applied when adding an
+ item to the positioner. The transition will only be applied to the
+ added item(s). Positioner transitions will only affect the
+ position (x, y) of items.
+
+ For a positioner, adding an item can mean that either the object
+ has been created or reparented, and thus is now a child or the
+ positioner, or that the object has had its opacity increased from
+ zero, and thus is now visible.
+
+ \sa move
+*/
+/*!
+ \qmlproperty Transition QtQuick2::Flow::move
+
+ This property holds the transition to be applied when moving an
+ item within the positioner. Positioner transitions will only affect
+ the position (x, y) of items.
+
+ This transition can be performed when other items are added or removed
+ from the positioner, or when items resize themselves.
+
+ \qml
+ Flow {
+ id: positioner
+ move: Transition {
+ NumberAnimation {
+ properties: "x,y"
+ ease: "easeOutBounce"
+ }
+ }
+ }
+ \endqml
+
+ \sa add, {declarative/positioners}{Positioners example}
+*/
+/*!
+ \qmlproperty int QtQuick2::Flow::spacing
+
+ spacing is the amount in pixels left empty between each adjacent
+ item, and defaults to 0.
+
+ \sa Grid::spacing
+*/
+
+class QQuickFlowPrivate : public QQuickBasePositionerPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickFlow)
+
+public:
+ QQuickFlowPrivate()
+ : QQuickBasePositionerPrivate(), flow(QQuickFlow::LeftToRight)
+ {}
+
+ QQuickFlow::Flow flow;
+};
+
+QQuickFlow::QQuickFlow(QQuickItem *parent)
+: QQuickBasePositioner(*(new QQuickFlowPrivate), Both, parent)
+{
+ Q_D(QQuickFlow);
+ // Flow layout requires relayout if its own size changes too.
+ d->addItemChangeListener(d, QQuickItemPrivate::Geometry);
+}
+
+/*!
+ \qmlproperty enumeration QtQuick2::Flow::flow
+ This property holds the flow of the layout.
+
+ Possible values are:
+
+ \list
+ \o Flow.LeftToRight (default) - Items are positioned next to
+ to each other according to the \l layoutDirection until the width of the Flow
+ is exceeded, then wrapped to the next line.
+ \o Flow.TopToBottom - Items are positioned next to each
+ other from top to bottom until the height of the Flow is exceeded,
+ then wrapped to the next column.
+ \endlist
+*/
+QQuickFlow::Flow QQuickFlow::flow() const
+{
+ Q_D(const QQuickFlow);
+ return d->flow;
+}
+
+void QQuickFlow::setFlow(Flow flow)
+{
+ Q_D(QQuickFlow);
+ if (d->flow != flow) {
+ d->flow = flow;
+ prePositioning();
+ emit flowChanged();
+ }
+}
+
+/*!
+ \qmlproperty enumeration QtQuick2::Flow::layoutDirection
+
+ This property holds the layout direction of the layout.
+
+ Possible values are:
+
+ \list
+ \o Qt.LeftToRight (default) - Items are positioned from the top to bottom,
+ and left to right. The flow direction is dependent on the
+ \l Flow::flow property.
+ \o Qt.RightToLeft - Items are positioned from the top to bottom,
+ and right to left. The flow direction is dependent on the
+ \l Flow::flow property.
+ \endlist
+
+ \sa Grid::layoutDirection, Row::layoutDirection, {declarative/righttoleft/layoutdirection}{Layout directions example}
+*/
+
+Qt::LayoutDirection QQuickFlow::layoutDirection() const
+{
+ Q_D(const QQuickFlow);
+ return d->layoutDirection;
+}
+
+void QQuickFlow::setLayoutDirection(Qt::LayoutDirection layoutDirection)
+{
+ Q_D(QQuickFlow);
+ if (d->layoutDirection != layoutDirection) {
+ d->layoutDirection = layoutDirection;
+ prePositioning();
+ emit layoutDirectionChanged();
+ emit effectiveLayoutDirectionChanged();
+ }
+}
+
+/*!
+ \qmlproperty enumeration QtQuick2::Flow::effectiveLayoutDirection
+ This property holds the effective layout direction of the flow positioner.
+
+ When using the attached property \l {LayoutMirroring::enabled}{LayoutMirroring::enabled} for locale layouts,
+ the visual layout direction of the grid positioner will be mirrored. However, the
+ property \l {Flow::layoutDirection}{layoutDirection} will remain unchanged.
+
+ \sa Flow::layoutDirection, {LayoutMirroring}{LayoutMirroring}
+*/
+
+Qt::LayoutDirection QQuickFlow::effectiveLayoutDirection() const
+{
+ return QQuickBasePositionerPrivate::getEffectiveLayoutDirection(this);
+}
+
+void QQuickFlow::doPositioning(QSizeF *contentSize)
+{
+ Q_D(QQuickFlow);
+
+ int hoffset = 0;
+ int voffset = 0;
+ int linemax = 0;
+ QList<int> hoffsets;
+
+ for (int i = 0; i < positionedItems.count(); ++i) {
+ const PositionedItem &child = positionedItems.at(i);
+ if (!child.item || !child.isVisible)
+ continue;
+
+ if (d->flow == LeftToRight) {
+ if (widthValid() && hoffset && hoffset + child.item->width() > width()) {
+ hoffset = 0;
+ voffset += linemax + spacing();
+ linemax = 0;
+ }
+ } else {
+ if (heightValid() && voffset && voffset + child.item->height() > height()) {
+ voffset = 0;
+ hoffset += linemax + spacing();
+ linemax = 0;
+ }
+ }
+
+ if (d->isLeftToRight()) {
+ if (child.item->x() != hoffset)
+ positionX(hoffset, child);
+ } else {
+ hoffsets << hoffset;
+ }
+ if (child.item->y() != voffset)
+ positionY(voffset, child);
+
+ contentSize->setWidth(qMax(contentSize->width(), hoffset + child.item->width()));
+ contentSize->setHeight(qMax(contentSize->height(), voffset + child.item->height()));
+
+ if (d->flow == LeftToRight) {
+ hoffset += child.item->width();
+ hoffset += spacing();
+ linemax = qMax(linemax, qCeil(child.item->height()));
+ } else {
+ voffset += child.item->height();
+ voffset += spacing();
+ linemax = qMax(linemax, qCeil(child.item->width()));
+ }
+ }
+ if (d->isLeftToRight())
+ return;
+
+ int end;
+ if (widthValid())
+ end = width();
+ else
+ end = contentSize->width();
+ int acc = 0;
+ for (int i = 0; i < positionedItems.count(); ++i) {
+ const PositionedItem &child = positionedItems.at(i);
+ if (!child.item || !child.isVisible)
+ continue;
+ hoffset = end - hoffsets[acc++] - child.item->width();
+ if (child.item->x() != hoffset)
+ positionX(hoffset, child);
+ }
+}
+
+void QQuickFlow::reportConflictingAnchors()
+{
+ Q_D(QQuickFlow);
+ for (int ii = 0; ii < positionedItems.count(); ++ii) {
+ const PositionedItem &child = positionedItems.at(ii);
+ if (child.item) {
+ QQuickAnchors *anchors = QQuickItemPrivate::get(static_cast<QQuickItem *>(child.item))->_anchors;
+ if (anchors && (anchors->usedAnchors() || anchors->fill() || anchors->centerIn())) {
+ d->anchorConflict = true;
+ break;
+ }
+ }
+ }
+ if (d->anchorConflict)
+ qmlInfo(this) << "Cannot specify anchors for items inside Flow";
+}
+
+QT_END_NAMESPACE