8ab4771ce3697892203e8fc192078008cf7f6235
[profile/ivi/qtdeclarative.git] / src / quick / items / qquickpositioners.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: http://www.qt-project.org/
6 **
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
8 **
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.
17 **
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.
21 **
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.
29 **
30 ** Other Usage
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.
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qquickpositioners_p.h"
43 #include "qquickpositioners_p_p.h"
44
45 #include <QtDeclarative/qdeclarative.h>
46 #include <QtDeclarative/qdeclarativeinfo.h>
47 #include <QtCore/qmath.h>
48 #include <QtCore/qcoreapplication.h>
49
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>
54
55 QT_BEGIN_NAMESPACE
56
57 static const QQuickItemPrivate::ChangeTypes watchedChanges
58     = QQuickItemPrivate::Geometry
59     | QQuickItemPrivate::SiblingOrder
60     | QQuickItemPrivate::Visibility
61     | QQuickItemPrivate::Destroyed;
62
63 void QQuickBasePositionerPrivate::watchChanges(QQuickItem *other)
64 {
65     QQuickItemPrivate *otherPrivate = QQuickItemPrivate::get(other);
66     otherPrivate->addItemChangeListener(this, watchedChanges);
67 }
68
69 void QQuickBasePositionerPrivate::unwatchChanges(QQuickItem* other)
70 {
71     QQuickItemPrivate *otherPrivate = QQuickItemPrivate::get(other);
72     otherPrivate->removeItemChangeListener(this, watchedChanges);
73 }
74
75 QQuickBasePositioner::QQuickBasePositioner(PositionerType at, QQuickItem *parent)
76     : QQuickImplicitSizeItem(*(new QQuickBasePositionerPrivate), parent)
77 {
78     Q_D(QQuickBasePositioner);
79     d->init(at);
80 }
81 /*!
82     \internal
83     \class QQuickBasePositioner
84     \brief The QQuickBasePositioner class provides a base for QQuickGraphics layouts.
85
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.
91
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.
94
95     Note that the subclass is responsible for adding the spacing in between items.
96
97     Positioning is usually delayed until before a frame is rendered, to batch multiple repositioning
98     changes into one calculation.
99 */
100
101 QQuickBasePositioner::QQuickBasePositioner(QQuickBasePositionerPrivate &dd, PositionerType at, QQuickItem *parent)
102     : QQuickImplicitSizeItem(dd, parent)
103 {
104     Q_D(QQuickBasePositioner);
105     d->init(at);
106 }
107
108 QQuickBasePositioner::~QQuickBasePositioner()
109 {
110     Q_D(QQuickBasePositioner);
111     for (int i = 0; i < positionedItems.count(); ++i)
112         d->unwatchChanges(positionedItems.at(i).item);
113     positionedItems.clear();
114 }
115
116 void QQuickBasePositioner::updatePolish()
117 {
118     Q_D(QQuickBasePositioner);
119     if (d->positioningDirty)
120         prePositioning();
121 }
122
123 int QQuickBasePositioner::spacing() const
124 {
125     Q_D(const QQuickBasePositioner);
126     return d->spacing;
127 }
128
129 void QQuickBasePositioner::setSpacing(int s)
130 {
131     Q_D(QQuickBasePositioner);
132     if (s==d->spacing)
133         return;
134     d->spacing = s;
135     d->setPositioningDirty();
136     emit spacingChanged();
137 }
138
139 QDeclarativeTransition *QQuickBasePositioner::move() const
140 {
141     Q_D(const QQuickBasePositioner);
142     return d->moveTransition;
143 }
144
145 void QQuickBasePositioner::setMove(QDeclarativeTransition *mt)
146 {
147     Q_D(QQuickBasePositioner);
148     if (mt == d->moveTransition)
149         return;
150     d->moveTransition = mt;
151     emit moveChanged();
152 }
153
154 QDeclarativeTransition *QQuickBasePositioner::add() const
155 {
156     Q_D(const QQuickBasePositioner);
157     return d->addTransition;
158 }
159
160 void QQuickBasePositioner::setAdd(QDeclarativeTransition *add)
161 {
162     Q_D(QQuickBasePositioner);
163     if (add == d->addTransition)
164         return;
165
166     d->addTransition = add;
167     emit addChanged();
168 }
169
170 void QQuickBasePositioner::componentComplete()
171 {
172     QQuickItem::componentComplete();
173     positionedItems.reserve(childItems().count());
174     prePositioning();
175 }
176
177 void QQuickBasePositioner::itemChange(ItemChange change, const ItemChangeData &value)
178 {
179     Q_D(QQuickBasePositioner);
180     if (change == ItemChildAddedChange){
181         d->setPositioningDirty();
182     } else if (change == ItemChildRemovedChange) {
183         QQuickItem *child = value.item;
184         QQuickBasePositioner::PositionedItem posItem(child);
185         int idx = positionedItems.find(posItem);
186         if (idx >= 0) {
187             d->unwatchChanges(child);
188             positionedItems.remove(idx);
189         }
190         d->setPositioningDirty();
191     }
192
193     QQuickItem::itemChange(change, value);
194 }
195
196 void QQuickBasePositioner::prePositioning()
197 {
198     Q_D(QQuickBasePositioner);
199     if (!isComponentComplete())
200         return;
201
202     if (d->doingPositioning)
203         return;
204
205     d->positioningDirty = false;
206     d->doingPositioning = true;
207     //Need to order children by creation order modified by stacking order
208     QList<QQuickItem *> children = childItems();
209
210     QPODVector<PositionedItem,8> oldItems;
211     positionedItems.copyAndClear(oldItems);
212     for (int ii = 0; ii < children.count(); ++ii) {
213         QQuickItem *child = children.at(ii);
214         QQuickItemPrivate *childPrivate = QQuickItemPrivate::get(child);
215         PositionedItem *item = 0;
216         PositionedItem posItem(child);
217         int wIdx = oldItems.find(posItem);
218         if (wIdx < 0) {
219             d->watchChanges(child);
220             positionedItems.append(posItem);
221             item = &positionedItems[positionedItems.count()-1];
222             item->isNew = true;
223             if (!childPrivate->explicitVisible || !child->width() || !child->height())
224                 item->isVisible = false;
225         } else {
226             item = &oldItems[wIdx];
227             // Items are only omitted from positioning if they are explicitly hidden
228             // i.e. their positioning is not affected if an ancestor is hidden.
229             if (!childPrivate->explicitVisible || !child->width() || !child->height()) {
230                 item->isVisible = false;
231             } else if (!item->isVisible) {
232                 item->isVisible = true;
233                 item->isNew = true;
234             } else {
235                 item->isNew = false;
236             }
237             positionedItems.append(*item);
238         }
239     }
240     QSizeF contentSize(0,0);
241     reportConflictingAnchors();
242     if (!d->anchorConflict) {
243         doPositioning(&contentSize);
244         updateAttachedProperties();
245     }
246     if (!d->addActions.isEmpty() || !d->moveActions.isEmpty())
247         finishApplyTransitions();
248     d->doingPositioning = false;
249     //Set implicit size to the size of its children
250     setImplicitSize(contentSize.width(), contentSize.height());
251 }
252
253 void QQuickBasePositioner::positionX(int x, const PositionedItem &target)
254 {
255     Q_D(QQuickBasePositioner);
256     if (d->type == Horizontal || d->type == Both) {
257         if (target.isNew) {
258             if (!d->addTransition || !d->addTransition->enabled())
259                 target.item->setX(x);
260             else
261                 d->addActions << QDeclarativeAction(target.item, QLatin1String("x"), QVariant(x));
262         } else if (x != target.item->x()) {
263             if (!d->moveTransition || !d->moveTransition->enabled())
264                 target.item->setX(x);
265             else
266                 d->moveActions << QDeclarativeAction(target.item, QLatin1String("x"), QVariant(x));
267         }
268     }
269 }
270
271 void QQuickBasePositioner::positionY(int y, const PositionedItem &target)
272 {
273     Q_D(QQuickBasePositioner);
274     if (d->type == Vertical || d->type == Both) {
275         if (target.isNew) {
276             if (!d->addTransition || !d->addTransition->enabled())
277                 target.item->setY(y);
278             else
279                 d->addActions << QDeclarativeAction(target.item, QLatin1String("y"), QVariant(y));
280         } else if (y != target.item->y()) {
281             if (!d->moveTransition || !d->moveTransition->enabled())
282                 target.item->setY(y);
283             else
284                 d->moveActions << QDeclarativeAction(target.item, QLatin1String("y"), QVariant(y));
285         }
286     }
287 }
288
289 void QQuickBasePositioner::finishApplyTransitions()
290 {
291     Q_D(QQuickBasePositioner);
292     // Note that if a transition is not set the transition manager will
293     // apply the changes directly, in the case add/move aren't set
294     d->addTransitionManager.transition(d->addActions, d->addTransition);
295     d->moveTransitionManager.transition(d->moveActions, d->moveTransition);
296     d->addActions.clear();
297     d->moveActions.clear();
298 }
299
300 QQuickPositionerAttached *QQuickBasePositioner::qmlAttachedProperties(QObject *obj)
301 {
302     return new QQuickPositionerAttached(obj);
303 }
304
305 void QQuickBasePositioner::updateAttachedProperties(QQuickPositionerAttached *specificProperty, QQuickItem *specificPropertyOwner) const
306 {
307     // If this function is deemed too expensive or shows up in profiles, it could
308     // be changed to run only when there are attached properties present. This
309     // could be a flag in the positioner that is set by the attached property
310     // constructor.
311     QQuickPositionerAttached *prevLastProperty = 0;
312     QQuickPositionerAttached *lastProperty = 0;
313
314     int visibleItemIndex = 0;
315     for (int ii = 0; ii < positionedItems.count(); ++ii) {
316         const PositionedItem &child = positionedItems.at(ii);
317         if (!child.item)
318             continue;
319
320         QQuickPositionerAttached *property = 0;
321
322         if (specificProperty) {
323             if (specificPropertyOwner == child.item) {
324                 property = specificProperty;
325             }
326         } else {
327             property = static_cast<QQuickPositionerAttached *>(qmlAttachedPropertiesObject<QQuickBasePositioner>(child.item, false));
328         }
329
330         if (child.isVisible) {
331             if (property) {
332               property->setIndex(visibleItemIndex);
333               property->setIsFirstItem(visibleItemIndex == 0);
334
335               if (property->isLastItem())
336                 prevLastProperty = property;
337             }
338
339             lastProperty = property;
340             ++visibleItemIndex;
341         } else if (property) {
342             property->setIndex(-1);
343             property->setIsFirstItem(false);
344             property->setIsLastItem(false);
345         }
346     }
347
348     if (prevLastProperty && prevLastProperty != lastProperty)
349         prevLastProperty->setIsLastItem(false);
350     if (lastProperty)
351       lastProperty->setIsLastItem(true);
352 }
353
354 /*!
355     \qmlclass Positioner QQuickPositionerAttached
356     \inqmlmodule QtQuick 2
357     \ingroup qml-positioning-elements
358     \brief The Positioner type provides attached properties that contain details on where an item exists in a positioner.
359
360     Positioner items (such as Column, Row, Flow and Grid) provide automatic layout
361     for child items. Attaching this property allows a child item to determine
362     where it exists within the positioner.
363 */
364
365 QQuickPositionerAttached::QQuickPositionerAttached(QObject *parent) : QObject(parent), m_index(-1), m_isFirstItem(false), m_isLastItem(false)
366 {
367     QQuickItem *attachedItem = qobject_cast<QQuickItem *>(parent);
368     if (attachedItem) {
369         QQuickBasePositioner *positioner = qobject_cast<QQuickBasePositioner *>(attachedItem->parent());
370         if (positioner) {
371             positioner->updateAttachedProperties(this, attachedItem);
372         }
373     }
374 }
375
376 /*!
377     \qmlattachedproperty int QtQuick2::Positioner::index
378
379     This property allows the item to determine
380     its index within the positioner.
381 */
382 void QQuickPositionerAttached::setIndex(int index)
383 {
384     if (m_index == index)
385         return;
386     m_index = index;
387     emit indexChanged();
388 }
389
390 /*!
391     \qmlattachedproperty bool QtQuick2::Positioner::isFirstItem
392     \qmlattachedproperty bool QtQuick2::Positioner::isLastItem
393
394     These properties allow the item to determine if it
395     is the first or last item in the positioner, respectively.
396 */
397 void QQuickPositionerAttached::setIsFirstItem(bool isFirstItem)
398 {
399     if (m_isFirstItem == isFirstItem)
400         return;
401     m_isFirstItem = isFirstItem;
402     emit isFirstItemChanged();
403 }
404
405 void QQuickPositionerAttached::setIsLastItem(bool isLastItem)
406 {
407     if (m_isLastItem == isLastItem)
408         return;
409     m_isLastItem = isLastItem;
410     emit isLastItemChanged();
411 }
412
413 /*!
414   \qmlclass Column QQuickColumn
415     \inqmlmodule QtQuick 2
416   \ingroup qml-positioning-elements
417   \brief The Column item arranges its children vertically.
418   \inherits Item
419
420   The Column item positions its child items so that they are vertically
421   aligned and not overlapping.
422
423   Spacing between items can be added using the \l spacing property.
424   Transitions can be used for cases where items managed by a Column are
425   added or moved. These are stored in the \l add and \l move properties
426   respectively.
427
428   See \l{Using QML Positioner and Repeater Items} for more details about this item and other
429   related items.
430
431   \section1 Example Usage
432
433   The following example positions differently shaped rectangles using a Column
434   item.
435
436   \image verticalpositioner_example.png
437
438   \snippet doc/src/snippets/declarative/column/vertical-positioner.qml document
439
440   \section1 Using Transitions
441
442   Transitions can be used to animate items that are added to, moved within,
443   or removed from a Column item. The \l add and \l move properties can be set to
444   the transitions that will be applied when items are added to, removed from,
445   or re-positioned within a Column item.
446
447   The use of transitions with positioners is described in more detail in the
448   \l{Using QML Positioner and Repeater Items#Using Transitions}{Using QML
449   Positioner and Repeater Items} document.
450
451   \image verticalpositioner_transition.gif
452
453   \qml
454   Column {
455       spacing: 2
456       add: Transition {
457           // Define an animation for adding a new item...
458       }
459       move: Transition {
460           // Define an animation for moving items within the column...
461       }
462       // ...
463   }
464   \endqml
465
466   \section1 Limitations
467
468   Note that the positioner assumes that the x and y positions of its children
469   will not change. If you manually change the x or y properties in script, bind
470   the x or y properties, use anchors on a child of a positioner, or have the
471   height of a child depend on the position of a child, then the
472   positioner may exhibit strange behavior. If you need to perform any of these
473   actions, consider positioning the items without the use of a Column.
474
475   Items with a width or height of 0 will not be positioned.
476
477   Positioning is batched and syncronized with painting to reduce the number of
478   calculations needed. This means that positioners may not reposition items immediately
479   when changes occur, but it will have moved by the next frame.
480
481   \sa Row, Grid, Flow, Positioner, {declarative/positioners}{Positioners example}
482 */
483 /*!
484     \qmlproperty Transition QtQuick2::Column::add
485
486     This property holds the transition to be applied when adding an
487     item to the positioner. The transition will only be applied to the
488     added item(s).  Positioner transitions will only affect the
489     position (x, y) of items.
490
491     For a positioner, adding an item can mean that either the object
492     has been created or reparented, and thus is now a child or the
493     positioner, or that the object has had its opacity increased from
494     zero, and thus is now visible.
495
496     \sa move
497 */
498 /*!
499     \qmlproperty Transition QtQuick2::Column::move
500
501     This property holds the transition to apply when moving an item
502     within the positioner.  Positioner transitions will only affect
503     the position (x, y) of items.
504
505     This transition can be performed when other items are added or removed
506     from the positioner, or when items resize themselves.
507
508     \image positioner-move.gif
509
510     \qml
511     Column {
512         move: Transition {
513             NumberAnimation {
514                 properties: "y"
515                 duration: 1000
516             }
517         }
518     }
519     \endqml
520
521     \sa add, {declarative/positioners}{Positioners example}
522 */
523 /*!
524   \qmlproperty int QtQuick2::Column::spacing
525
526   The spacing is the amount in pixels left empty between adjacent
527   items. The default spacing is 0.
528
529   \sa Grid::spacing
530 */
531 QQuickColumn::QQuickColumn(QQuickItem *parent)
532 : QQuickBasePositioner(Vertical, parent)
533 {
534 }
535
536 void QQuickColumn::doPositioning(QSizeF *contentSize)
537 {
538     int voffset = 0;
539
540     for (int ii = 0; ii < positionedItems.count(); ++ii) {
541         const PositionedItem &child = positionedItems.at(ii);
542         if (!child.item || !child.isVisible)
543             continue;
544
545         if (child.item->y() != voffset)
546             positionY(voffset, child);
547
548         contentSize->setWidth(qMax(contentSize->width(), child.item->width()));
549
550         voffset += child.item->height();
551         voffset += spacing();
552     }
553
554     if (voffset != 0)//If we positioned any items, undo the spacing from the last item
555         voffset -= spacing();
556     contentSize->setHeight(voffset);
557 }
558
559 void QQuickColumn::reportConflictingAnchors()
560 {
561     QQuickBasePositionerPrivate *d = static_cast<QQuickBasePositionerPrivate*>(QQuickBasePositionerPrivate::get(this));
562     for (int ii = 0; ii < positionedItems.count(); ++ii) {
563         const PositionedItem &child = positionedItems.at(ii);
564         if (child.item) {
565             QQuickAnchors *anchors = QQuickItemPrivate::get(static_cast<QQuickItem *>(child.item))->_anchors;
566             if (anchors) {
567                 QQuickAnchors::Anchors usedAnchors = anchors->usedAnchors();
568                 if (usedAnchors & QQuickAnchors::TopAnchor ||
569                     usedAnchors & QQuickAnchors::BottomAnchor ||
570                     usedAnchors & QQuickAnchors::VCenterAnchor ||
571                     anchors->fill() || anchors->centerIn()) {
572                     d->anchorConflict = true;
573                     break;
574                 }
575             }
576         }
577     }
578     if (d->anchorConflict) {
579         qmlInfo(this) << "Cannot specify top, bottom, verticalCenter, fill or centerIn anchors for items inside Column."
580             << " Column will not function.";
581     }
582 }
583 /*!
584   \qmlclass Row QQuickRow
585     \inqmlmodule QtQuick 2
586   \ingroup qml-positioning-elements
587   \brief The Row item arranges its children horizontally.
588   \inherits Item
589
590   The Row item positions its child items so that they are horizontally
591   aligned and not overlapping.
592
593   Use \l spacing to set the spacing between items in a Row, and use the
594   \l add and \l move properties to set the transitions that should be applied
595   when items are added to, removed from, or re-positioned within the Row.
596
597   See \l{Using QML Positioner and Repeater Items} for more details about this item and other
598   related items.
599
600   \section1 Example Usage
601
602   The following example lays out differently shaped rectangles using a Row.
603
604   \image horizontalpositioner_example.png
605
606   \snippet doc/src/snippets/declarative/row/row.qml document
607
608   \section1 Using Transitions
609
610   Transitions can be used to animate items that are added to, moved within,
611   or removed from a Grid item. The \l add and \l move properties can be set to
612   the transitions that will be applied when items are added to, removed from,
613   or re-positioned within a Row item.
614
615   \section1 Limitations
616
617   Note that the positioner assumes that the x and y positions of its children
618   will not change. If you manually change the x or y properties in script, bind
619   the x or y properties, use anchors on a child of a positioner, or have the
620   width of a child depend on the position of a child, then the
621   positioner may exhibit strange behavior. If you need to perform any of these
622   actions, consider positioning the items without the use of a Row.
623
624   Items with a width or height of 0 will not be positioned.
625
626   Positioning is batched and syncronized with painting to reduce the number of
627   calculations needed. This means that positioners may not reposition items immediately
628   when changes occur, but it will have moved by the next frame.
629
630   \sa Column, Grid, Flow, Positioner, {declarative/positioners}{Positioners example}
631 */
632 /*!
633     \qmlproperty Transition QtQuick2::Row::add
634
635     This property holds the transition to be applied when adding an
636     item to the positioner. The transition will only be applied to the
637     added item(s).  Positioner transitions will only affect the
638     position (x, y) of items.
639
640     For a positioner, adding an item can mean that either the object
641     has been created or reparented, and thus is now a child or the
642     positioner, or that the object has had its opacity increased from
643     zero, and thus is now visible.
644
645     \sa move
646 */
647 /*!
648     \qmlproperty Transition QtQuick2::Row::move
649
650     This property holds the transition to be applied when moving an
651     item within the positioner. Positioner transitions will only affect
652     the position (x, y) of items.
653
654     This transition can be performed when other items are added or removed
655     from the positioner, or when items resize themselves.
656
657     \qml
658     Row {
659         id: positioner
660         move: Transition {
661             NumberAnimation {
662                 properties: "x"
663                 duration: 1000
664             }
665         }
666     }
667     \endqml
668
669     \sa add, {declarative/positioners}{Positioners example}
670 */
671 /*!
672   \qmlproperty int QtQuick2::Row::spacing
673
674   The spacing is the amount in pixels left empty between adjacent
675   items. The default spacing is 0.
676
677   \sa Grid::spacing
678 */
679
680 QQuickRow::QQuickRow(QQuickItem *parent)
681 : QQuickBasePositioner(Horizontal, parent)
682 {
683 }
684 /*!
685     \qmlproperty enumeration QtQuick2::Row::layoutDirection
686
687     This property holds the layoutDirection of the row.
688
689     Possible values:
690
691     \list
692     \o Qt.LeftToRight (default) - Items are laid out from left to right. If the width of the row is explicitly set,
693     the left anchor remains to the left of the row.
694     \o Qt.RightToLeft - Items are laid out from right to left. If the width of the row is explicitly set,
695     the right anchor remains to the right of the row.
696     \endlist
697
698     \sa Grid::layoutDirection, Flow::layoutDirection, {declarative/righttoleft/layoutdirection}{Layout directions example}
699 */
700
701 Qt::LayoutDirection QQuickRow::layoutDirection() const
702 {
703     return QQuickBasePositionerPrivate::getLayoutDirection(this);
704 }
705
706 void QQuickRow::setLayoutDirection(Qt::LayoutDirection layoutDirection)
707 {
708     QQuickBasePositionerPrivate *d = static_cast<QQuickBasePositionerPrivate* >(QQuickBasePositionerPrivate::get(this));
709     if (d->layoutDirection != layoutDirection) {
710         d->layoutDirection = layoutDirection;
711         // For RTL layout the positioning changes when the width changes.
712         if (d->layoutDirection == Qt::RightToLeft)
713             d->addItemChangeListener(d, QQuickItemPrivate::Geometry);
714         else
715             d->removeItemChangeListener(d, QQuickItemPrivate::Geometry);
716         prePositioning();
717         emit layoutDirectionChanged();
718         emit effectiveLayoutDirectionChanged();
719     }
720 }
721 /*!
722     \qmlproperty enumeration QtQuick2::Row::effectiveLayoutDirection
723     This property holds the effective layout direction of the row positioner.
724
725     When using the attached property \l {LayoutMirroring::enabled}{LayoutMirroring::enabled} for locale layouts,
726     the visual layout direction of the row positioner will be mirrored. However, the
727     property \l {Row::layoutDirection}{layoutDirection} will remain unchanged.
728
729     \sa Row::layoutDirection, {LayoutMirroring}{LayoutMirroring}
730 */
731
732 Qt::LayoutDirection QQuickRow::effectiveLayoutDirection() const
733 {
734     return QQuickBasePositionerPrivate::getEffectiveLayoutDirection(this);
735 }
736
737 void QQuickRow::doPositioning(QSizeF *contentSize)
738 {
739     QQuickBasePositionerPrivate *d = static_cast<QQuickBasePositionerPrivate* >(QQuickBasePositionerPrivate::get(this));
740     int hoffset = 0;
741
742     QList<int> hoffsets;
743     for (int ii = 0; ii < positionedItems.count(); ++ii) {
744         const PositionedItem &child = positionedItems.at(ii);
745         if (!child.item || !child.isVisible)
746             continue;
747
748         if (d->isLeftToRight()) {
749             if (child.item->x() != hoffset)
750                 positionX(hoffset, child);
751         } else {
752             hoffsets << hoffset;
753         }
754
755         contentSize->setHeight(qMax(contentSize->height(), child.item->height()));
756
757         hoffset += child.item->width();
758         hoffset += spacing();
759     }
760
761     if (hoffset != 0)//If we positioned any items, undo the extra spacing from the last item
762         hoffset -= spacing();
763     contentSize->setWidth(hoffset);
764
765     if (d->isLeftToRight())
766         return;
767
768     //Right to Left layout
769     int end = 0;
770     if (!widthValid())
771         end = contentSize->width();
772     else
773         end = width();
774
775     int acc = 0;
776     for (int ii = 0; ii < positionedItems.count(); ++ii) {
777         const PositionedItem &child = positionedItems.at(ii);
778         if (!child.item || !child.isVisible)
779             continue;
780         hoffset = end - hoffsets[acc++] - child.item->width();
781         if (child.item->x() != hoffset)
782             positionX(hoffset, child);
783     }
784 }
785
786 void QQuickRow::reportConflictingAnchors()
787 {
788     QQuickBasePositionerPrivate *d = static_cast<QQuickBasePositionerPrivate*>(QQuickBasePositionerPrivate::get(this));
789     for (int ii = 0; ii < positionedItems.count(); ++ii) {
790         const PositionedItem &child = positionedItems.at(ii);
791         if (child.item) {
792             QQuickAnchors *anchors = QQuickItemPrivate::get(static_cast<QQuickItem *>(child.item))->_anchors;
793             if (anchors) {
794                 QQuickAnchors::Anchors usedAnchors = anchors->usedAnchors();
795                 if (usedAnchors & QQuickAnchors::LeftAnchor ||
796                     usedAnchors & QQuickAnchors::RightAnchor ||
797                     usedAnchors & QQuickAnchors::HCenterAnchor ||
798                     anchors->fill() || anchors->centerIn()) {
799                     d->anchorConflict = true;
800                     break;
801                 }
802             }
803         }
804     }
805     if (d->anchorConflict)
806         qmlInfo(this) << "Cannot specify left, right, horizontalCenter, fill or centerIn anchors for items inside Row."
807             << " Row will not function.";
808 }
809
810 /*!
811   \qmlclass Grid QQuickGrid
812     \inqmlmodule QtQuick 2
813   \ingroup qml-positioning-elements
814   \brief The Grid item positions its children in a grid.
815   \inherits Item
816
817   The Grid item positions its child items so that they are
818   aligned in a grid and are not overlapping.
819
820   The grid positioner calculates a grid of rectangular cells of sufficient
821   size to hold all items, placing the items in the cells, from left to right
822   and top to bottom. Each item is positioned in the top-left corner of its
823   cell with position (0, 0).
824
825   A Grid defaults to four columns, and as many rows as are necessary to
826   fit all child items. The number of rows and columns can be constrained
827   by setting the \l rows and \l columns properties.
828
829   Spacing can be added between child items by setting the \l spacing
830   property. The amount of spacing applied will be the same in the
831   horizontal and vertical directions.
832
833   See \l{Using QML Positioner and Repeater Items} for more details about this item and other
834   related items.
835
836   \section1 Example Usage
837
838   The following example demonstrates this.
839
840   \image gridLayout_example.png
841
842   \snippet doc/src/snippets/declarative/grid/grid.qml document
843
844   \section1 Using Transitions
845
846   Transitions can be used to animate items that are added to, moved within,
847   or removed from a Grid item. The \l add and \l move properties can be set to
848   the transitions that will be applied when items are added to, removed from,
849   or re-positioned within a Grid item.
850
851   \section1 Limitations
852
853   Note that the positioner assumes that the x and y positions of its children
854   will not change. If you manually change the x or y properties in script, bind
855   the x or y properties, use anchors on a child of a positioner, or have the
856   width or height of a child depend on the position of a child, then the
857   positioner may exhibit strange behavior. If you need to perform any of these
858   actions, consider positioning the items without the use of a Grid.
859
860   Items with a width or height of 0 will not be positioned.
861
862   Positioning is batched and syncronized with painting to reduce the number of
863   calculations needed. This means that positioners may not reposition items immediately
864   when changes occur, but it will have moved by the next frame.
865
866   \sa Flow, Row, Column, Positioner, {declarative/positioners}{Positioners example}
867 */
868 /*!
869     \qmlproperty Transition QtQuick2::Grid::add
870
871     This property holds the transition to be applied when adding an
872     item to the positioner. The transition will only be applied to the
873     added item(s).  Positioner transitions will only affect the
874     position (x, y) of items.
875
876     For a positioner, adding an item can mean that either the object
877     has been created or reparented, and thus is now a child or the
878     positioner, or that the object has had its opacity increased from
879     zero, and thus is now visible.
880
881     \sa move
882 */
883 /*!
884     \qmlproperty Transition QtQuick2::Grid::move
885
886     This property holds the transition to be applied when moving an
887     item within the positioner. Positioner transitions will only affect
888     the position (x, y) of items.
889
890     This transition can be performed when other items are added or removed
891     from the positioner, or when items resize themselves.
892
893     \qml
894     Grid {
895         move: Transition {
896             NumberAnimation {
897                 properties: "x,y"
898                 duration: 1000
899             }
900         }
901     }
902     \endqml
903
904     \sa add, {declarative/positioners}{Positioners example}
905 */
906 /*!
907   \qmlproperty int QtQuick2::Grid::spacing
908
909   The spacing is the amount in pixels left empty between adjacent
910   items. The default spacing is 0.
911
912   The below example places a Grid containing a red, a blue and a
913   green rectangle on a gray background. The area the grid positioner
914   occupies is colored white. The positioner on the left has the
915   no spacing (the default), and the positioner on the right has
916   a spacing of 6.
917
918   \inlineimage qml-grid-no-spacing.png
919   \inlineimage qml-grid-spacing.png
920
921   \sa rows, columns
922 */
923 QQuickGrid::QQuickGrid(QQuickItem *parent) :
924     QQuickBasePositioner(Both, parent), m_rows(-1), m_columns(-1), m_rowSpacing(-1), m_columnSpacing(-1), m_flow(LeftToRight)
925 {
926 }
927
928 /*!
929     \qmlproperty int QtQuick2::Grid::columns
930
931     This property holds the number of columns in the grid. The default
932     number of columns is 4.
933
934     If the grid does not have enough items to fill the specified
935     number of columns, some columns will be of zero width.
936 */
937
938 /*!
939     \qmlproperty int QtQuick2::Grid::rows
940     This property holds the number of rows in the grid.
941
942     If the grid does not have enough items to fill the specified
943     number of rows, some rows will be of zero width.
944 */
945
946 void QQuickGrid::setColumns(const int columns)
947 {
948     if (columns == m_columns)
949         return;
950     m_columns = columns;
951     prePositioning();
952     emit columnsChanged();
953 }
954
955 void QQuickGrid::setRows(const int rows)
956 {
957     if (rows == m_rows)
958         return;
959     m_rows = rows;
960     prePositioning();
961     emit rowsChanged();
962 }
963
964 /*!
965     \qmlproperty enumeration QtQuick2::Grid::flow
966     This property holds the flow of the layout.
967
968     Possible values are:
969
970     \list
971     \o Grid.LeftToRight (default) - Items are positioned next to
972        each other in the \l layoutDirection, then wrapped to the next line.
973     \o Grid.TopToBottom - Items are positioned next to each
974        other from top to bottom, then wrapped to the next column.
975     \endlist
976 */
977 QQuickGrid::Flow QQuickGrid::flow() const
978 {
979     return m_flow;
980 }
981
982 void QQuickGrid::setFlow(Flow flow)
983 {
984     if (m_flow != flow) {
985         m_flow = flow;
986         prePositioning();
987         emit flowChanged();
988     }
989 }
990
991 /*!
992     \qmlproperty int QtQuick2::Grid::rowSpacing
993
994     This property holds the spacing in pixels between rows.
995
996     \sa columnSpacing
997     \since QtQuick2.0
998 */
999 void QQuickGrid::setRowSpacing(const int rowSpacing)
1000 {
1001     if (rowSpacing == m_rowSpacing)
1002         return;
1003     m_rowSpacing = rowSpacing;
1004     prePositioning();
1005     emit rowSpacingChanged();
1006 }
1007
1008 /*!
1009     \qmlproperty int QtQuick2::Grid::columnSpacing
1010
1011     This property holds the spacing in pixels between columns.
1012
1013     \sa rowSpacing
1014     \since QtQuick2.0
1015 */
1016 void QQuickGrid::setColumnSpacing(const int columnSpacing)
1017 {
1018     if (columnSpacing == m_columnSpacing)
1019         return;
1020     m_columnSpacing = columnSpacing;
1021     prePositioning();
1022     emit columnSpacingChanged();
1023 }
1024
1025 /*!
1026     \qmlproperty enumeration QtQuick2::Grid::layoutDirection
1027
1028     This property holds the layout direction of the layout.
1029
1030     Possible values are:
1031
1032     \list
1033     \o Qt.LeftToRight (default) - Items are positioned from the top to bottom,
1034     and left to right. The flow direction is dependent on the
1035     \l Grid::flow property.
1036     \o Qt.RightToLeft - Items are positioned from the top to bottom,
1037     and right to left. The flow direction is dependent on the
1038     \l Grid::flow property.
1039     \endlist
1040
1041     \sa Flow::layoutDirection, Row::layoutDirection, {declarative/righttoleft/layoutdirection}{Layout directions example}
1042 */
1043 Qt::LayoutDirection QQuickGrid::layoutDirection() const
1044 {
1045     return QQuickBasePositionerPrivate::getLayoutDirection(this);
1046 }
1047
1048 void QQuickGrid::setLayoutDirection(Qt::LayoutDirection layoutDirection)
1049 {
1050     QQuickBasePositionerPrivate *d = static_cast<QQuickBasePositionerPrivate*>(QQuickBasePositionerPrivate::get(this));
1051     if (d->layoutDirection != layoutDirection) {
1052         d->layoutDirection = layoutDirection;
1053         // For RTL layout the positioning changes when the width changes.
1054         if (d->layoutDirection == Qt::RightToLeft)
1055             d->addItemChangeListener(d, QQuickItemPrivate::Geometry);
1056         else
1057             d->removeItemChangeListener(d, QQuickItemPrivate::Geometry);
1058         prePositioning();
1059         emit layoutDirectionChanged();
1060         emit effectiveLayoutDirectionChanged();
1061     }
1062 }
1063
1064 /*!
1065     \qmlproperty enumeration QtQuick2::Grid::effectiveLayoutDirection
1066     This property holds the effective layout direction of the grid positioner.
1067
1068     When using the attached property \l {LayoutMirroring::enabled}{LayoutMirroring::enabled} for locale layouts,
1069     the visual layout direction of the grid positioner will be mirrored. However, the
1070     property \l {Grid::layoutDirection}{layoutDirection} will remain unchanged.
1071
1072     \sa Grid::layoutDirection, {LayoutMirroring}{LayoutMirroring}
1073 */
1074 Qt::LayoutDirection QQuickGrid::effectiveLayoutDirection() const
1075 {
1076     return QQuickBasePositionerPrivate::getEffectiveLayoutDirection(this);
1077 }
1078
1079 void QQuickGrid::doPositioning(QSizeF *contentSize)
1080 {
1081     QQuickBasePositionerPrivate *d = static_cast<QQuickBasePositionerPrivate*>(QQuickBasePositionerPrivate::get(this));
1082     int c = m_columns;
1083     int r = m_rows;
1084     //Is allocating the extra QPODVector too much overhead?
1085     QPODVector<PositionedItem, 8> visibleItems;//we aren't concerned with invisible items
1086     visibleItems.reserve(positionedItems.count());
1087     for (int i=0; i<positionedItems.count(); i++)
1088         if (positionedItems[i].item && positionedItems[i].isVisible)
1089             visibleItems.append(positionedItems[i]);
1090
1091     int numVisible = visibleItems.count();
1092     if (m_columns <= 0 && m_rows <= 0){
1093         c = 4;
1094         r = (numVisible+3)/4;
1095     } else if (m_rows <= 0){
1096         r = (numVisible+(m_columns-1))/m_columns;
1097     } else if (m_columns <= 0){
1098         c = (numVisible+(m_rows-1))/m_rows;
1099     }
1100
1101     if (r==0 || c==0)
1102         return; //Nothing to do
1103
1104     QList<int> maxColWidth;
1105     QList<int> maxRowHeight;
1106     int childIndex =0;
1107     if (m_flow == LeftToRight) {
1108         for (int i=0; i < r; i++){
1109             for (int j=0; j < c; j++){
1110                 if (j==0)
1111                     maxRowHeight << 0;
1112                 if (i==0)
1113                     maxColWidth << 0;
1114
1115                 if (childIndex == visibleItems.count())
1116                     break;
1117
1118                 const PositionedItem &child = visibleItems.at(childIndex++);
1119                 if (child.item->width() > maxColWidth[j])
1120                     maxColWidth[j] = child.item->width();
1121                 if (child.item->height() > maxRowHeight[i])
1122                     maxRowHeight[i] = child.item->height();
1123             }
1124         }
1125     } else {
1126         for (int j=0; j < c; j++){
1127             for (int i=0; i < r; i++){
1128                 if (j==0)
1129                     maxRowHeight << 0;
1130                 if (i==0)
1131                     maxColWidth << 0;
1132
1133                 if (childIndex == visibleItems.count())
1134                     break;
1135
1136                 const PositionedItem &child = visibleItems.at(childIndex++);
1137                 if (child.item->width() > maxColWidth[j])
1138                     maxColWidth[j] = child.item->width();
1139                 if (child.item->height() > maxRowHeight[i])
1140                     maxRowHeight[i] = child.item->height();
1141             }
1142         }
1143     }
1144
1145     int columnSpacing = m_columnSpacing;
1146     if (columnSpacing == -1)
1147         columnSpacing = spacing();
1148
1149     int rowSpacing = m_rowSpacing;
1150     if (rowSpacing == -1)
1151         rowSpacing = spacing();
1152
1153     int widthSum = 0;
1154     for (int j=0; j < maxColWidth.size(); j++){
1155         if (j)
1156             widthSum += columnSpacing;
1157         widthSum += maxColWidth[j];
1158     }
1159
1160     int heightSum = 0;
1161     for (int i=0; i < maxRowHeight.size(); i++){
1162         if (i)
1163             heightSum += rowSpacing;
1164         heightSum += maxRowHeight[i];
1165     }
1166
1167     contentSize->setHeight(heightSum);
1168     contentSize->setWidth(widthSum);
1169
1170     int end = 0;
1171     if (widthValid())
1172         end = width();
1173     else
1174         end = widthSum;
1175
1176     int xoffset=0;
1177     if (!d->isLeftToRight())
1178         xoffset = end;
1179     int yoffset=0;
1180     int curRow =0;
1181     int curCol =0;
1182     for (int i = 0; i < visibleItems.count(); ++i) {
1183         const PositionedItem &child = visibleItems.at(i);
1184         int childXOffset = xoffset;
1185         if (!d->isLeftToRight())
1186             childXOffset -= child.item->width();
1187         if ((child.item->x() != childXOffset) || (child.item->y() != yoffset)){
1188             positionX(childXOffset, child);
1189             positionY(yoffset, child);
1190         }
1191
1192         if (m_flow == LeftToRight) {
1193             if (d->isLeftToRight())
1194                 xoffset += maxColWidth[curCol]+columnSpacing;
1195             else
1196                 xoffset -= maxColWidth[curCol]+columnSpacing;
1197             curCol++;
1198             curCol%=c;
1199             if (!curCol){
1200                 yoffset += maxRowHeight[curRow]+rowSpacing;
1201                 if (d->isLeftToRight())
1202                     xoffset = 0;
1203                 else
1204                     xoffset = end;
1205                 curRow++;
1206                 if (curRow>=r)
1207                     break;
1208             }
1209         } else {
1210             yoffset+=maxRowHeight[curRow]+rowSpacing;
1211             curRow++;
1212             curRow%=r;
1213             if (!curRow){
1214                 if (d->isLeftToRight())
1215                     xoffset += maxColWidth[curCol]+columnSpacing;
1216                 else
1217                     xoffset -= maxColWidth[curCol]+columnSpacing;
1218                 yoffset=0;
1219                 curCol++;
1220                 if (curCol>=c)
1221                     break;
1222             }
1223         }
1224     }
1225 }
1226
1227 void QQuickGrid::reportConflictingAnchors()
1228 {
1229     QQuickBasePositionerPrivate *d = static_cast<QQuickBasePositionerPrivate*>(QQuickBasePositionerPrivate::get(this));
1230     for (int ii = 0; ii < positionedItems.count(); ++ii) {
1231         const PositionedItem &child = positionedItems.at(ii);
1232         if (child.item) {
1233             QQuickAnchors *anchors = QQuickItemPrivate::get(static_cast<QQuickItem *>(child.item))->_anchors;
1234             if (anchors && (anchors->usedAnchors() || anchors->fill() || anchors->centerIn())) {
1235                 d->anchorConflict = true;
1236                 break;
1237             }
1238         }
1239     }
1240     if (d->anchorConflict)
1241         qmlInfo(this) << "Cannot specify anchors for items inside Grid." << " Grid will not function.";
1242 }
1243
1244 /*!
1245   \qmlclass Flow QQuickFlow
1246     \inqmlmodule QtQuick 2
1247   \ingroup qml-positioning-elements
1248   \brief The Flow item arranges its children side by side, wrapping as necessary.
1249   \inherits Item
1250
1251   The Flow item positions its child items like words on a page, wrapping them
1252   to create rows or columns of items that do not overlap.
1253
1254   Spacing between items can be added using the \l spacing property.
1255   Transitions can be used for cases where items managed by a Column are
1256   added or moved. These are stored in the \l add and \l move properties
1257   respectively.
1258
1259   See \l{Using QML Positioner and Repeater Items} for more details about this item and other
1260   related items.
1261
1262   \section1 Example Usage
1263
1264   The following example positions \l Text items within a parent item using
1265   a Flow item.
1266
1267   \image qml-flow-snippet.png
1268
1269   \snippet doc/src/snippets/declarative/flow.qml flow item
1270
1271   \section1 Using Transitions
1272
1273   Transitions can be used to animate items that are added to, moved within,
1274   or removed from a Flow item. The \l add and \l move properties can be set to
1275   the transitions that will be applied when items are added to, removed from,
1276   or re-positioned within a Flow item.
1277
1278   The use of transitions with positioners is described in more detail in the
1279   \l{Using QML Positioner and Repeater Items#Using Transitions}{Using QML
1280   Positioner and Repeater Items} document.
1281
1282   \section1 Limitations
1283
1284   Note that the positioner assumes that the x and y positions of its children
1285   will not change. If you manually change the x or y properties in script, bind
1286   the x or y properties, use anchors on a child of a positioner, or have the
1287   width or height of a child depend on the position of a child, then the
1288   positioner may exhibit strange behavior.  If you need to perform any of these
1289   actions, consider positioning the items without the use of a Flow.
1290
1291   Items with a width or height of 0 will not be positioned.
1292
1293   Positioning is batched and syncronized with painting to reduce the number of
1294   calculations needed. This means that positioners may not reposition items immediately
1295   when changes occur, but it will have moved by the next frame.
1296
1297   \sa Column, Row, Grid, Positioner, {declarative/positioners}{Positioners example}
1298 */
1299 /*!
1300     \qmlproperty Transition QtQuick2::Flow::add
1301
1302     This property holds the transition to be applied when adding an
1303     item to the positioner. The transition will only be applied to the
1304     added item(s).  Positioner transitions will only affect the
1305     position (x, y) of items.
1306
1307     For a positioner, adding an item can mean that either the object
1308     has been created or reparented, and thus is now a child or the
1309     positioner, or that the object has had its opacity increased from
1310     zero, and thus is now visible.
1311
1312     \sa move
1313 */
1314 /*!
1315     \qmlproperty Transition QtQuick2::Flow::move
1316
1317     This property holds the transition to be applied when moving an
1318     item within the positioner. Positioner transitions will only affect
1319     the position (x, y) of items.
1320
1321     This transition can be performed when other items are added or removed
1322     from the positioner, or when items resize themselves.
1323
1324     \qml
1325     Flow {
1326         id: positioner
1327         move: Transition {
1328             NumberAnimation {
1329                 properties: "x,y"
1330                 ease: "easeOutBounce"
1331             }
1332         }
1333     }
1334     \endqml
1335
1336     \sa add, {declarative/positioners}{Positioners example}
1337 */
1338 /*!
1339   \qmlproperty int QtQuick2::Flow::spacing
1340
1341   spacing is the amount in pixels left empty between each adjacent
1342   item, and defaults to 0.
1343
1344   \sa Grid::spacing
1345 */
1346
1347 class QQuickFlowPrivate : public QQuickBasePositionerPrivate
1348 {
1349     Q_DECLARE_PUBLIC(QQuickFlow)
1350
1351 public:
1352     QQuickFlowPrivate()
1353         : QQuickBasePositionerPrivate(), flow(QQuickFlow::LeftToRight)
1354     {}
1355
1356     QQuickFlow::Flow flow;
1357 };
1358
1359 QQuickFlow::QQuickFlow(QQuickItem *parent)
1360 : QQuickBasePositioner(*(new QQuickFlowPrivate), Both, parent)
1361 {
1362     Q_D(QQuickFlow);
1363     // Flow layout requires relayout if its own size changes too.
1364     d->addItemChangeListener(d, QQuickItemPrivate::Geometry);
1365 }
1366
1367 /*!
1368     \qmlproperty enumeration QtQuick2::Flow::flow
1369     This property holds the flow of the layout.
1370
1371     Possible values are:
1372
1373     \list
1374     \o Flow.LeftToRight (default) - Items are positioned next to
1375     to each other according to the \l layoutDirection until the width of the Flow
1376     is exceeded, then wrapped to the next line.
1377     \o Flow.TopToBottom - Items are positioned next to each
1378     other from top to bottom until the height of the Flow is exceeded,
1379     then wrapped to the next column.
1380     \endlist
1381 */
1382 QQuickFlow::Flow QQuickFlow::flow() const
1383 {
1384     Q_D(const QQuickFlow);
1385     return d->flow;
1386 }
1387
1388 void QQuickFlow::setFlow(Flow flow)
1389 {
1390     Q_D(QQuickFlow);
1391     if (d->flow != flow) {
1392         d->flow = flow;
1393         prePositioning();
1394         emit flowChanged();
1395     }
1396 }
1397
1398 /*!
1399     \qmlproperty enumeration QtQuick2::Flow::layoutDirection
1400
1401     This property holds the layout direction of the layout.
1402
1403     Possible values are:
1404
1405     \list
1406     \o Qt.LeftToRight (default) - Items are positioned from the top to bottom,
1407     and left to right. The flow direction is dependent on the
1408     \l Flow::flow property.
1409     \o Qt.RightToLeft - Items are positioned from the top to bottom,
1410     and right to left. The flow direction is dependent on the
1411     \l Flow::flow property.
1412     \endlist
1413
1414     \sa Grid::layoutDirection, Row::layoutDirection, {declarative/righttoleft/layoutdirection}{Layout directions example}
1415 */
1416
1417 Qt::LayoutDirection QQuickFlow::layoutDirection() const
1418 {
1419     Q_D(const QQuickFlow);
1420     return d->layoutDirection;
1421 }
1422
1423 void QQuickFlow::setLayoutDirection(Qt::LayoutDirection layoutDirection)
1424 {
1425     Q_D(QQuickFlow);
1426     if (d->layoutDirection != layoutDirection) {
1427         d->layoutDirection = layoutDirection;
1428         prePositioning();
1429         emit layoutDirectionChanged();
1430         emit effectiveLayoutDirectionChanged();
1431     }
1432 }
1433
1434 /*!
1435     \qmlproperty enumeration QtQuick2::Flow::effectiveLayoutDirection
1436     This property holds the effective layout direction of the flow positioner.
1437
1438     When using the attached property \l {LayoutMirroring::enabled}{LayoutMirroring::enabled} for locale layouts,
1439     the visual layout direction of the grid positioner will be mirrored. However, the
1440     property \l {Flow::layoutDirection}{layoutDirection} will remain unchanged.
1441
1442     \sa Flow::layoutDirection, {LayoutMirroring}{LayoutMirroring}
1443 */
1444
1445 Qt::LayoutDirection QQuickFlow::effectiveLayoutDirection() const
1446 {
1447     return QQuickBasePositionerPrivate::getEffectiveLayoutDirection(this);
1448 }
1449
1450 void QQuickFlow::doPositioning(QSizeF *contentSize)
1451 {
1452     Q_D(QQuickFlow);
1453
1454     int hoffset = 0;
1455     int voffset = 0;
1456     int linemax = 0;
1457     QList<int> hoffsets;
1458
1459     for (int i = 0; i < positionedItems.count(); ++i) {
1460         const PositionedItem &child = positionedItems.at(i);
1461         if (!child.item || !child.isVisible)
1462             continue;
1463
1464         if (d->flow == LeftToRight)  {
1465             if (widthValid() && hoffset && hoffset + child.item->width() > width()) {
1466                 hoffset = 0;
1467                 voffset += linemax + spacing();
1468                 linemax = 0;
1469             }
1470         } else {
1471             if (heightValid() && voffset && voffset + child.item->height() > height()) {
1472                 voffset = 0;
1473                 hoffset += linemax + spacing();
1474                 linemax = 0;
1475             }
1476         }
1477
1478         if (d->isLeftToRight()) {
1479             if (child.item->x() != hoffset)
1480                 positionX(hoffset, child);
1481         } else {
1482             hoffsets << hoffset;
1483         }
1484         if (child.item->y() != voffset)
1485             positionY(voffset, child);
1486
1487         contentSize->setWidth(qMax(contentSize->width(), hoffset + child.item->width()));
1488         contentSize->setHeight(qMax(contentSize->height(), voffset + child.item->height()));
1489
1490         if (d->flow == LeftToRight)  {
1491             hoffset += child.item->width();
1492             hoffset += spacing();
1493             linemax = qMax(linemax, qCeil(child.item->height()));
1494         } else {
1495             voffset += child.item->height();
1496             voffset += spacing();
1497             linemax = qMax(linemax, qCeil(child.item->width()));
1498         }
1499     }
1500     if (d->isLeftToRight())
1501         return;
1502
1503     int end;
1504     if (widthValid())
1505         end = width();
1506     else
1507         end = contentSize->width();
1508     int acc = 0;
1509     for (int i = 0; i < positionedItems.count(); ++i) {
1510         const PositionedItem &child = positionedItems.at(i);
1511         if (!child.item || !child.isVisible)
1512             continue;
1513         hoffset = end - hoffsets[acc++] - child.item->width();
1514         if (child.item->x() != hoffset)
1515             positionX(hoffset, child);
1516     }
1517 }
1518
1519 void QQuickFlow::reportConflictingAnchors()
1520 {
1521     Q_D(QQuickFlow);
1522     for (int ii = 0; ii < positionedItems.count(); ++ii) {
1523         const PositionedItem &child = positionedItems.at(ii);
1524         if (child.item) {
1525             QQuickAnchors *anchors = QQuickItemPrivate::get(static_cast<QQuickItem *>(child.item))->_anchors;
1526             if (anchors && (anchors->usedAnchors() || anchors->fill() || anchors->centerIn())) {
1527                 d->anchorConflict = true;
1528                 break;
1529             }
1530         }
1531     }
1532     if (d->anchorConflict)
1533         qmlInfo(this) << "Cannot specify anchors for items inside Flow." << " Flow will not function.";
1534 }
1535
1536 QT_END_NAMESPACE