1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qquickpositioners_p.h"
43 #include "qquickpositioners_p_p.h"
45 #include <QtDeclarative/qdeclarative.h>
46 #include <QtDeclarative/qdeclarativeinfo.h>
47 #include <QtCore/qmath.h>
48 #include <QtCore/qcoreapplication.h>
50 #include <QtQuick/private/qdeclarativestate_p.h>
51 #include <QtQuick/private/qdeclarativestategroup_p.h>
52 #include <private/qdeclarativestateoperations_p.h>
53 #include <QtQuick/private/qdeclarativetransition_p.h>
57 static const QQuickItemPrivate::ChangeTypes watchedChanges
58 = QQuickItemPrivate::Geometry
59 | QQuickItemPrivate::SiblingOrder
60 | QQuickItemPrivate::Visibility
61 | QQuickItemPrivate::Destroyed;
63 void QQuickBasePositionerPrivate::watchChanges(QQuickItem *other)
65 QQuickItemPrivate *otherPrivate = QQuickItemPrivate::get(other);
66 otherPrivate->addItemChangeListener(this, watchedChanges);
69 void QQuickBasePositionerPrivate::unwatchChanges(QQuickItem* other)
71 QQuickItemPrivate *otherPrivate = QQuickItemPrivate::get(other);
72 otherPrivate->removeItemChangeListener(this, watchedChanges);
75 QQuickBasePositioner::QQuickBasePositioner(PositionerType at, QQuickItem *parent)
76 : QQuickImplicitSizeItem(*(new QQuickBasePositionerPrivate), parent)
78 Q_D(QQuickBasePositioner);
83 \class QQuickBasePositioner
84 \brief The QQuickBasePositioner class provides a base for QQuickGraphics layouts.
86 To create a QQuickGraphics Positioner, simply subclass QQuickBasePositioner and implement
87 doLayout(), which is automatically called when the layout might need
88 updating. In doLayout() use the setX and setY functions from QQuickBasePositioner, and the
89 base class will apply the positions along with the appropriate transitions. The items to
90 position are provided in order as the protected member positionedItems.
92 You also need to set a PositionerType, to declare whether you are positioning the x, y or both
93 for the child items. Depending on the chosen type, only x or y changes will be applied.
95 Note that the subclass is responsible for adding the spacing in between items.
97 Positioning is usually delayed until before a frame is rendered, to batch multiple repositioning
98 changes into one calculation.
101 QQuickBasePositioner::QQuickBasePositioner(QQuickBasePositionerPrivate &dd, PositionerType at, QQuickItem *parent)
102 : QQuickImplicitSizeItem(dd, parent)
104 Q_D(QQuickBasePositioner);
108 QQuickBasePositioner::~QQuickBasePositioner()
110 Q_D(QQuickBasePositioner);
111 for (int i = 0; i < positionedItems.count(); ++i)
112 d->unwatchChanges(positionedItems.at(i).item);
113 positionedItems.clear();
116 void QQuickBasePositioner::updatePolish()
118 Q_D(QQuickBasePositioner);
119 if (d->positioningDirty)
123 int QQuickBasePositioner::spacing() const
125 Q_D(const QQuickBasePositioner);
129 void QQuickBasePositioner::setSpacing(int s)
131 Q_D(QQuickBasePositioner);
135 d->setPositioningDirty();
136 emit spacingChanged();
139 QDeclarativeTransition *QQuickBasePositioner::move() const
141 Q_D(const QQuickBasePositioner);
142 return d->moveTransition;
145 void QQuickBasePositioner::setMove(QDeclarativeTransition *mt)
147 Q_D(QQuickBasePositioner);
148 if (mt == d->moveTransition)
150 d->moveTransition = mt;
154 QDeclarativeTransition *QQuickBasePositioner::add() const
156 Q_D(const QQuickBasePositioner);
157 return d->addTransition;
160 void QQuickBasePositioner::setAdd(QDeclarativeTransition *add)
162 Q_D(QQuickBasePositioner);
163 if (add == d->addTransition)
166 d->addTransition = add;
170 void QQuickBasePositioner::componentComplete()
172 QQuickItem::componentComplete();
173 positionedItems.reserve(childItems().count());
175 reportConflictingAnchors();
178 void QQuickBasePositioner::itemChange(ItemChange change, const ItemChangeData &value)
180 Q_D(QQuickBasePositioner);
181 if (change == ItemChildAddedChange){
182 d->setPositioningDirty();
183 } else if (change == ItemChildRemovedChange) {
184 QQuickItem *child = value.item;
185 QQuickBasePositioner::PositionedItem posItem(child);
186 int idx = positionedItems.find(posItem);
188 d->unwatchChanges(child);
189 positionedItems.remove(idx);
191 d->setPositioningDirty();
194 QQuickItem::itemChange(change, value);
197 void QQuickBasePositioner::prePositioning()
199 Q_D(QQuickBasePositioner);
200 if (!isComponentComplete())
203 if (d->doingPositioning)
206 d->positioningDirty = false;
207 d->doingPositioning = true;
208 //Need to order children by creation order modified by stacking order
209 QList<QQuickItem *> children = childItems();
211 QPODVector<PositionedItem,8> oldItems;
212 positionedItems.copyAndClear(oldItems);
213 for (int ii = 0; ii < children.count(); ++ii) {
214 QQuickItem *child = children.at(ii);
215 QQuickItemPrivate *childPrivate = QQuickItemPrivate::get(child);
216 PositionedItem *item = 0;
217 PositionedItem posItem(child);
218 int wIdx = oldItems.find(posItem);
220 d->watchChanges(child);
221 positionedItems.append(posItem);
222 item = &positionedItems[positionedItems.count()-1];
224 if (!childPrivate->explicitVisible || !child->width() || !child->height())
225 item->isVisible = false;
227 item = &oldItems[wIdx];
228 // Items are only omitted from positioning if they are explicitly hidden
229 // i.e. their positioning is not affected if an ancestor is hidden.
230 if (!childPrivate->explicitVisible || !child->width() || !child->height()) {
231 item->isVisible = false;
232 } else if (!item->isVisible) {
233 item->isVisible = true;
238 positionedItems.append(*item);
241 QSizeF contentSize(0,0);
242 doPositioning(&contentSize);
243 updateAttachedProperties();
244 if (!d->addActions.isEmpty() || !d->moveActions.isEmpty())
245 finishApplyTransitions();
246 d->doingPositioning = false;
247 //Set implicit size to the size of its children
248 setImplicitSize(contentSize.width(), contentSize.height());
251 void QQuickBasePositioner::positionX(int x, const PositionedItem &target)
253 Q_D(QQuickBasePositioner);
254 if (d->type == Horizontal || d->type == Both) {
256 if (!d->addTransition || !d->addTransition->enabled())
257 target.item->setX(x);
259 d->addActions << QDeclarativeAction(target.item, QLatin1String("x"), QVariant(x));
260 } else if (x != target.item->x()) {
261 if (!d->moveTransition || !d->moveTransition->enabled())
262 target.item->setX(x);
264 d->moveActions << QDeclarativeAction(target.item, QLatin1String("x"), QVariant(x));
269 void QQuickBasePositioner::positionY(int y, const PositionedItem &target)
271 Q_D(QQuickBasePositioner);
272 if (d->type == Vertical || d->type == Both) {
274 if (!d->addTransition || !d->addTransition->enabled())
275 target.item->setY(y);
277 d->addActions << QDeclarativeAction(target.item, QLatin1String("y"), QVariant(y));
278 } else if (y != target.item->y()) {
279 if (!d->moveTransition || !d->moveTransition->enabled())
280 target.item->setY(y);
282 d->moveActions << QDeclarativeAction(target.item, QLatin1String("y"), QVariant(y));
287 void QQuickBasePositioner::finishApplyTransitions()
289 Q_D(QQuickBasePositioner);
290 // Note that if a transition is not set the transition manager will
291 // apply the changes directly, in the case add/move aren't set
292 d->addTransitionManager.transition(d->addActions, d->addTransition);
293 d->moveTransitionManager.transition(d->moveActions, d->moveTransition);
294 d->addActions.clear();
295 d->moveActions.clear();
298 QQuickPositionerAttached *QQuickBasePositioner::qmlAttachedProperties(QObject *obj)
300 return new QQuickPositionerAttached(obj);
303 void QQuickBasePositioner::updateAttachedProperties(QQuickPositionerAttached *specificProperty, QQuickItem *specificPropertyOwner) const
305 // If this function is deemed too expensive or shows up in profiles, it could
306 // be changed to run only when there are attached properties present. This
307 // could be a flag in the positioner that is set by the attached property
309 QQuickPositionerAttached *prevLastProperty = 0;
310 QQuickPositionerAttached *lastProperty = 0;
312 int visibleItemIndex = 0;
313 for (int ii = 0; ii < positionedItems.count(); ++ii) {
314 const PositionedItem &child = positionedItems.at(ii);
318 QQuickPositionerAttached *property = 0;
320 if (specificProperty) {
321 if (specificPropertyOwner == child.item) {
322 property = specificProperty;
325 property = static_cast<QQuickPositionerAttached *>(qmlAttachedPropertiesObject<QQuickBasePositioner>(child.item, false));
328 if (child.isVisible) {
330 property->setIndex(visibleItemIndex);
331 property->setIsFirstItem(visibleItemIndex == 0);
333 if (property->isLastItem())
334 prevLastProperty = property;
337 lastProperty = property;
339 } else if (property) {
340 property->setIndex(-1);
341 property->setIsFirstItem(false);
342 property->setIsLastItem(false);
346 if (prevLastProperty && prevLastProperty != lastProperty)
347 prevLastProperty->setIsLastItem(false);
349 lastProperty->setIsLastItem(true);
353 \qmlclass Positioner QQuickPositionerAttached
354 \inqmlmodule QtQuick 2
355 \ingroup qml-positioning-elements
356 \brief The Positioner type provides attached properties that contain details on where an item exists in a positioner.
358 Positioner items (such as Column, Row, Flow and Grid) provide automatic layout
359 for child items. Attaching this property allows a child item to determine
360 where it exists within the positioner.
363 QQuickPositionerAttached::QQuickPositionerAttached(QObject *parent) : QObject(parent), m_index(-1), m_isFirstItem(false), m_isLastItem(false)
365 QQuickItem *attachedItem = qobject_cast<QQuickItem *>(parent);
367 QQuickBasePositioner *positioner = qobject_cast<QQuickBasePositioner *>(attachedItem->parent());
369 positioner->updateAttachedProperties(this, attachedItem);
375 \qmlattachedproperty Item QtQuick2::Positioner::index
377 This property allows the item to determine
378 its index within the positioner.
380 void QQuickPositionerAttached::setIndex(int index)
382 if (m_index == index)
389 \qmlattachedproperty Item QtQuick2::Positioner::isFirstItem
390 \qmlattachedproperty Item QtQuick2::Positioner::isLastItem
392 These properties allow the item to determine if it
393 is the first or last item in the positioner, respectively.
395 void QQuickPositionerAttached::setIsFirstItem(bool isFirstItem)
397 if (m_isFirstItem == isFirstItem)
399 m_isFirstItem = isFirstItem;
400 emit isFirstItemChanged();
403 void QQuickPositionerAttached::setIsLastItem(bool isLastItem)
405 if (m_isLastItem == isLastItem)
407 m_isLastItem = isLastItem;
408 emit isLastItemChanged();
412 \qmlclass Column QQuickColumn
413 \inqmlmodule QtQuick 2
414 \ingroup qml-positioning-elements
415 \brief The Column item arranges its children vertically.
418 The Column item positions its child items so that they are vertically
419 aligned and not overlapping.
421 Spacing between items can be added using the \l spacing property.
422 Transitions can be used for cases where items managed by a Column are
423 added or moved. These are stored in the \l add and \l move properties
426 See \l{Using QML Positioner and Repeater Items} for more details about this item and other
429 \section1 Example Usage
431 The following example positions differently shaped rectangles using a Column
434 \image verticalpositioner_example.png
436 \snippet doc/src/snippets/declarative/column/vertical-positioner.qml document
438 \section1 Using Transitions
440 Transitions can be used to animate items that are added to, moved within,
441 or removed from a Column item. The \l add and \l move properties can be set to
442 the transitions that will be applied when items are added to, removed from,
443 or re-positioned within a Column item.
445 The use of transitions with positioners is described in more detail in the
446 \l{Using QML Positioner and Repeater Items#Using Transitions}{Using QML
447 Positioner and Repeater Items} document.
449 \image verticalpositioner_transition.gif
455 // Define an animation for adding a new item...
458 // Define an animation for moving items within the column...
464 \section1 Limitations
466 Note that the positioner assumes that the x and y positions of its children
467 will not change. If you manually change the x or y properties in script, bind
468 the x or y properties, use anchors on a child of a positioner, or have the
469 height of a child depend on the position of a child, then the
470 positioner may exhibit strange behavior. If you need to perform any of these
471 actions, consider positioning the items without the use of a Column.
473 Items with a width or height of 0 will not be positioned.
475 Positioning is batched and syncronized with painting to reduce the number of
476 calculations needed. This means that positioners may not reposition items immediately
477 when changes occur, but it will have moved by the next frame.
479 \sa Row, Grid, Flow, Positioner, {declarative/positioners}{Positioners example}
482 \qmlproperty Transition QtQuick2::Column::add
484 This property holds the transition to be applied when adding an
485 item to the positioner. The transition will only be applied to the
486 added item(s). Positioner transitions will only affect the
487 position (x, y) of items.
489 For a positioner, adding an item can mean that either the object
490 has been created or reparented, and thus is now a child or the
491 positioner, or that the object has had its opacity increased from
492 zero, and thus is now visible.
497 \qmlproperty Transition QtQuick2::Column::move
499 This property holds the transition to apply when moving an item
500 within the positioner. Positioner transitions will only affect
501 the position (x, y) of items.
503 This transition can be performed when other items are added or removed
504 from the positioner, or when items resize themselves.
506 \image positioner-move.gif
519 \sa add, {declarative/positioners}{Positioners example}
522 \qmlproperty int QtQuick2::Column::spacing
524 The spacing is the amount in pixels left empty between adjacent
525 items. The default spacing is 0.
529 QQuickColumn::QQuickColumn(QQuickItem *parent)
530 : QQuickBasePositioner(Vertical, parent)
534 void QQuickColumn::doPositioning(QSizeF *contentSize)
538 for (int ii = 0; ii < positionedItems.count(); ++ii) {
539 const PositionedItem &child = positionedItems.at(ii);
540 if (!child.item || !child.isVisible)
543 if (child.item->y() != voffset)
544 positionY(voffset, child);
546 contentSize->setWidth(qMax(contentSize->width(), child.item->width()));
548 voffset += child.item->height();
549 voffset += spacing();
552 if (voffset != 0)//If we positioned any items, undo the spacing from the last item
553 voffset -= spacing();
554 contentSize->setHeight(voffset);
557 void QQuickColumn::reportConflictingAnchors()
559 QQuickBasePositionerPrivate *d = static_cast<QQuickBasePositionerPrivate*>(QQuickBasePositionerPrivate::get(this));
560 for (int ii = 0; ii < positionedItems.count(); ++ii) {
561 const PositionedItem &child = positionedItems.at(ii);
563 QQuickAnchors *anchors = QQuickItemPrivate::get(static_cast<QQuickItem *>(child.item))->_anchors;
565 QQuickAnchors::Anchors usedAnchors = anchors->usedAnchors();
566 if (usedAnchors & QQuickAnchors::TopAnchor ||
567 usedAnchors & QQuickAnchors::BottomAnchor ||
568 usedAnchors & QQuickAnchors::VCenterAnchor ||
569 anchors->fill() || anchors->centerIn()) {
570 d->anchorConflict = true;
576 if (d->anchorConflict) {
577 qmlInfo(this) << "Cannot specify top, bottom, verticalCenter, fill or centerIn anchors for items inside Column";
581 \qmlclass Row QQuickRow
582 \inqmlmodule QtQuick 2
583 \ingroup qml-positioning-elements
584 \brief The Row item arranges its children horizontally.
587 The Row item positions its child items so that they are horizontally
588 aligned and not overlapping.
590 Use \l spacing to set the spacing between items in a Row, and use the
591 \l add and \l move properties to set the transitions that should be applied
592 when items are added to, removed from, or re-positioned within the Row.
594 See \l{Using QML Positioner and Repeater Items} for more details about this item and other
597 \section1 Example Usage
599 The following example lays out differently shaped rectangles using a Row.
601 \image horizontalpositioner_example.png
603 \snippet doc/src/snippets/declarative/row/row.qml document
605 \section1 Using Transitions
607 Transitions can be used to animate items that are added to, moved within,
608 or removed from a Grid item. The \l add and \l move properties can be set to
609 the transitions that will be applied when items are added to, removed from,
610 or re-positioned within a Row item.
612 \section1 Limitations
614 Note that the positioner assumes that the x and y positions of its children
615 will not change. If you manually change the x or y properties in script, bind
616 the x or y properties, use anchors on a child of a positioner, or have the
617 width of a child depend on the position of a child, then the
618 positioner may exhibit strange behavior. If you need to perform any of these
619 actions, consider positioning the items without the use of a Row.
621 Items with a width or height of 0 will not be positioned.
623 Positioning is batched and syncronized with painting to reduce the number of
624 calculations needed. This means that positioners may not reposition items immediately
625 when changes occur, but it will have moved by the next frame.
627 \sa Column, Grid, Flow, Positioner, {declarative/positioners}{Positioners example}
630 \qmlproperty Transition QtQuick2::Row::add
632 This property holds the transition to be applied when adding an
633 item to the positioner. The transition will only be applied to the
634 added item(s). Positioner transitions will only affect the
635 position (x, y) of items.
637 For a positioner, adding an item can mean that either the object
638 has been created or reparented, and thus is now a child or the
639 positioner, or that the object has had its opacity increased from
640 zero, and thus is now visible.
645 \qmlproperty Transition QtQuick2::Row::move
647 This property holds the transition to be applied when moving an
648 item within the positioner. Positioner transitions will only affect
649 the position (x, y) of items.
651 This transition can be performed when other items are added or removed
652 from the positioner, or when items resize themselves.
666 \sa add, {declarative/positioners}{Positioners example}
669 \qmlproperty int QtQuick2::Row::spacing
671 The spacing is the amount in pixels left empty between adjacent
672 items. The default spacing is 0.
677 QQuickRow::QQuickRow(QQuickItem *parent)
678 : QQuickBasePositioner(Horizontal, parent)
682 \qmlproperty enumeration QtQuick2::Row::layoutDirection
684 This property holds the layoutDirection of the row.
689 \o Qt.LeftToRight (default) - Items are laid out from left to right. If the width of the row is explicitly set,
690 the left anchor remains to the left of the row.
691 \o Qt.RightToLeft - Items are laid out from right to left. If the width of the row is explicitly set,
692 the right anchor remains to the right of the row.
695 \sa Grid::layoutDirection, Flow::layoutDirection, {declarative/righttoleft/layoutdirection}{Layout directions example}
698 Qt::LayoutDirection QQuickRow::layoutDirection() const
700 return QQuickBasePositionerPrivate::getLayoutDirection(this);
703 void QQuickRow::setLayoutDirection(Qt::LayoutDirection layoutDirection)
705 QQuickBasePositionerPrivate *d = static_cast<QQuickBasePositionerPrivate* >(QQuickBasePositionerPrivate::get(this));
706 if (d->layoutDirection != layoutDirection) {
707 d->layoutDirection = layoutDirection;
708 // For RTL layout the positioning changes when the width changes.
709 if (d->layoutDirection == Qt::RightToLeft)
710 d->addItemChangeListener(d, QQuickItemPrivate::Geometry);
712 d->removeItemChangeListener(d, QQuickItemPrivate::Geometry);
714 emit layoutDirectionChanged();
715 emit effectiveLayoutDirectionChanged();
719 \qmlproperty enumeration QtQuick2::Row::effectiveLayoutDirection
720 This property holds the effective layout direction of the row positioner.
722 When using the attached property \l {LayoutMirroring::enabled}{LayoutMirroring::enabled} for locale layouts,
723 the visual layout direction of the row positioner will be mirrored. However, the
724 property \l {Row::layoutDirection}{layoutDirection} will remain unchanged.
726 \sa Row::layoutDirection, {LayoutMirroring}{LayoutMirroring}
729 Qt::LayoutDirection QQuickRow::effectiveLayoutDirection() const
731 return QQuickBasePositionerPrivate::getEffectiveLayoutDirection(this);
734 void QQuickRow::doPositioning(QSizeF *contentSize)
736 QQuickBasePositionerPrivate *d = static_cast<QQuickBasePositionerPrivate* >(QQuickBasePositionerPrivate::get(this));
740 for (int ii = 0; ii < positionedItems.count(); ++ii) {
741 const PositionedItem &child = positionedItems.at(ii);
742 if (!child.item || !child.isVisible)
745 if (d->isLeftToRight()) {
746 if (child.item->x() != hoffset)
747 positionX(hoffset, child);
752 contentSize->setHeight(qMax(contentSize->height(), child.item->height()));
754 hoffset += child.item->width();
755 hoffset += spacing();
758 if (hoffset != 0)//If we positioned any items, undo the extra spacing from the last item
759 hoffset -= spacing();
760 contentSize->setWidth(hoffset);
762 if (d->isLeftToRight())
765 //Right to Left layout
768 end = contentSize->width();
773 for (int ii = 0; ii < positionedItems.count(); ++ii) {
774 const PositionedItem &child = positionedItems.at(ii);
775 if (!child.item || !child.isVisible)
777 hoffset = end - hoffsets[acc++] - child.item->width();
778 if (child.item->x() != hoffset)
779 positionX(hoffset, child);
783 void QQuickRow::reportConflictingAnchors()
785 QQuickBasePositionerPrivate *d = static_cast<QQuickBasePositionerPrivate*>(QQuickBasePositionerPrivate::get(this));
786 for (int ii = 0; ii < positionedItems.count(); ++ii) {
787 const PositionedItem &child = positionedItems.at(ii);
789 QQuickAnchors *anchors = QQuickItemPrivate::get(static_cast<QQuickItem *>(child.item))->_anchors;
791 QQuickAnchors::Anchors usedAnchors = anchors->usedAnchors();
792 if (usedAnchors & QQuickAnchors::LeftAnchor ||
793 usedAnchors & QQuickAnchors::RightAnchor ||
794 usedAnchors & QQuickAnchors::HCenterAnchor ||
795 anchors->fill() || anchors->centerIn()) {
796 d->anchorConflict = true;
802 if (d->anchorConflict)
803 qmlInfo(this) << "Cannot specify left, right, horizontalCenter, fill or centerIn anchors for items inside Row";
807 \qmlclass Grid QQuickGrid
808 \inqmlmodule QtQuick 2
809 \ingroup qml-positioning-elements
810 \brief The Grid item positions its children in a grid.
813 The Grid item positions its child items so that they are
814 aligned in a grid and are not overlapping.
816 The grid positioner calculates a grid of rectangular cells of sufficient
817 size to hold all items, placing the items in the cells, from left to right
818 and top to bottom. Each item is positioned in the top-left corner of its
819 cell with position (0, 0).
821 A Grid defaults to four columns, and as many rows as are necessary to
822 fit all child items. The number of rows and columns can be constrained
823 by setting the \l rows and \l columns properties.
825 Spacing can be added between child items by setting the \l spacing
826 property. The amount of spacing applied will be the same in the
827 horizontal and vertical directions.
829 See \l{Using QML Positioner and Repeater Items} for more details about this item and other
832 \section1 Example Usage
834 The following example demonstrates this.
836 \image gridLayout_example.png
838 \snippet doc/src/snippets/declarative/grid/grid.qml document
840 \section1 Using Transitions
842 Transitions can be used to animate items that are added to, moved within,
843 or removed from a Grid item. The \l add and \l move properties can be set to
844 the transitions that will be applied when items are added to, removed from,
845 or re-positioned within a Grid item.
847 \section1 Limitations
849 Note that the positioner assumes that the x and y positions of its children
850 will not change. If you manually change the x or y properties in script, bind
851 the x or y properties, use anchors on a child of a positioner, or have the
852 width or height of a child depend on the position of a child, then the
853 positioner may exhibit strange behavior. If you need to perform any of these
854 actions, consider positioning the items without the use of a Grid.
856 Items with a width or height of 0 will not be positioned.
858 Positioning is batched and syncronized with painting to reduce the number of
859 calculations needed. This means that positioners may not reposition items immediately
860 when changes occur, but it will have moved by the next frame.
862 \sa Flow, Row, Column, Positioner, {declarative/positioners}{Positioners example}
865 \qmlproperty Transition QtQuick2::Grid::add
867 This property holds the transition to be applied when adding an
868 item to the positioner. The transition will only be applied to the
869 added item(s). Positioner transitions will only affect the
870 position (x, y) of items.
872 For a positioner, adding an item can mean that either the object
873 has been created or reparented, and thus is now a child or the
874 positioner, or that the object has had its opacity increased from
875 zero, and thus is now visible.
880 \qmlproperty Transition QtQuick2::Grid::move
882 This property holds the transition to be applied when moving an
883 item within the positioner. Positioner transitions will only affect
884 the position (x, y) of items.
886 This transition can be performed when other items are added or removed
887 from the positioner, or when items resize themselves.
900 \sa add, {declarative/positioners}{Positioners example}
903 \qmlproperty int QtQuick2::Grid::spacing
905 The spacing is the amount in pixels left empty between adjacent
906 items. The default spacing is 0.
908 The below example places a Grid containing a red, a blue and a
909 green rectangle on a gray background. The area the grid positioner
910 occupies is colored white. The positioner on the left has the
911 no spacing (the default), and the positioner on the right has
914 \inlineimage qml-grid-no-spacing.png
915 \inlineimage qml-grid-spacing.png
919 QQuickGrid::QQuickGrid(QQuickItem *parent) :
920 QQuickBasePositioner(Both, parent), m_rows(-1), m_columns(-1), m_rowSpacing(-1), m_columnSpacing(-1), m_flow(LeftToRight)
925 \qmlproperty int QtQuick2::Grid::columns
927 This property holds the number of columns in the grid. The default
928 number of columns is 4.
930 If the grid does not have enough items to fill the specified
931 number of columns, some columns will be of zero width.
935 \qmlproperty int QtQuick2::Grid::rows
936 This property holds the number of rows in the grid.
938 If the grid does not have enough items to fill the specified
939 number of rows, some rows will be of zero width.
942 void QQuickGrid::setColumns(const int columns)
944 if (columns == m_columns)
948 emit columnsChanged();
951 void QQuickGrid::setRows(const int rows)
961 \qmlproperty enumeration QtQuick2::Grid::flow
962 This property holds the flow of the layout.
967 \o Grid.LeftToRight (default) - Items are positioned next to
968 each other in the \l layoutDirection, then wrapped to the next line.
969 \o Grid.TopToBottom - Items are positioned next to each
970 other from top to bottom, then wrapped to the next column.
973 QQuickGrid::Flow QQuickGrid::flow() const
978 void QQuickGrid::setFlow(Flow flow)
980 if (m_flow != flow) {
988 \qmlproperty int QtQuick2::Grid::rowSpacing
990 This property holds the spacing in pixels between rows.
995 void QQuickGrid::setRowSpacing(const int rowSpacing)
997 if (rowSpacing == m_rowSpacing)
999 m_rowSpacing = rowSpacing;
1001 emit rowSpacingChanged();
1005 \qmlproperty int QtQuick2::Grid::columnSpacing
1007 This property holds the spacing in pixels between columns.
1012 void QQuickGrid::setColumnSpacing(const int columnSpacing)
1014 if (columnSpacing == m_columnSpacing)
1016 m_columnSpacing = columnSpacing;
1018 emit columnSpacingChanged();
1022 \qmlproperty enumeration QtQuick2::Grid::layoutDirection
1024 This property holds the layout direction of the layout.
1026 Possible values are:
1029 \o Qt.LeftToRight (default) - Items are positioned from the top to bottom,
1030 and left to right. The flow direction is dependent on the
1031 \l Grid::flow property.
1032 \o Qt.RightToLeft - Items are positioned from the top to bottom,
1033 and right to left. The flow direction is dependent on the
1034 \l Grid::flow property.
1037 \sa Flow::layoutDirection, Row::layoutDirection, {declarative/righttoleft/layoutdirection}{Layout directions example}
1039 Qt::LayoutDirection QQuickGrid::layoutDirection() const
1041 return QQuickBasePositionerPrivate::getLayoutDirection(this);
1044 void QQuickGrid::setLayoutDirection(Qt::LayoutDirection layoutDirection)
1046 QQuickBasePositionerPrivate *d = static_cast<QQuickBasePositionerPrivate*>(QQuickBasePositionerPrivate::get(this));
1047 if (d->layoutDirection != layoutDirection) {
1048 d->layoutDirection = layoutDirection;
1049 // For RTL layout the positioning changes when the width changes.
1050 if (d->layoutDirection == Qt::RightToLeft)
1051 d->addItemChangeListener(d, QQuickItemPrivate::Geometry);
1053 d->removeItemChangeListener(d, QQuickItemPrivate::Geometry);
1055 emit layoutDirectionChanged();
1056 emit effectiveLayoutDirectionChanged();
1061 \qmlproperty enumeration QtQuick2::Grid::effectiveLayoutDirection
1062 This property holds the effective layout direction of the grid positioner.
1064 When using the attached property \l {LayoutMirroring::enabled}{LayoutMirroring::enabled} for locale layouts,
1065 the visual layout direction of the grid positioner will be mirrored. However, the
1066 property \l {Grid::layoutDirection}{layoutDirection} will remain unchanged.
1068 \sa Grid::layoutDirection, {LayoutMirroring}{LayoutMirroring}
1070 Qt::LayoutDirection QQuickGrid::effectiveLayoutDirection() const
1072 return QQuickBasePositionerPrivate::getEffectiveLayoutDirection(this);
1075 void QQuickGrid::doPositioning(QSizeF *contentSize)
1077 QQuickBasePositionerPrivate *d = static_cast<QQuickBasePositionerPrivate*>(QQuickBasePositionerPrivate::get(this));
1080 //Is allocating the extra QPODVector too much overhead?
1081 QPODVector<PositionedItem, 8> visibleItems;//we aren't concerned with invisible items
1082 visibleItems.reserve(positionedItems.count());
1083 for (int i=0; i<positionedItems.count(); i++)
1084 if (positionedItems[i].item && positionedItems[i].isVisible)
1085 visibleItems.append(positionedItems[i]);
1087 int numVisible = visibleItems.count();
1088 if (m_columns <= 0 && m_rows <= 0){
1090 r = (numVisible+3)/4;
1091 } else if (m_rows <= 0){
1092 r = (numVisible+(m_columns-1))/m_columns;
1093 } else if (m_columns <= 0){
1094 c = (numVisible+(m_rows-1))/m_rows;
1098 return; //Nothing to do
1100 QList<int> maxColWidth;
1101 QList<int> maxRowHeight;
1103 if (m_flow == LeftToRight) {
1104 for (int i=0; i < r; i++){
1105 for (int j=0; j < c; j++){
1111 if (childIndex == visibleItems.count())
1114 const PositionedItem &child = visibleItems.at(childIndex++);
1115 if (child.item->width() > maxColWidth[j])
1116 maxColWidth[j] = child.item->width();
1117 if (child.item->height() > maxRowHeight[i])
1118 maxRowHeight[i] = child.item->height();
1122 for (int j=0; j < c; j++){
1123 for (int i=0; i < r; i++){
1129 if (childIndex == visibleItems.count())
1132 const PositionedItem &child = visibleItems.at(childIndex++);
1133 if (child.item->width() > maxColWidth[j])
1134 maxColWidth[j] = child.item->width();
1135 if (child.item->height() > maxRowHeight[i])
1136 maxRowHeight[i] = child.item->height();
1141 int columnSpacing = m_columnSpacing;
1142 if (columnSpacing == -1)
1143 columnSpacing = spacing();
1145 int rowSpacing = m_rowSpacing;
1146 if (rowSpacing == -1)
1147 rowSpacing = spacing();
1150 for (int j=0; j < maxColWidth.size(); j++){
1152 widthSum += columnSpacing;
1153 widthSum += maxColWidth[j];
1157 for (int i=0; i < maxRowHeight.size(); i++){
1159 heightSum += rowSpacing;
1160 heightSum += maxRowHeight[i];
1163 contentSize->setHeight(heightSum);
1164 contentSize->setWidth(widthSum);
1173 if (!d->isLeftToRight())
1178 for (int i = 0; i < visibleItems.count(); ++i) {
1179 const PositionedItem &child = visibleItems.at(i);
1180 int childXOffset = xoffset;
1181 if (!d->isLeftToRight())
1182 childXOffset -= child.item->width();
1183 if ((child.item->x() != childXOffset) || (child.item->y() != yoffset)){
1184 positionX(childXOffset, child);
1185 positionY(yoffset, child);
1188 if (m_flow == LeftToRight) {
1189 if (d->isLeftToRight())
1190 xoffset += maxColWidth[curCol]+columnSpacing;
1192 xoffset -= maxColWidth[curCol]+columnSpacing;
1196 yoffset += maxRowHeight[curRow]+rowSpacing;
1197 if (d->isLeftToRight())
1206 yoffset+=maxRowHeight[curRow]+rowSpacing;
1210 if (d->isLeftToRight())
1211 xoffset += maxColWidth[curCol]+columnSpacing;
1213 xoffset -= maxColWidth[curCol]+columnSpacing;
1223 void QQuickGrid::reportConflictingAnchors()
1225 QQuickBasePositionerPrivate *d = static_cast<QQuickBasePositionerPrivate*>(QQuickBasePositionerPrivate::get(this));
1226 for (int ii = 0; ii < positionedItems.count(); ++ii) {
1227 const PositionedItem &child = positionedItems.at(ii);
1229 QQuickAnchors *anchors = QQuickItemPrivate::get(static_cast<QQuickItem *>(child.item))->_anchors;
1230 if (anchors && (anchors->usedAnchors() || anchors->fill() || anchors->centerIn())) {
1231 d->anchorConflict = true;
1236 if (d->anchorConflict)
1237 qmlInfo(this) << "Cannot specify anchors for items inside Grid";
1241 \qmlclass Flow QQuickFlow
1242 \inqmlmodule QtQuick 2
1243 \ingroup qml-positioning-elements
1244 \brief The Flow item arranges its children side by side, wrapping as necessary.
1247 The Flow item positions its child items like words on a page, wrapping them
1248 to create rows or columns of items that do not overlap.
1250 Spacing between items can be added using the \l spacing property.
1251 Transitions can be used for cases where items managed by a Column are
1252 added or moved. These are stored in the \l add and \l move properties
1255 See \l{Using QML Positioner and Repeater Items} for more details about this item and other
1258 \section1 Example Usage
1260 The following example positions \l Text items within a parent item using
1263 \image qml-flow-snippet.png
1265 \snippet doc/src/snippets/declarative/flow.qml flow item
1267 \section1 Using Transitions
1269 Transitions can be used to animate items that are added to, moved within,
1270 or removed from a Flow item. The \l add and \l move properties can be set to
1271 the transitions that will be applied when items are added to, removed from,
1272 or re-positioned within a Flow item.
1274 The use of transitions with positioners is described in more detail in the
1275 \l{Using QML Positioner and Repeater Items#Using Transitions}{Using QML
1276 Positioner and Repeater Items} document.
1278 \section1 Limitations
1280 Note that the positioner assumes that the x and y positions of its children
1281 will not change. If you manually change the x or y properties in script, bind
1282 the x or y properties, use anchors on a child of a positioner, or have the
1283 width or height of a child depend on the position of a child, then the
1284 positioner may exhibit strange behavior. If you need to perform any of these
1285 actions, consider positioning the items without the use of a Flow.
1287 Items with a width or height of 0 will not be positioned.
1289 Positioning is batched and syncronized with painting to reduce the number of
1290 calculations needed. This means that positioners may not reposition items immediately
1291 when changes occur, but it will have moved by the next frame.
1293 \sa Column, Row, Grid, Positioner, {declarative/positioners}{Positioners example}
1296 \qmlproperty Transition QtQuick2::Flow::add
1298 This property holds the transition to be applied when adding an
1299 item to the positioner. The transition will only be applied to the
1300 added item(s). Positioner transitions will only affect the
1301 position (x, y) of items.
1303 For a positioner, adding an item can mean that either the object
1304 has been created or reparented, and thus is now a child or the
1305 positioner, or that the object has had its opacity increased from
1306 zero, and thus is now visible.
1311 \qmlproperty Transition QtQuick2::Flow::move
1313 This property holds the transition to be applied when moving an
1314 item within the positioner. Positioner transitions will only affect
1315 the position (x, y) of items.
1317 This transition can be performed when other items are added or removed
1318 from the positioner, or when items resize themselves.
1326 ease: "easeOutBounce"
1332 \sa add, {declarative/positioners}{Positioners example}
1335 \qmlproperty int QtQuick2::Flow::spacing
1337 spacing is the amount in pixels left empty between each adjacent
1338 item, and defaults to 0.
1343 class QQuickFlowPrivate : public QQuickBasePositionerPrivate
1345 Q_DECLARE_PUBLIC(QQuickFlow)
1349 : QQuickBasePositionerPrivate(), flow(QQuickFlow::LeftToRight)
1352 QQuickFlow::Flow flow;
1355 QQuickFlow::QQuickFlow(QQuickItem *parent)
1356 : QQuickBasePositioner(*(new QQuickFlowPrivate), Both, parent)
1359 // Flow layout requires relayout if its own size changes too.
1360 d->addItemChangeListener(d, QQuickItemPrivate::Geometry);
1364 \qmlproperty enumeration QtQuick2::Flow::flow
1365 This property holds the flow of the layout.
1367 Possible values are:
1370 \o Flow.LeftToRight (default) - Items are positioned next to
1371 to each other according to the \l layoutDirection until the width of the Flow
1372 is exceeded, then wrapped to the next line.
1373 \o Flow.TopToBottom - Items are positioned next to each
1374 other from top to bottom until the height of the Flow is exceeded,
1375 then wrapped to the next column.
1378 QQuickFlow::Flow QQuickFlow::flow() const
1380 Q_D(const QQuickFlow);
1384 void QQuickFlow::setFlow(Flow flow)
1387 if (d->flow != flow) {
1395 \qmlproperty enumeration QtQuick2::Flow::layoutDirection
1397 This property holds the layout direction of the layout.
1399 Possible values are:
1402 \o Qt.LeftToRight (default) - Items are positioned from the top to bottom,
1403 and left to right. The flow direction is dependent on the
1404 \l Flow::flow property.
1405 \o Qt.RightToLeft - Items are positioned from the top to bottom,
1406 and right to left. The flow direction is dependent on the
1407 \l Flow::flow property.
1410 \sa Grid::layoutDirection, Row::layoutDirection, {declarative/righttoleft/layoutdirection}{Layout directions example}
1413 Qt::LayoutDirection QQuickFlow::layoutDirection() const
1415 Q_D(const QQuickFlow);
1416 return d->layoutDirection;
1419 void QQuickFlow::setLayoutDirection(Qt::LayoutDirection layoutDirection)
1422 if (d->layoutDirection != layoutDirection) {
1423 d->layoutDirection = layoutDirection;
1425 emit layoutDirectionChanged();
1426 emit effectiveLayoutDirectionChanged();
1431 \qmlproperty enumeration QtQuick2::Flow::effectiveLayoutDirection
1432 This property holds the effective layout direction of the flow positioner.
1434 When using the attached property \l {LayoutMirroring::enabled}{LayoutMirroring::enabled} for locale layouts,
1435 the visual layout direction of the grid positioner will be mirrored. However, the
1436 property \l {Flow::layoutDirection}{layoutDirection} will remain unchanged.
1438 \sa Flow::layoutDirection, {LayoutMirroring}{LayoutMirroring}
1441 Qt::LayoutDirection QQuickFlow::effectiveLayoutDirection() const
1443 return QQuickBasePositionerPrivate::getEffectiveLayoutDirection(this);
1446 void QQuickFlow::doPositioning(QSizeF *contentSize)
1453 QList<int> hoffsets;
1455 for (int i = 0; i < positionedItems.count(); ++i) {
1456 const PositionedItem &child = positionedItems.at(i);
1457 if (!child.item || !child.isVisible)
1460 if (d->flow == LeftToRight) {
1461 if (widthValid() && hoffset && hoffset + child.item->width() > width()) {
1463 voffset += linemax + spacing();
1467 if (heightValid() && voffset && voffset + child.item->height() > height()) {
1469 hoffset += linemax + spacing();
1474 if (d->isLeftToRight()) {
1475 if (child.item->x() != hoffset)
1476 positionX(hoffset, child);
1478 hoffsets << hoffset;
1480 if (child.item->y() != voffset)
1481 positionY(voffset, child);
1483 contentSize->setWidth(qMax(contentSize->width(), hoffset + child.item->width()));
1484 contentSize->setHeight(qMax(contentSize->height(), voffset + child.item->height()));
1486 if (d->flow == LeftToRight) {
1487 hoffset += child.item->width();
1488 hoffset += spacing();
1489 linemax = qMax(linemax, qCeil(child.item->height()));
1491 voffset += child.item->height();
1492 voffset += spacing();
1493 linemax = qMax(linemax, qCeil(child.item->width()));
1496 if (d->isLeftToRight())
1503 end = contentSize->width();
1505 for (int i = 0; i < positionedItems.count(); ++i) {
1506 const PositionedItem &child = positionedItems.at(i);
1507 if (!child.item || !child.isVisible)
1509 hoffset = end - hoffsets[acc++] - child.item->width();
1510 if (child.item->x() != hoffset)
1511 positionX(hoffset, child);
1515 void QQuickFlow::reportConflictingAnchors()
1518 for (int ii = 0; ii < positionedItems.count(); ++ii) {
1519 const PositionedItem &child = positionedItems.at(ii);
1521 QQuickAnchors *anchors = QQuickItemPrivate::get(static_cast<QQuickItem *>(child.item))->_anchors;
1522 if (anchors && (anchors->usedAnchors() || anchors->fill() || anchors->centerIn())) {
1523 d->anchorConflict = true;
1528 if (d->anchorConflict)
1529 qmlInfo(this) << "Cannot specify anchors for items inside Flow";