1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtDeclarative module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** 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 \inqmlmodule QtQuick 1
329 \ingroup qml-positioning-elements
331 \brief The Column item arranges its children vertically.
334 The Column item positions its child items so that they are vertically
335 aligned and not overlapping.
337 Spacing between items can be added using the \l spacing property.
338 Transitions can be used for cases where items managed by a Column are
339 added or moved. These are stored in the \l add and \l move properties
342 See \l{Using QML Positioner and Repeater Items} for more details about this item and other
345 \section1 Example Usage
347 The following example positions differently shaped rectangles using a Column
350 \image verticalpositioner_example.png
352 \snippet doc/src/snippets/qtquick1/column/vertical-positioner.qml document
354 \section1 Using Transitions
356 Transitions can be used to animate items that are added to, moved within,
357 or removed from a Column item. The \l add and \l move properties can be set to
358 the transitions that will be applied when items are added to, removed from,
359 or re-positioned within a Column item.
361 The use of transitions with positioners is described in more detail in the
362 \l{Using QML Positioner and Repeater Items#Using Transitions}{Using QML
363 Positioner and Repeater Items} document.
365 \image verticalpositioner_transition.gif
371 // Define an animation for adding a new item...
374 // Define an animation for moving items within the column...
380 \section1 Limitations
382 Note that the positioner assumes that the x and y positions of its children
383 will not change. If you manually change the x or y properties in script, bind
384 the x or y properties, use anchors on a child of a positioner, or have the
385 height of a child depend on the position of a child, then the
386 positioner may exhibit strange behavior. If you need to perform any of these
387 actions, consider positioning the items without the use of a Column.
389 Items with a width or height of 0 will not be positioned.
391 \sa Row, Grid, Flow, {declarative/positioners}{Positioners example}
394 \qmlproperty Transition QtQuick1::Column::add
396 This property holds the transition to be applied when adding an
397 item to the positioner. The transition will only be applied to the
398 added item(s). Positioner transitions will only affect the
399 position (x, y) of items.
401 For a positioner, adding an item can mean that either the object
402 has been created or reparented, and thus is now a child or the
403 positioner, or that the object has had its opacity increased from
404 zero, and thus is now visible.
409 \qmlproperty Transition QtQuick1::Column::move
411 This property holds the transition to apply when moving an item
412 within the positioner. Positioner transitions will only affect
413 the position (x, y) of items.
415 This transition can be performed when other items are added or removed
416 from the positioner, or when items resize themselves.
418 \image positioner-move.gif
431 \sa add, {declarative/positioners}{Positioners example}
434 \qmlproperty int QtQuick1::Column::spacing
436 The spacing is the amount in pixels left empty between adjacent
437 items. The default spacing is 0.
441 QDeclarative1Column::QDeclarative1Column(QDeclarativeItem *parent)
442 : QDeclarative1BasePositioner(Vertical, parent)
446 void QDeclarative1Column::doPositioning(QSizeF *contentSize)
450 for (int ii = 0; ii < positionedItems.count(); ++ii) {
451 const PositionedItem &child = positionedItems.at(ii);
452 if (!child.item || !child.isVisible)
455 if(child.item->y() != voffset)
456 positionY(voffset, child);
458 contentSize->setWidth(qMax(contentSize->width(), QGraphicsItemPrivate::get(child.item)->width()));
460 voffset += QGraphicsItemPrivate::get(child.item)->height();
461 voffset += spacing();
464 contentSize->setHeight(voffset - spacing());
467 void QDeclarative1Column::reportConflictingAnchors()
469 QDeclarative1BasePositionerPrivate *d = static_cast<QDeclarative1BasePositionerPrivate*>(QDeclarative1BasePositionerPrivate::get(this));
470 for (int ii = 0; ii < positionedItems.count(); ++ii) {
471 const PositionedItem &child = positionedItems.at(ii);
472 if (child.item && QGraphicsItemPrivate::get(child.item)->isDeclarativeItem) {
473 QDeclarative1Anchors *anchors = QDeclarativeItemPrivate::get(static_cast<QDeclarativeItem *>(child.item))->_anchors;
475 QDeclarative1Anchors::Anchors usedAnchors = anchors->usedAnchors();
476 if (usedAnchors & QDeclarative1Anchors::TopAnchor ||
477 usedAnchors & QDeclarative1Anchors::BottomAnchor ||
478 usedAnchors & QDeclarative1Anchors::VCenterAnchor ||
479 anchors->fill() || anchors->centerIn()) {
480 d->anchorConflict = true;
486 if (d->anchorConflict) {
487 qmlInfo(this) << "Cannot specify top, bottom, verticalCenter, fill or centerIn anchors for items inside Column";
492 \qmlclass Row QDeclarative1Row
493 \inqmlmodule QtQuick 1
494 \ingroup qml-positioning-elements
496 \brief The Row item arranges its children horizontally.
499 The Row item positions its child items so that they are horizontally
500 aligned and not overlapping.
502 Use \l spacing to set the spacing between items in a Row, and use the
503 \l add and \l move properties to set the transitions that should be applied
504 when items are added to, removed from, or re-positioned within the Row.
506 See \l{Using QML Positioner and Repeater Items} for more details about this item and other
509 \section1 Example Usage
511 The following example lays out differently shaped rectangles using a Row.
513 \image horizontalpositioner_example.png
515 \snippet doc/src/snippets/qtquick1/row/row.qml document
517 \section1 Using Transitions
519 Transitions can be used to animate items that are added to, moved within,
520 or removed from a Grid item. The \l add and \l move properties can be set to
521 the transitions that will be applied when items are added to, removed from,
522 or re-positioned within a Row item.
524 \section1 Limitations
526 Note that the positioner assumes that the x and y positions of its children
527 will not change. If you manually change the x or y properties in script, bind
528 the x or y properties, use anchors on a child of a positioner, or have the
529 width of a child depend on the position of a child, then the
530 positioner may exhibit strange behaviour. If you need to perform any of these
531 actions, consider positioning the items without the use of a Row.
533 Items with a width or height of 0 will not be positioned.
535 \sa Column, Grid, Flow, {declarative/positioners}{Positioners example}
538 \qmlproperty Transition QtQuick1::Row::add
540 This property holds the transition to be applied when adding an
541 item to the positioner. The transition will only be applied to the
542 added item(s). Positioner transitions will only affect the
543 position (x, y) of items.
545 For a positioner, adding an item can mean that either the object
546 has been created or reparented, and thus is now a child or the
547 positioner, or that the object has had its opacity increased from
548 zero, and thus is now visible.
553 \qmlproperty Transition QtQuick1::Row::move
555 This property holds the transition to be applied when moving an
556 item within the positioner. Positioner transitions will only affect
557 the position (x, y) of items.
559 This transition can be performed when other items are added or removed
560 from the positioner, or when items resize themselves.
574 \sa add, {declarative/positioners}{Positioners example}
577 \qmlproperty int QtQuick1::Row::spacing
579 The spacing is the amount in pixels left empty between adjacent
580 items. The default spacing is 0.
584 QDeclarative1Row::QDeclarative1Row(QDeclarativeItem *parent)
585 : QDeclarative1BasePositioner(Horizontal, parent)
590 \qmlproperty enumeration QtQuick1::Row::layoutDirection
593 This property holds the layoutDirection of the row.
598 \o Qt.LeftToRight (default) - Items are laid out from left to right. If the width of the row is explicitly set,
599 the left anchor remains to the left of the row.
600 \o Qt.RightToLeft - Items are laid out from right to left. If the width of the row is explicitly set,
601 the right anchor remains to the right of the row.
604 \sa Grid::layoutDirection, Flow::layoutDirection, {declarative/righttoleft/layoutdirection}{Layout directions example}
606 Qt::LayoutDirection QDeclarative1Row::layoutDirection() const
608 return QDeclarative1BasePositionerPrivate::getLayoutDirection(this);
611 void QDeclarative1Row::setLayoutDirection(Qt::LayoutDirection layoutDirection)
613 QDeclarative1BasePositionerPrivate *d = static_cast<QDeclarative1BasePositionerPrivate* >(QDeclarative1BasePositionerPrivate::get(this));
614 if (d->layoutDirection != layoutDirection) {
615 d->layoutDirection = layoutDirection;
616 // For RTL layout the positioning changes when the width changes.
617 if (d->layoutDirection == Qt::RightToLeft)
618 d->addItemChangeListener(d, QDeclarativeItemPrivate::Geometry);
620 d->removeItemChangeListener(d, QDeclarativeItemPrivate::Geometry);
622 emit layoutDirectionChanged();
623 emit effectiveLayoutDirectionChanged();
628 \qmlproperty enumeration QtQuick1::Row::effectiveLayoutDirection
629 This property holds the effective layout direction of the row positioner.
631 When using the attached property \l {LayoutMirroring::enabled}{LayoutMirroring::enabled} for locale layouts,
632 the visual layout direction of the row positioner will be mirrored. However, the
633 property \l {Row::layoutDirection}{layoutDirection} will remain unchanged.
635 \sa Row::layoutDirection, {LayoutMirroring}{LayoutMirroring}
638 Qt::LayoutDirection QDeclarative1Row::effectiveLayoutDirection() const
640 return QDeclarative1BasePositionerPrivate::getEffectiveLayoutDirection(this);
643 void QDeclarative1Row::doPositioning(QSizeF *contentSize)
645 QDeclarative1BasePositionerPrivate *d = static_cast<QDeclarative1BasePositionerPrivate*>(QDeclarative1BasePositionerPrivate::get(this));
649 for (int ii = 0; ii < positionedItems.count(); ++ii) {
650 const PositionedItem &child = positionedItems.at(ii);
651 if (!child.item || !child.isVisible)
654 if(d->isLeftToRight()){
655 if(child.item->x() != hoffset)
656 positionX(hoffset, child);
661 contentSize->setHeight(qMax(contentSize->height(), QGraphicsItemPrivate::get(child.item)->height()));
663 hoffset += QGraphicsItemPrivate::get(child.item)->width();
664 hoffset += spacing();
667 contentSize->setWidth(hoffset - spacing());
669 if(d->isLeftToRight())
672 //Right to Left layout
675 end = contentSize->width();
680 for (int ii = 0; ii < positionedItems.count(); ++ii) {
681 const PositionedItem &child = positionedItems.at(ii);
682 if (!child.item || !child.isVisible)
684 hoffset = end - hoffsets[acc++] - QGraphicsItemPrivate::get(child.item)->width();
685 if(child.item->x() != hoffset)
686 positionX(hoffset, child);
690 void QDeclarative1Row::reportConflictingAnchors()
692 QDeclarative1BasePositionerPrivate *d = static_cast<QDeclarative1BasePositionerPrivate*>(QDeclarative1BasePositionerPrivate::get(this));
693 for (int ii = 0; ii < positionedItems.count(); ++ii) {
694 const PositionedItem &child = positionedItems.at(ii);
695 if (child.item && QGraphicsItemPrivate::get(child.item)->isDeclarativeItem) {
696 QDeclarative1Anchors *anchors = QDeclarativeItemPrivate::get(static_cast<QDeclarativeItem *>(child.item))->_anchors;
698 QDeclarative1Anchors::Anchors usedAnchors = anchors->usedAnchors();
699 if (usedAnchors & QDeclarative1Anchors::LeftAnchor ||
700 usedAnchors & QDeclarative1Anchors::RightAnchor ||
701 usedAnchors & QDeclarative1Anchors::HCenterAnchor ||
702 anchors->fill() || anchors->centerIn()) {
703 d->anchorConflict = true;
709 if (d->anchorConflict)
710 qmlInfo(this) << "Cannot specify left, right, horizontalCenter, fill or centerIn anchors for items inside Row";
714 \qmlclass Grid QDeclarative1Grid
715 \inqmlmodule QtQuick 1
716 \ingroup qml-positioning-elements
718 \brief The Grid item positions its children in a grid.
721 The Grid item positions its child items so that they are
722 aligned in a grid and are not overlapping.
724 The grid positioner calculates a grid of rectangular cells of sufficient
725 size to hold all items, placing the items in the cells, from left to right
726 and top to bottom. Each item is positioned in the top-left corner of its
727 cell with position (0, 0).
729 A Grid defaults to four columns, and as many rows as are necessary to
730 fit all child items. The number of rows and columns can be constrained
731 by setting the \l rows and \l columns properties.
733 Spacing can be added between child items by setting the \l spacing
734 property. The amount of spacing applied will be the same in the
735 horizontal and vertical directions.
737 See \l{Using QML Positioner and Repeater Items} for more details about this item and other
740 \section1 Example Usage
742 The following example demonstrates this.
744 \image gridLayout_example.png
746 \snippet doc/src/snippets/qtquick1/grid/grid.qml document
748 \section1 Using Transitions
750 Transitions can be used to animate items that are added to, moved within,
751 or removed from a Grid item. The \l add and \l move properties can be set to
752 the transitions that will be applied when items are added to, removed from,
753 or re-positioned within a Grid item.
755 \section1 Limitations
757 Note that the positioner assumes that the x and y positions of its children
758 will not change. If you manually change the x or y properties in script, bind
759 the x or y properties, use anchors on a child of a positioner, or have the
760 width or height of a child depend on the position of a child, then the
761 positioner may exhibit strange behaviour. If you need to perform any of these
762 actions, consider positioning the items without the use of a Grid.
764 Items with a width or height of 0 will not be positioned.
766 \sa Flow, Row, Column, {declarative/positioners}{Positioners example}
769 \qmlproperty Transition QtQuick1::Grid::add
771 This property holds the transition to be applied when adding an
772 item to the positioner. The transition will only be applied to the
773 added item(s). Positioner transitions will only affect the
774 position (x, y) of items.
776 For a positioner, adding an item can mean that either the object
777 has been created or reparented, and thus is now a child or the
778 positioner, or that the object has had its opacity increased from
779 zero, and thus is now visible.
784 \qmlproperty Transition QtQuick1::Grid::move
786 This property holds the transition to be applied when moving an
787 item within the positioner. Positioner transitions will only affect
788 the position (x, y) of items.
790 This transition can be performed when other items are added or removed
791 from the positioner, or when items resize themselves.
804 \sa add, {declarative/positioners}{Positioners example}
807 \qmlproperty int QtQuick1::Grid::spacing
809 The spacing is the amount in pixels left empty between adjacent
810 items. The default spacing is 0.
812 The below example places a Grid containing a red, a blue and a
813 green rectangle on a gray background. The area the grid positioner
814 occupies is colored white. The positioner on the left has the
815 no spacing (the default), and the positioner on the right has
818 \inlineimage qml-grid-no-spacing.png
819 \inlineimage qml-grid-spacing.png
823 QDeclarative1Grid::QDeclarative1Grid(QDeclarativeItem *parent) :
824 QDeclarative1BasePositioner(Both, parent), m_rows(-1), m_columns(-1), m_flow(LeftToRight)
829 \qmlproperty int QtQuick1::Grid::columns
831 This property holds the number of columns in the grid. The default
832 number of columns is 4.
834 If the grid does not have enough items to fill the specified
835 number of columns, some columns will be of zero width.
839 \qmlproperty int QtQuick1::Grid::rows
840 This property holds the number of rows in the grid.
842 If the grid does not have enough items to fill the specified
843 number of rows, some rows will be of zero width.
846 void QDeclarative1Grid::setColumns(const int columns)
848 if (columns == m_columns)
852 emit columnsChanged();
855 void QDeclarative1Grid::setRows(const int rows)
865 \qmlproperty enumeration QtQuick1::Grid::flow
866 This property holds the flow of the layout.
871 \o Grid.LeftToRight (default) - Items are positioned next to
872 each other in the \l layoutDirection, then wrapped to the next line.
873 \o Grid.TopToBottom - Items are positioned next to each
874 other from top to bottom, then wrapped to the next column.
877 QDeclarative1Grid::Flow QDeclarative1Grid::flow() const
882 void QDeclarative1Grid::setFlow(Flow flow)
884 if (m_flow != flow) {
892 \qmlproperty enumeration QtQuick1::Grid::layoutDirection
895 This property holds the layout direction of the layout.
900 \o Qt.LeftToRight (default) - Items are positioned from the top to bottom,
901 and left to right. The flow direction is dependent on the
902 \l Grid::flow property.
903 \o Qt.RightToLeft - Items are positioned from the top to bottom,
904 and right to left. The flow direction is dependent on the
905 \l Grid::flow property.
908 \sa Flow::layoutDirection, Row::layoutDirection, {declarative/righttoleft/layoutdirection}{Layout directions example}
910 Qt::LayoutDirection QDeclarative1Grid::layoutDirection() const
912 return QDeclarative1BasePositionerPrivate::getLayoutDirection(this);
915 void QDeclarative1Grid::setLayoutDirection(Qt::LayoutDirection layoutDirection)
917 QDeclarative1BasePositionerPrivate *d = static_cast<QDeclarative1BasePositionerPrivate*>(QDeclarative1BasePositionerPrivate::get(this));
918 if (d->layoutDirection != layoutDirection) {
919 d->layoutDirection = layoutDirection;
920 // For RTL layout the positioning changes when the width changes.
921 if (d->layoutDirection == Qt::RightToLeft)
922 d->addItemChangeListener(d, QDeclarativeItemPrivate::Geometry);
924 d->removeItemChangeListener(d, QDeclarativeItemPrivate::Geometry);
926 emit layoutDirectionChanged();
927 emit effectiveLayoutDirectionChanged();
932 \qmlproperty enumeration QtQuick1::Grid::effectiveLayoutDirection
933 This property holds the effective layout direction of the grid positioner.
935 When using the attached property \l {LayoutMirroring::enabled}{LayoutMirroring::enabled} for locale layouts,
936 the visual layout direction of the grid positioner will be mirrored. However, the
937 property \l {Grid::layoutDirection}{layoutDirection} will remain unchanged.
939 \sa Grid::layoutDirection, {LayoutMirroring}{LayoutMirroring}
942 Qt::LayoutDirection QDeclarative1Grid::effectiveLayoutDirection() const
944 return QDeclarative1BasePositionerPrivate::getEffectiveLayoutDirection(this);
947 void QDeclarative1Grid::doPositioning(QSizeF *contentSize)
949 QDeclarative1BasePositionerPrivate *d = static_cast<QDeclarative1BasePositionerPrivate*>(QDeclarative1BasePositionerPrivate::get(this));
952 //Is allocating the extra QPODVector too much overhead?
953 QPODVector<PositionedItem, 8> visibleItems;//we aren't concerned with invisible items
954 visibleItems.reserve(positionedItems.count());
955 for(int i=0; i<positionedItems.count(); i++)
956 if(positionedItems[i].item && positionedItems[i].isVisible)
957 visibleItems.append(positionedItems[i]);
959 int numVisible = visibleItems.count();
960 if (m_columns <= 0 && m_rows <= 0){
962 r = (numVisible+3)/4;
963 } else if (m_rows <= 0){
964 r = (numVisible+(m_columns-1))/m_columns;
965 } else if (m_columns <= 0){
966 c = (numVisible+(m_rows-1))/m_rows;
970 return; //Nothing to do
972 QList<int> maxColWidth;
973 QList<int> maxRowHeight;
975 if (m_flow == LeftToRight) {
976 for (int i=0; i < r; i++){
977 for (int j=0; j < c; j++){
983 if (childIndex == visibleItems.count())
986 const PositionedItem &child = visibleItems.at(childIndex++);
987 QGraphicsItemPrivate *childPrivate = QGraphicsItemPrivate::get(child.item);
988 if (childPrivate->width() > maxColWidth[j])
989 maxColWidth[j] = childPrivate->width();
990 if (childPrivate->height() > maxRowHeight[i])
991 maxRowHeight[i] = childPrivate->height();
995 for (int j=0; j < c; j++){
996 for (int i=0; i < r; i++){
1002 if (childIndex == visibleItems.count())
1005 const PositionedItem &child = visibleItems.at(childIndex++);
1006 QGraphicsItemPrivate *childPrivate = QGraphicsItemPrivate::get(child.item);
1007 if (childPrivate->width() > maxColWidth[j])
1008 maxColWidth[j] = childPrivate->width();
1009 if (childPrivate->height() > maxRowHeight[i])
1010 maxRowHeight[i] = childPrivate->height();
1016 for(int j=0; j < maxColWidth.size(); j++){
1018 widthSum += spacing();
1019 widthSum += maxColWidth[j];
1023 for(int i=0; i < maxRowHeight.size(); i++){
1025 heightSum += spacing();
1026 heightSum += maxRowHeight[i];
1029 contentSize->setHeight(heightSum);
1030 contentSize->setWidth(widthSum);
1039 if(!d->isLeftToRight())
1044 for (int i = 0; i < visibleItems.count(); ++i) {
1045 const PositionedItem &child = visibleItems.at(i);
1046 int childXOffset = xoffset;
1047 if(!d->isLeftToRight())
1048 childXOffset -= QGraphicsItemPrivate::get(child.item)->width();
1049 if((child.item->x()!=childXOffset)||(child.item->y()!=yoffset)){
1050 positionX(childXOffset, child);
1051 positionY(yoffset, child);
1054 if (m_flow == LeftToRight) {
1055 if(d->isLeftToRight())
1056 xoffset+=maxColWidth[curCol]+spacing();
1058 xoffset-=maxColWidth[curCol]+spacing();
1062 yoffset+=maxRowHeight[curRow]+spacing();
1063 if(d->isLeftToRight())
1072 yoffset+=maxRowHeight[curRow]+spacing();
1076 if(d->isLeftToRight())
1077 xoffset+=maxColWidth[curCol]+spacing();
1079 xoffset-=maxColWidth[curCol]+spacing();
1089 void QDeclarative1Grid::reportConflictingAnchors()
1091 QDeclarative1BasePositionerPrivate *d = static_cast<QDeclarative1BasePositionerPrivate*>(QDeclarative1BasePositionerPrivate::get(this));
1092 for (int ii = 0; ii < positionedItems.count(); ++ii) {
1093 const PositionedItem &child = positionedItems.at(ii);
1094 if (child.item && QGraphicsItemPrivate::get(child.item)->isDeclarativeItem) {
1095 QDeclarative1Anchors *anchors = QDeclarativeItemPrivate::get(static_cast<QDeclarativeItem *>(child.item))->_anchors;
1096 if (anchors && (anchors->usedAnchors() || anchors->fill() || anchors->centerIn())) {
1097 d->anchorConflict = true;
1102 if (d->anchorConflict)
1103 qmlInfo(this) << "Cannot specify anchors for items inside Grid";
1107 \qmlclass Flow QDeclarative1Flow
1108 \inqmlmodule QtQuick 1
1109 \ingroup qml-positioning-elements
1111 \brief The Flow item arranges its children side by side, wrapping as necessary.
1114 The Flow item positions its child items like words on a page, wrapping them
1115 to create rows or columns of items that do not overlap.
1117 Spacing between items can be added using the \l spacing property.
1118 Transitions can be used for cases where items managed by a Column are
1119 added or moved. These are stored in the \l add and \l move properties
1122 See \l{Using QML Positioner and Repeater Items} for more details about this item and other
1125 \section1 Example Usage
1127 The following example positions \l Text items within a parent item using
1130 \image qml-flow-snippet.png
1132 \snippet doc/src/snippets/qtquick1/flow.qml flow item
1134 \section1 Using Transitions
1136 Transitions can be used to animate items that are added to, moved within,
1137 or removed from a Flow item. The \l add and \l move properties can be set to
1138 the transitions that will be applied when items are added to, removed from,
1139 or re-positioned within a Flow item.
1141 The use of transitions with positioners is described in more detail in the
1142 \l{Using QML Positioner and Repeater Items#Using Transitions}{Using QML
1143 Positioner and Repeater Items} document.
1145 \section1 Limitations
1147 Note that the positioner assumes that the x and y positions of its children
1148 will not change. If you manually change the x or y properties in script, bind
1149 the x or y properties, use anchors on a child of a positioner, or have the
1150 width or height of a child depend on the position of a child, then the
1151 positioner may exhibit strange behaviour. If you need to perform any of these
1152 actions, consider positioning the items without the use of a Flow.
1154 Items with a width or height of 0 will not be positioned.
1156 \sa Column, Row, Grid, {declarative/positioners}{Positioners example}
1159 \qmlproperty Transition QtQuick1::Flow::add
1161 This property holds the transition to be applied when adding an
1162 item to the positioner. The transition will only be applied to the
1163 added item(s). Positioner transitions will only affect the
1164 position (x, y) of items.
1166 For a positioner, adding an item can mean that either the object
1167 has been created or reparented, and thus is now a child or the
1168 positioner, or that the object has had its opacity increased from
1169 zero, and thus is now visible.
1174 \qmlproperty Transition QtQuick1::Flow::move
1176 This property holds the transition to be applied when moving an
1177 item within the positioner. Positioner transitions will only affect
1178 the position (x, y) of items.
1180 This transition can be performed when other items are added or removed
1181 from the positioner, or when items resize themselves.
1189 ease: "easeOutBounce"
1195 \sa add, {declarative/positioners}{Positioners example}
1198 \qmlproperty int QtQuick1::Flow::spacing
1200 spacing is the amount in pixels left empty between each adjacent
1201 item, and defaults to 0.
1206 class QDeclarative1FlowPrivate : public QDeclarative1BasePositionerPrivate
1208 Q_DECLARE_PUBLIC(QDeclarative1Flow)
1211 QDeclarative1FlowPrivate()
1212 : QDeclarative1BasePositionerPrivate(), flow(QDeclarative1Flow::LeftToRight)
1215 QDeclarative1Flow::Flow flow;
1218 QDeclarative1Flow::QDeclarative1Flow(QDeclarativeItem *parent)
1219 : QDeclarative1BasePositioner(*(new QDeclarative1FlowPrivate), Both, parent)
1221 Q_D(QDeclarative1Flow);
1222 // Flow layout requires relayout if its own size changes too.
1223 d->addItemChangeListener(d, QDeclarativeItemPrivate::Geometry);
1227 \qmlproperty enumeration QtQuick1::Flow::flow
1228 This property holds the flow of the layout.
1230 Possible values are:
1233 \o Flow.LeftToRight (default) - Items are positioned next to
1234 to each other according to the \l layoutDirection until the width of the Flow
1235 is exceeded, then wrapped to the next line.
1236 \o Flow.TopToBottom - Items are positioned next to each
1237 other from top to bottom until the height of the Flow is exceeded,
1238 then wrapped to the next column.
1241 QDeclarative1Flow::Flow QDeclarative1Flow::flow() const
1243 Q_D(const QDeclarative1Flow);
1247 void QDeclarative1Flow::setFlow(Flow flow)
1249 Q_D(QDeclarative1Flow);
1250 if (d->flow != flow) {
1258 \qmlproperty enumeration QtQuick1::Flow::layoutDirection
1261 This property holds the layout direction of the layout.
1263 Possible values are:
1266 \o Qt.LeftToRight (default) - Items are positioned from the top to bottom,
1267 and left to right. The flow direction is dependent on the
1268 \l Flow::flow property.
1269 \o Qt.RightToLeft - Items are positioned from the top to bottom,
1270 and right to left. The flow direction is dependent on the
1271 \l Flow::flow property.
1274 \sa Grid::layoutDirection, Row::layoutDirection, {declarative/righttoleft/layoutdirection}{Layout directions example}
1277 Qt::LayoutDirection QDeclarative1Flow::layoutDirection() const
1279 Q_D(const QDeclarative1Flow);
1280 return d->layoutDirection;
1283 void QDeclarative1Flow::setLayoutDirection(Qt::LayoutDirection layoutDirection)
1285 Q_D(QDeclarative1Flow);
1286 if (d->layoutDirection != layoutDirection) {
1287 d->layoutDirection = layoutDirection;
1289 emit layoutDirectionChanged();
1290 emit effectiveLayoutDirectionChanged();
1295 \qmlproperty enumeration QtQuick1::Flow::effectiveLayoutDirection
1296 This property holds the effective layout direction of the flow positioner.
1298 When using the attached property \l {LayoutMirroring::enabled}{LayoutMirroring::enabled} for locale layouts,
1299 the visual layout direction of the grid positioner will be mirrored. However, the
1300 property \l {Flow::layoutDirection}{layoutDirection} will remain unchanged.
1302 \sa Flow::layoutDirection, {LayoutMirroring}{LayoutMirroring}
1305 Qt::LayoutDirection QDeclarative1Flow::effectiveLayoutDirection() const
1307 return QDeclarative1BasePositionerPrivate::getEffectiveLayoutDirection(this);
1310 void QDeclarative1Flow::doPositioning(QSizeF *contentSize)
1312 Q_D(QDeclarative1Flow);
1317 QList<int> hoffsets;
1319 for (int i = 0; i < positionedItems.count(); ++i) {
1320 const PositionedItem &child = positionedItems.at(i);
1321 if (!child.item || !child.isVisible)
1324 QGraphicsItemPrivate *childPrivate = QGraphicsItemPrivate::get(child.item);
1325 if (d->flow == LeftToRight) {
1326 if (widthValid() && hoffset && hoffset + childPrivate->width() > width()) {
1328 voffset += linemax + spacing();
1332 if (heightValid() && voffset && voffset + childPrivate->height() > height()) {
1334 hoffset += linemax + spacing();
1339 if(d->isLeftToRight()){
1340 if(child.item->x() != hoffset)
1341 positionX(hoffset, child);
1343 hoffsets << hoffset;
1345 if(child.item->y() != voffset)
1346 positionY(voffset, child);
1348 contentSize->setWidth(qMax(contentSize->width(), hoffset + childPrivate->width()));
1349 contentSize->setHeight(qMax(contentSize->height(), voffset + childPrivate->height()));
1351 if (d->flow == LeftToRight) {
1352 hoffset += childPrivate->width();
1353 hoffset += spacing();
1354 linemax = qMax(linemax, qCeil(childPrivate->height()));
1356 voffset += childPrivate->height();
1357 voffset += spacing();
1358 linemax = qMax(linemax, qCeil(childPrivate->width()));
1362 if(d->isLeftToRight())
1369 end = contentSize->width();
1371 for (int i = 0; i < positionedItems.count(); ++i) {
1372 const PositionedItem &child = positionedItems.at(i);
1373 if (!child.item || !child.isVisible)
1375 hoffset = end - hoffsets[acc++] - QGraphicsItemPrivate::get(child.item)->width();
1376 if(child.item->x() != hoffset)
1377 positionX(hoffset, child);
1381 void QDeclarative1Flow::reportConflictingAnchors()
1383 Q_D(QDeclarative1Flow);
1384 for (int ii = 0; ii < positionedItems.count(); ++ii) {
1385 const PositionedItem &child = positionedItems.at(ii);
1386 if (child.item && QGraphicsItemPrivate::get(child.item)->isDeclarativeItem) {
1387 QDeclarative1Anchors *anchors = QDeclarativeItemPrivate::get(static_cast<QDeclarativeItem *>(child.item))->_anchors;
1388 if (anchors && (anchors->usedAnchors() || anchors->fill() || anchors->centerIn())) {
1389 d->anchorConflict = true;
1394 if (d->anchorConflict)
1395 qmlInfo(this) << "Cannot specify anchors for items inside Flow";