src/declarative/graphicsitems/qdeclarativepositioners.cpp
changeset 30 5dc02b23752f
child 33 3e2da88830cd
equal deleted inserted replaced
29:b72c6db6890b 30:5dc02b23752f
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include "private/qdeclarativepositioners_p.h"
       
    43 #include "private/qdeclarativepositioners_p_p.h"
       
    44 
       
    45 #include <qdeclarative.h>
       
    46 #include <qdeclarativestate_p.h>
       
    47 #include <qdeclarativestategroup_p.h>
       
    48 #include <qdeclarativestateoperations_p.h>
       
    49 #include <qdeclarativeinfo.h>
       
    50 #include <QtCore/qmath.h>
       
    51 
       
    52 #include <QDebug>
       
    53 #include <QCoreApplication>
       
    54 
       
    55 QT_BEGIN_NAMESPACE
       
    56 
       
    57 static const QDeclarativeItemPrivate::ChangeTypes watchedChanges
       
    58     = QDeclarativeItemPrivate::Geometry
       
    59     | QDeclarativeItemPrivate::SiblingOrder
       
    60     | QDeclarativeItemPrivate::Visibility
       
    61     | QDeclarativeItemPrivate::Opacity
       
    62     | QDeclarativeItemPrivate::Destroyed;
       
    63 
       
    64 void QDeclarativeBasePositionerPrivate::watchChanges(QDeclarativeItem *other)
       
    65 {
       
    66     QDeclarativeItemPrivate *otherPrivate = static_cast<QDeclarativeItemPrivate*>(QGraphicsItemPrivate::get(other));
       
    67     otherPrivate->addItemChangeListener(this, watchedChanges);
       
    68 }
       
    69 
       
    70 void QDeclarativeBasePositionerPrivate::unwatchChanges(QDeclarativeItem* other)
       
    71 {
       
    72     QDeclarativeItemPrivate *otherPrivate = static_cast<QDeclarativeItemPrivate*>(QGraphicsItemPrivate::get(other));
       
    73     otherPrivate->removeItemChangeListener(this, watchedChanges);
       
    74 }
       
    75 
       
    76 /*!
       
    77     \internal
       
    78     \class QDeclarativeBasePositioner
       
    79     \brief The QDeclarativeBasePositioner class provides a base for QDeclarativeGraphics layouts.
       
    80 
       
    81     To create a QDeclarativeGraphics Positioner, simply subclass QDeclarativeBasePositioner and implement
       
    82     doLayout(), which is automatically called when the layout might need
       
    83     updating. In doLayout() use the setX and setY functions from QDeclarativeBasePositioner, and the
       
    84     base class will apply the positions along with the appropriate transitions. The items to
       
    85     position are provided in order as the protected member positionedItems.
       
    86 
       
    87     You also need to set a PositionerType, to declare whether you are positioning the x, y or both
       
    88     for the child items. Depending on the chosen type, only x or y changes will be applied.
       
    89 
       
    90     Note that the subclass is responsible for adding the
       
    91     spacing in between items.
       
    92 */
       
    93 QDeclarativeBasePositioner::QDeclarativeBasePositioner(PositionerType at, QDeclarativeItem *parent)
       
    94     : QDeclarativeItem(*(new QDeclarativeBasePositionerPrivate), parent)
       
    95 {
       
    96     Q_D(QDeclarativeBasePositioner);
       
    97     d->init(at);
       
    98 }
       
    99 
       
   100 QDeclarativeBasePositioner::QDeclarativeBasePositioner(QDeclarativeBasePositionerPrivate &dd, PositionerType at, QDeclarativeItem *parent)
       
   101     : QDeclarativeItem(dd, parent)
       
   102 {
       
   103     Q_D(QDeclarativeBasePositioner);
       
   104     d->init(at);
       
   105 }
       
   106 
       
   107 QDeclarativeBasePositioner::~QDeclarativeBasePositioner()
       
   108 {
       
   109     Q_D(QDeclarativeBasePositioner);
       
   110     for (int i = 0; i < positionedItems.count(); ++i)
       
   111         d->unwatchChanges(positionedItems.at(i).item);
       
   112     positionedItems.clear();
       
   113 }
       
   114 
       
   115 int QDeclarativeBasePositioner::spacing() const
       
   116 {
       
   117     Q_D(const QDeclarativeBasePositioner);
       
   118     return d->spacing;
       
   119 }
       
   120 
       
   121 void QDeclarativeBasePositioner::setSpacing(int s)
       
   122 {
       
   123     Q_D(QDeclarativeBasePositioner);
       
   124     if (s==d->spacing)
       
   125         return;
       
   126     d->spacing = s;
       
   127     prePositioning();
       
   128     emit spacingChanged();
       
   129 }
       
   130 
       
   131 QDeclarativeTransition *QDeclarativeBasePositioner::move() const
       
   132 {
       
   133     Q_D(const QDeclarativeBasePositioner);
       
   134     return d->moveTransition;
       
   135 }
       
   136 
       
   137 void QDeclarativeBasePositioner::setMove(QDeclarativeTransition *mt)
       
   138 {
       
   139     Q_D(QDeclarativeBasePositioner);
       
   140     if (mt == d->moveTransition)
       
   141         return;
       
   142     d->moveTransition = mt;
       
   143     emit moveChanged();
       
   144 }
       
   145 
       
   146 QDeclarativeTransition *QDeclarativeBasePositioner::add() const
       
   147 {
       
   148     Q_D(const QDeclarativeBasePositioner);
       
   149     return d->addTransition;
       
   150 }
       
   151 
       
   152 void QDeclarativeBasePositioner::setAdd(QDeclarativeTransition *add)
       
   153 {
       
   154     Q_D(QDeclarativeBasePositioner);
       
   155     if (add == d->addTransition)
       
   156         return;
       
   157 
       
   158     d->addTransition = add;
       
   159     emit addChanged();
       
   160 }
       
   161 
       
   162 void QDeclarativeBasePositioner::componentComplete()
       
   163 {
       
   164     Q_D(QDeclarativeBasePositioner);
       
   165     QDeclarativeItem::componentComplete();
       
   166     positionedItems.reserve(d->QGraphicsItemPrivate::children.count());
       
   167     prePositioning();
       
   168     reportConflictingAnchors();
       
   169 }
       
   170 
       
   171 QVariant QDeclarativeBasePositioner::itemChange(GraphicsItemChange change,
       
   172                                        const QVariant &value)
       
   173 {
       
   174     Q_D(QDeclarativeBasePositioner);
       
   175     if (change == ItemChildAddedChange){
       
   176         QGraphicsItem* item = value.value<QGraphicsItem*>();
       
   177         QDeclarativeItem* child = 0;
       
   178         if(item)
       
   179             child = qobject_cast<QDeclarativeItem*>(item->toGraphicsObject());
       
   180         if (child)
       
   181             prePositioning();
       
   182     } else if (change == ItemChildRemovedChange) {
       
   183         QGraphicsItem* item = value.value<QGraphicsItem*>();
       
   184         QDeclarativeItem* child = 0;
       
   185         if(item)
       
   186             child = qobject_cast<QDeclarativeItem*>(item->toGraphicsObject());
       
   187         if (child) {
       
   188             QDeclarativeBasePositioner::PositionedItem posItem(child);
       
   189             int idx = positionedItems.find(posItem);
       
   190             if (idx >= 0) {
       
   191                 d->unwatchChanges(child);
       
   192                 positionedItems.remove(idx);
       
   193             }
       
   194             prePositioning();
       
   195         }
       
   196     }
       
   197 
       
   198     return QDeclarativeItem::itemChange(change, value);
       
   199 }
       
   200 
       
   201 void QDeclarativeBasePositioner::prePositioning()
       
   202 {
       
   203     Q_D(QDeclarativeBasePositioner);
       
   204     if (!isComponentComplete())
       
   205         return;
       
   206 
       
   207     if (d->doingPositioning)
       
   208         return;
       
   209 
       
   210     d->queuedPositioning = false;
       
   211     d->doingPositioning = true;
       
   212     //Need to order children by creation order modified by stacking order
       
   213     QList<QGraphicsItem *> children = d->QGraphicsItemPrivate::children;
       
   214     qSort(children.begin(), children.end(), d->insertionOrder);
       
   215 
       
   216     QPODVector<PositionedItem,8> oldItems;
       
   217     positionedItems.copyAndClear(oldItems);
       
   218     for (int ii = 0; ii < children.count(); ++ii) {
       
   219         QDeclarativeItem *child = qobject_cast<QDeclarativeItem *>(children.at(ii));
       
   220         if (!child)
       
   221             continue;
       
   222         PositionedItem *item = 0;
       
   223         PositionedItem posItem(child);
       
   224         int wIdx = oldItems.find(posItem);
       
   225         if (wIdx < 0) {
       
   226             d->watchChanges(child);
       
   227             positionedItems.append(posItem);
       
   228             item = &positionedItems[positionedItems.count()-1];
       
   229             item->isNew = true;
       
   230             if (child->opacity() <= 0.0 || !child->isVisible())
       
   231                 item->isVisible = false;
       
   232         } else {
       
   233             item = &oldItems[wIdx];
       
   234             if (child->opacity() <= 0.0 || !child->isVisible()) {
       
   235                 item->isVisible = false;
       
   236             } else if (!item->isVisible) {
       
   237                 item->isVisible = true;
       
   238                 item->isNew = true;
       
   239             } else {
       
   240                 item->isNew = false;
       
   241             }
       
   242             positionedItems.append(*item);
       
   243         }
       
   244     }
       
   245     QSizeF contentSize;
       
   246     doPositioning(&contentSize);
       
   247     if(d->addTransition || d->moveTransition)
       
   248         finishApplyTransitions();
       
   249     d->doingPositioning = false;
       
   250     //Set implicit size to the size of its children
       
   251     setImplicitHeight(contentSize.height());
       
   252     setImplicitWidth(contentSize.width());
       
   253 }
       
   254 
       
   255 void QDeclarativeBasePositioner::positionX(int x, const PositionedItem &target)
       
   256 {
       
   257     Q_D(QDeclarativeBasePositioner);
       
   258     if(d->type == Horizontal || d->type == Both){
       
   259         if (target.isNew) {
       
   260             if (!d->addTransition)
       
   261                 target.item->setX(x);
       
   262             else
       
   263                 d->addActions << QDeclarativeAction(target.item, QLatin1String("x"), QVariant(x));
       
   264         } else if (x != target.item->x()) {
       
   265             if (!d->moveTransition)
       
   266                 target.item->setX(x);
       
   267             else
       
   268                 d->moveActions << QDeclarativeAction(target.item, QLatin1String("x"), QVariant(x));
       
   269         }
       
   270     }
       
   271 }
       
   272 
       
   273 void QDeclarativeBasePositioner::positionY(int y, const PositionedItem &target)
       
   274 {
       
   275     Q_D(QDeclarativeBasePositioner);
       
   276     if(d->type == Vertical || d->type == Both){
       
   277         if (target.isNew) {
       
   278             if (!d->addTransition)
       
   279                 target.item->setY(y);
       
   280             else
       
   281                 d->addActions << QDeclarativeAction(target.item, QLatin1String("y"), QVariant(y));
       
   282         } else if (y != target.item->y()) {
       
   283             if (!d->moveTransition)
       
   284                 target.item->setY(y);
       
   285             else
       
   286                 d->moveActions << QDeclarativeAction(target.item, QLatin1String("y"), QVariant(y));
       
   287         }
       
   288     }
       
   289 }
       
   290 
       
   291 void QDeclarativeBasePositioner::finishApplyTransitions()
       
   292 {
       
   293     Q_D(QDeclarativeBasePositioner);
       
   294     // Note that if a transition is not set the transition manager will
       
   295     // apply the changes directly, in the case add/move aren't set
       
   296     d->addTransitionManager.transition(d->addActions, d->addTransition);
       
   297     d->moveTransitionManager.transition(d->moveActions, d->moveTransition);
       
   298     d->addActions.clear();
       
   299     d->moveActions.clear();
       
   300 }
       
   301 
       
   302 /*!
       
   303   \qmlclass Column QDeclarativeColumn
       
   304     \since 4.7
       
   305   \brief The Column item lines up its children vertically.
       
   306   \inherits Item
       
   307 
       
   308   The Column item positions its child items so that they are vertically
       
   309     aligned and not overlapping. Spacing between items can be added.
       
   310 
       
   311   The below example positions differently shaped rectangles using a Column.
       
   312   \table
       
   313   \row
       
   314   \o \image verticalpositioner_example.png
       
   315   \o
       
   316   \qml
       
   317 Column {
       
   318     spacing: 2
       
   319     Rectangle { color: "red"; width: 50; height: 50 }
       
   320     Rectangle { color: "green"; width: 20; height: 50 }
       
   321     Rectangle { color: "blue"; width: 50; height: 20 }
       
   322 }
       
   323   \endqml
       
   324   \endtable
       
   325 
       
   326   Column also provides for transitions to be set when items are added, moved,
       
   327   or removed in the positioner. Adding and removing apply both to items which are deleted
       
   328   or have their position in the document changed so as to no longer be children of the positioner,
       
   329   as well as to items which have their opacity set to or from zero so as to appear or disappear.
       
   330 
       
   331   \table
       
   332   \row
       
   333   \o \image verticalpositioner_transition.gif
       
   334   \o
       
   335   \qml
       
   336 Column {
       
   337     spacing: 2
       
   338     add: ...
       
   339     move: ...
       
   340     ...
       
   341 }
       
   342   \endqml
       
   343   \endtable
       
   344 
       
   345   Note that the positioner assumes that the x and y positions of its children
       
   346   will not change. If you manually change the x or y properties in script, bind
       
   347   the x or y properties, use anchors on a child of a positioner, or have the
       
   348   height of a child depend on the position of a child, then the
       
   349   positioner may exhibit strange behaviour.
       
   350 
       
   351 */
       
   352 /*!
       
   353     \qmlproperty Transition Column::add
       
   354 
       
   355     This property holds the transition to be applied when adding an
       
   356     item to the positioner. The transition will only be applied to the
       
   357     added item(s).  Positioner transitions will only affect the
       
   358     position (x,y) of items.
       
   359 
       
   360     Added can mean that either the object has been created or
       
   361     reparented, and thus is now a child or the positioner, or that the
       
   362     object has had its opacity increased from zero, and thus is now
       
   363     visible.
       
   364 
       
   365 
       
   366 */
       
   367 /*!
       
   368     \qmlproperty Transition Column::move
       
   369 
       
   370     This property holds the transition to apply when moving an item
       
   371     within the positioner.  Positioner transitions will only affect
       
   372     the position (x,y) of items.
       
   373 
       
   374     This can happen when other items are added or removed from the
       
   375     positioner, or when items resize themselves.
       
   376 
       
   377     \table
       
   378     \row
       
   379     \o \image positioner-move.gif
       
   380     \o
       
   381     \qml
       
   382 Column {
       
   383     move: Transition {
       
   384         NumberAnimation {
       
   385             properties: "y"
       
   386             easing.type: Easing.OutBounce
       
   387         }
       
   388     }
       
   389 }
       
   390     \endqml
       
   391     \endtable
       
   392 */
       
   393 /*!
       
   394   \qmlproperty int Column::spacing
       
   395 
       
   396   spacing is the amount in pixels left empty between each adjacent
       
   397   item, and defaults to 0.
       
   398 
       
   399   The below example places a Grid containing a red, a blue and a
       
   400   green rectangle on a gray background. The area the grid positioner
       
   401   occupies is colored white. The top positioner has the default of no spacing,
       
   402   and the bottom positioner has its spacing set to 2.
       
   403 
       
   404   \image spacing_a.png
       
   405   \image spacing_b.png
       
   406 
       
   407 */
       
   408 /*!
       
   409     \internal
       
   410     \class QDeclarativeColumn
       
   411     \brief The QDeclarativeColumn class lines up items vertically.
       
   412 */
       
   413 QDeclarativeColumn::QDeclarativeColumn(QDeclarativeItem *parent)
       
   414 : QDeclarativeBasePositioner(Vertical, parent)
       
   415 {
       
   416 }
       
   417 
       
   418 static inline bool isInvisible(QDeclarativeItem *child)
       
   419 {
       
   420     return child->opacity() == 0.0 || !child->isVisible() || !child->width() || !child->height();
       
   421 }
       
   422 
       
   423 void QDeclarativeColumn::doPositioning(QSizeF *contentSize)
       
   424 {
       
   425     int voffset = 0;
       
   426 
       
   427     for (int ii = 0; ii < positionedItems.count(); ++ii) {
       
   428         const PositionedItem &child = positionedItems.at(ii);
       
   429         if (!child.item || isInvisible(child.item))
       
   430             continue;
       
   431 
       
   432         if(child.item->y() != voffset)
       
   433             positionY(voffset, child);
       
   434 
       
   435         contentSize->setWidth(qMax(contentSize->width(), child.item->width()));
       
   436 
       
   437         voffset += child.item->height();
       
   438         voffset += spacing();
       
   439     }
       
   440 
       
   441     contentSize->setHeight(voffset - spacing());
       
   442 }
       
   443 
       
   444 void QDeclarativeColumn::reportConflictingAnchors()
       
   445 {
       
   446     QDeclarativeBasePositionerPrivate *d = static_cast<QDeclarativeBasePositionerPrivate*>(QDeclarativeBasePositionerPrivate::get(this));
       
   447     for (int ii = 0; ii < positionedItems.count(); ++ii) {
       
   448         const PositionedItem &child = positionedItems.at(ii);
       
   449         if (child.item) {
       
   450             QDeclarativeAnchors *anchors = QDeclarativeItemPrivate::get(child.item)->_anchors;
       
   451             if (anchors) {
       
   452                 QDeclarativeAnchors::Anchors usedAnchors = anchors->usedAnchors();
       
   453                 if (usedAnchors & QDeclarativeAnchors::TopAnchor ||
       
   454                     usedAnchors & QDeclarativeAnchors::BottomAnchor ||
       
   455                     usedAnchors & QDeclarativeAnchors::VCenterAnchor ||
       
   456                     anchors->fill() || anchors->centerIn()) {
       
   457                     d->anchorConflict = true;
       
   458                     break;
       
   459                 }
       
   460             }
       
   461         }
       
   462     }
       
   463     if (d->anchorConflict) {
       
   464         qmlInfo(this) << "Cannot specify top, bottom, verticalCenter, fill or centerIn anchors for items inside Column";
       
   465     }
       
   466 }
       
   467 
       
   468 /*!
       
   469   \qmlclass Row QDeclarativeRow
       
   470   \since 4.7
       
   471   \brief The Row item lines up its children horizontally.
       
   472   \inherits Item
       
   473 
       
   474   The Row item positions its child items so that they are
       
   475   horizontally aligned and not overlapping. Spacing can be added between the
       
   476   items, and a margin around all items can also be added. It also provides for
       
   477   transitions to be set when items are added, moved, or removed in the
       
   478   positioner. Adding and removing apply both to items which are deleted or have
       
   479   their position in the document changed so as to no longer be children of the
       
   480   positioner, as well as to items which have their opacity set to or from zero
       
   481   so as to appear or disappear.
       
   482 
       
   483   The below example lays out differently shaped rectangles using a Row.
       
   484   \qml
       
   485 Row {
       
   486     spacing: 2
       
   487     Rectangle { color: "red"; width: 50; height: 50 }
       
   488     Rectangle { color: "green"; width: 20; height: 50 }
       
   489     Rectangle { color: "blue"; width: 50; height: 20 }
       
   490 }
       
   491   \endqml
       
   492   \image horizontalpositioner_example.png
       
   493 
       
   494   Note that the positioner assumes that the x and y positions of its children
       
   495   will not change. If you manually change the x or y properties in script, bind
       
   496   the x or y properties, use anchors on a child of a positioner, or have the
       
   497   width of a child depend on the position of a child, then the
       
   498   positioner may exhibit strange behaviour.
       
   499 
       
   500 */
       
   501 /*!
       
   502     \qmlproperty Transition Row::add
       
   503     This property holds the transition to apply when adding an item to the positioner.
       
   504     The transition will only be applied to the added item(s).
       
   505     Positioner transitions will only affect the position (x,y) of items.
       
   506 
       
   507     Added can mean that either the object has been created or
       
   508     reparented, and thus is now a child or the positioner, or that the
       
   509     object has had its opacity increased from zero, and thus is now
       
   510     visible.
       
   511 
       
   512 
       
   513 */
       
   514 /*!
       
   515     \qmlproperty Transition Row::move
       
   516 
       
   517     This property holds the transition to apply when moving an item
       
   518     within the positioner.  Positioner transitions will only affect
       
   519     the position (x,y) of items.
       
   520 
       
   521     This can happen when other items are added or removed from the
       
   522     positioner, or when items resize themselves.
       
   523 
       
   524     \qml
       
   525 Row {
       
   526     id: positioner
       
   527     move: Transition {
       
   528         NumberAnimation {
       
   529             properties: "x"
       
   530             ease: "easeOutBounce"
       
   531         }
       
   532     }
       
   533 }
       
   534     \endqml
       
   535 
       
   536 */
       
   537 /*!
       
   538   \qmlproperty int Row::spacing
       
   539 
       
   540   spacing is the amount in pixels left empty between each adjacent
       
   541   item, and defaults to 0.
       
   542 
       
   543   The below example places a Grid containing a red, a blue and a
       
   544   green rectangle on a gray background. The area the grid positioner
       
   545   occupies is colored white. The top positioner has the default of no spacing,
       
   546   and the bottom positioner has its spacing set to 2.
       
   547 
       
   548   \image spacing_a.png
       
   549   \image spacing_b.png
       
   550 
       
   551 */
       
   552 /*!
       
   553     \internal
       
   554     \class QDeclarativeRow
       
   555     \brief The QDeclarativeRow class lines up items horizontally.
       
   556 */
       
   557 QDeclarativeRow::QDeclarativeRow(QDeclarativeItem *parent)
       
   558 : QDeclarativeBasePositioner(Horizontal, parent)
       
   559 {
       
   560 }
       
   561 
       
   562 void QDeclarativeRow::doPositioning(QSizeF *contentSize)
       
   563 {
       
   564     int hoffset = 0;
       
   565 
       
   566     for (int ii = 0; ii < positionedItems.count(); ++ii) {
       
   567         const PositionedItem &child = positionedItems.at(ii);
       
   568         if (!child.item || isInvisible(child.item))
       
   569             continue;
       
   570 
       
   571         if(child.item->x() != hoffset)
       
   572             positionX(hoffset, child);
       
   573 
       
   574         contentSize->setHeight(qMax(contentSize->height(), child.item->height()));
       
   575 
       
   576         hoffset += child.item->width();
       
   577         hoffset += spacing();
       
   578     }
       
   579 
       
   580     contentSize->setWidth(hoffset - spacing());
       
   581 }
       
   582 
       
   583 void QDeclarativeRow::reportConflictingAnchors()
       
   584 {
       
   585     QDeclarativeBasePositionerPrivate *d = static_cast<QDeclarativeBasePositionerPrivate*>(QDeclarativeBasePositionerPrivate::get(this));
       
   586     for (int ii = 0; ii < positionedItems.count(); ++ii) {
       
   587         const PositionedItem &child = positionedItems.at(ii);
       
   588         if (child.item) {
       
   589             QDeclarativeAnchors *anchors = QDeclarativeItemPrivate::get(child.item)->_anchors;
       
   590             if (anchors) {
       
   591                 QDeclarativeAnchors::Anchors usedAnchors = anchors->usedAnchors();
       
   592                 if (usedAnchors & QDeclarativeAnchors::LeftAnchor ||
       
   593                     usedAnchors & QDeclarativeAnchors::RightAnchor ||
       
   594                     usedAnchors & QDeclarativeAnchors::HCenterAnchor ||
       
   595                     anchors->fill() || anchors->centerIn()) {
       
   596                     d->anchorConflict = true;
       
   597                     break;
       
   598                 }
       
   599             }
       
   600         }
       
   601     }
       
   602     if (d->anchorConflict)
       
   603         qmlInfo(this) << "Cannot specify left, right, horizontalCenter, fill or centerIn anchors for items inside Row";
       
   604 }
       
   605 
       
   606 /*!
       
   607   \qmlclass Grid QDeclarativeGrid
       
   608   \since 4.7
       
   609   \brief The Grid item positions its children in a grid.
       
   610   \inherits Item
       
   611 
       
   612   The Grid item positions its child items so that they are
       
   613   aligned in a grid and are not overlapping. Spacing can be added
       
   614   between the items. It also provides for transitions to be set when items are
       
   615   added, moved, or removed in the positioner. Adding and removing apply
       
   616   both to items which are deleted or have their position in the
       
   617   document changed so as to no longer be children of the positioner, as
       
   618   well as to items which have their opacity set to or from zero so
       
   619   as to appear or disappear.
       
   620 
       
   621   The Grid defaults to using four columns, and as many rows as
       
   622   are necessary to fit all the child items. The number of rows
       
   623   and/or the number of columns can be constrained by setting the rows
       
   624   or columns properties. The grid positioner calculates a grid with
       
   625   rectangular cells of sufficient size to hold all items, and then
       
   626   places the items in the cells, going across then down, and
       
   627   positioning each item at the (0,0) corner of the cell. The below
       
   628   example demonstrates this.
       
   629 
       
   630   \table
       
   631   \row
       
   632   \o \image gridLayout_example.png
       
   633   \o
       
   634   \qml
       
   635 Grid {
       
   636     columns: 3
       
   637     spacing: 2
       
   638     Rectangle { color: "red"; width: 50; height: 50 }
       
   639     Rectangle { color: "green"; width: 20; height: 50 }
       
   640     Rectangle { color: "blue"; width: 50; height: 20 }
       
   641     Rectangle { color: "cyan"; width: 50; height: 50 }
       
   642     Rectangle { color: "magenta"; width: 10; height: 10 }
       
   643 }
       
   644   \endqml
       
   645   \endtable
       
   646 
       
   647   Note that the positioner assumes that the x and y positions of its children
       
   648   will not change. If you manually change the x or y properties in script, bind
       
   649   the x or y properties, use anchors on a child of a positioner, or have the
       
   650   width or height of a child depend on the position of a child, then the
       
   651   positioner may exhibit strange behaviour.
       
   652 */
       
   653 /*!
       
   654     \qmlproperty Transition Grid::add
       
   655     This property holds the transition to apply when adding an item to the positioner.
       
   656     The transition is only applied to the added item(s).
       
   657     Positioner transitions will only affect the position (x,y) of items,
       
   658     as that is all the positioners affect. To animate other property change
       
   659     you will have to do so based on how you have changed those properties.
       
   660 
       
   661     Added can mean that either the object has been created or
       
   662     reparented, and thus is now a child or the positioner, or that the
       
   663     object has had its opacity increased from zero, and thus is now
       
   664     visible.
       
   665 
       
   666 
       
   667 */
       
   668 /*!
       
   669     \qmlproperty Transition Grid::move
       
   670     This property holds the transition to apply when moving an item within the positioner.
       
   671     Positioner transitions will only affect the position (x,y) of items.
       
   672 
       
   673     This can happen when other items are added or removed from the positioner, or
       
   674     when items resize themselves.
       
   675 
       
   676     \qml
       
   677 Grid {
       
   678     move: Transition {
       
   679         NumberAnimation {
       
   680             properties: "x,y"
       
   681             ease: "easeOutBounce"
       
   682         }
       
   683     }
       
   684 }
       
   685     \endqml
       
   686 
       
   687 */
       
   688 /*!
       
   689   \qmlproperty int Grid::spacing
       
   690 
       
   691   spacing is the amount in pixels left empty between each adjacent
       
   692   item, and defaults to 0.
       
   693 
       
   694   The below example places a Grid containing a red, a blue and a
       
   695   green rectangle on a gray background. The area the grid positioner
       
   696   occupies is colored white. The top positioner has the default of no spacing,
       
   697   and the bottom positioner has its spacing set to 2.
       
   698 
       
   699   \image spacing_a.png
       
   700   \image spacing_b.png
       
   701 
       
   702 */
       
   703 /*!
       
   704     \internal
       
   705     \class QDeclarativeGrid
       
   706     \brief The QDeclarativeGrid class lays out items in a grid.
       
   707 */
       
   708 QDeclarativeGrid::QDeclarativeGrid(QDeclarativeItem *parent) :
       
   709     QDeclarativeBasePositioner(Both, parent), m_rows(-1), m_columns(-1), m_flow(LeftToRight)
       
   710 {
       
   711 }
       
   712 
       
   713 /*!
       
   714     \qmlproperty int Grid::columns
       
   715     This property holds the number of columns in the grid.
       
   716 
       
   717     When the columns property is set the Grid will always have
       
   718     that many columns. Note that if you do not have enough items to
       
   719     fill this many columns some columns will be of zero width.
       
   720 */
       
   721 
       
   722 /*!
       
   723     \qmlproperty int Grid::rows
       
   724     This property holds the number of rows in the grid.
       
   725 
       
   726     When the rows property is set the Grid will always have that
       
   727     many rows. Note that if you do not have enough items to fill this
       
   728     many rows some rows will be of zero width.
       
   729 */
       
   730 
       
   731 void QDeclarativeGrid::setColumns(const int columns)
       
   732 {
       
   733     if (columns == m_columns)
       
   734         return;
       
   735     m_columns = columns;
       
   736     prePositioning();
       
   737     emit columnsChanged();
       
   738 }
       
   739 
       
   740 void QDeclarativeGrid::setRows(const int rows)
       
   741 {
       
   742     if (rows == m_rows)
       
   743         return;
       
   744     m_rows = rows;
       
   745     prePositioning();
       
   746     emit rowsChanged();
       
   747 }
       
   748 
       
   749 /*!
       
   750     \qmlproperty enumeration Grid::flow
       
   751     This property holds the flow of the layout.
       
   752 
       
   753     Possible values are \c Grid.LeftToRight (default) and \c Grid.TopToBottom.
       
   754 
       
   755     If \a flow is \c Grid.LeftToRight, the items are positioned next to
       
   756     to each other from left to right, then wrapped to the next line.
       
   757     If \a flow is \c Grid.TopToBottom, the items are positioned next to each
       
   758     other from top to bottom, then wrapped to the next column.
       
   759 */
       
   760 QDeclarativeGrid::Flow QDeclarativeGrid::flow() const
       
   761 {
       
   762     return m_flow;
       
   763 }
       
   764 
       
   765 void QDeclarativeGrid::setFlow(Flow flow)
       
   766 {
       
   767     if (m_flow != flow) {
       
   768         m_flow = flow;
       
   769         prePositioning();
       
   770         emit flowChanged();
       
   771     }
       
   772 }
       
   773 
       
   774 void QDeclarativeGrid::doPositioning(QSizeF *contentSize)
       
   775 {
       
   776     int c = m_columns;
       
   777     int r = m_rows;
       
   778     int numVisible = positionedItems.count();
       
   779     if (m_columns <= 0 && m_rows <= 0){
       
   780         c = 4;
       
   781         r = (numVisible+3)/4;
       
   782     } else if (m_rows <= 0){
       
   783         r = (numVisible+(m_columns-1))/m_columns;
       
   784     } else if (m_columns <= 0){
       
   785         c = (numVisible+(m_rows-1))/m_rows;
       
   786     }
       
   787 
       
   788     QList<int> maxColWidth;
       
   789     QList<int> maxRowHeight;
       
   790     int childIndex =0;
       
   791     if (m_flow == LeftToRight) {
       
   792         for (int i=0; i < r; i++){
       
   793             for (int j=0; j < c; j++){
       
   794                 if (j==0)
       
   795                     maxRowHeight << 0;
       
   796                 if (i==0)
       
   797                     maxColWidth << 0;
       
   798 
       
   799                 if (childIndex == positionedItems.count())
       
   800                     continue;
       
   801                 const PositionedItem &child = positionedItems.at(childIndex++);
       
   802                 if (!child.item || isInvisible(child.item))
       
   803                     continue;
       
   804                 if (child.item->width() > maxColWidth[j])
       
   805                     maxColWidth[j] = child.item->width();
       
   806                 if (child.item->height() > maxRowHeight[i])
       
   807                     maxRowHeight[i] = child.item->height();
       
   808             }
       
   809         }
       
   810     } else {
       
   811         for (int j=0; j < c; j++){
       
   812             for (int i=0; i < r; i++){
       
   813                 if (j==0)
       
   814                     maxRowHeight << 0;
       
   815                 if (i==0)
       
   816                     maxColWidth << 0;
       
   817 
       
   818                 if (childIndex == positionedItems.count())
       
   819                     continue;
       
   820                 const PositionedItem &child = positionedItems.at(childIndex++);
       
   821                 if (!child.item || isInvisible(child.item))
       
   822                     continue;
       
   823                 if (child.item->width() > maxColWidth[j])
       
   824                     maxColWidth[j] = child.item->width();
       
   825                 if (child.item->height() > maxRowHeight[i])
       
   826                     maxRowHeight[i] = child.item->height();
       
   827             }
       
   828         }
       
   829     }
       
   830 
       
   831     int xoffset=0;
       
   832     int yoffset=0;
       
   833     int curRow =0;
       
   834     int curCol =0;
       
   835     for (int i = 0; i < positionedItems.count(); ++i) {
       
   836         const PositionedItem &child = positionedItems.at(i);
       
   837         if (!child.item || isInvisible(child.item))
       
   838             continue;
       
   839         if((child.item->x()!=xoffset)||(child.item->y()!=yoffset)){
       
   840             positionX(xoffset, child);
       
   841             positionY(yoffset, child);
       
   842         }
       
   843 
       
   844         if (m_flow == LeftToRight) {
       
   845             contentSize->setWidth(qMax(contentSize->width(), xoffset + child.item->width()));
       
   846             contentSize->setHeight(yoffset + maxRowHeight[curRow]);
       
   847 
       
   848             xoffset+=maxColWidth[curCol]+spacing();
       
   849             curCol++;
       
   850             curCol%=c;
       
   851             if (!curCol){
       
   852                 yoffset+=maxRowHeight[curRow]+spacing();
       
   853                 xoffset=0;
       
   854                 curRow++;
       
   855                 if (curRow>=r)
       
   856                     break;
       
   857             }
       
   858         } else {
       
   859             contentSize->setHeight(qMax(contentSize->height(), yoffset + child.item->height()));
       
   860             contentSize->setWidth(xoffset + maxColWidth[curCol]);
       
   861 
       
   862             yoffset+=maxRowHeight[curRow]+spacing();
       
   863             curRow++;
       
   864             curRow%=r;
       
   865             if (!curRow){
       
   866                 xoffset+=maxColWidth[curCol]+spacing();
       
   867                 yoffset=0;
       
   868                 curCol++;
       
   869                 if (curCol>=c)
       
   870                     break;
       
   871             }
       
   872         }
       
   873     }
       
   874 }
       
   875 
       
   876 void QDeclarativeGrid::reportConflictingAnchors()
       
   877 {
       
   878     QDeclarativeBasePositionerPrivate *d = static_cast<QDeclarativeBasePositionerPrivate*>(QDeclarativeBasePositionerPrivate::get(this));
       
   879     for (int ii = 0; ii < positionedItems.count(); ++ii) {
       
   880         const PositionedItem &child = positionedItems.at(ii);
       
   881         if (child.item) {
       
   882             QDeclarativeAnchors *anchors = QDeclarativeItemPrivate::get(child.item)->_anchors;
       
   883             if (anchors && (anchors->usedAnchors() || anchors->fill() || anchors->centerIn())) {
       
   884                 d->anchorConflict = true;
       
   885                 break;
       
   886             }
       
   887         }
       
   888     }
       
   889     if (d->anchorConflict)
       
   890         qmlInfo(this) << "Cannot specify anchors for items inside Grid";
       
   891 }
       
   892 
       
   893 /*!
       
   894   \qmlclass Flow QDeclarativeFlow
       
   895   \since 4.7
       
   896   \brief The Flow item lines up its children side by side, wrapping as necessary.
       
   897   \inherits Item
       
   898 
       
   899   Note that the positioner assumes that the x and y positions of its children
       
   900   will not change. If you manually change the x or y properties in script, bind
       
   901   the x or y properties, use anchors on a child of a positioner, or have the
       
   902   width or height of a child depend on the position of a child, then the
       
   903   positioner may exhibit strange behaviour.
       
   904 
       
   905 */
       
   906 /*!
       
   907     \qmlproperty Transition Flow::add
       
   908     This property holds the transition to apply when adding an item to the positioner.
       
   909     The transition will only be applied to the added item(s).
       
   910     Positioner transitions will only affect the position (x,y) of items.
       
   911 
       
   912     Added can mean that either the object has been created or reparented, and thus is now a child or the positioner, or that the object has had its opacity increased from zero, and thus is now visible.
       
   913 
       
   914 
       
   915 */
       
   916 /*!
       
   917     \qmlproperty Transition Flow::move
       
   918     This property holds the transition to apply when moving an item within the positioner.
       
   919     Positioner transitions will only affect the position (x,y) of items.
       
   920 
       
   921     This can happen when other items are added or removed from the positioner, or when items resize themselves.
       
   922 
       
   923     \qml
       
   924 Flow {
       
   925     id: positioner
       
   926     move: Transition {
       
   927         NumberAnimation {
       
   928             properties: "x,y"
       
   929             ease: "easeOutBounce"
       
   930         }
       
   931     }
       
   932 }
       
   933     \endqml
       
   934 
       
   935 */
       
   936 /*!
       
   937   \qmlproperty int Flow::spacing
       
   938 
       
   939   spacing is the amount in pixels left empty between each adjacent
       
   940   item, and defaults to 0.
       
   941 
       
   942 */
       
   943 
       
   944 class QDeclarativeFlowPrivate : public QDeclarativeBasePositionerPrivate
       
   945 {
       
   946     Q_DECLARE_PUBLIC(QDeclarativeFlow)
       
   947 
       
   948 public:
       
   949     QDeclarativeFlowPrivate()
       
   950         : QDeclarativeBasePositionerPrivate(), flow(QDeclarativeFlow::LeftToRight)
       
   951     {}
       
   952 
       
   953     QDeclarativeFlow::Flow flow;
       
   954 };
       
   955 
       
   956 QDeclarativeFlow::QDeclarativeFlow(QDeclarativeItem *parent)
       
   957 : QDeclarativeBasePositioner(*(new QDeclarativeFlowPrivate), Both, parent)
       
   958 {
       
   959     Q_D(QDeclarativeFlow);
       
   960     // Flow layout requires relayout if its own size changes too.
       
   961     d->addItemChangeListener(d, QDeclarativeItemPrivate::Geometry);
       
   962 }
       
   963 
       
   964 /*!
       
   965     \qmlproperty enumeration Flow::flow
       
   966     This property holds the flow of the layout.
       
   967 
       
   968     Possible values are \c Flow.LeftToRight (default) and \c Flow.TopToBottom.
       
   969 
       
   970     If \a flow is \c Flow.LeftToRight, the items are positioned next to
       
   971     to each other from left to right until the width of the Flow
       
   972     is exceeded, then wrapped to the next line.
       
   973     If \a flow is \c Flow.TopToBottom, the items are positioned next to each
       
   974     other from top to bottom until the height of the Flow is exceeded,
       
   975     then wrapped to the next column.
       
   976 */
       
   977 QDeclarativeFlow::Flow QDeclarativeFlow::flow() const
       
   978 {
       
   979     Q_D(const QDeclarativeFlow);
       
   980     return d->flow;
       
   981 }
       
   982 
       
   983 void QDeclarativeFlow::setFlow(Flow flow)
       
   984 {
       
   985     Q_D(QDeclarativeFlow);
       
   986     if (d->flow != flow) {
       
   987         d->flow = flow;
       
   988         prePositioning();
       
   989         emit flowChanged();
       
   990     }
       
   991 }
       
   992 
       
   993 void QDeclarativeFlow::doPositioning(QSizeF *contentSize)
       
   994 {
       
   995     Q_D(QDeclarativeFlow);
       
   996 
       
   997     int hoffset = 0;
       
   998     int voffset = 0;
       
   999     int linemax = 0;
       
  1000 
       
  1001     for (int i = 0; i < positionedItems.count(); ++i) {
       
  1002         const PositionedItem &child = positionedItems.at(i);
       
  1003         if (!child.item || isInvisible(child.item))
       
  1004             continue;
       
  1005 
       
  1006         if (d->flow == LeftToRight)  {
       
  1007             if (hoffset && hoffset + child.item->width() > width()) {
       
  1008                 hoffset = 0;
       
  1009                 voffset += linemax + spacing();
       
  1010                 linemax = 0;
       
  1011             }
       
  1012         } else {
       
  1013             if (voffset && voffset + child.item->height() > height()) {
       
  1014                 voffset = 0;
       
  1015                 hoffset += linemax + spacing();
       
  1016                 linemax = 0;
       
  1017             }
       
  1018         }
       
  1019 
       
  1020         if(child.item->x() != hoffset || child.item->y() != voffset){
       
  1021             positionX(hoffset, child);
       
  1022             positionY(voffset, child);
       
  1023         }
       
  1024 
       
  1025         contentSize->setWidth(qMax(contentSize->width(), hoffset + child.item->width()));
       
  1026         contentSize->setHeight(qMax(contentSize->height(), voffset + child.item->height()));
       
  1027 
       
  1028         if (d->flow == LeftToRight)  {
       
  1029             hoffset += child.item->width();
       
  1030             hoffset += spacing();
       
  1031             linemax = qMax(linemax, qCeil(child.item->height()));
       
  1032         } else {
       
  1033             voffset += child.item->height();
       
  1034             voffset += spacing();
       
  1035             linemax = qMax(linemax, qCeil(child.item->width()));
       
  1036         }
       
  1037     }
       
  1038 }
       
  1039 
       
  1040 void QDeclarativeFlow::reportConflictingAnchors()
       
  1041 {
       
  1042     Q_D(QDeclarativeFlow);
       
  1043     for (int ii = 0; ii < positionedItems.count(); ++ii) {
       
  1044         const PositionedItem &child = positionedItems.at(ii);
       
  1045         if (child.item) {
       
  1046             QDeclarativeAnchors *anchors = QDeclarativeItemPrivate::get(child.item)->_anchors;
       
  1047             if (anchors && (anchors->usedAnchors() || anchors->fill() || anchors->centerIn())) {
       
  1048                 d->anchorConflict = true;
       
  1049                 break;
       
  1050             }
       
  1051         }
       
  1052     }
       
  1053     if (d->anchorConflict)
       
  1054         qmlInfo(this) << "Cannot specify anchors for items inside Flow";
       
  1055 }
       
  1056 
       
  1057 QT_END_NAMESPACE