1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "QtQuick1/private/qdeclarativepositioners_p.h"
43 #include "QtQuick1/private/qdeclarativepositioners_p_p.h"
45 #include <QtDeclarative/qdeclarative.h>
46 #include <QtQuick1/private/qdeclarativestate_p.h>
47 #include <QtQuick1/private/qdeclarativestategroup_p.h>
48 #include <QtQuick1/private/qdeclarativestateoperations_p.h>
49 #include <QtDeclarative/qdeclarativeinfo.h>
50 #include <QtCore/qmath.h>
53 #include <QCoreApplication>
59 static const QDeclarativeItemPrivate::ChangeTypes watchedChanges
60 = QDeclarativeItemPrivate::Geometry
61 | QDeclarativeItemPrivate::SiblingOrder
62 | QDeclarativeItemPrivate::Visibility
63 | QDeclarativeItemPrivate::Opacity
64 | QDeclarativeItemPrivate::Destroyed;
66 void QDeclarative1BasePositionerPrivate::watchChanges(QGraphicsObject *other)
68 if (QGraphicsItemPrivate::get(other)->isDeclarativeItem) {
69 QDeclarativeItemPrivate *otherPrivate = static_cast<QDeclarativeItemPrivate*>(QGraphicsItemPrivate::get(other));
70 otherPrivate->addItemChangeListener(this, watchedChanges);
72 Q_Q(QDeclarative1BasePositioner);
73 QObject::connect(other, SIGNAL(widthChanged()), q, SLOT(graphicsWidgetGeometryChanged()));
74 QObject::connect(other, SIGNAL(heightChanged()), q, SLOT(graphicsWidgetGeometryChanged()));
75 QObject::connect(other, SIGNAL(opacityChanged()), q, SLOT(graphicsWidgetGeometryChanged()));
76 QObject::connect(other, SIGNAL(visibleChanged()), q, SLOT(graphicsWidgetGeometryChanged()));
80 void QDeclarative1BasePositionerPrivate::unwatchChanges(QGraphicsObject* other)
82 if (QGraphicsItemPrivate::get(other)->isDeclarativeItem) {
83 QDeclarativeItemPrivate *otherPrivate = static_cast<QDeclarativeItemPrivate*>(QGraphicsItemPrivate::get(other));
84 otherPrivate->removeItemChangeListener(this, watchedChanges);
86 Q_Q(QDeclarative1BasePositioner);
87 QObject::disconnect(other, SIGNAL(widthChanged()), q, SLOT(graphicsWidgetGeometryChanged()));
88 QObject::disconnect(other, SIGNAL(heightChanged()), q, SLOT(graphicsWidgetGeometryChanged()));
89 QObject::disconnect(other, SIGNAL(opacityChanged()), q, SLOT(graphicsWidgetGeometryChanged()));
90 QObject::disconnect(other, SIGNAL(visibleChanged()), q, SLOT(graphicsWidgetGeometryChanged()));
94 void QDeclarative1BasePositioner::graphicsWidgetGeometryChanged()
101 \class QDeclarative1BasePositioner
102 \brief The QDeclarative1BasePositioner class provides a base for QDeclarative1Graphics layouts.
104 To create a QDeclarative1Graphics Positioner, simply subclass QDeclarative1BasePositioner and implement
105 doLayout(), which is automatically called when the layout might need
106 updating. In doLayout() use the setX and setY functions from QDeclarative1BasePositioner, and the
107 base class will apply the positions along with the appropriate transitions. The items to
108 position are provided in order as the protected member positionedItems.
110 You also need to set a PositionerType, to declare whether you are positioning the x, y or both
111 for the child items. Depending on the chosen type, only x or y changes will be applied.
113 Note that the subclass is responsible for adding the spacing in between items.
115 QDeclarative1BasePositioner::QDeclarative1BasePositioner(PositionerType at, QDeclarativeItem *parent)
116 : QDeclarative1ImplicitSizeItem(*(new QDeclarative1BasePositionerPrivate), parent)
118 Q_D(QDeclarative1BasePositioner);
122 QDeclarative1BasePositioner::QDeclarative1BasePositioner(QDeclarative1BasePositionerPrivate &dd, PositionerType at, QDeclarativeItem *parent)
123 : QDeclarative1ImplicitSizeItem(dd, parent)
125 Q_D(QDeclarative1BasePositioner);
129 QDeclarative1BasePositioner::~QDeclarative1BasePositioner()
131 Q_D(QDeclarative1BasePositioner);
132 for (int i = 0; i < positionedItems.count(); ++i)
133 d->unwatchChanges(positionedItems.at(i).item);
134 positionedItems.clear();
137 int QDeclarative1BasePositioner::spacing() const
139 Q_D(const QDeclarative1BasePositioner);
143 void QDeclarative1BasePositioner::setSpacing(int s)
145 Q_D(QDeclarative1BasePositioner);
150 emit spacingChanged();
153 QDeclarative1Transition *QDeclarative1BasePositioner::move() const
155 Q_D(const QDeclarative1BasePositioner);
156 return d->moveTransition;
159 void QDeclarative1BasePositioner::setMove(QDeclarative1Transition *mt)
161 Q_D(QDeclarative1BasePositioner);
162 if (mt == d->moveTransition)
164 d->moveTransition = mt;
168 QDeclarative1Transition *QDeclarative1BasePositioner::add() const
170 Q_D(const QDeclarative1BasePositioner);
171 return d->addTransition;
174 void QDeclarative1BasePositioner::setAdd(QDeclarative1Transition *add)
176 Q_D(QDeclarative1BasePositioner);
177 if (add == d->addTransition)
180 d->addTransition = add;
184 void QDeclarative1BasePositioner::componentComplete()
186 Q_D(QDeclarative1BasePositioner);
187 QDeclarativeItem::componentComplete();
188 positionedItems.reserve(d->QGraphicsItemPrivate::children.count());
190 reportConflictingAnchors();
193 QVariant QDeclarative1BasePositioner::itemChange(GraphicsItemChange change,
194 const QVariant &value)
196 Q_D(QDeclarative1BasePositioner);
197 if (change == ItemChildAddedChange){
198 QGraphicsItem* item = value.value<QGraphicsItem*>();
199 QGraphicsObject* child = 0;
201 child = item->toGraphicsObject();
204 } else if (change == ItemChildRemovedChange) {
205 QGraphicsItem* item = value.value<QGraphicsItem*>();
206 QGraphicsObject* child = 0;
208 child = item->toGraphicsObject();
210 QDeclarative1BasePositioner::PositionedItem posItem(child);
211 int idx = positionedItems.find(posItem);
213 d->unwatchChanges(child);
214 positionedItems.remove(idx);
219 return QDeclarativeItem::itemChange(change, value);
222 void QDeclarative1BasePositioner::prePositioning()
224 Q_D(QDeclarative1BasePositioner);
225 if (!isComponentComplete())
228 if (d->doingPositioning)
231 d->queuedPositioning = false;
232 d->doingPositioning = true;
233 //Need to order children by creation order modified by stacking order
234 QList<QGraphicsItem *> children = d->QGraphicsItemPrivate::children;
235 qSort(children.begin(), children.end(), d->insertionOrder);
237 QPODVector<PositionedItem,8> oldItems;
238 positionedItems.copyAndClear(oldItems);
239 for (int ii = 0; ii < children.count(); ++ii) {
240 QGraphicsObject *child = children.at(ii)->toGraphicsObject();
243 QGraphicsItemPrivate *childPrivate = static_cast<QGraphicsItemPrivate*>(QGraphicsItemPrivate::get(child));
244 PositionedItem *item = 0;
245 PositionedItem posItem(child);
246 int wIdx = oldItems.find(posItem);
248 d->watchChanges(child);
249 positionedItems.append(posItem);
250 item = &positionedItems[positionedItems.count()-1];
252 if (child->opacity() <= 0.0 || childPrivate->explicitlyHidden || !childPrivate->width() || !childPrivate->height())
253 item->isVisible = false;
255 item = &oldItems[wIdx];
256 // Items are only omitted from positioning if they are explicitly hidden
257 // i.e. their positioning is not affected if an ancestor is hidden.
258 if (child->opacity() <= 0.0 || childPrivate->explicitlyHidden || !childPrivate->width() || !childPrivate->height()) {
259 item->isVisible = false;
260 } else if (!item->isVisible) {
261 item->isVisible = true;
266 positionedItems.append(*item);
270 doPositioning(&contentSize);
271 if(d->addTransition || d->moveTransition)
272 finishApplyTransitions();
273 d->doingPositioning = false;
274 //Set implicit size to the size of its children
275 setImplicitHeight(contentSize.height());
276 setImplicitWidth(contentSize.width());
279 void QDeclarative1BasePositioner::positionX(int x, const PositionedItem &target)
281 Q_D(QDeclarative1BasePositioner);
282 if(d->type == Horizontal || d->type == Both){
284 if (!d->addTransition)
285 target.item->setX(x);
287 d->addActions << QDeclarative1Action(target.item, QLatin1String("x"), QVariant(x));
288 } else if (x != target.item->x()) {
289 if (!d->moveTransition)
290 target.item->setX(x);
292 d->moveActions << QDeclarative1Action(target.item, QLatin1String("x"), QVariant(x));
297 void QDeclarative1BasePositioner::positionY(int y, const PositionedItem &target)
299 Q_D(QDeclarative1BasePositioner);
300 if(d->type == Vertical || d->type == Both){
302 if (!d->addTransition)
303 target.item->setY(y);
305 d->addActions << QDeclarative1Action(target.item, QLatin1String("y"), QVariant(y));
306 } else if (y != target.item->y()) {
307 if (!d->moveTransition)
308 target.item->setY(y);
310 d->moveActions << QDeclarative1Action(target.item, QLatin1String("y"), QVariant(y));
315 void QDeclarative1BasePositioner::finishApplyTransitions()
317 Q_D(QDeclarative1BasePositioner);
318 // Note that if a transition is not set the transition manager will
319 // apply the changes directly, in the case add/move aren't set
320 d->addTransitionManager.transition(d->addActions, d->addTransition);
321 d->moveTransitionManager.transition(d->moveActions, d->moveTransition);
322 d->addActions.clear();
323 d->moveActions.clear();
327 \qmlclass Column QDeclarative1Column
328 \ingroup qml-positioning-elements
330 \brief The Column item arranges its children vertically.
333 The Column item positions its child items so that they are vertically
334 aligned and not overlapping.
336 Spacing between items can be added using the \l spacing property.
337 Transitions can be used for cases where items managed by a Column are
338 added or moved. These are stored in the \l add and \l move properties
341 See \l{Using QML Positioner and Repeater Items} for more details about this item and other
344 \section1 Example Usage
346 The following example positions differently shaped rectangles using a Column
349 \image verticalpositioner_example.png
351 \snippet doc/src/snippets/declarative/column/vertical-positioner.qml document
353 \section1 Using Transitions
355 Transitions can be used to animate items that are added to, moved within,
356 or removed from a Column item. The \l add and \l move properties can be set to
357 the transitions that will be applied when items are added to, removed from,
358 or re-positioned within a Column item.
360 The use of transitions with positioners is described in more detail in the
361 \l{Using QML Positioner and Repeater Items#Using Transitions}{Using QML
362 Positioner and Repeater Items} document.
364 \image verticalpositioner_transition.gif
370 // Define an animation for adding a new item...
373 // Define an animation for moving items within the column...
379 \section1 Limitations
381 Note that the positioner assumes that the x and y positions of its children
382 will not change. If you manually change the x or y properties in script, bind
383 the x or y properties, use anchors on a child of a positioner, or have the
384 height of a child depend on the position of a child, then the
385 positioner may exhibit strange behavior. If you need to perform any of these
386 actions, consider positioning the items without the use of a Column.
388 Items with a width or height of 0 will not be positioned.
390 \sa Row, Grid, Flow, {declarative/positioners}{Positioners example}
393 \qmlproperty Transition Column::add
395 This property holds the transition to be applied when adding an
396 item to the positioner. The transition will only be applied to the
397 added item(s). Positioner transitions will only affect the
398 position (x, y) of items.
400 For a positioner, adding an item can mean that either the object
401 has been created or reparented, and thus is now a child or the
402 positioner, or that the object has had its opacity increased from
403 zero, and thus is now visible.
408 \qmlproperty Transition Column::move
410 This property holds the transition to apply when moving an item
411 within the positioner. Positioner transitions will only affect
412 the position (x, y) of items.
414 This transition can be performed when other items are added or removed
415 from the positioner, or when items resize themselves.
417 \image positioner-move.gif
430 \sa add, {declarative/positioners}{Positioners example}
433 \qmlproperty int Column::spacing
435 The spacing is the amount in pixels left empty between adjacent
436 items. The default spacing is 0.
440 QDeclarative1Column::QDeclarative1Column(QDeclarativeItem *parent)
441 : QDeclarative1BasePositioner(Vertical, parent)
445 void QDeclarative1Column::doPositioning(QSizeF *contentSize)
449 for (int ii = 0; ii < positionedItems.count(); ++ii) {
450 const PositionedItem &child = positionedItems.at(ii);
451 if (!child.item || !child.isVisible)
454 if(child.item->y() != voffset)
455 positionY(voffset, child);
457 contentSize->setWidth(qMax(contentSize->width(), QGraphicsItemPrivate::get(child.item)->width()));
459 voffset += QGraphicsItemPrivate::get(child.item)->height();
460 voffset += spacing();
463 contentSize->setHeight(voffset - spacing());
466 void QDeclarative1Column::reportConflictingAnchors()
468 QDeclarative1BasePositionerPrivate *d = static_cast<QDeclarative1BasePositionerPrivate*>(QDeclarative1BasePositionerPrivate::get(this));
469 for (int ii = 0; ii < positionedItems.count(); ++ii) {
470 const PositionedItem &child = positionedItems.at(ii);
471 if (child.item && QGraphicsItemPrivate::get(child.item)->isDeclarativeItem) {
472 QDeclarative1Anchors *anchors = QDeclarativeItemPrivate::get(static_cast<QDeclarativeItem *>(child.item))->_anchors;
474 QDeclarative1Anchors::Anchors usedAnchors = anchors->usedAnchors();
475 if (usedAnchors & QDeclarative1Anchors::TopAnchor ||
476 usedAnchors & QDeclarative1Anchors::BottomAnchor ||
477 usedAnchors & QDeclarative1Anchors::VCenterAnchor ||
478 anchors->fill() || anchors->centerIn()) {
479 d->anchorConflict = true;
485 if (d->anchorConflict) {
486 qmlInfo(this) << "Cannot specify top, bottom, verticalCenter, fill or centerIn anchors for items inside Column";
491 \qmlclass Row QDeclarative1Row
492 \ingroup qml-positioning-elements
494 \brief The Row item arranges its children horizontally.
497 The Row item positions its child items so that they are horizontally
498 aligned and not overlapping.
500 Use \l spacing to set the spacing between items in a Row, and use the
501 \l add and \l move properties to set the transitions that should be applied
502 when items are added to, removed from, or re-positioned within the Row.
504 See \l{Using QML Positioner and Repeater Items} for more details about this item and other
507 \section1 Example Usage
509 The following example lays out differently shaped rectangles using a Row.
511 \image horizontalpositioner_example.png
513 \snippet doc/src/snippets/declarative/row/row.qml document
515 \section1 Using Transitions
517 Transitions can be used to animate items that are added to, moved within,
518 or removed from a Grid item. The \l add and \l move properties can be set to
519 the transitions that will be applied when items are added to, removed from,
520 or re-positioned within a Row item.
522 \section1 Limitations
524 Note that the positioner assumes that the x and y positions of its children
525 will not change. If you manually change the x or y properties in script, bind
526 the x or y properties, use anchors on a child of a positioner, or have the
527 width of a child depend on the position of a child, then the
528 positioner may exhibit strange behaviour. If you need to perform any of these
529 actions, consider positioning the items without the use of a Row.
531 Items with a width or height of 0 will not be positioned.
533 \sa Column, Grid, Flow, {declarative/positioners}{Positioners example}
536 \qmlproperty Transition Row::add
538 This property holds the transition to be applied when adding an
539 item to the positioner. The transition will only be applied to the
540 added item(s). Positioner transitions will only affect the
541 position (x, y) of items.
543 For a positioner, adding an item can mean that either the object
544 has been created or reparented, and thus is now a child or the
545 positioner, or that the object has had its opacity increased from
546 zero, and thus is now visible.
551 \qmlproperty Transition Row::move
553 This property holds the transition to be applied when moving an
554 item within the positioner. Positioner transitions will only affect
555 the position (x, y) of items.
557 This transition can be performed when other items are added or removed
558 from the positioner, or when items resize themselves.
572 \sa add, {declarative/positioners}{Positioners example}
575 \qmlproperty int Row::spacing
577 The spacing is the amount in pixels left empty between adjacent
578 items. The default spacing is 0.
582 QDeclarative1Row::QDeclarative1Row(QDeclarativeItem *parent)
583 : QDeclarative1BasePositioner(Horizontal, parent)
588 \qmlproperty enumeration Row::layoutDirection
591 This property holds the layoutDirection of the row.
596 \o Qt.LeftToRight (default) - Items are laid out from left to right. If the width of the row is explicitly set,
597 the left anchor remains to the left of the row.
598 \o Qt.RightToLeft - Items are laid out from right to left. If the width of the row is explicitly set,
599 the right anchor remains to the right of the row.
602 \sa Grid::layoutDirection, Flow::layoutDirection, {declarative/righttoleft/layoutdirection}{Layout directions example}
604 Qt::LayoutDirection QDeclarative1Row::layoutDirection() const
606 return QDeclarative1BasePositionerPrivate::getLayoutDirection(this);
609 void QDeclarative1Row::setLayoutDirection(Qt::LayoutDirection layoutDirection)
611 QDeclarative1BasePositionerPrivate *d = static_cast<QDeclarative1BasePositionerPrivate* >(QDeclarative1BasePositionerPrivate::get(this));
612 if (d->layoutDirection != layoutDirection) {
613 d->layoutDirection = layoutDirection;
614 // For RTL layout the positioning changes when the width changes.
615 if (d->layoutDirection == Qt::RightToLeft)
616 d->addItemChangeListener(d, QDeclarativeItemPrivate::Geometry);
618 d->removeItemChangeListener(d, QDeclarativeItemPrivate::Geometry);
620 emit layoutDirectionChanged();
621 emit effectiveLayoutDirectionChanged();
626 \qmlproperty enumeration Row::effectiveLayoutDirection
627 This property holds the effective layout direction of the row positioner.
629 When using the attached property \l {LayoutMirroring::enabled}{LayoutMirroring::enabled} for locale layouts,
630 the visual layout direction of the row positioner will be mirrored. However, the
631 property \l {Row::layoutDirection}{layoutDirection} will remain unchanged.
633 \sa Row::layoutDirection, {LayoutMirroring}{LayoutMirroring}
636 Qt::LayoutDirection QDeclarative1Row::effectiveLayoutDirection() const
638 return QDeclarative1BasePositionerPrivate::getEffectiveLayoutDirection(this);
641 void QDeclarative1Row::doPositioning(QSizeF *contentSize)
643 QDeclarative1BasePositionerPrivate *d = static_cast<QDeclarative1BasePositionerPrivate*>(QDeclarative1BasePositionerPrivate::get(this));
647 for (int ii = 0; ii < positionedItems.count(); ++ii) {
648 const PositionedItem &child = positionedItems.at(ii);
649 if (!child.item || !child.isVisible)
652 if(d->isLeftToRight()){
653 if(child.item->x() != hoffset)
654 positionX(hoffset, child);
659 contentSize->setHeight(qMax(contentSize->height(), QGraphicsItemPrivate::get(child.item)->height()));
661 hoffset += QGraphicsItemPrivate::get(child.item)->width();
662 hoffset += spacing();
665 contentSize->setWidth(hoffset - spacing());
667 if(d->isLeftToRight())
670 //Right to Left layout
673 end = contentSize->width();
678 for (int ii = 0; ii < positionedItems.count(); ++ii) {
679 const PositionedItem &child = positionedItems.at(ii);
680 if (!child.item || !child.isVisible)
682 hoffset = end - hoffsets[acc++] - QGraphicsItemPrivate::get(child.item)->width();
683 if(child.item->x() != hoffset)
684 positionX(hoffset, child);
688 void QDeclarative1Row::reportConflictingAnchors()
690 QDeclarative1BasePositionerPrivate *d = static_cast<QDeclarative1BasePositionerPrivate*>(QDeclarative1BasePositionerPrivate::get(this));
691 for (int ii = 0; ii < positionedItems.count(); ++ii) {
692 const PositionedItem &child = positionedItems.at(ii);
693 if (child.item && QGraphicsItemPrivate::get(child.item)->isDeclarativeItem) {
694 QDeclarative1Anchors *anchors = QDeclarativeItemPrivate::get(static_cast<QDeclarativeItem *>(child.item))->_anchors;
696 QDeclarative1Anchors::Anchors usedAnchors = anchors->usedAnchors();
697 if (usedAnchors & QDeclarative1Anchors::LeftAnchor ||
698 usedAnchors & QDeclarative1Anchors::RightAnchor ||
699 usedAnchors & QDeclarative1Anchors::HCenterAnchor ||
700 anchors->fill() || anchors->centerIn()) {
701 d->anchorConflict = true;
707 if (d->anchorConflict)
708 qmlInfo(this) << "Cannot specify left, right, horizontalCenter, fill or centerIn anchors for items inside Row";
712 \qmlclass Grid QDeclarative1Grid
713 \ingroup qml-positioning-elements
715 \brief The Grid item positions its children in a grid.
718 The Grid item positions its child items so that they are
719 aligned in a grid and are not overlapping.
721 The grid positioner calculates a grid of rectangular cells of sufficient
722 size to hold all items, placing the items in the cells, from left to right
723 and top to bottom. Each item is positioned in the top-left corner of its
724 cell with position (0, 0).
726 A Grid defaults to four columns, and as many rows as are necessary to
727 fit all child items. The number of rows and columns can be constrained
728 by setting the \l rows and \l columns properties.
730 Spacing can be added between child items by setting the \l spacing
731 property. The amount of spacing applied will be the same in the
732 horizontal and vertical directions.
734 See \l{Using QML Positioner and Repeater Items} for more details about this item and other
737 \section1 Example Usage
739 The following example demonstrates this.
741 \image gridLayout_example.png
743 \snippet doc/src/snippets/declarative/grid/grid.qml document
745 \section1 Using Transitions
747 Transitions can be used to animate items that are added to, moved within,
748 or removed from a Grid item. The \l add and \l move properties can be set to
749 the transitions that will be applied when items are added to, removed from,
750 or re-positioned within a Grid item.
752 \section1 Limitations
754 Note that the positioner assumes that the x and y positions of its children
755 will not change. If you manually change the x or y properties in script, bind
756 the x or y properties, use anchors on a child of a positioner, or have the
757 width or height of a child depend on the position of a child, then the
758 positioner may exhibit strange behaviour. If you need to perform any of these
759 actions, consider positioning the items without the use of a Grid.
761 Items with a width or height of 0 will not be positioned.
763 \sa Flow, Row, Column, {declarative/positioners}{Positioners example}
766 \qmlproperty Transition Grid::add
768 This property holds the transition to be applied when adding an
769 item to the positioner. The transition will only be applied to the
770 added item(s). Positioner transitions will only affect the
771 position (x, y) of items.
773 For a positioner, adding an item can mean that either the object
774 has been created or reparented, and thus is now a child or the
775 positioner, or that the object has had its opacity increased from
776 zero, and thus is now visible.
781 \qmlproperty Transition Grid::move
783 This property holds the transition to be applied when moving an
784 item within the positioner. Positioner transitions will only affect
785 the position (x, y) of items.
787 This transition can be performed when other items are added or removed
788 from the positioner, or when items resize themselves.
801 \sa add, {declarative/positioners}{Positioners example}
804 \qmlproperty int Grid::spacing
806 The spacing is the amount in pixels left empty between adjacent
807 items. The default spacing is 0.
809 The below example places a Grid containing a red, a blue and a
810 green rectangle on a gray background. The area the grid positioner
811 occupies is colored white. The positioner on the left has the
812 no spacing (the default), and the positioner on the right has
815 \inlineimage qml-grid-no-spacing.png
816 \inlineimage qml-grid-spacing.png
820 QDeclarative1Grid::QDeclarative1Grid(QDeclarativeItem *parent) :
821 QDeclarative1BasePositioner(Both, parent), m_rows(-1), m_columns(-1), m_flow(LeftToRight)
826 \qmlproperty int Grid::columns
828 This property holds the number of columns in the grid. The default
829 number of columns is 4.
831 If the grid does not have enough items to fill the specified
832 number of columns, some columns will be of zero width.
836 \qmlproperty int Grid::rows
837 This property holds the number of rows in the grid.
839 If the grid does not have enough items to fill the specified
840 number of rows, some rows will be of zero width.
843 void QDeclarative1Grid::setColumns(const int columns)
845 if (columns == m_columns)
849 emit columnsChanged();
852 void QDeclarative1Grid::setRows(const int rows)
862 \qmlproperty enumeration Grid::flow
863 This property holds the flow of the layout.
868 \o Grid.LeftToRight (default) - Items are positioned next to
869 each other in the \l layoutDirection, then wrapped to the next line.
870 \o Grid.TopToBottom - Items are positioned next to each
871 other from top to bottom, then wrapped to the next column.
874 QDeclarative1Grid::Flow QDeclarative1Grid::flow() const
879 void QDeclarative1Grid::setFlow(Flow flow)
881 if (m_flow != flow) {
889 \qmlproperty enumeration Grid::layoutDirection
892 This property holds the layout direction of the layout.
897 \o Qt.LeftToRight (default) - Items are positioned from the top to bottom,
898 and left to right. The flow direction is dependent on the
899 \l Grid::flow property.
900 \o Qt.RightToLeft - Items are positioned from the top to bottom,
901 and right to left. The flow direction is dependent on the
902 \l Grid::flow property.
905 \sa Flow::layoutDirection, Row::layoutDirection, {declarative/righttoleft/layoutdirection}{Layout directions example}
907 Qt::LayoutDirection QDeclarative1Grid::layoutDirection() const
909 return QDeclarative1BasePositionerPrivate::getLayoutDirection(this);
912 void QDeclarative1Grid::setLayoutDirection(Qt::LayoutDirection layoutDirection)
914 QDeclarative1BasePositionerPrivate *d = static_cast<QDeclarative1BasePositionerPrivate*>(QDeclarative1BasePositionerPrivate::get(this));
915 if (d->layoutDirection != layoutDirection) {
916 d->layoutDirection = layoutDirection;
917 // For RTL layout the positioning changes when the width changes.
918 if (d->layoutDirection == Qt::RightToLeft)
919 d->addItemChangeListener(d, QDeclarativeItemPrivate::Geometry);
921 d->removeItemChangeListener(d, QDeclarativeItemPrivate::Geometry);
923 emit layoutDirectionChanged();
924 emit effectiveLayoutDirectionChanged();
929 \qmlproperty enumeration Grid::effectiveLayoutDirection
930 This property holds the effective layout direction of the grid positioner.
932 When using the attached property \l {LayoutMirroring::enabled}{LayoutMirroring::enabled} for locale layouts,
933 the visual layout direction of the grid positioner will be mirrored. However, the
934 property \l {Grid::layoutDirection}{layoutDirection} will remain unchanged.
936 \sa Grid::layoutDirection, {LayoutMirroring}{LayoutMirroring}
939 Qt::LayoutDirection QDeclarative1Grid::effectiveLayoutDirection() const
941 return QDeclarative1BasePositionerPrivate::getEffectiveLayoutDirection(this);
944 void QDeclarative1Grid::doPositioning(QSizeF *contentSize)
946 QDeclarative1BasePositionerPrivate *d = static_cast<QDeclarative1BasePositionerPrivate*>(QDeclarative1BasePositionerPrivate::get(this));
949 //Is allocating the extra QPODVector too much overhead?
950 QPODVector<PositionedItem, 8> visibleItems;//we aren't concerned with invisible items
951 visibleItems.reserve(positionedItems.count());
952 for(int i=0; i<positionedItems.count(); i++)
953 if(positionedItems[i].item && positionedItems[i].isVisible)
954 visibleItems.append(positionedItems[i]);
956 int numVisible = visibleItems.count();
957 if (m_columns <= 0 && m_rows <= 0){
959 r = (numVisible+3)/4;
960 } else if (m_rows <= 0){
961 r = (numVisible+(m_columns-1))/m_columns;
962 } else if (m_columns <= 0){
963 c = (numVisible+(m_rows-1))/m_rows;
967 return; //Nothing to do
969 QList<int> maxColWidth;
970 QList<int> maxRowHeight;
972 if (m_flow == LeftToRight) {
973 for (int i=0; i < r; i++){
974 for (int j=0; j < c; j++){
980 if (childIndex == visibleItems.count())
983 const PositionedItem &child = visibleItems.at(childIndex++);
984 QGraphicsItemPrivate *childPrivate = QGraphicsItemPrivate::get(child.item);
985 if (childPrivate->width() > maxColWidth[j])
986 maxColWidth[j] = childPrivate->width();
987 if (childPrivate->height() > maxRowHeight[i])
988 maxRowHeight[i] = childPrivate->height();
992 for (int j=0; j < c; j++){
993 for (int i=0; i < r; i++){
999 if (childIndex == visibleItems.count())
1002 const PositionedItem &child = visibleItems.at(childIndex++);
1003 QGraphicsItemPrivate *childPrivate = QGraphicsItemPrivate::get(child.item);
1004 if (childPrivate->width() > maxColWidth[j])
1005 maxColWidth[j] = childPrivate->width();
1006 if (childPrivate->height() > maxRowHeight[i])
1007 maxRowHeight[i] = childPrivate->height();
1013 for(int j=0; j < maxColWidth.size(); j++){
1015 widthSum += spacing();
1016 widthSum += maxColWidth[j];
1020 for(int i=0; i < maxRowHeight.size(); i++){
1022 heightSum += spacing();
1023 heightSum += maxRowHeight[i];
1026 contentSize->setHeight(heightSum);
1027 contentSize->setWidth(widthSum);
1036 if(!d->isLeftToRight())
1041 for (int i = 0; i < visibleItems.count(); ++i) {
1042 const PositionedItem &child = visibleItems.at(i);
1043 int childXOffset = xoffset;
1044 if(!d->isLeftToRight())
1045 childXOffset -= QGraphicsItemPrivate::get(child.item)->width();
1046 if((child.item->x()!=childXOffset)||(child.item->y()!=yoffset)){
1047 positionX(childXOffset, child);
1048 positionY(yoffset, child);
1051 if (m_flow == LeftToRight) {
1052 if(d->isLeftToRight())
1053 xoffset+=maxColWidth[curCol]+spacing();
1055 xoffset-=maxColWidth[curCol]+spacing();
1059 yoffset+=maxRowHeight[curRow]+spacing();
1060 if(d->isLeftToRight())
1069 yoffset+=maxRowHeight[curRow]+spacing();
1073 if(d->isLeftToRight())
1074 xoffset+=maxColWidth[curCol]+spacing();
1076 xoffset-=maxColWidth[curCol]+spacing();
1086 void QDeclarative1Grid::reportConflictingAnchors()
1088 QDeclarative1BasePositionerPrivate *d = static_cast<QDeclarative1BasePositionerPrivate*>(QDeclarative1BasePositionerPrivate::get(this));
1089 for (int ii = 0; ii < positionedItems.count(); ++ii) {
1090 const PositionedItem &child = positionedItems.at(ii);
1091 if (child.item && QGraphicsItemPrivate::get(child.item)->isDeclarativeItem) {
1092 QDeclarative1Anchors *anchors = QDeclarativeItemPrivate::get(static_cast<QDeclarativeItem *>(child.item))->_anchors;
1093 if (anchors && (anchors->usedAnchors() || anchors->fill() || anchors->centerIn())) {
1094 d->anchorConflict = true;
1099 if (d->anchorConflict)
1100 qmlInfo(this) << "Cannot specify anchors for items inside Grid";
1104 \qmlclass Flow QDeclarative1Flow
1105 \ingroup qml-positioning-elements
1107 \brief The Flow item arranges its children side by side, wrapping as necessary.
1110 The Flow item positions its child items like words on a page, wrapping them
1111 to create rows or columns of items that do not overlap.
1113 Spacing between items can be added using the \l spacing property.
1114 Transitions can be used for cases where items managed by a Column are
1115 added or moved. These are stored in the \l add and \l move properties
1118 See \l{Using QML Positioner and Repeater Items} for more details about this item and other
1121 \section1 Example Usage
1123 The following example positions \l Text items within a parent item using
1126 \image qml-flow-snippet.png
1128 \snippet doc/src/snippets/declarative/flow.qml flow item
1130 \section1 Using Transitions
1132 Transitions can be used to animate items that are added to, moved within,
1133 or removed from a Flow item. The \l add and \l move properties can be set to
1134 the transitions that will be applied when items are added to, removed from,
1135 or re-positioned within a Flow item.
1137 The use of transitions with positioners is described in more detail in the
1138 \l{Using QML Positioner and Repeater Items#Using Transitions}{Using QML
1139 Positioner and Repeater Items} document.
1141 \section1 Limitations
1143 Note that the positioner assumes that the x and y positions of its children
1144 will not change. If you manually change the x or y properties in script, bind
1145 the x or y properties, use anchors on a child of a positioner, or have the
1146 width or height of a child depend on the position of a child, then the
1147 positioner may exhibit strange behaviour. If you need to perform any of these
1148 actions, consider positioning the items without the use of a Flow.
1150 Items with a width or height of 0 will not be positioned.
1152 \sa Column, Row, Grid, {declarative/positioners}{Positioners example}
1155 \qmlproperty Transition Flow::add
1157 This property holds the transition to be applied when adding an
1158 item to the positioner. The transition will only be applied to the
1159 added item(s). Positioner transitions will only affect the
1160 position (x, y) of items.
1162 For a positioner, adding an item can mean that either the object
1163 has been created or reparented, and thus is now a child or the
1164 positioner, or that the object has had its opacity increased from
1165 zero, and thus is now visible.
1170 \qmlproperty Transition Flow::move
1172 This property holds the transition to be applied when moving an
1173 item within the positioner. Positioner transitions will only affect
1174 the position (x, y) of items.
1176 This transition can be performed when other items are added or removed
1177 from the positioner, or when items resize themselves.
1185 ease: "easeOutBounce"
1191 \sa add, {declarative/positioners}{Positioners example}
1194 \qmlproperty int Flow::spacing
1196 spacing is the amount in pixels left empty between each adjacent
1197 item, and defaults to 0.
1202 class QDeclarative1FlowPrivate : public QDeclarative1BasePositionerPrivate
1204 Q_DECLARE_PUBLIC(QDeclarative1Flow)
1207 QDeclarative1FlowPrivate()
1208 : QDeclarative1BasePositionerPrivate(), flow(QDeclarative1Flow::LeftToRight)
1211 QDeclarative1Flow::Flow flow;
1214 QDeclarative1Flow::QDeclarative1Flow(QDeclarativeItem *parent)
1215 : QDeclarative1BasePositioner(*(new QDeclarative1FlowPrivate), Both, parent)
1217 Q_D(QDeclarative1Flow);
1218 // Flow layout requires relayout if its own size changes too.
1219 d->addItemChangeListener(d, QDeclarativeItemPrivate::Geometry);
1223 \qmlproperty enumeration Flow::flow
1224 This property holds the flow of the layout.
1226 Possible values are:
1229 \o Flow.LeftToRight (default) - Items are positioned next to
1230 to each other according to the \l layoutDirection until the width of the Flow
1231 is exceeded, then wrapped to the next line.
1232 \o Flow.TopToBottom - Items are positioned next to each
1233 other from top to bottom until the height of the Flow is exceeded,
1234 then wrapped to the next column.
1237 QDeclarative1Flow::Flow QDeclarative1Flow::flow() const
1239 Q_D(const QDeclarative1Flow);
1243 void QDeclarative1Flow::setFlow(Flow flow)
1245 Q_D(QDeclarative1Flow);
1246 if (d->flow != flow) {
1254 \qmlproperty enumeration Flow::layoutDirection
1257 This property holds the layout direction of the layout.
1259 Possible values are:
1262 \o Qt.LeftToRight (default) - Items are positioned from the top to bottom,
1263 and left to right. The flow direction is dependent on the
1264 \l Flow::flow property.
1265 \o Qt.RightToLeft - Items are positioned from the top to bottom,
1266 and right to left. The flow direction is dependent on the
1267 \l Flow::flow property.
1270 \sa Grid::layoutDirection, Row::layoutDirection, {declarative/righttoleft/layoutdirection}{Layout directions example}
1273 Qt::LayoutDirection QDeclarative1Flow::layoutDirection() const
1275 Q_D(const QDeclarative1Flow);
1276 return d->layoutDirection;
1279 void QDeclarative1Flow::setLayoutDirection(Qt::LayoutDirection layoutDirection)
1281 Q_D(QDeclarative1Flow);
1282 if (d->layoutDirection != layoutDirection) {
1283 d->layoutDirection = layoutDirection;
1285 emit layoutDirectionChanged();
1286 emit effectiveLayoutDirectionChanged();
1291 \qmlproperty enumeration Flow::effectiveLayoutDirection
1292 This property holds the effective layout direction of the flow positioner.
1294 When using the attached property \l {LayoutMirroring::enabled}{LayoutMirroring::enabled} for locale layouts,
1295 the visual layout direction of the grid positioner will be mirrored. However, the
1296 property \l {Flow::layoutDirection}{layoutDirection} will remain unchanged.
1298 \sa Flow::layoutDirection, {LayoutMirroring}{LayoutMirroring}
1301 Qt::LayoutDirection QDeclarative1Flow::effectiveLayoutDirection() const
1303 return QDeclarative1BasePositionerPrivate::getEffectiveLayoutDirection(this);
1306 void QDeclarative1Flow::doPositioning(QSizeF *contentSize)
1308 Q_D(QDeclarative1Flow);
1313 QList<int> hoffsets;
1315 for (int i = 0; i < positionedItems.count(); ++i) {
1316 const PositionedItem &child = positionedItems.at(i);
1317 if (!child.item || !child.isVisible)
1320 QGraphicsItemPrivate *childPrivate = QGraphicsItemPrivate::get(child.item);
1321 if (d->flow == LeftToRight) {
1322 if (widthValid() && hoffset && hoffset + childPrivate->width() > width()) {
1324 voffset += linemax + spacing();
1328 if (heightValid() && voffset && voffset + childPrivate->height() > height()) {
1330 hoffset += linemax + spacing();
1335 if(d->isLeftToRight()){
1336 if(child.item->x() != hoffset)
1337 positionX(hoffset, child);
1339 hoffsets << hoffset;
1341 if(child.item->y() != voffset)
1342 positionY(voffset, child);
1344 contentSize->setWidth(qMax(contentSize->width(), hoffset + childPrivate->width()));
1345 contentSize->setHeight(qMax(contentSize->height(), voffset + childPrivate->height()));
1347 if (d->flow == LeftToRight) {
1348 hoffset += childPrivate->width();
1349 hoffset += spacing();
1350 linemax = qMax(linemax, qCeil(childPrivate->height()));
1352 voffset += childPrivate->height();
1353 voffset += spacing();
1354 linemax = qMax(linemax, qCeil(childPrivate->width()));
1358 if(d->isLeftToRight())
1365 end = contentSize->width();
1367 for (int i = 0; i < positionedItems.count(); ++i) {
1368 const PositionedItem &child = positionedItems.at(i);
1369 if (!child.item || !child.isVisible)
1371 hoffset = end - hoffsets[acc++] - QGraphicsItemPrivate::get(child.item)->width();
1372 if(child.item->x() != hoffset)
1373 positionX(hoffset, child);
1377 void QDeclarative1Flow::reportConflictingAnchors()
1379 Q_D(QDeclarative1Flow);
1380 for (int ii = 0; ii < positionedItems.count(); ++ii) {
1381 const PositionedItem &child = positionedItems.at(ii);
1382 if (child.item && QGraphicsItemPrivate::get(child.item)->isDeclarativeItem) {
1383 QDeclarative1Anchors *anchors = QDeclarativeItemPrivate::get(static_cast<QDeclarativeItem *>(child.item))->_anchors;
1384 if (anchors && (anchors->usedAnchors() || anchors->fill() || anchors->centerIn())) {
1385 d->anchorConflict = true;
1390 if (d->anchorConflict)
1391 qmlInfo(this) << "Cannot specify anchors for items inside Flow";