Initial import from qtquick2.
[profile/ivi/qtdeclarative.git] / src / declarative / items / qsgpositioners.cpp
1 // Commit: 1f38d41854fa2daa51d938a4eb398752b1751e0b
2 /****************************************************************************
3 **
4 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
5 ** All rights reserved.
6 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 **
8 ** This file is part of the QtDeclarative module of the Qt Toolkit.
9 **
10 ** $QT_BEGIN_LICENSE:LGPL$
11 ** No Commercial Usage
12 ** This file contains pre-release code and may not be distributed.
13 ** You may use this file in accordance with the terms and conditions
14 ** contained in the Technology Preview License Agreement accompanying
15 ** this package.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file.  Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Nokia gives you certain additional
26 ** rights.  These rights are described in the Nokia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** If you have questions regarding the use of this file, please contact
30 ** Nokia at qt-info@nokia.com.
31 **
32 **
33 **
34 **
35 **
36 **
37 **
38 **
39 ** $QT_END_LICENSE$
40 **
41 ****************************************************************************/
42
43 #include "qsgpositioners_p.h"
44 #include "qsgpositioners_p_p.h"
45
46 #include <QtDeclarative/qdeclarative.h>
47 #include <QtDeclarative/qdeclarativeinfo.h>
48 #include <QtCore/qmath.h>
49 #include <QtCore/qcoreapplication.h>
50
51 #include <private/qdeclarativestate_p.h>
52 #include <private/qdeclarativestategroup_p.h>
53 #include <private/qdeclarativestateoperations_p.h>
54
55 QT_BEGIN_NAMESPACE
56
57 static const QSGItemPrivate::ChangeTypes watchedChanges
58     = QSGItemPrivate::Geometry
59     | QSGItemPrivate::SiblingOrder
60     | QSGItemPrivate::Visibility
61     | QSGItemPrivate::Opacity
62     | QSGItemPrivate::Destroyed;
63
64 void QSGBasePositionerPrivate::watchChanges(QSGItem *other)
65 {
66     QSGItemPrivate *otherPrivate = QSGItemPrivate::get(other);
67     otherPrivate->addItemChangeListener(this, watchedChanges);
68 }
69
70 void QSGBasePositionerPrivate::unwatchChanges(QSGItem* other)
71 {
72     QSGItemPrivate *otherPrivate = QSGItemPrivate::get(other);
73     otherPrivate->removeItemChangeListener(this, watchedChanges);
74 }
75
76 QSGBasePositioner::QSGBasePositioner(PositionerType at, QSGItem *parent)
77     : QSGImplicitSizeItem(*(new QSGBasePositionerPrivate), parent)
78 {
79     Q_D(QSGBasePositioner);
80     d->init(at);
81 }
82
83 QSGBasePositioner::QSGBasePositioner(QSGBasePositionerPrivate &dd, PositionerType at, QSGItem *parent)
84     : QSGImplicitSizeItem(dd, parent)
85 {
86     Q_D(QSGBasePositioner);
87     d->init(at);
88 }
89
90 QSGBasePositioner::~QSGBasePositioner()
91 {
92     Q_D(QSGBasePositioner);
93     for (int i = 0; i < positionedItems.count(); ++i)
94         d->unwatchChanges(positionedItems.at(i).item);
95     positionedItems.clear();
96 }
97
98 int QSGBasePositioner::spacing() const
99 {
100     Q_D(const QSGBasePositioner);
101     return d->spacing;
102 }
103
104 void QSGBasePositioner::setSpacing(int s)
105 {
106     Q_D(QSGBasePositioner);
107     if (s==d->spacing)
108         return;
109     d->spacing = s;
110     prePositioning();
111     emit spacingChanged();
112 }
113
114 QDeclarativeTransition *QSGBasePositioner::move() const
115 {
116     Q_D(const QSGBasePositioner);
117     return d->moveTransition;
118 }
119
120 void QSGBasePositioner::setMove(QDeclarativeTransition *mt)
121 {
122     Q_D(QSGBasePositioner);
123     if (mt == d->moveTransition)
124         return;
125     d->moveTransition = mt;
126     emit moveChanged();
127 }
128
129 QDeclarativeTransition *QSGBasePositioner::add() const
130 {
131     Q_D(const QSGBasePositioner);
132     return d->addTransition;
133 }
134
135 void QSGBasePositioner::setAdd(QDeclarativeTransition *add)
136 {
137     Q_D(QSGBasePositioner);
138     if (add == d->addTransition)
139         return;
140
141     d->addTransition = add;
142     emit addChanged();
143 }
144
145 void QSGBasePositioner::componentComplete()
146 {
147     QSGItem::componentComplete();
148     positionedItems.reserve(childItems().count());
149     prePositioning();
150     reportConflictingAnchors();
151 }
152
153 void QSGBasePositioner::itemChange(ItemChange change, const ItemChangeData &value)
154 {
155     Q_D(QSGBasePositioner);
156     if (change == ItemChildAddedChange){
157         prePositioning();
158     } else if (change == ItemChildRemovedChange) {
159         QSGItem *child = value.item;
160         QSGBasePositioner::PositionedItem posItem(child);
161         int idx = positionedItems.find(posItem);
162         if (idx >= 0) {
163             d->unwatchChanges(child);
164             positionedItems.remove(idx);
165         }
166         prePositioning();
167     }
168
169     QSGItem::itemChange(change, value);
170 }
171
172 void QSGBasePositioner::prePositioning()
173 {
174     Q_D(QSGBasePositioner);
175     if (!isComponentComplete())
176         return;
177
178     if (d->doingPositioning)
179         return;
180
181     d->queuedPositioning = false;
182     d->doingPositioning = true;
183     //Need to order children by creation order modified by stacking order
184     QList<QSGItem *> children = childItems();
185
186     QPODVector<PositionedItem,8> oldItems;
187     positionedItems.copyAndClear(oldItems);
188     for (int ii = 0; ii < children.count(); ++ii) {
189         QSGItem *child = children.at(ii);
190         QSGItemPrivate *childPrivate = QSGItemPrivate::get(child);
191         PositionedItem *item = 0;
192         PositionedItem posItem(child);
193         int wIdx = oldItems.find(posItem);
194         if (wIdx < 0) {
195             d->watchChanges(child);
196             positionedItems.append(posItem);
197             item = &positionedItems[positionedItems.count()-1];
198             item->isNew = true;
199             if (child->opacity() <= 0.0 || !childPrivate->explicitVisible || !child->width() || !child->height())
200                 item->isVisible = false;
201         } else {
202             item = &oldItems[wIdx];
203             // Items are only omitted from positioning if they are explicitly hidden
204             // i.e. their positioning is not affected if an ancestor is hidden.
205             if (child->opacity() <= 0.0 || !childPrivate->explicitVisible || !child->width() || !child->height()) {
206                 item->isVisible = false;
207             } else if (!item->isVisible) {
208                 item->isVisible = true;
209                 item->isNew = true;
210             } else {
211                 item->isNew = false;
212             }
213             positionedItems.append(*item);
214         }
215     }
216     QSizeF contentSize;
217     doPositioning(&contentSize);
218     if(d->addTransition || d->moveTransition)
219         finishApplyTransitions();
220     d->doingPositioning = false;
221     //Set implicit size to the size of its children
222     setImplicitHeight(contentSize.height());
223     setImplicitWidth(contentSize.width());
224 }
225
226 void QSGBasePositioner::positionX(int x, const PositionedItem &target)
227 {
228     Q_D(QSGBasePositioner);
229     if(d->type == Horizontal || d->type == Both){
230         if (target.isNew) {
231             if (!d->addTransition)
232                 target.item->setX(x);
233             else
234                 d->addActions << QDeclarativeAction(target.item, QLatin1String("x"), QVariant(x));
235         } else if (x != target.item->x()) {
236             if (!d->moveTransition)
237                 target.item->setX(x);
238             else
239                 d->moveActions << QDeclarativeAction(target.item, QLatin1String("x"), QVariant(x));
240         }
241     }
242 }
243
244 void QSGBasePositioner::positionY(int y, const PositionedItem &target)
245 {
246     Q_D(QSGBasePositioner);
247     if(d->type == Vertical || d->type == Both){
248         if (target.isNew) {
249             if (!d->addTransition)
250                 target.item->setY(y);
251             else
252                 d->addActions << QDeclarativeAction(target.item, QLatin1String("y"), QVariant(y));
253         } else if (y != target.item->y()) {
254             if (!d->moveTransition)
255                 target.item->setY(y);
256             else
257                 d->moveActions << QDeclarativeAction(target.item, QLatin1String("y"), QVariant(y));
258         }
259     }
260 }
261
262 void QSGBasePositioner::finishApplyTransitions()
263 {
264     Q_D(QSGBasePositioner);
265     // Note that if a transition is not set the transition manager will
266     // apply the changes directly, in the case add/move aren't set
267     d->addTransitionManager.transition(d->addActions, d->addTransition);
268     d->moveTransitionManager.transition(d->moveActions, d->moveTransition);
269     d->addActions.clear();
270     d->moveActions.clear();
271 }
272
273 QSGColumn::QSGColumn(QSGItem *parent)
274 : QSGBasePositioner(Vertical, parent)
275 {
276 }
277
278 void QSGColumn::doPositioning(QSizeF *contentSize)
279 {
280     int voffset = 0;
281
282     for (int ii = 0; ii < positionedItems.count(); ++ii) {
283         const PositionedItem &child = positionedItems.at(ii);
284         if (!child.item || !child.isVisible)
285             continue;
286
287         if(child.item->y() != voffset)
288             positionY(voffset, child);
289
290         contentSize->setWidth(qMax(contentSize->width(), child.item->width()));
291
292         voffset += child.item->height();
293         voffset += spacing();
294     }
295
296     contentSize->setHeight(voffset - spacing());
297 }
298
299 void QSGColumn::reportConflictingAnchors()
300 {
301     QSGBasePositionerPrivate *d = static_cast<QSGBasePositionerPrivate*>(QSGBasePositionerPrivate::get(this));
302     for (int ii = 0; ii < positionedItems.count(); ++ii) {
303         const PositionedItem &child = positionedItems.at(ii);
304         if (child.item) {
305             QSGAnchors *anchors = QSGItemPrivate::get(static_cast<QSGItem *>(child.item))->_anchors;
306             if (anchors) {
307                 QSGAnchors::Anchors usedAnchors = anchors->usedAnchors();
308                 if (usedAnchors & QSGAnchors::TopAnchor ||
309                     usedAnchors & QSGAnchors::BottomAnchor ||
310                     usedAnchors & QSGAnchors::VCenterAnchor ||
311                     anchors->fill() || anchors->centerIn()) {
312                     d->anchorConflict = true;
313                     break;
314                 }
315             }
316         }
317     }
318     if (d->anchorConflict) {
319         qmlInfo(this) << "Cannot specify top, bottom, verticalCenter, fill or centerIn anchors for items inside Column";
320     }
321 }
322
323 QSGRow::QSGRow(QSGItem *parent)
324 : QSGBasePositioner(Horizontal, parent)
325 {
326 }
327
328 Qt::LayoutDirection QSGRow::layoutDirection() const
329 {
330     return QSGBasePositionerPrivate::getLayoutDirection(this);
331 }
332
333 void QSGRow::setLayoutDirection(Qt::LayoutDirection layoutDirection)
334 {
335     QSGBasePositionerPrivate *d = static_cast<QSGBasePositionerPrivate* >(QSGBasePositionerPrivate::get(this));
336     if (d->layoutDirection != layoutDirection) {
337         d->layoutDirection = layoutDirection;
338         // For RTL layout the positioning changes when the width changes.
339         if (d->layoutDirection == Qt::RightToLeft)
340             d->addItemChangeListener(d, QSGItemPrivate::Geometry);
341         else
342             d->removeItemChangeListener(d, QSGItemPrivate::Geometry);
343         prePositioning();
344         emit layoutDirectionChanged();
345         emit effectiveLayoutDirectionChanged();
346     }
347 }
348
349 Qt::LayoutDirection QSGRow::effectiveLayoutDirection() const
350 {
351     return QSGBasePositionerPrivate::getEffectiveLayoutDirection(this);
352 }
353
354 void QSGRow::doPositioning(QSizeF *contentSize)
355 {
356     QSGBasePositionerPrivate *d = static_cast<QSGBasePositionerPrivate* >(QSGBasePositionerPrivate::get(this));
357     int hoffset = 0;
358
359     QList<int> hoffsets;
360     for (int ii = 0; ii < positionedItems.count(); ++ii) {
361         const PositionedItem &child = positionedItems.at(ii);
362         if (!child.item || !child.isVisible)
363             continue;
364
365         if (d->isLeftToRight()) {
366             if (child.item->x() != hoffset)
367                 positionX(hoffset, child);
368         } else {
369             hoffsets << hoffset;
370         }
371
372         contentSize->setHeight(qMax(contentSize->height(), child.item->height()));
373
374         hoffset += child.item->width();
375         hoffset += spacing();
376     }
377
378     contentSize->setWidth(hoffset - spacing());
379
380     if (d->isLeftToRight())
381         return;
382
383     //Right to Left layout
384     int end = 0;
385     if (!widthValid())
386         end = contentSize->width();
387     else
388         end = width();
389
390     int acc = 0;
391     for (int ii = 0; ii < positionedItems.count(); ++ii) {
392         const PositionedItem &child = positionedItems.at(ii);
393         if (!child.item || !child.isVisible)
394             continue;
395         hoffset = end - hoffsets[acc++] - child.item->width();
396         if (child.item->x() != hoffset)
397             positionX(hoffset, child);
398     }
399 }
400
401 void QSGRow::reportConflictingAnchors()
402 {
403     QSGBasePositionerPrivate *d = static_cast<QSGBasePositionerPrivate*>(QSGBasePositionerPrivate::get(this));
404     for (int ii = 0; ii < positionedItems.count(); ++ii) {
405         const PositionedItem &child = positionedItems.at(ii);
406         if (child.item) {
407             QSGAnchors *anchors = QSGItemPrivate::get(static_cast<QSGItem *>(child.item))->_anchors;
408             if (anchors) {
409                 QSGAnchors::Anchors usedAnchors = anchors->usedAnchors();
410                 if (usedAnchors & QSGAnchors::LeftAnchor ||
411                     usedAnchors & QSGAnchors::RightAnchor ||
412                     usedAnchors & QSGAnchors::HCenterAnchor ||
413                     anchors->fill() || anchors->centerIn()) {
414                     d->anchorConflict = true;
415                     break;
416                 }
417             }
418         }
419     }
420     if (d->anchorConflict)
421         qmlInfo(this) << "Cannot specify left, right, horizontalCenter, fill or centerIn anchors for items inside Row";
422 }
423
424 QSGGrid::QSGGrid(QSGItem *parent) :
425     QSGBasePositioner(Both, parent), m_rows(-1), m_columns(-1), m_flow(LeftToRight)
426 {
427 }
428
429 void QSGGrid::setColumns(const int columns)
430 {
431     if (columns == m_columns)
432         return;
433     m_columns = columns;
434     prePositioning();
435     emit columnsChanged();
436 }
437
438 void QSGGrid::setRows(const int rows)
439 {
440     if (rows == m_rows)
441         return;
442     m_rows = rows;
443     prePositioning();
444     emit rowsChanged();
445 }
446
447 QSGGrid::Flow QSGGrid::flow() const
448 {
449     return m_flow;
450 }
451
452 void QSGGrid::setFlow(Flow flow)
453 {
454     if (m_flow != flow) {
455         m_flow = flow;
456         prePositioning();
457         emit flowChanged();
458     }
459 }
460
461 Qt::LayoutDirection QSGGrid::layoutDirection() const
462 {
463     return QSGBasePositionerPrivate::getLayoutDirection(this);
464 }
465
466 void QSGGrid::setLayoutDirection(Qt::LayoutDirection layoutDirection)
467 {
468     QSGBasePositionerPrivate *d = static_cast<QSGBasePositionerPrivate*>(QSGBasePositionerPrivate::get(this));
469     if (d->layoutDirection != layoutDirection) {
470         d->layoutDirection = layoutDirection;
471         // For RTL layout the positioning changes when the width changes.
472         if (d->layoutDirection == Qt::RightToLeft)
473             d->addItemChangeListener(d, QSGItemPrivate::Geometry);
474         else
475             d->removeItemChangeListener(d, QSGItemPrivate::Geometry);
476         prePositioning();
477         emit layoutDirectionChanged();
478         emit effectiveLayoutDirectionChanged();
479     }
480 }
481
482 Qt::LayoutDirection QSGGrid::effectiveLayoutDirection() const
483 {
484     return QSGBasePositionerPrivate::getEffectiveLayoutDirection(this);
485 }
486
487 void QSGGrid::doPositioning(QSizeF *contentSize)
488 {
489     QSGBasePositionerPrivate *d = static_cast<QSGBasePositionerPrivate*>(QSGBasePositionerPrivate::get(this));
490     int c = m_columns;
491     int r = m_rows;
492     //Is allocating the extra QPODVector too much overhead?
493     QPODVector<PositionedItem, 8> visibleItems;//we aren't concerned with invisible items
494     visibleItems.reserve(positionedItems.count());
495     for(int i=0; i<positionedItems.count(); i++)
496         if(positionedItems[i].item && positionedItems[i].isVisible)
497             visibleItems.append(positionedItems[i]);
498
499     int numVisible = visibleItems.count();
500     if (m_columns <= 0 && m_rows <= 0){
501         c = 4;
502         r = (numVisible+3)/4;
503     } else if (m_rows <= 0){
504         r = (numVisible+(m_columns-1))/m_columns;
505     } else if (m_columns <= 0){
506         c = (numVisible+(m_rows-1))/m_rows;
507     }
508
509     if(r==0 || c==0)
510         return; //Nothing to do
511
512     QList<int> maxColWidth;
513     QList<int> maxRowHeight;
514     int childIndex =0;
515     if (m_flow == LeftToRight) {
516         for (int i=0; i < r; i++){
517             for (int j=0; j < c; j++){
518                 if (j==0)
519                     maxRowHeight << 0;
520                 if (i==0)
521                     maxColWidth << 0;
522
523                 if (childIndex == visibleItems.count())
524                     break;
525
526                 const PositionedItem &child = visibleItems.at(childIndex++);
527                 if (child.item->width() > maxColWidth[j])
528                     maxColWidth[j] = child.item->width();
529                 if (child.item->height() > maxRowHeight[i])
530                     maxRowHeight[i] = child.item->height();
531             }
532         }
533     } else {
534         for (int j=0; j < c; j++){
535             for (int i=0; i < r; i++){
536                 if (j==0)
537                     maxRowHeight << 0;
538                 if (i==0)
539                     maxColWidth << 0;
540
541                 if (childIndex == visibleItems.count())
542                     break;
543
544                 const PositionedItem &child = visibleItems.at(childIndex++);
545                 if (child.item->width() > maxColWidth[j])
546                     maxColWidth[j] = child.item->width();
547                 if (child.item->height() > maxRowHeight[i])
548                     maxRowHeight[i] = child.item->height();
549             }
550         }
551     }
552
553     int widthSum = 0;
554     for (int j=0; j < maxColWidth.size(); j++){
555         if (j)
556             widthSum += spacing();
557         widthSum += maxColWidth[j];
558     }
559
560     int heightSum = 0;
561     for (int i=0; i < maxRowHeight.size(); i++){
562         if (i)
563             heightSum += spacing();
564         heightSum += maxRowHeight[i];
565     }
566
567     contentSize->setHeight(heightSum);
568     contentSize->setWidth(widthSum);
569
570     int end = 0;
571     if (widthValid())
572         end = width();
573     else
574         end = widthSum;
575
576     int xoffset=0;
577     if (!d->isLeftToRight())
578         xoffset = end;
579     int yoffset=0;
580     int curRow =0;
581     int curCol =0;
582     for (int i = 0; i < visibleItems.count(); ++i) {
583         const PositionedItem &child = visibleItems.at(i);
584         int childXOffset = xoffset;
585         if (!d->isLeftToRight())
586             childXOffset -= child.item->width();
587         if ((child.item->x() != childXOffset) || (child.item->y() != yoffset)){
588             positionX(childXOffset, child);
589             positionY(yoffset, child);
590         }
591
592         if (m_flow == LeftToRight) {
593             if (d->isLeftToRight())
594                 xoffset += maxColWidth[curCol]+spacing();
595             else
596                 xoffset -= maxColWidth[curCol]+spacing();
597             curCol++;
598             curCol%=c;
599             if (!curCol){
600                 yoffset += maxRowHeight[curRow]+spacing();
601                 if (d->isLeftToRight())
602                     xoffset = 0;
603                 else
604                     xoffset = end;
605                 curRow++;
606                 if (curRow>=r)
607                     break;
608             }
609         } else {
610             yoffset+=maxRowHeight[curRow]+spacing();
611             curRow++;
612             curRow%=r;
613             if (!curRow){
614                 if (d->isLeftToRight())
615                     xoffset += maxColWidth[curCol]+spacing();
616                 else
617                     xoffset -= maxColWidth[curCol]+spacing();
618                 yoffset=0;
619                 curCol++;
620                 if (curCol>=c)
621                     break;
622             }
623         }
624     }
625 }
626
627 void QSGGrid::reportConflictingAnchors()
628 {
629     QSGBasePositionerPrivate *d = static_cast<QSGBasePositionerPrivate*>(QSGBasePositionerPrivate::get(this));
630     for (int ii = 0; ii < positionedItems.count(); ++ii) {
631         const PositionedItem &child = positionedItems.at(ii);
632         if (child.item) {
633             QSGAnchors *anchors = QSGItemPrivate::get(static_cast<QSGItem *>(child.item))->_anchors;
634             if (anchors && (anchors->usedAnchors() || anchors->fill() || anchors->centerIn())) {
635                 d->anchorConflict = true;
636                 break;
637             }
638         }
639     }
640     if (d->anchorConflict)
641         qmlInfo(this) << "Cannot specify anchors for items inside Grid";
642 }
643
644 class QSGFlowPrivate : public QSGBasePositionerPrivate
645 {
646     Q_DECLARE_PUBLIC(QSGFlow)
647
648 public:
649     QSGFlowPrivate()
650         : QSGBasePositionerPrivate(), flow(QSGFlow::LeftToRight)
651     {}
652
653     QSGFlow::Flow flow;
654 };
655
656 QSGFlow::QSGFlow(QSGItem *parent)
657 : QSGBasePositioner(*(new QSGFlowPrivate), Both, parent)
658 {
659     Q_D(QSGFlow);
660     // Flow layout requires relayout if its own size changes too.
661     d->addItemChangeListener(d, QSGItemPrivate::Geometry);
662 }
663
664 QSGFlow::Flow QSGFlow::flow() const
665 {
666     Q_D(const QSGFlow);
667     return d->flow;
668 }
669
670 void QSGFlow::setFlow(Flow flow)
671 {
672     Q_D(QSGFlow);
673     if (d->flow != flow) {
674         d->flow = flow;
675         prePositioning();
676         emit flowChanged();
677     }
678 }
679
680 Qt::LayoutDirection QSGFlow::layoutDirection() const
681 {
682     Q_D(const QSGFlow);
683     return d->layoutDirection;
684 }
685
686 void QSGFlow::setLayoutDirection(Qt::LayoutDirection layoutDirection)
687 {
688     Q_D(QSGFlow);
689     if (d->layoutDirection != layoutDirection) {
690         d->layoutDirection = layoutDirection;
691         prePositioning();
692         emit layoutDirectionChanged();
693         emit effectiveLayoutDirectionChanged();
694     }
695 }
696
697 Qt::LayoutDirection QSGFlow::effectiveLayoutDirection() const
698 {
699     return QSGBasePositionerPrivate::getEffectiveLayoutDirection(this);
700 }
701
702 void QSGFlow::doPositioning(QSizeF *contentSize)
703 {
704     Q_D(QSGFlow);
705
706     int hoffset = 0;
707     int voffset = 0;
708     int linemax = 0;
709     QList<int> hoffsets;
710
711     for (int i = 0; i < positionedItems.count(); ++i) {
712         const PositionedItem &child = positionedItems.at(i);
713         if (!child.item || !child.isVisible)
714             continue;
715
716         if (d->flow == LeftToRight)  {
717             if (widthValid() && hoffset && hoffset + child.item->width() > width()) {
718                 hoffset = 0;
719                 voffset += linemax + spacing();
720                 linemax = 0;
721             }
722         } else {
723             if (heightValid() && voffset && voffset + child.item->height() > height()) {
724                 voffset = 0;
725                 hoffset += linemax + spacing();
726                 linemax = 0;
727             }
728         }
729
730         if (d->isLeftToRight()) {
731             if (child.item->x() != hoffset)
732                 positionX(hoffset, child);
733         } else {
734             hoffsets << hoffset;
735         }
736         if (child.item->y() != voffset)
737             positionY(voffset, child);
738
739         contentSize->setWidth(qMax(contentSize->width(), hoffset + child.item->width()));
740         contentSize->setHeight(qMax(contentSize->height(), voffset + child.item->height()));
741
742         if (d->flow == LeftToRight)  {
743             hoffset += child.item->width();
744             hoffset += spacing();
745             linemax = qMax(linemax, qCeil(child.item->height()));
746         } else {
747             voffset += child.item->height();
748             voffset += spacing();
749             linemax = qMax(linemax, qCeil(child.item->width()));
750         }
751     }
752     if (d->isLeftToRight())
753         return;
754
755     int end;
756     if (widthValid())
757         end = width();
758     else
759         end = contentSize->width();
760     int acc = 0;
761     for (int i = 0; i < positionedItems.count(); ++i) {
762         const PositionedItem &child = positionedItems.at(i);
763         if (!child.item || !child.isVisible)
764             continue;
765         hoffset = end - hoffsets[acc++] - child.item->width();
766         if (child.item->x() != hoffset)
767             positionX(hoffset, child);
768     }
769 }
770
771 void QSGFlow::reportConflictingAnchors()
772 {
773     Q_D(QSGFlow);
774     for (int ii = 0; ii < positionedItems.count(); ++ii) {
775         const PositionedItem &child = positionedItems.at(ii);
776         if (child.item) {
777             QSGAnchors *anchors = QSGItemPrivate::get(static_cast<QSGItem *>(child.item))->_anchors;
778             if (anchors && (anchors->usedAnchors() || anchors->fill() || anchors->centerIn())) {
779                 d->anchorConflict = true;
780                 break;
781             }
782         }
783     }
784     if (d->anchorConflict)
785         qmlInfo(this) << "Cannot specify anchors for items inside Flow";
786 }
787
788 QT_END_NAMESPACE