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 <private/qdeclarativestate_p.h>
51 #include <private/qdeclarativestategroup_p.h>
52 #include <private/qdeclarativestateoperations_p.h>
53 #include <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 setImplicitHeight(contentSize.height());
249 setImplicitWidth(contentSize.width());
252 void QQuickBasePositioner::positionX(int x, const PositionedItem &target)
254 Q_D(QQuickBasePositioner);
255 if (d->type == Horizontal || d->type == Both) {
257 if (!d->addTransition || !d->addTransition->enabled())
258 target.item->setX(x);
260 d->addActions << QDeclarativeAction(target.item, QLatin1String("x"), QVariant(x));
261 } else if (x != target.item->x()) {
262 if (!d->moveTransition || !d->moveTransition->enabled())
263 target.item->setX(x);
265 d->moveActions << QDeclarativeAction(target.item, QLatin1String("x"), QVariant(x));
270 void QQuickBasePositioner::positionY(int y, const PositionedItem &target)
272 Q_D(QQuickBasePositioner);
273 if (d->type == Vertical || d->type == Both) {
275 if (!d->addTransition || !d->addTransition->enabled())
276 target.item->setY(y);
278 d->addActions << QDeclarativeAction(target.item, QLatin1String("y"), QVariant(y));
279 } else if (y != target.item->y()) {
280 if (!d->moveTransition || !d->moveTransition->enabled())
281 target.item->setY(y);
283 d->moveActions << QDeclarativeAction(target.item, QLatin1String("y"), QVariant(y));
288 void QQuickBasePositioner::finishApplyTransitions()
290 Q_D(QQuickBasePositioner);
291 // Note that if a transition is not set the transition manager will
292 // apply the changes directly, in the case add/move aren't set
293 d->addTransitionManager.transition(d->addActions, d->addTransition);
294 d->moveTransitionManager.transition(d->moveActions, d->moveTransition);
295 d->addActions.clear();
296 d->moveActions.clear();
299 QQuickPositionerAttached *QQuickBasePositioner::qmlAttachedProperties(QObject *obj)
301 return new QQuickPositionerAttached(obj);
304 void QQuickBasePositioner::updateAttachedProperties(QQuickPositionerAttached *specificProperty, QQuickItem *specificPropertyOwner) const
306 // If this function is deemed too expensive or shows up in profiles, it could
307 // be changed to run only when there are attached properties present. This
308 // could be a flag in the positioner that is set by the attached property
310 QQuickPositionerAttached *prevLastProperty = 0;
311 QQuickPositionerAttached *lastProperty = 0;
313 int visibleItemIndex = 0;
314 for (int ii = 0; ii < positionedItems.count(); ++ii) {
315 const PositionedItem &child = positionedItems.at(ii);
319 QQuickPositionerAttached *property = 0;
321 if (specificProperty) {
322 if (specificPropertyOwner == child.item) {
323 property = specificProperty;
326 property = static_cast<QQuickPositionerAttached *>(qmlAttachedPropertiesObject<QQuickBasePositioner>(child.item, false));
329 if (child.isVisible) {
331 property->setIndex(visibleItemIndex);
332 property->setIsFirstItem(visibleItemIndex == 0);
334 if (property->isLastItem())
335 prevLastProperty = property;
338 lastProperty = property;
340 } else if (property) {
341 property->setIndex(-1);
342 property->setIsFirstItem(false);
343 property->setIsLastItem(false);
347 if (prevLastProperty && prevLastProperty != lastProperty)
348 prevLastProperty->setIsLastItem(false);
350 lastProperty->setIsLastItem(true);
354 \qmlclass Positioner QQuickPositionerAttached
355 \inqmlmodule QtQuick 2
356 \ingroup qml-positioning-elements
357 \brief The Positioner type provides attached properties that contain details on where an item exists in a positioner.
359 Positioner items (such as Column, Row, Flow and Grid) provide automatic layout
360 for child items. Attaching this property allows a child item to determine
361 where it exists within the positioner.
364 QQuickPositionerAttached::QQuickPositionerAttached(QObject *parent) : QObject(parent), m_index(-1), m_isFirstItem(false), m_isLastItem(false)
366 QQuickItem *attachedItem = qobject_cast<QQuickItem *>(parent);
368 QQuickBasePositioner *positioner = qobject_cast<QQuickBasePositioner *>(attachedItem->parent());
370 positioner->updateAttachedProperties(this, attachedItem);
376 \qmlattachedproperty Item QtQuick2::Positioner::index
378 This property allows the item to determine
379 its index within the positioner.
381 void QQuickPositionerAttached::setIndex(int index)
383 if (m_index == index)
390 \qmlattachedproperty Item QtQuick2::Positioner::isFirstItem
391 \qmlattachedproperty Item QtQuick2::Positioner::isLastItem
393 These properties allow the item to determine if it
394 is the first or last item in the positioner, respectively.
396 void QQuickPositionerAttached::setIsFirstItem(bool isFirstItem)
398 if (m_isFirstItem == isFirstItem)
400 m_isFirstItem = isFirstItem;
401 emit isFirstItemChanged();
404 void QQuickPositionerAttached::setIsLastItem(bool isLastItem)
406 if (m_isLastItem == isLastItem)
408 m_isLastItem = isLastItem;
409 emit isLastItemChanged();
413 \qmlclass Column QQuickColumn
414 \inqmlmodule QtQuick 2
415 \ingroup qml-positioning-elements
416 \brief The Column item arranges its children vertically.
419 The Column item positions its child items so that they are vertically
420 aligned and not overlapping.
422 Spacing between items can be added using the \l spacing property.
423 Transitions can be used for cases where items managed by a Column are
424 added or moved. These are stored in the \l add and \l move properties
427 See \l{Using QML Positioner and Repeater Items} for more details about this item and other
430 \section1 Example Usage
432 The following example positions differently shaped rectangles using a Column
435 \image verticalpositioner_example.png
437 \snippet doc/src/snippets/declarative/column/vertical-positioner.qml document
439 \section1 Using Transitions
441 Transitions can be used to animate items that are added to, moved within,
442 or removed from a Column item. The \l add and \l move properties can be set to
443 the transitions that will be applied when items are added to, removed from,
444 or re-positioned within a Column item.
446 The use of transitions with positioners is described in more detail in the
447 \l{Using QML Positioner and Repeater Items#Using Transitions}{Using QML
448 Positioner and Repeater Items} document.
450 \image verticalpositioner_transition.gif
456 // Define an animation for adding a new item...
459 // Define an animation for moving items within the column...
465 \section1 Limitations
467 Note that the positioner assumes that the x and y positions of its children
468 will not change. If you manually change the x or y properties in script, bind
469 the x or y properties, use anchors on a child of a positioner, or have the
470 height of a child depend on the position of a child, then the
471 positioner may exhibit strange behavior. If you need to perform any of these
472 actions, consider positioning the items without the use of a Column.
474 Items with a width or height of 0 will not be positioned.
476 Positioning is batched and syncronized with painting to reduce the number of
477 calculations needed. This means that positioners may not reposition items immediately
478 when changes occur, but it will have moved by the next frame.
480 \sa Row, Grid, Flow, Positioner, {declarative/positioners}{Positioners example}
483 \qmlproperty Transition QtQuick2::Column::add
485 This property holds the transition to be applied when adding an
486 item to the positioner. The transition will only be applied to the
487 added item(s). Positioner transitions will only affect the
488 position (x, y) of items.
490 For a positioner, adding an item can mean that either the object
491 has been created or reparented, and thus is now a child or the
492 positioner, or that the object has had its opacity increased from
493 zero, and thus is now visible.
498 \qmlproperty Transition QtQuick2::Column::move
500 This property holds the transition to apply when moving an item
501 within the positioner. Positioner transitions will only affect
502 the position (x, y) of items.
504 This transition can be performed when other items are added or removed
505 from the positioner, or when items resize themselves.
507 \image positioner-move.gif
520 \sa add, {declarative/positioners}{Positioners example}
523 \qmlproperty int QtQuick2::Column::spacing
525 The spacing is the amount in pixels left empty between adjacent
526 items. The default spacing is 0.
530 QQuickColumn::QQuickColumn(QQuickItem *parent)
531 : QQuickBasePositioner(Vertical, parent)
535 void QQuickColumn::doPositioning(QSizeF *contentSize)
539 for (int ii = 0; ii < positionedItems.count(); ++ii) {
540 const PositionedItem &child = positionedItems.at(ii);
541 if (!child.item || !child.isVisible)
544 if (child.item->y() != voffset)
545 positionY(voffset, child);
547 contentSize->setWidth(qMax(contentSize->width(), child.item->width()));
549 voffset += child.item->height();
550 voffset += spacing();
553 if (voffset != 0)//If we positioned any items, undo the spacing from the last item
554 voffset -= spacing();
555 contentSize->setHeight(voffset);
558 void QQuickColumn::reportConflictingAnchors()
560 QQuickBasePositionerPrivate *d = static_cast<QQuickBasePositionerPrivate*>(QQuickBasePositionerPrivate::get(this));
561 for (int ii = 0; ii < positionedItems.count(); ++ii) {
562 const PositionedItem &child = positionedItems.at(ii);
564 QQuickAnchors *anchors = QQuickItemPrivate::get(static_cast<QQuickItem *>(child.item))->_anchors;
566 QQuickAnchors::Anchors usedAnchors = anchors->usedAnchors();
567 if (usedAnchors & QQuickAnchors::TopAnchor ||
568 usedAnchors & QQuickAnchors::BottomAnchor ||
569 usedAnchors & QQuickAnchors::VCenterAnchor ||
570 anchors->fill() || anchors->centerIn()) {
571 d->anchorConflict = true;
577 if (d->anchorConflict) {
578 qmlInfo(this) << "Cannot specify top, bottom, verticalCenter, fill or centerIn anchors for items inside Column";
582 \qmlclass Row QQuickRow
583 \inqmlmodule QtQuick 2
584 \ingroup qml-positioning-elements
585 \brief The Row item arranges its children horizontally.
588 The Row item positions its child items so that they are horizontally
589 aligned and not overlapping.
591 Use \l spacing to set the spacing between items in a Row, and use the
592 \l add and \l move properties to set the transitions that should be applied
593 when items are added to, removed from, or re-positioned within the Row.
595 See \l{Using QML Positioner and Repeater Items} for more details about this item and other
598 \section1 Example Usage
600 The following example lays out differently shaped rectangles using a Row.
602 \image horizontalpositioner_example.png
604 \snippet doc/src/snippets/declarative/row/row.qml document
606 \section1 Using Transitions
608 Transitions can be used to animate items that are added to, moved within,
609 or removed from a Grid item. The \l add and \l move properties can be set to
610 the transitions that will be applied when items are added to, removed from,
611 or re-positioned within a Row item.
613 \section1 Limitations
615 Note that the positioner assumes that the x and y positions of its children
616 will not change. If you manually change the x or y properties in script, bind
617 the x or y properties, use anchors on a child of a positioner, or have the
618 width of a child depend on the position of a child, then the
619 positioner may exhibit strange behaviour. If you need to perform any of these
620 actions, consider positioning the items without the use of a Row.
622 Items with a width or height of 0 will not be positioned.
624 Positioning is batched and syncronized with painting to reduce the number of
625 calculations needed. This means that positioners may not reposition items immediately
626 when changes occur, but it will have moved by the next frame.
628 \sa Column, Grid, Flow, Positioner, {declarative/positioners}{Positioners example}
631 \qmlproperty Transition QtQuick2::Row::add
633 This property holds the transition to be applied when adding an
634 item to the positioner. The transition will only be applied to the
635 added item(s). Positioner transitions will only affect the
636 position (x, y) of items.
638 For a positioner, adding an item can mean that either the object
639 has been created or reparented, and thus is now a child or the
640 positioner, or that the object has had its opacity increased from
641 zero, and thus is now visible.
646 \qmlproperty Transition QtQuick2::Row::move
648 This property holds the transition to be applied when moving an
649 item within the positioner. Positioner transitions will only affect
650 the position (x, y) of items.
652 This transition can be performed when other items are added or removed
653 from the positioner, or when items resize themselves.
667 \sa add, {declarative/positioners}{Positioners example}
670 \qmlproperty int QtQuick2::Row::spacing
672 The spacing is the amount in pixels left empty between adjacent
673 items. The default spacing is 0.
678 QQuickRow::QQuickRow(QQuickItem *parent)
679 : QQuickBasePositioner(Horizontal, parent)
683 \qmlproperty enumeration QtQuick2::Row::layoutDirection
685 This property holds the layoutDirection of the row.
690 \o Qt.LeftToRight (default) - Items are laid out from left to right. If the width of the row is explicitly set,
691 the left anchor remains to the left of the row.
692 \o Qt.RightToLeft - Items are laid out from right to left. If the width of the row is explicitly set,
693 the right anchor remains to the right of the row.
696 \sa Grid::layoutDirection, Flow::layoutDirection, {declarative/righttoleft/layoutdirection}{Layout directions example}
699 Qt::LayoutDirection QQuickRow::layoutDirection() const
701 return QQuickBasePositionerPrivate::getLayoutDirection(this);
704 void QQuickRow::setLayoutDirection(Qt::LayoutDirection layoutDirection)
706 QQuickBasePositionerPrivate *d = static_cast<QQuickBasePositionerPrivate* >(QQuickBasePositionerPrivate::get(this));
707 if (d->layoutDirection != layoutDirection) {
708 d->layoutDirection = layoutDirection;
709 // For RTL layout the positioning changes when the width changes.
710 if (d->layoutDirection == Qt::RightToLeft)
711 d->addItemChangeListener(d, QQuickItemPrivate::Geometry);
713 d->removeItemChangeListener(d, QQuickItemPrivate::Geometry);
715 emit layoutDirectionChanged();
716 emit effectiveLayoutDirectionChanged();
720 \qmlproperty enumeration QtQuick2::Row::effectiveLayoutDirection
721 This property holds the effective layout direction of the row positioner.
723 When using the attached property \l {LayoutMirroring::enabled}{LayoutMirroring::enabled} for locale layouts,
724 the visual layout direction of the row positioner will be mirrored. However, the
725 property \l {Row::layoutDirection}{layoutDirection} will remain unchanged.
727 \sa Row::layoutDirection, {LayoutMirroring}{LayoutMirroring}
730 Qt::LayoutDirection QQuickRow::effectiveLayoutDirection() const
732 return QQuickBasePositionerPrivate::getEffectiveLayoutDirection(this);
735 void QQuickRow::doPositioning(QSizeF *contentSize)
737 QQuickBasePositionerPrivate *d = static_cast<QQuickBasePositionerPrivate* >(QQuickBasePositionerPrivate::get(this));
741 for (int ii = 0; ii < positionedItems.count(); ++ii) {
742 const PositionedItem &child = positionedItems.at(ii);
743 if (!child.item || !child.isVisible)
746 if (d->isLeftToRight()) {
747 if (child.item->x() != hoffset)
748 positionX(hoffset, child);
753 contentSize->setHeight(qMax(contentSize->height(), child.item->height()));
755 hoffset += child.item->width();
756 hoffset += spacing();
759 if (hoffset != 0)//If we positioned any items, undo the extra spacing from the last item
760 hoffset -= spacing();
761 contentSize->setWidth(hoffset);
763 if (d->isLeftToRight())
766 //Right to Left layout
769 end = contentSize->width();
774 for (int ii = 0; ii < positionedItems.count(); ++ii) {
775 const PositionedItem &child = positionedItems.at(ii);
776 if (!child.item || !child.isVisible)
778 hoffset = end - hoffsets[acc++] - child.item->width();
779 if (child.item->x() != hoffset)
780 positionX(hoffset, child);
784 void QQuickRow::reportConflictingAnchors()
786 QQuickBasePositionerPrivate *d = static_cast<QQuickBasePositionerPrivate*>(QQuickBasePositionerPrivate::get(this));
787 for (int ii = 0; ii < positionedItems.count(); ++ii) {
788 const PositionedItem &child = positionedItems.at(ii);
790 QQuickAnchors *anchors = QQuickItemPrivate::get(static_cast<QQuickItem *>(child.item))->_anchors;
792 QQuickAnchors::Anchors usedAnchors = anchors->usedAnchors();
793 if (usedAnchors & QQuickAnchors::LeftAnchor ||
794 usedAnchors & QQuickAnchors::RightAnchor ||
795 usedAnchors & QQuickAnchors::HCenterAnchor ||
796 anchors->fill() || anchors->centerIn()) {
797 d->anchorConflict = true;
803 if (d->anchorConflict)
804 qmlInfo(this) << "Cannot specify left, right, horizontalCenter, fill or centerIn anchors for items inside Row";
808 \qmlclass Grid QQuickGrid
809 \inqmlmodule QtQuick 2
810 \ingroup qml-positioning-elements
811 \brief The Grid item positions its children in a grid.
814 The Grid item positions its child items so that they are
815 aligned in a grid and are not overlapping.
817 The grid positioner calculates a grid of rectangular cells of sufficient
818 size to hold all items, placing the items in the cells, from left to right
819 and top to bottom. Each item is positioned in the top-left corner of its
820 cell with position (0, 0).
822 A Grid defaults to four columns, and as many rows as are necessary to
823 fit all child items. The number of rows and columns can be constrained
824 by setting the \l rows and \l columns properties.
826 Spacing can be added between child items by setting the \l spacing
827 property. The amount of spacing applied will be the same in the
828 horizontal and vertical directions.
830 See \l{Using QML Positioner and Repeater Items} for more details about this item and other
833 \section1 Example Usage
835 The following example demonstrates this.
837 \image gridLayout_example.png
839 \snippet doc/src/snippets/declarative/grid/grid.qml document
841 \section1 Using Transitions
843 Transitions can be used to animate items that are added to, moved within,
844 or removed from a Grid item. The \l add and \l move properties can be set to
845 the transitions that will be applied when items are added to, removed from,
846 or re-positioned within a Grid item.
848 \section1 Limitations
850 Note that the positioner assumes that the x and y positions of its children
851 will not change. If you manually change the x or y properties in script, bind
852 the x or y properties, use anchors on a child of a positioner, or have the
853 width or height of a child depend on the position of a child, then the
854 positioner may exhibit strange behaviour. If you need to perform any of these
855 actions, consider positioning the items without the use of a Grid.
857 Items with a width or height of 0 will not be positioned.
859 Positioning is batched and syncronized with painting to reduce the number of
860 calculations needed. This means that positioners may not reposition items immediately
861 when changes occur, but it will have moved by the next frame.
863 \sa Flow, Row, Column, Positioner, {declarative/positioners}{Positioners example}
866 \qmlproperty Transition QtQuick2::Grid::add
868 This property holds the transition to be applied when adding an
869 item to the positioner. The transition will only be applied to the
870 added item(s). Positioner transitions will only affect the
871 position (x, y) of items.
873 For a positioner, adding an item can mean that either the object
874 has been created or reparented, and thus is now a child or the
875 positioner, or that the object has had its opacity increased from
876 zero, and thus is now visible.
881 \qmlproperty Transition QtQuick2::Grid::move
883 This property holds the transition to be applied when moving an
884 item within the positioner. Positioner transitions will only affect
885 the position (x, y) of items.
887 This transition can be performed when other items are added or removed
888 from the positioner, or when items resize themselves.
901 \sa add, {declarative/positioners}{Positioners example}
904 \qmlproperty int QtQuick2::Grid::spacing
906 The spacing is the amount in pixels left empty between adjacent
907 items. The default spacing is 0.
909 The below example places a Grid containing a red, a blue and a
910 green rectangle on a gray background. The area the grid positioner
911 occupies is colored white. The positioner on the left has the
912 no spacing (the default), and the positioner on the right has
915 \inlineimage qml-grid-no-spacing.png
916 \inlineimage qml-grid-spacing.png
920 QQuickGrid::QQuickGrid(QQuickItem *parent) :
921 QQuickBasePositioner(Both, parent), m_rows(-1), m_columns(-1), m_rowSpacing(-1), m_columnSpacing(-1), m_flow(LeftToRight)
926 \qmlproperty int QtQuick2::Grid::columns
928 This property holds the number of columns in the grid. The default
929 number of columns is 4.
931 If the grid does not have enough items to fill the specified
932 number of columns, some columns will be of zero width.
936 \qmlproperty int QtQuick2::Grid::rows
937 This property holds the number of rows in the grid.
939 If the grid does not have enough items to fill the specified
940 number of rows, some rows will be of zero width.
943 void QQuickGrid::setColumns(const int columns)
945 if (columns == m_columns)
949 emit columnsChanged();
952 void QQuickGrid::setRows(const int rows)
962 \qmlproperty enumeration QtQuick2::Grid::flow
963 This property holds the flow of the layout.
968 \o Grid.LeftToRight (default) - Items are positioned next to
969 each other in the \l layoutDirection, then wrapped to the next line.
970 \o Grid.TopToBottom - Items are positioned next to each
971 other from top to bottom, then wrapped to the next column.
974 QQuickGrid::Flow QQuickGrid::flow() const
979 void QQuickGrid::setFlow(Flow flow)
981 if (m_flow != flow) {
989 \qmlproperty int QtQuick2::Grid::rowSpacing
991 This property holds the spacing in pixels between rows.
996 void QQuickGrid::setRowSpacing(const int rowSpacing)
998 if (rowSpacing == m_rowSpacing)
1000 m_rowSpacing = rowSpacing;
1002 emit rowSpacingChanged();
1006 \qmlproperty int QtQuick2::Grid::columnSpacing
1008 This property holds the spacing in pixels between columns.
1013 void QQuickGrid::setColumnSpacing(const int columnSpacing)
1015 if (columnSpacing == m_columnSpacing)
1017 m_columnSpacing = columnSpacing;
1019 emit columnSpacingChanged();
1023 \qmlproperty enumeration QtQuick2::Grid::layoutDirection
1025 This property holds the layout direction of the layout.
1027 Possible values are:
1030 \o Qt.LeftToRight (default) - Items are positioned from the top to bottom,
1031 and left to right. The flow direction is dependent on the
1032 \l Grid::flow property.
1033 \o Qt.RightToLeft - Items are positioned from the top to bottom,
1034 and right to left. The flow direction is dependent on the
1035 \l Grid::flow property.
1038 \sa Flow::layoutDirection, Row::layoutDirection, {declarative/righttoleft/layoutdirection}{Layout directions example}
1040 Qt::LayoutDirection QQuickGrid::layoutDirection() const
1042 return QQuickBasePositionerPrivate::getLayoutDirection(this);
1045 void QQuickGrid::setLayoutDirection(Qt::LayoutDirection layoutDirection)
1047 QQuickBasePositionerPrivate *d = static_cast<QQuickBasePositionerPrivate*>(QQuickBasePositionerPrivate::get(this));
1048 if (d->layoutDirection != layoutDirection) {
1049 d->layoutDirection = layoutDirection;
1050 // For RTL layout the positioning changes when the width changes.
1051 if (d->layoutDirection == Qt::RightToLeft)
1052 d->addItemChangeListener(d, QQuickItemPrivate::Geometry);
1054 d->removeItemChangeListener(d, QQuickItemPrivate::Geometry);
1056 emit layoutDirectionChanged();
1057 emit effectiveLayoutDirectionChanged();
1062 \qmlproperty enumeration QtQuick2::Grid::effectiveLayoutDirection
1063 This property holds the effective layout direction of the grid positioner.
1065 When using the attached property \l {LayoutMirroring::enabled}{LayoutMirroring::enabled} for locale layouts,
1066 the visual layout direction of the grid positioner will be mirrored. However, the
1067 property \l {Grid::layoutDirection}{layoutDirection} will remain unchanged.
1069 \sa Grid::layoutDirection, {LayoutMirroring}{LayoutMirroring}
1071 Qt::LayoutDirection QQuickGrid::effectiveLayoutDirection() const
1073 return QQuickBasePositionerPrivate::getEffectiveLayoutDirection(this);
1076 void QQuickGrid::doPositioning(QSizeF *contentSize)
1078 QQuickBasePositionerPrivate *d = static_cast<QQuickBasePositionerPrivate*>(QQuickBasePositionerPrivate::get(this));
1081 //Is allocating the extra QPODVector too much overhead?
1082 QPODVector<PositionedItem, 8> visibleItems;//we aren't concerned with invisible items
1083 visibleItems.reserve(positionedItems.count());
1084 for (int i=0; i<positionedItems.count(); i++)
1085 if (positionedItems[i].item && positionedItems[i].isVisible)
1086 visibleItems.append(positionedItems[i]);
1088 int numVisible = visibleItems.count();
1089 if (m_columns <= 0 && m_rows <= 0){
1091 r = (numVisible+3)/4;
1092 } else if (m_rows <= 0){
1093 r = (numVisible+(m_columns-1))/m_columns;
1094 } else if (m_columns <= 0){
1095 c = (numVisible+(m_rows-1))/m_rows;
1099 return; //Nothing to do
1101 QList<int> maxColWidth;
1102 QList<int> maxRowHeight;
1104 if (m_flow == LeftToRight) {
1105 for (int i=0; i < r; i++){
1106 for (int j=0; j < c; j++){
1112 if (childIndex == visibleItems.count())
1115 const PositionedItem &child = visibleItems.at(childIndex++);
1116 if (child.item->width() > maxColWidth[j])
1117 maxColWidth[j] = child.item->width();
1118 if (child.item->height() > maxRowHeight[i])
1119 maxRowHeight[i] = child.item->height();
1123 for (int j=0; j < c; j++){
1124 for (int i=0; i < r; i++){
1130 if (childIndex == visibleItems.count())
1133 const PositionedItem &child = visibleItems.at(childIndex++);
1134 if (child.item->width() > maxColWidth[j])
1135 maxColWidth[j] = child.item->width();
1136 if (child.item->height() > maxRowHeight[i])
1137 maxRowHeight[i] = child.item->height();
1142 int columnSpacing = m_columnSpacing;
1143 if (columnSpacing == -1)
1144 columnSpacing = spacing();
1146 int rowSpacing = m_rowSpacing;
1147 if (rowSpacing == -1)
1148 rowSpacing = spacing();
1151 for (int j=0; j < maxColWidth.size(); j++){
1153 widthSum += columnSpacing;
1154 widthSum += maxColWidth[j];
1158 for (int i=0; i < maxRowHeight.size(); i++){
1160 heightSum += rowSpacing;
1161 heightSum += maxRowHeight[i];
1164 contentSize->setHeight(heightSum);
1165 contentSize->setWidth(widthSum);
1174 if (!d->isLeftToRight())
1179 for (int i = 0; i < visibleItems.count(); ++i) {
1180 const PositionedItem &child = visibleItems.at(i);
1181 int childXOffset = xoffset;
1182 if (!d->isLeftToRight())
1183 childXOffset -= child.item->width();
1184 if ((child.item->x() != childXOffset) || (child.item->y() != yoffset)){
1185 positionX(childXOffset, child);
1186 positionY(yoffset, child);
1189 if (m_flow == LeftToRight) {
1190 if (d->isLeftToRight())
1191 xoffset += maxColWidth[curCol]+columnSpacing;
1193 xoffset -= maxColWidth[curCol]+columnSpacing;
1197 yoffset += maxRowHeight[curRow]+rowSpacing;
1198 if (d->isLeftToRight())
1207 yoffset+=maxRowHeight[curRow]+rowSpacing;
1211 if (d->isLeftToRight())
1212 xoffset += maxColWidth[curCol]+columnSpacing;
1214 xoffset -= maxColWidth[curCol]+columnSpacing;
1224 void QQuickGrid::reportConflictingAnchors()
1226 QQuickBasePositionerPrivate *d = static_cast<QQuickBasePositionerPrivate*>(QQuickBasePositionerPrivate::get(this));
1227 for (int ii = 0; ii < positionedItems.count(); ++ii) {
1228 const PositionedItem &child = positionedItems.at(ii);
1230 QQuickAnchors *anchors = QQuickItemPrivate::get(static_cast<QQuickItem *>(child.item))->_anchors;
1231 if (anchors && (anchors->usedAnchors() || anchors->fill() || anchors->centerIn())) {
1232 d->anchorConflict = true;
1237 if (d->anchorConflict)
1238 qmlInfo(this) << "Cannot specify anchors for items inside Grid";
1242 \qmlclass Flow QQuickFlow
1243 \inqmlmodule QtQuick 2
1244 \ingroup qml-positioning-elements
1245 \brief The Flow item arranges its children side by side, wrapping as necessary.
1248 The Flow item positions its child items like words on a page, wrapping them
1249 to create rows or columns of items that do not overlap.
1251 Spacing between items can be added using the \l spacing property.
1252 Transitions can be used for cases where items managed by a Column are
1253 added or moved. These are stored in the \l add and \l move properties
1256 See \l{Using QML Positioner and Repeater Items} for more details about this item and other
1259 \section1 Example Usage
1261 The following example positions \l Text items within a parent item using
1264 \image qml-flow-snippet.png
1266 \snippet doc/src/snippets/declarative/flow.qml flow item
1268 \section1 Using Transitions
1270 Transitions can be used to animate items that are added to, moved within,
1271 or removed from a Flow item. The \l add and \l move properties can be set to
1272 the transitions that will be applied when items are added to, removed from,
1273 or re-positioned within a Flow item.
1275 The use of transitions with positioners is described in more detail in the
1276 \l{Using QML Positioner and Repeater Items#Using Transitions}{Using QML
1277 Positioner and Repeater Items} document.
1279 \section1 Limitations
1281 Note that the positioner assumes that the x and y positions of its children
1282 will not change. If you manually change the x or y properties in script, bind
1283 the x or y properties, use anchors on a child of a positioner, or have the
1284 width or height of a child depend on the position of a child, then the
1285 positioner may exhibit strange behaviour. If you need to perform any of these
1286 actions, consider positioning the items without the use of a Flow.
1288 Items with a width or height of 0 will not be positioned.
1290 Positioning is batched and syncronized with painting to reduce the number of
1291 calculations needed. This means that positioners may not reposition items immediately
1292 when changes occur, but it will have moved by the next frame.
1294 \sa Column, Row, Grid, Positioner, {declarative/positioners}{Positioners example}
1297 \qmlproperty Transition QtQuick2::Flow::add
1299 This property holds the transition to be applied when adding an
1300 item to the positioner. The transition will only be applied to the
1301 added item(s). Positioner transitions will only affect the
1302 position (x, y) of items.
1304 For a positioner, adding an item can mean that either the object
1305 has been created or reparented, and thus is now a child or the
1306 positioner, or that the object has had its opacity increased from
1307 zero, and thus is now visible.
1312 \qmlproperty Transition QtQuick2::Flow::move
1314 This property holds the transition to be applied when moving an
1315 item within the positioner. Positioner transitions will only affect
1316 the position (x, y) of items.
1318 This transition can be performed when other items are added or removed
1319 from the positioner, or when items resize themselves.
1327 ease: "easeOutBounce"
1333 \sa add, {declarative/positioners}{Positioners example}
1336 \qmlproperty int QtQuick2::Flow::spacing
1338 spacing is the amount in pixels left empty between each adjacent
1339 item, and defaults to 0.
1344 class QQuickFlowPrivate : public QQuickBasePositionerPrivate
1346 Q_DECLARE_PUBLIC(QQuickFlow)
1350 : QQuickBasePositionerPrivate(), flow(QQuickFlow::LeftToRight)
1353 QQuickFlow::Flow flow;
1356 QQuickFlow::QQuickFlow(QQuickItem *parent)
1357 : QQuickBasePositioner(*(new QQuickFlowPrivate), Both, parent)
1360 // Flow layout requires relayout if its own size changes too.
1361 d->addItemChangeListener(d, QQuickItemPrivate::Geometry);
1365 \qmlproperty enumeration QtQuick2::Flow::flow
1366 This property holds the flow of the layout.
1368 Possible values are:
1371 \o Flow.LeftToRight (default) - Items are positioned next to
1372 to each other according to the \l layoutDirection until the width of the Flow
1373 is exceeded, then wrapped to the next line.
1374 \o Flow.TopToBottom - Items are positioned next to each
1375 other from top to bottom until the height of the Flow is exceeded,
1376 then wrapped to the next column.
1379 QQuickFlow::Flow QQuickFlow::flow() const
1381 Q_D(const QQuickFlow);
1385 void QQuickFlow::setFlow(Flow flow)
1388 if (d->flow != flow) {
1396 \qmlproperty enumeration QtQuick2::Flow::layoutDirection
1398 This property holds the layout direction of the layout.
1400 Possible values are:
1403 \o Qt.LeftToRight (default) - Items are positioned from the top to bottom,
1404 and left to right. The flow direction is dependent on the
1405 \l Flow::flow property.
1406 \o Qt.RightToLeft - Items are positioned from the top to bottom,
1407 and right to left. The flow direction is dependent on the
1408 \l Flow::flow property.
1411 \sa Grid::layoutDirection, Row::layoutDirection, {declarative/righttoleft/layoutdirection}{Layout directions example}
1414 Qt::LayoutDirection QQuickFlow::layoutDirection() const
1416 Q_D(const QQuickFlow);
1417 return d->layoutDirection;
1420 void QQuickFlow::setLayoutDirection(Qt::LayoutDirection layoutDirection)
1423 if (d->layoutDirection != layoutDirection) {
1424 d->layoutDirection = layoutDirection;
1426 emit layoutDirectionChanged();
1427 emit effectiveLayoutDirectionChanged();
1432 \qmlproperty enumeration QtQuick2::Flow::effectiveLayoutDirection
1433 This property holds the effective layout direction of the flow positioner.
1435 When using the attached property \l {LayoutMirroring::enabled}{LayoutMirroring::enabled} for locale layouts,
1436 the visual layout direction of the grid positioner will be mirrored. However, the
1437 property \l {Flow::layoutDirection}{layoutDirection} will remain unchanged.
1439 \sa Flow::layoutDirection, {LayoutMirroring}{LayoutMirroring}
1442 Qt::LayoutDirection QQuickFlow::effectiveLayoutDirection() const
1444 return QQuickBasePositionerPrivate::getEffectiveLayoutDirection(this);
1447 void QQuickFlow::doPositioning(QSizeF *contentSize)
1454 QList<int> hoffsets;
1456 for (int i = 0; i < positionedItems.count(); ++i) {
1457 const PositionedItem &child = positionedItems.at(i);
1458 if (!child.item || !child.isVisible)
1461 if (d->flow == LeftToRight) {
1462 if (widthValid() && hoffset && hoffset + child.item->width() > width()) {
1464 voffset += linemax + spacing();
1468 if (heightValid() && voffset && voffset + child.item->height() > height()) {
1470 hoffset += linemax + spacing();
1475 if (d->isLeftToRight()) {
1476 if (child.item->x() != hoffset)
1477 positionX(hoffset, child);
1479 hoffsets << hoffset;
1481 if (child.item->y() != voffset)
1482 positionY(voffset, child);
1484 contentSize->setWidth(qMax(contentSize->width(), hoffset + child.item->width()));
1485 contentSize->setHeight(qMax(contentSize->height(), voffset + child.item->height()));
1487 if (d->flow == LeftToRight) {
1488 hoffset += child.item->width();
1489 hoffset += spacing();
1490 linemax = qMax(linemax, qCeil(child.item->height()));
1492 voffset += child.item->height();
1493 voffset += spacing();
1494 linemax = qMax(linemax, qCeil(child.item->width()));
1497 if (d->isLeftToRight())
1504 end = contentSize->width();
1506 for (int i = 0; i < positionedItems.count(); ++i) {
1507 const PositionedItem &child = positionedItems.at(i);
1508 if (!child.item || !child.isVisible)
1510 hoffset = end - hoffsets[acc++] - child.item->width();
1511 if (child.item->x() != hoffset)
1512 positionX(hoffset, child);
1516 void QQuickFlow::reportConflictingAnchors()
1519 for (int ii = 0; ii < positionedItems.count(); ++ii) {
1520 const PositionedItem &child = positionedItems.at(ii);
1522 QQuickAnchors *anchors = QQuickItemPrivate::get(static_cast<QQuickItem *>(child.item))->_anchors;
1523 if (anchors && (anchors->usedAnchors() || anchors->fill() || anchors->centerIn())) {
1524 d->anchorConflict = true;
1529 if (d->anchorConflict)
1530 qmlInfo(this) << "Cannot specify anchors for items inside Flow";