Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qquickpositioners.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
7
8#include <QtQml/qqml.h>
9#include <QtQml/qqmlinfo.h>
10#include <QtCore/qcoreapplication.h>
11
12#include <QtQuick/private/qquicktransition_p.h>
13
14#include <algorithm>
15
17
19 = QQuickItemPrivate::Geometry
20 | QQuickItemPrivate::SiblingOrder
21 | QQuickItemPrivate::Visibility
22 | QQuickItemPrivate::Destroyed;
23
25{
26 QQuickItemPrivate *otherPrivate = QQuickItemPrivate::get(other);
27 otherPrivate->addItemChangeListener(this, positionerWatchedChanges);
28}
29
31{
32 QQuickItemPrivate *otherPrivate = QQuickItemPrivate::get(other);
33 otherPrivate->removeItemChangeListener(this, positionerWatchedChanges);
34}
35
36
37QQuickBasePositioner::PositionedItem::PositionedItem(QQuickItem *i)
38 : item(i)
39#if QT_CONFIG(quick_viewtransitions)
40 , transitionableItem(nullptr)
41#endif
42 , index(-1)
43 , isNew(false)
44 , isVisible(true)
45 , topPadding(0)
46 , leftPadding(0)
47 , rightPadding(0)
48 , bottomPadding(0)
49{
50}
51
52qreal QQuickBasePositioner::PositionedItem::itemX() const
53{
54 return
55#if QT_CONFIG(quick_viewtransitions)
56 transitionableItem ? transitionableItem->itemX() :
57#endif
58 item->x();
59}
60
61qreal QQuickBasePositioner::PositionedItem::itemY() const
62{
63 return
64#if QT_CONFIG(quick_viewtransitions)
65 transitionableItem ? transitionableItem->itemY() :
66#endif
67 item->y();
68}
69
70void QQuickBasePositioner::PositionedItem::moveTo(const QPointF &pos)
71{
72#if QT_CONFIG(quick_viewtransitions)
73 if (transitionableItem)
74 transitionableItem->moveTo(pos);
75 else
76#endif
77 item->setPosition(pos);
78}
79
80#if QT_CONFIG(quick_viewtransitions)
81void QQuickBasePositioner::PositionedItem::transitionNextReposition(QQuickItemViewTransitioner *transitioner, QQuickItemViewTransitioner::TransitionType type, bool asTarget)
82{
83 if (!transitioner)
84 return;
85 if (!transitionableItem)
86 transitionableItem = std::make_unique<QQuickItemViewTransitionableItem>(item);
87 transitioner->transitionNextReposition(transitionableItem.get(), type, asTarget);
88}
89
90bool QQuickBasePositioner::PositionedItem::prepareTransition(QQuickItemViewTransitioner *transitioner, const QRectF &viewBounds)
91{
92 return transitionableItem ? transitionableItem->prepareTransition(transitioner, index, viewBounds) : false;
93}
94
95void QQuickBasePositioner::PositionedItem::startTransition(QQuickItemViewTransitioner *transitioner)
96{
97 if (transitionableItem)
98 transitionableItem->startTransition(transitioner, index);
99}
100#endif
101
102void QQuickBasePositioner::PositionedItem::updatePadding(qreal lp, qreal tp, qreal rp, qreal bp)
103{
104 leftPadding = lp;
105 topPadding = tp;
106 rightPadding = rp;
107 bottomPadding = bp;
108}
109
110QQuickBasePositioner::QQuickBasePositioner(PositionerType at, QQuickItem *parent)
111 : QQuickImplicitSizeItem(*(new QQuickBasePositionerPrivate), parent)
112{
113 Q_D(QQuickBasePositioner);
114 d->init(at);
115}
116/*!
117 \internal
118 \class QQuickBasePositioner
119 \brief For specifying a base for QQuickGraphics layouts
120
121 To create a QQuickGraphics Positioner, simply subclass QQuickBasePositioner and implement
122 doLayout(), which is automatically called when the layout might need
123 updating. In doLayout() use the setX and setY functions from QQuickBasePositioner, and the
124 base class will apply the positions along with the appropriate transitions. The items to
125 position are provided in order as the protected member positionedItems.
126
127 You also need to set a PositionerType, to declare whether you are positioning the x, y or both
128 for the child items. Depending on the chosen type, only x or y changes will be applied.
129
130 Note that the subclass is responsible for adding the spacing in between items.
131
132 Positioning is batched and synchronized with painting to reduce the number of
133 calculations needed. This means that positioners may not reposition items immediately
134 when changes occur, but it will have moved by the next frame.
135*/
136
137QQuickBasePositioner::QQuickBasePositioner(QQuickBasePositionerPrivate &dd, PositionerType at, QQuickItem *parent)
138 : QQuickImplicitSizeItem(dd, parent)
139{
140 Q_D(QQuickBasePositioner);
141 d->init(at);
142}
143
144QQuickBasePositioner::~QQuickBasePositioner()
145{
146 Q_D(QQuickBasePositioner);
147#if QT_CONFIG(quick_viewtransitions)
148 delete d->transitioner;
149#endif
150 for (const PositionedItem &pi : positionedItems)
151 d->unwatchChanges(pi.item);
152 for (const PositionedItem &pi : unpositionedItems)
153 d->unwatchChanges(pi.item);
154 positionedItems.clear();
155 unpositionedItems.clear();
156}
157
158void QQuickBasePositioner::updatePolish()
159{
160 Q_D(QQuickBasePositioner);
161 if (d->positioningDirty)
162 prePositioning();
163}
164
165qreal QQuickBasePositioner::spacing() const
166{
167 Q_D(const QQuickBasePositioner);
168 return d->spacing;
169}
170
171void QQuickBasePositioner::setSpacing(qreal s)
172{
173 Q_D(QQuickBasePositioner);
174 if (s == d->spacing)
175 return;
176 d->spacing = s;
177 d->setPositioningDirty();
178 emit spacingChanged();
179}
180
181#if QT_CONFIG(quick_viewtransitions)
182QQuickTransition *QQuickBasePositioner::populate() const
183{
184 Q_D(const QQuickBasePositioner);
185 return d->transitioner ? d->transitioner->populateTransition : nullptr;
186}
187
188void QQuickBasePositioner::setPopulate(QQuickTransition *transition)
189{
190 Q_D(QQuickBasePositioner);
191 if (!d->transitioner)
192 d->transitioner = new QQuickItemViewTransitioner;
193 if (d->transitioner->populateTransition != transition) {
194 d->transitioner->populateTransition = transition;
195 emit populateChanged();
196 }
197}
198
199QQuickTransition *QQuickBasePositioner::move() const
200{
201 Q_D(const QQuickBasePositioner);
202 return d->transitioner ? d->transitioner->displacedTransition : nullptr;
203}
204
205void QQuickBasePositioner::setMove(QQuickTransition *mt)
206{
207 Q_D(QQuickBasePositioner);
208 if (!d->transitioner)
209 d->transitioner = new QQuickItemViewTransitioner;
210 if (mt == d->transitioner->displacedTransition)
211 return;
212
213 d->transitioner->displacedTransition = mt;
214 emit moveChanged();
215}
216
217QQuickTransition *QQuickBasePositioner::add() const
218{
219 Q_D(const QQuickBasePositioner);
220 return d->transitioner ? d->transitioner->addTransition : nullptr;
221}
222
223void QQuickBasePositioner::setAdd(QQuickTransition *add)
224{
225 Q_D(QQuickBasePositioner);
226 if (!d->transitioner)
227 d->transitioner = new QQuickItemViewTransitioner;
228 if (add == d->transitioner->addTransition)
229 return;
230
231 d->transitioner->addTransition = add;
232 emit addChanged();
233}
234#endif
235
236void QQuickBasePositioner::componentComplete()
237{
238#if QT_CONFIG(quick_viewtransitions)
239 Q_D(QQuickBasePositioner);
240#endif
241 QQuickItem::componentComplete();
242#if QT_CONFIG(quick_viewtransitions)
243 if (d->transitioner)
244 d->transitioner->setPopulateTransitionEnabled(true);
245#endif
246 positionedItems.reserve(childItems().size());
247 prePositioning();
248#if QT_CONFIG(quick_viewtransitions)
249 if (d->transitioner)
250 d->transitioner->setPopulateTransitionEnabled(false);
251#endif
252}
253
254void QQuickBasePositioner::itemChange(ItemChange change, const ItemChangeData &value)
255{
256 Q_D(QQuickBasePositioner);
257 if (change == ItemChildAddedChange) {
258 d->setPositioningDirty();
259 } else if (change == ItemChildRemovedChange) {
260 QQuickItem *child = value.item;
261 auto it = std::find(positionedItems.begin(), positionedItems.end(), child);
262 if (it != positionedItems.end()) {
263 d->unwatchChanges(child);
264 positionedItems.erase(it);
265 } else {
266 it = std::find(unpositionedItems.begin(), unpositionedItems.end(), child);
267 if (it != unpositionedItems.end()) {
268 d->unwatchChanges(child);
269 unpositionedItems.erase(it);
270 }
271 }
272 d->setPositioningDirty();
273 }
274
275 QQuickItem::itemChange(change, value);
276}
277
278void QQuickBasePositioner::forceLayout()
279{
280 updatePolish();
281}
282
283void QQuickBasePositioner::prePositioning()
284{
285 Q_D(QQuickBasePositioner);
286 if (!isComponentComplete())
287 return;
288
289 if (d->doingPositioning)
290 return;
291
292 d->positioningDirty = false;
293 d->doingPositioning = true;
294 //Need to order children by creation order modified by stacking order
295 QList<QQuickItem *> children = childItems();
296
297 std::vector<PositionedItem> oldItems;
298 oldItems.reserve(positionedItems.size() + unpositionedItems.size());
299
300 std::move(positionedItems.begin(), positionedItems.end(),
301 std::back_inserter(oldItems));
302 positionedItems.clear();
303
304 std::move(unpositionedItems.begin(), unpositionedItems.end(),
305 std::back_inserter(oldItems));
306 unpositionedItems.clear();
307
308#if QT_CONFIG(quick_viewtransitions)
309 int addedIndex = -1;
310#endif
311
312 for (int ii = 0; ii < children.size(); ++ii) {
313 QQuickItem *child = children.at(ii);
314 if (QQuickItemPrivate::get(child)->isTransparentForPositioner())
315 continue;
316 QQuickItemPrivate *childPrivate = QQuickItemPrivate::get(child);
317 PositionedItem posItem(child);
318 auto it = std::find(oldItems.begin(), oldItems.end(), posItem);
319 if (it == oldItems.end()) {
320 // This is a newly added item.
321 d->watchChanges(child);
322 posItem.isNew = true;
323 if (!childPrivate->explicitVisible || !child->width() || !child->height()) {
324 posItem.isVisible = false;
325 posItem.index = -1;
326 // If we hide a zero-width or height item by setting visible to false,
327 // the !childPrivate->explicitVisible will then always trigger. We can't
328 // overwrite what the user has set, and we don't want to introduce a separate
329 // flag to track whether the visible property was actually explicitly set so
330 // that we can implicitly set it, so instead we use culled for this.
331 childPrivate->setCulled(true);
332 unpositionedItems.push_back(std::move(posItem));
333 } else {
334 const int posIndex = int(positionedItems.size());
335 posItem.index = posIndex;
336 positionedItems.push_back(std::move(posItem));
337
338#if QT_CONFIG(quick_viewtransitions)
339 if (d->transitioner) {
340 if (addedIndex < 0)
341 addedIndex = posIndex;
342 PositionedItem *theItem = &positionedItems.back();
343 if (d->transitioner->canTransition(QQuickItemViewTransitioner::PopulateTransition, true))
344 theItem->transitionNextReposition(d->transitioner, QQuickItemViewTransitioner::PopulateTransition, true);
345 else if (!d->transitioner->populateTransitionEnabled())
346 theItem->transitionNextReposition(d->transitioner, QQuickItemViewTransitioner::AddTransition, true);
347 }
348#endif
349 }
350 } else {
351 // This item already existed within us.
352 PositionedItem *item = &*it;
353 // Items are only omitted from positioning if they are explicitly hidden
354 // i.e. their positioning is not affected if an ancestor is hidden.
355 if (!childPrivate->explicitVisible || !child->width() || !child->height()) {
356 item->isVisible = false;
357 item->index = -1;
358 childPrivate->setCulled(true);
359 unpositionedItems.push_back(std::move(*item));
360 } else if (!item->isVisible) {
361 // item changed from non-visible to visible, treat it as a "new" item
362 item->isVisible = true;
363 item->isNew = true;
364 const int itemIndex = int(positionedItems.size());
365 item->index = itemIndex;
366 childPrivate->setCulled(false);
367 positionedItems.push_back(std::move(*item));
368
369#if QT_CONFIG(quick_viewtransitions)
370 if (d->transitioner) {
371 if (addedIndex < 0)
372 addedIndex = itemIndex;
373 positionedItems.back().transitionNextReposition(d->transitioner, QQuickItemViewTransitioner::AddTransition, true);
374 }
375#endif
376 } else {
377 item->isNew = false;
378 const int itemIndex = int(positionedItems.size());
379 item->index = itemIndex;
380 positionedItems.push_back(std::move(*item));
381 }
382 }
383 }
384
385#if QT_CONFIG(quick_viewtransitions)
386 if (d->transitioner) {
387 for (PositionedItem &item : positionedItems) {
388 if (!item.isNew) {
389 if (addedIndex >= 0) {
390 item.transitionNextReposition(d->transitioner, QQuickItemViewTransitioner::AddTransition, false);
391 } else {
392 // just queue the item for a move-type displace - if the item hasn't
393 // moved anywhere, it won't be transitioned anyway
394 item.transitionNextReposition(d->transitioner, QQuickItemViewTransitioner::MoveTransition, false);
395 }
396 }
397 }
398 }
399#endif
400
401 QSizeF contentSize(0,0);
402 reportConflictingAnchors();
403 if (!d->anchorConflict) {
404 doPositioning(&contentSize);
405 updateAttachedProperties();
406 }
407
408#if QT_CONFIG(quick_viewtransitions)
409 if (d->transitioner) {
410 QRectF viewBounds(QPointF(), contentSize);
411 for (PositionedItem &item : positionedItems)
412 item.prepareTransition(d->transitioner, viewBounds);
413 for (PositionedItem &item : positionedItems)
414 item.startTransition(d->transitioner);
415 d->transitioner->resetTargetLists();
416 }
417#endif
418
419 d->doingPositioning = false;
420
421 //Set implicit size to the size of its children
422 setImplicitSize(contentSize.width(), contentSize.height());
423
424 emit positioningComplete();
425}
426
427void QQuickBasePositioner::positionItem(qreal x, qreal y, PositionedItem *target)
428{
429 if ( target->itemX() != x || target->itemY() != y )
430 target->moveTo(QPointF(x, y));
431}
432
433void QQuickBasePositioner::positionItemX(qreal x, PositionedItem *target)
434{
435 Q_D(QQuickBasePositioner);
436 if (target->itemX() != x
437 && (d->type == Horizontal || d->type == Both)) {
438 target->moveTo(QPointF(x, target->itemY()));
439 }
440}
441
442void QQuickBasePositioner::positionItemY(qreal y, PositionedItem *target)
443{
444 Q_D(QQuickBasePositioner);
445 if (target->itemY() != y
446 && (d->type == Vertical || d->type == Both)) {
447 target->moveTo(QPointF(target->itemX(), y));
448 }
449}
450
451QQuickPositionerAttached *QQuickBasePositioner::qmlAttachedProperties(QObject *obj)
452{
453 return new QQuickPositionerAttached(obj);
454}
455
456void QQuickBasePositioner::updateAttachedProperties(QQuickPositionerAttached *specificProperty, QQuickItem *specificPropertyOwner) const
457{
458 // If this function is deemed too expensive or shows up in profiles, it could
459 // be changed to run only when there are attached properties present. This
460 // could be a flag in the positioner that is set by the attached property
461 // constructor.
462 QQuickPositionerAttached *prevLastProperty = nullptr;
463 QQuickPositionerAttached *lastProperty = nullptr;
464
465 const int positionedItemsSize = int(positionedItems.size());
466 for (int ii = 0; ii < positionedItemsSize; ++ii) {
467 const PositionedItem &child = positionedItems[ii];
468 if (!child.item)
469 continue;
470
471 QQuickPositionerAttached *property = nullptr;
472
473 if (specificProperty) {
474 if (specificPropertyOwner == child.item) {
475 property = specificProperty;
476 }
477 } else {
478 property = static_cast<QQuickPositionerAttached *>(qmlAttachedPropertiesObject<QQuickBasePositioner>(child.item, false));
479 }
480
481 if (property) {
482 property->setIndex(ii);
483 property->setIsFirstItem(ii == 0);
484
485 if (property->isLastItem()) {
486 if (prevLastProperty)
487 prevLastProperty->setIsLastItem(false); // there can be only one last property
488 prevLastProperty = property;
489 }
490 }
491
492 lastProperty = property;
493 }
494
495 if (prevLastProperty && prevLastProperty != lastProperty)
496 prevLastProperty->setIsLastItem(false);
497 if (lastProperty)
498 lastProperty->setIsLastItem(true);
499
500 // clear attached properties for unpositioned items
501 for (const PositionedItem &child : unpositionedItems) {
502 if (!child.item)
503 continue;
504
505 QQuickPositionerAttached *property = nullptr;
506
507 if (specificProperty) {
508 if (specificPropertyOwner == child.item) {
509 property = specificProperty;
510 }
511 } else {
512 property = static_cast<QQuickPositionerAttached *>(qmlAttachedPropertiesObject<QQuickBasePositioner>(child.item, false));
513 }
514
515 if (property) {
516 property->setIndex(-1);
517 property->setIsFirstItem(false);
518 property->setIsLastItem(false);
519 }
520 }
521}
522
523qreal QQuickBasePositioner::padding() const
524{
525 Q_D(const QQuickBasePositioner);
526 return d->padding();
527}
528
529void QQuickBasePositioner::setPadding(qreal padding)
530{
531 Q_D(QQuickBasePositioner);
532 if (qFuzzyCompare(d->padding(), padding))
533 return;
534
535 d->extra.value().padding = padding;
536 d->setPositioningDirty();
537 emit paddingChanged();
538 if (!d->extra.isAllocated() || !d->extra->explicitTopPadding)
539 emit topPaddingChanged();
540 if (!d->extra.isAllocated() || !d->extra->explicitLeftPadding)
541 emit leftPaddingChanged();
542 if (!d->extra.isAllocated() || !d->extra->explicitRightPadding)
543 emit rightPaddingChanged();
544 if (!d->extra.isAllocated() || !d->extra->explicitBottomPadding)
545 emit bottomPaddingChanged();
546}
547
548void QQuickBasePositioner::resetPadding()
549{
550 setPadding(0);
551}
552
553qreal QQuickBasePositioner::topPadding() const
554{
555 Q_D(const QQuickBasePositioner);
556 if (d->extra.isAllocated() && d->extra->explicitTopPadding)
557 return d->extra->topPadding;
558 return d->padding();
559}
560
561void QQuickBasePositioner::setTopPadding(qreal padding)
562{
563 Q_D(QQuickBasePositioner);
564 d->setTopPadding(padding);
565}
566
567void QQuickBasePositioner::resetTopPadding()
568{
569 Q_D(QQuickBasePositioner);
570 d->setTopPadding(0, true);
571}
572
573qreal QQuickBasePositioner::leftPadding() const
574{
575 Q_D(const QQuickBasePositioner);
576 if (d->extra.isAllocated() && d->extra->explicitLeftPadding)
577 return d->extra->leftPadding;
578 return d->padding();
579}
580
581void QQuickBasePositioner::setLeftPadding(qreal padding)
582{
583 Q_D(QQuickBasePositioner);
584 d->setLeftPadding(padding);
585}
586
587void QQuickBasePositioner::resetLeftPadding()
588{
589 Q_D(QQuickBasePositioner);
590 d->setLeftPadding(0, true);
591}
592
593qreal QQuickBasePositioner::rightPadding() const
594{
595 Q_D(const QQuickBasePositioner);
596 if (d->extra.isAllocated() && d->extra->explicitRightPadding)
597 return d->extra->rightPadding;
598 return d->padding();
599}
600
601void QQuickBasePositioner::setRightPadding(qreal padding)
602{
603 Q_D(QQuickBasePositioner);
604 d->setRightPadding(padding);
605}
606
607void QQuickBasePositioner::resetRightPadding()
608{
609 Q_D(QQuickBasePositioner);
610 d->setRightPadding(0, true);
611}
612
613qreal QQuickBasePositioner::bottomPadding() const
614{
615 Q_D(const QQuickBasePositioner);
616 if (d->extra.isAllocated() && d->extra->explicitBottomPadding)
617 return d->extra->bottomPadding;
618 return d->padding();
619}
620
621void QQuickBasePositioner::setBottomPadding(qreal padding)
622{
623 Q_D(QQuickBasePositioner);
624 d->setBottomPadding(padding);
625}
626
627void QQuickBasePositioner::resetBottomPadding()
628{
629 Q_D(QQuickBasePositioner);
630 d->setBottomPadding(0, true);
631}
632
633QQuickBasePositionerPrivate::ExtraData::ExtraData()
634 : padding(0)
635 , topPadding(0)
636 , leftPadding(0)
637 , rightPadding(0)
638 , bottomPadding(0)
639 , explicitTopPadding(false)
640 , explicitLeftPadding(false)
641 , explicitRightPadding(false)
642 , explicitBottomPadding(false)
643{
644}
645
646void QQuickBasePositionerPrivate::setTopPadding(qreal value, bool reset)
647{
648 Q_Q(QQuickBasePositioner);
649 qreal oldPadding = q->topPadding();
650 if (!reset || extra.isAllocated()) {
651 extra.value().topPadding = value;
652 extra.value().explicitTopPadding = !reset;
653 }
654 if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) {
656 emit q->topPaddingChanged();
657 }
658}
659
660void QQuickBasePositionerPrivate::setLeftPadding(qreal value, bool reset)
661{
662 Q_Q(QQuickBasePositioner);
663 qreal oldPadding = q->leftPadding();
664 if (!reset || extra.isAllocated()) {
665 extra.value().leftPadding = value;
666 extra.value().explicitLeftPadding = !reset;
667 }
668 if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) {
670 emit q->leftPaddingChanged();
671 }
672}
673
674void QQuickBasePositionerPrivate::setRightPadding(qreal value, bool reset)
675{
676 Q_Q(QQuickBasePositioner);
677 qreal oldPadding = q->rightPadding();
678 if (!reset || extra.isAllocated()) {
679 extra.value().rightPadding = value;
680 extra.value().explicitRightPadding = !reset;
681 }
682 if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) {
684 emit q->rightPaddingChanged();
685 }
686}
687
688void QQuickBasePositionerPrivate::setBottomPadding(qreal value, bool reset)
689{
690 Q_Q(QQuickBasePositioner);
691 qreal oldPadding = q->bottomPadding();
692 if (!reset || extra.isAllocated()) {
693 extra.value().bottomPadding = value;
694 extra.value().explicitBottomPadding = !reset;
695 }
696 if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) {
698 emit q->bottomPaddingChanged();
699 }
700}
701
702/*!
703 \qmltype Positioner
704 \nativetype QQuickPositionerAttached
705 \inqmlmodule QtQuick
706 \ingroup qtquick-positioners
707 \brief Provides attached properties that contain details on where an item exists in a positioner.
708
709 An object of type Positioner is attached to the top-level child item within a
710 Column, Row, Flow or Grid. It provides properties that allow a child item to determine
711 where it exists within the layout of its parent Column, Row, Flow or Grid.
712
713 For example, below is a \l Grid with 16 child rectangles, as created through a \l Repeater.
714 Each \l Rectangle displays its index in the Grid using \l {Positioner::index}{Positioner.index}, and the first
715 item is colored differently by taking \l {Positioner::isFirstItem}{Positioner.isFirstItem} into account:
716
717 \code
718 Grid {
719 Repeater {
720 model: 16
721
722 Rectangle {
723 id: rect
724 width: 30; height: 30
725 border.width: 1
726 color: Positioner.isFirstItem ? "yellow" : "lightsteelblue"
727
728 Text { text: rect.Positioner.index }
729 }
730 }
731 }
732 \endcode
733
734 \image positioner-example.png {Grid with 16 rectangles numbered 0-15,
735 first item yellow indicating Positioner.isFirstItem}
736*/
737
738QQuickPositionerAttached::QQuickPositionerAttached(QObject *parent) : QObject(parent), m_index(-1), m_isFirstItem(false), m_isLastItem(false)
739{
740 QQuickItem *attachedItem = qobject_cast<QQuickItem *>(parent);
741 if (attachedItem) {
742 QQuickBasePositioner *positioner = qobject_cast<QQuickBasePositioner *>(attachedItem->parent());
743 if (positioner) {
744 positioner->updateAttachedProperties(this, attachedItem);
745 }
746 }
747}
748
749/*!
750 \qmlattachedproperty int QtQuick::Positioner::index
751
752 This property allows the item to determine
753 its index within the positioner.
754*/
755void QQuickPositionerAttached::setIndex(int index)
756{
757 if (m_index == index)
758 return;
759 m_index = index;
760 emit indexChanged();
761}
762
763/*!
764 \qmlattachedproperty bool QtQuick::Positioner::isFirstItem
765 \qmlattachedproperty bool QtQuick::Positioner::isLastItem
766
767 These properties allow the item to determine if it
768 is the first or last item in the positioner, respectively.
769*/
771{
772 if (m_isFirstItem == isFirstItem)
773 return;
774 m_isFirstItem = isFirstItem;
775 emit isFirstItemChanged();
776}
777
779{
780 if (m_isLastItem == isLastItem)
781 return;
782 m_isLastItem = isLastItem;
783 emit isLastItemChanged();
784}
785
786/*!
787 \qmltype Column
788 \nativetype QQuickColumn
789 \inqmlmodule QtQuick
790 \inherits Item
791 \ingroup qtquick-positioners
792 \brief Positions its children in a column.
793
794 Column is a type that positions its child items along a single column.
795 It can be used as a convenient way to vertically position a series of items without
796 using \l {Positioning with Anchors}{anchors}.
797
798 Below is a Column that contains three rectangles of various sizes:
799
800 \snippet qml/column/vertical-positioner.qml document
801
802 The Column automatically positions these items in a vertical formation, like this:
803
804 \image verticalpositioner_example.png {Three colored rectangles
805 stacked vertically in a Column}
806
807 If an item within a Column is not \l {Item::}{visible}, or if it has a width or
808 height of 0, the item will not be laid out and it will not be visible within the
809 column. Also, since a Column automatically positions its children vertically, a child
810 item within a Column should not set its \l {Item::y}{y} position or vertically
811 anchor itself using the \l {Item::anchors.top}{top}, \l {Item::anchors.bottom}{bottom},
812 \l {Item::anchors.verticalCenter}{anchors.verticalCenter}, \l {Item::anchors.fill}{fill}
813 or \l {Item::anchors.centerIn}{centerIn} anchors. If you need to perform these actions,
814 consider positioning the items without the use of a Column.
815
816 Note that items in a Column can use the \l Positioner attached property to access
817 more information about its position within the Column.
818
819 For more information on using Column and other related positioner-types, see
820 \l{Item Positioners}.
821
822
823 \section1 Using Transitions
824
825 A Column animate items using specific transitions when items are added to or moved
826 within a Column.
827
828 For example, the Column below sets the \l move property to a specific \l Transition:
829
830 \snippet qml/column/column-transitions.qml document
831
832 When the Space key is pressed, the \l {Item::visible}{visible} value of the green
833 \l Rectangle is toggled. As it appears and disappears, the blue \l Rectangle moves within
834 the Column, and the \l move transition is automatically applied to the blue \l Rectangle:
835
836 \image verticalpositioner_transition.gif {Blue rectangle animating
837 up and down as green rectangle toggles visibility}
838
839 \sa Row, Grid, Flow, Positioner, ColumnLayout, {Qt Quick Examples - Positioners}
840*/
841/*!
842 \since 5.6
843 \qmlproperty real QtQuick::Column::padding
844 \qmlproperty real QtQuick::Column::topPadding
845 \qmlproperty real QtQuick::Column::leftPadding
846 \qmlproperty real QtQuick::Column::bottomPadding
847 \qmlproperty real QtQuick::Column::rightPadding
848
849 These properties hold the padding around the content.
850*/
851/*!
852 \qmlproperty Transition QtQuick::Column::populate
853
854 This property holds the transition to be run for items that are part of
855 this positioner at the time of its creation. The transition is run when the positioner
856 is first created.
857
858 The transition can use the \l ViewTransition property to access more details about
859 the item that is being added. See the \l ViewTransition documentation for more details
860 and examples on using these transitions.
861
862 \sa add, ViewTransition, {Qt Quick Examples - Positioners}
863*/
864/*!
865 \qmlproperty Transition QtQuick::Column::add
866
867 This property holds the transition to be run for items that are added to this
868 positioner. For a positioner, this applies to:
869
870 \list
871 \li Items that are created or reparented as a child of the positioner after the
872 positioner has been created
873 \li Child items that change their \l Item::visible property from false to true, and thus
874 are now visible
875 \endlist
876
877 The transition can use the \l ViewTransition property to access more details about
878 the item that is being added. See the \l ViewTransition documentation for more details
879 and examples on using these transitions.
880
881 \note This transition is not applied to the items that are already part of the positioner
882 at the time of its creation. In this case, the \l populate transition is applied instead.
883
884 \sa populate, ViewTransition, {Qt Quick Examples - Positioners}
885*/
886/*!
887 \qmlproperty Transition QtQuick::Column::move
888
889 This property holds the transition to run for items that have moved within the
890 positioner. For a positioner, this applies to:
891
892 \list
893 \li Child items that move when they are displaced due to the addition, removal or
894 rearrangement of other items in the positioner
895 \li Child items that are repositioned due to the resizing of other items in the positioner
896 \endlist
897
898 The transition can use the \l ViewTransition property to access more details about
899 the item that is being moved. Note, however, that for this move transition, the
900 ViewTransition.targetIndexes and ViewTransition.targetItems lists are only set when
901 this transition is triggered by the addition of other items in the positioner; in other
902 cases, these lists will be empty. See the \l ViewTransition documentation for more details
903 and examples on using these transitions.
904
905 \sa add, populate, ViewTransition, {Qt Quick Examples - Positioners}
906*/
907/*!
908 \qmlproperty real QtQuick::Column::spacing
909
910 The spacing is the amount in pixels left empty between adjacent
911 items. The default spacing is 0.
912
913 \sa Grid::spacing
914*/
915/*!
916 \qmlmethod void QtQuick::Column::forceLayout()
917 \since 5.9
918
919 Column typically positions its children once per frame. This means that
920 inside script blocks it is possible for the underlying children to have changed,
921 but the Column to have not yet been updated accordingly.
922
923 This method forces the Column to immediately respond to any outstanding
924 changes in its children.
925
926 \b Note: methods in general should only be called after the Component has completed.
927*/
928/*!
929 \qmlsignal QtQuick::Column::positioningComplete()
930 \since 5.9
931
932 This signal is emitted when positioning has been completed.
933*/
934
935QQuickColumn::QQuickColumn(QQuickItem *parent)
936: QQuickBasePositioner(Vertical, parent)
937{
938}
939
940void QQuickColumn::doPositioning(QSizeF *contentSize)
941{
942 //Precondition: All items in the positioned list have a valid item pointer and should be positioned
943 qreal voffset = topPadding();
944 const qreal padding = leftPadding() + rightPadding();
945 contentSize->setWidth(qMax(contentSize->width(), padding));
946
947 for (PositionedItem &child : positionedItems) {
948 positionItem(child.itemX() + leftPadding() - child.leftPadding, voffset, &child);
949 child.updatePadding(leftPadding(), topPadding(), rightPadding(), bottomPadding());
950 contentSize->setWidth(qMax(contentSize->width(), child.item->width() + padding));
951
952 voffset += child.item->height();
953 voffset += spacing();
954 }
955
956 if (voffset - topPadding() != 0)//If we positioned any items, undo the spacing from the last item
957 voffset -= spacing();
958 contentSize->setHeight(voffset + bottomPadding());
959}
960
961void QQuickColumn::reportConflictingAnchors()
962{
963 QQuickBasePositionerPrivate *d = static_cast<QQuickBasePositionerPrivate*>(QQuickBasePositionerPrivate::get(this));
964 for (const PositionedItem &child : positionedItems) {
965 if (child.item) {
966 QQuickAnchors *anchors = QQuickItemPrivate::get(static_cast<QQuickItem *>(child.item))->_anchors;
967 if (anchors) {
968 QQuickAnchors::Anchors usedAnchors = anchors->usedAnchors();
969 if (usedAnchors & QQuickAnchors::TopAnchor ||
970 usedAnchors & QQuickAnchors::BottomAnchor ||
971 usedAnchors & QQuickAnchors::VCenterAnchor ||
972 anchors->fill() || anchors->centerIn()) {
973 d->anchorConflict = true;
974 break;
975 }
976 }
977 }
978 }
979 if (d->anchorConflict) {
980 qmlWarning(this) << "Cannot specify top, bottom, verticalCenter, fill or centerIn anchors for items inside Column."
981 << " Column will not function.";
982 }
983}
984/*!
985 \qmltype Row
986 \nativetype QQuickRow
987 \inqmlmodule QtQuick
988 \inherits Item
989 \ingroup qtquick-positioners
990 \brief Positions its children in a row.
991
992 Row is a type that positions its child items along a single row.
993 It can be used as a convenient way to horizontally position a series of items without
994 using \l {Positioning with Anchors}{anchors}.
995
996 Below is a Row that contains three rectangles of various sizes:
997
998 \snippet qml/row/row.qml document
999
1000 The Row automatically positions these items in a horizontal formation, like this:
1001
1002 \image horizontalpositioner_example.png {Three colored rectangles
1003 arranged horizontally in a Row}
1004
1005 If an item within a Row is not \l {Item::}{visible}, or if it has a width or
1006 height of 0, the item will not be laid out and it will not be visible within the
1007 row. Also, since a Row automatically positions its children horizontally, a child
1008 item within a Row should not set its \l {Item::x}{x} position or horizontally
1009 anchor itself using the \l {Item::anchors.left}{left}, \l {Item::anchors.right}{right},
1010 \l {Item::anchors.horizontalCenter}{anchors.horizontalCenter}, \l {Item::anchors.fill}{fill}
1011 or \l {Item::anchors.centerIn}{centerIn} anchors. If you need to perform these actions,
1012 consider positioning the items without the use of a Row.
1013
1014 Note that items in a Row can use the \l Positioner attached property to access
1015 more information about its position within the Row.
1016
1017 For more information on using Row and other related positioner-types, see
1018 \l{Item Positioners}.
1019
1020
1021 \sa Column, Grid, Flow, Positioner, RowLayout, {Qt Quick Examples - Positioners}
1022*/
1023/*!
1024 \since 5.6
1025 \qmlproperty real QtQuick::Row::padding
1026 \qmlproperty real QtQuick::Row::topPadding
1027 \qmlproperty real QtQuick::Row::leftPadding
1028 \qmlproperty real QtQuick::Row::bottomPadding
1029 \qmlproperty real QtQuick::Row::rightPadding
1030
1031 These properties hold the padding around the content.
1032*/
1033/*!
1034 \qmlproperty Transition QtQuick::Row::populate
1035
1036 This property holds the transition to be run for items that are part of
1037 this positioner at the time of its creation. The transition is run when the positioner
1038 is first created.
1039
1040 The transition can use the \l ViewTransition property to access more details about
1041 the item that is being added. See the \l ViewTransition documentation for more details
1042 and examples on using these transitions.
1043
1044 \sa add, ViewTransition, {Qt Quick Examples - Positioners}
1045*/
1046/*!
1047 \qmlproperty Transition QtQuick::Row::add
1048
1049 This property holds the transition to be run for items that are added to this
1050 positioner. For a positioner, this applies to:
1051
1052 \list
1053 \li Items that are created or reparented as a child of the positioner after the
1054 positioner has been created
1055 \li Child items that change their \l Item::visible property from false to true, and thus
1056 are now visible
1057 \endlist
1058
1059 The transition can use the \l ViewTransition property to access more details about
1060 the item that is being added. See the \l ViewTransition documentation for more details
1061 and examples on using these transitions.
1062
1063 \note This transition is not applied to the items that are already part of the positioner
1064 at the time of its creation. In this case, the \l populate transition is applied instead.
1065
1066 \sa populate, ViewTransition, {Qt Quick Examples - Positioners}
1067*/
1068/*!
1069 \qmlproperty Transition QtQuick::Row::move
1070
1071 This property holds the transition to run for items that have moved within the
1072 positioner. For a positioner, this applies to:
1073
1074 \list
1075 \li Child items that move when they are displaced due to the addition, removal or
1076 rearrangement of other items in the positioner
1077 \li Child items that are repositioned due to the resizing of other items in the positioner
1078 \endlist
1079
1080 The transition can use the \l ViewTransition property to access more details about
1081 the item that is being moved. Note, however, that for this move transition, the
1082 ViewTransition.targetIndexes and ViewTransition.targetItems lists are only set when
1083 this transition is triggered by the addition of other items in the positioner; in other
1084 cases, these lists will be empty. See the \l ViewTransition documentation for more details
1085 and examples on using these transitions.
1086
1087 \sa add, populate, ViewTransition, {Qt Quick Examples - Positioners}
1088*/
1089/*!
1090 \qmlproperty real QtQuick::Row::spacing
1091
1092 The spacing is the amount in pixels left empty between adjacent
1093 items. The default spacing is 0.
1094
1095 \sa Grid::spacing
1096*/
1097/*!
1098 \qmlmethod void QtQuick::Row::forceLayout()
1099 \since 5.9
1100
1101 Row typically positions its children once per frame. This means that
1102 inside script blocks it is possible for the underlying children to have changed,
1103 but the Row to have not yet been updated accordingly.
1104
1105 This method forces the Row to immediately respond to any outstanding
1106 changes in its children.
1107
1108 \b Note: methods in general should only be called after the Component has completed.
1109*/
1110/*!
1111 \qmlsignal QtQuick::Row::positioningComplete()
1112 \since 5.9
1113
1114 This signal is emitted when positioning has been completed.
1115*/
1116
1118{
1119 Q_DECLARE_PUBLIC(QQuickRow)
1120
1121public:
1125
1127 {
1128 Q_Q(QQuickRow);
1129 // For RTL layout the positioning changes when the width changes.
1132 else
1134 // Don't postpone, as it might be the only trigger for visible changes.
1135 q->prePositioning();
1137 }
1138};
1139
1140QQuickRow::QQuickRow(QQuickItem *parent)
1141: QQuickBasePositioner(*new QQuickRowPrivate, Horizontal, parent)
1142{
1143}
1144/*!
1145 \qmlproperty enumeration QtQuick::Row::layoutDirection
1146
1147 This property holds the layoutDirection of the row.
1148
1149 Possible values:
1150
1151 \value Qt.LeftToRight (default) Items are laid out from left to right. If the width of the row is
1152 explicitly set, the left anchor remains to the left of the row.
1153 \value Qt.RightToLeft Items are laid out from right to left. If the width of the row is
1154 explicitly set, the right anchor remains to the right of the row.
1155
1156 \sa Grid::layoutDirection, Flow::layoutDirection
1157*/
1158
1159Qt::LayoutDirection QQuickRow::layoutDirection() const
1160{
1161 return QQuickBasePositionerPrivate::getLayoutDirection(this);
1162}
1163
1164void QQuickRow::setLayoutDirection(Qt::LayoutDirection layoutDirection)
1165{
1166 QQuickBasePositionerPrivate *d = static_cast<QQuickBasePositionerPrivate* >(QQuickBasePositionerPrivate::get(this));
1167 if (d->layoutDirection != layoutDirection) {
1168 d->layoutDirection = layoutDirection;
1169 emit layoutDirectionChanged();
1170 d->effectiveLayoutDirectionChange();
1171 }
1172}
1173/*!
1174 \qmlproperty enumeration QtQuick::Row::effectiveLayoutDirection
1175 This property holds the effective layout direction of the row.
1176
1177 When using the attached property \l {LayoutMirroring::enabled}{LayoutMirroring::enabled} for locale layouts,
1178 the visual layout direction of the row positioner will be mirrored. However, the
1179 property \l {Row::layoutDirection}{layoutDirection} will remain unchanged.
1180
1181 \sa Row::layoutDirection, {LayoutMirroring}{LayoutMirroring}
1182*/
1183
1184Qt::LayoutDirection QQuickRow::effectiveLayoutDirection() const
1185{
1186 return QQuickBasePositionerPrivate::getEffectiveLayoutDirection(this);
1187}
1188
1189void QQuickRow::doPositioning(QSizeF *contentSize)
1190{
1191 //Precondition: All items in the positioned list have a valid item pointer and should be positioned
1192 QQuickBasePositionerPrivate *d = static_cast<QQuickBasePositionerPrivate* >(QQuickBasePositionerPrivate::get(this));
1193 qreal hoffset1 = leftPadding();
1194 qreal hoffset2 = rightPadding();
1195 if (!d->isLeftToRight())
1196 qSwap(hoffset1, hoffset2);
1197 qreal hoffset = hoffset1;
1198 const qreal padding = topPadding() + bottomPadding();
1199 contentSize->setHeight(qMax(contentSize->height(), padding));
1200
1201 QList<qreal> hoffsets;
1202 for (PositionedItem &child : positionedItems) {
1203 if (d->isLeftToRight()) {
1204 positionItem(hoffset, child.itemY() + topPadding() - child.topPadding, &child);
1205 child.updatePadding(leftPadding(), topPadding(), rightPadding(), bottomPadding());
1206 } else {
1207 hoffsets << hoffset;
1208 }
1209
1210 contentSize->setHeight(qMax(contentSize->height(), child.item->height() + padding));
1211
1212 hoffset += child.item->width();
1213 hoffset += spacing();
1214 }
1215
1216 if (hoffset - hoffset1 != 0)//If we positioned any items, undo the extra spacing from the last item
1217 hoffset -= spacing();
1218 contentSize->setWidth(hoffset + hoffset2);
1219
1220 if (d->isLeftToRight())
1221 return;
1222
1223 //Right to Left layout
1224 qreal end = 0;
1225 if (!widthValid())
1226 end = contentSize->width();
1227 else
1228 end = width();
1229
1230 int acc = 0;
1231 for (PositionedItem &child : positionedItems) {
1232 hoffset = end - hoffsets[acc++] - child.item->width();
1233 positionItem(hoffset, child.itemY() + topPadding() - child.topPadding, &child);
1234 child.updatePadding(leftPadding(), topPadding(), rightPadding(), bottomPadding());
1235 }
1236}
1237
1238void QQuickRow::reportConflictingAnchors()
1239{
1240 QQuickBasePositionerPrivate *d = static_cast<QQuickBasePositionerPrivate*>(QQuickBasePositionerPrivate::get(this));
1241 for (const PositionedItem &child : positionedItems) {
1242 if (child.item) {
1243 QQuickAnchors *anchors = QQuickItemPrivate::get(static_cast<QQuickItem *>(child.item))->_anchors;
1244 if (anchors) {
1245 QQuickAnchors::Anchors usedAnchors = anchors->usedAnchors();
1246 if (usedAnchors & QQuickAnchors::LeftAnchor ||
1247 usedAnchors & QQuickAnchors::RightAnchor ||
1248 usedAnchors & QQuickAnchors::HCenterAnchor ||
1249 anchors->fill() || anchors->centerIn()) {
1250 d->anchorConflict = true;
1251 break;
1252 }
1253 }
1254 }
1255 }
1256 if (d->anchorConflict)
1257 qmlWarning(this) << "Cannot specify left, right, horizontalCenter, fill or centerIn anchors for items inside Row."
1258 << " Row will not function.";
1259}
1260
1261/*!
1262 \qmltype Grid
1263 \nativetype QQuickGrid
1264 \inqmlmodule QtQuick
1265 \inherits Item
1266 \ingroup qtquick-positioners
1267 \brief Positions its children in grid formation.
1268
1269 Grid is a type that positions its child items in grid formation.
1270
1271 A Grid creates a grid of cells that is large enough to hold all of its
1272 child items, and places these items in the cells from left to right
1273 and top to bottom. Each item is positioned at the top-left corner of its
1274 cell with position (0, 0).
1275
1276 A Grid defaults to four columns, and creates as many rows as are necessary to
1277 fit all of its child items. The number of rows and columns can be constrained
1278 by setting the \l rows and \l columns properties.
1279
1280 For example, below is a Grid that contains five rectangles of various sizes:
1281
1282 \snippet qml/grid/grid.qml document
1283
1284 The Grid automatically positions the child items in a grid formation:
1285
1286 \image gridLayout_example.png {Five colored rectangles arranged
1287 in a grid formation}
1288
1289 If an item within a Grid is not \l {Item::}{visible}, or if it has a width or
1290 height of 0, the item will not be laid out and it will not be visible within the
1291 column. Also, since a Grid automatically positions its children, a child
1292 item within a Grid should not set its \l {Item::x}{x} or \l {Item::y}{y} positions
1293 or anchor itself with any of the \l {Item::anchors}{anchor} properties.
1294
1295 For more information on using Grid and other related positioner-types, see
1296 \l{Item Positioners}.
1297
1298
1299 \sa Flow, Row, Column, Positioner, GridLayout, {Qt Quick Examples - Positioners}
1300*/
1301/*!
1302 \since 5.6
1303 \qmlproperty real QtQuick::Grid::padding
1304 \qmlproperty real QtQuick::Grid::topPadding
1305 \qmlproperty real QtQuick::Grid::leftPadding
1306 \qmlproperty real QtQuick::Grid::bottomPadding
1307 \qmlproperty real QtQuick::Grid::rightPadding
1308
1309 These properties hold the padding around the content.
1310*/
1311/*!
1312 \qmlproperty Transition QtQuick::Grid::populate
1313
1314 This property holds the transition to be run for items that are part of
1315 this positioner at the time of its creation. The transition is run when the positioner
1316 is first created.
1317
1318 The transition can use the \l ViewTransition property to access more details about
1319 the item that is being added. See the \l ViewTransition documentation for more details
1320 and examples on using these transitions.
1321
1322 \sa add, ViewTransition, {Qt Quick Examples - Positioners}
1323*/
1324/*!
1325 \qmlproperty Transition QtQuick::Grid::add
1326
1327 This property holds the transition to be run for items that are added to this
1328 positioner. For a positioner, this applies to:
1329
1330 \list
1331 \li Items that are created or reparented as a child of the positioner after the
1332 positioner has been created
1333 \li Child items that change their \l Item::visible property from false to true, and thus
1334 are now visible
1335 \endlist
1336
1337 The transition can use the \l ViewTransition property to access more details about
1338 the item that is being added. See the \l ViewTransition documentation for more details
1339 and examples on using these transitions.
1340
1341 \note This transition is not applied to the items that are already part of the positioner
1342 at the time of its creation. In this case, the \l populate transition is applied instead.
1343
1344 \sa populate, ViewTransition, {Qt Quick Examples - Positioners}
1345*/
1346/*!
1347 \qmlproperty Transition QtQuick::Grid::move
1348
1349 This property holds the transition to run for items that have moved within the
1350 positioner. For a positioner, this applies to:
1351
1352 \list
1353 \li Child items that move when they are displaced due to the addition, removal or
1354 rearrangement of other items in the positioner
1355 \li Child items that are repositioned due to the resizing of other items in the positioner
1356 \endlist
1357
1358 The transition can use the \l ViewTransition property to access more details about
1359 the item that is being moved. Note, however, that for this move transition, the
1360 ViewTransition.targetIndexes and ViewTransition.targetItems lists are only set when
1361 this transition is triggered by the addition of other items in the positioner; in other
1362 cases, these lists will be empty. See the \l ViewTransition documentation for more details
1363 and examples on using these transitions.
1364
1365 \sa add, populate, ViewTransition, {Qt Quick Examples - Positioners}
1366*/
1367/*!
1368 \qmlproperty real QtQuick::Grid::spacing
1369
1370 The spacing is the amount in pixels left empty between adjacent
1371 items. The amount of spacing applied will be the same in the
1372 horizontal and vertical directions. The default spacing is 0.
1373
1374 The below example places a Grid containing a red, a blue and a
1375 green rectangle on a gray background. The area the grid positioner
1376 occupies is colored white. The positioner on the left has the
1377 no spacing (the default), and the positioner on the right has
1378 a spacing of 6.
1379
1380 \inlineimage qml-grid-no-spacing.png
1381 {Four colored squares in a grid with no spacing}
1382 \inlineimage qml-grid-spacing.png
1383 {Four colored squares in a grid with spacing between them}
1384
1385 \sa rows, columns
1386*/
1387/*!
1388 \qmlmethod void QtQuick::Grid::forceLayout()
1389 \since 5.9
1390
1391 Grid typically positions its children once per frame. This means that
1392 inside script blocks it is possible for the underlying children to have changed,
1393 but the Grid to have not yet been updated accordingly.
1394
1395 This method forces the Grid to immediately respond to any outstanding
1396 changes in its children.
1397
1398 \b Note: methods in general should only be called after the Component has completed.
1399*/
1400/*!
1401 \qmlsignal QtQuick::Grid::positioningComplete()
1402 \since 5.9
1403
1404 This signal is emitted when positioning has been completed.
1405*/
1406
1408{
1409 Q_DECLARE_PUBLIC(QQuickGrid)
1410
1411public:
1415
1417 {
1418 Q_Q(QQuickGrid);
1419 // For RTL layout the positioning changes when the width changes.
1422 else
1424 // Don't postpone, as it might be the only trigger for visible changes.
1425 q->prePositioning();
1428 }
1429};
1430
1431QQuickGrid::QQuickGrid(QQuickItem *parent)
1432 : QQuickBasePositioner(*new QQuickGridPrivate, Both, parent)
1433 , m_rows(-1)
1434 , m_columns(-1)
1435 , m_rowSpacing(-1)
1436 , m_columnSpacing(-1)
1437 , m_useRowSpacing(false)
1438 , m_useColumnSpacing(false)
1439 , m_flow(LeftToRight)
1440 , m_hItemAlign(AlignLeft)
1441 , m_vItemAlign(AlignTop)
1442{
1443}
1444
1445/*!
1446 \qmlproperty int QtQuick::Grid::columns
1447
1448 This property holds the number of columns in the grid. The default
1449 number of columns is 4.
1450
1451 If the grid does not have enough items to fill the specified
1452 number of columns, some columns will be of zero width.
1453*/
1454
1455/*!
1456 \qmlproperty int QtQuick::Grid::rows
1457 This property holds the number of rows in the grid.
1458
1459 If the grid does not have enough items to fill the specified
1460 number of rows, some rows will be of zero width.
1461*/
1462
1463void QQuickGrid::setColumns(const int columns)
1464{
1465 if (columns == m_columns)
1466 return;
1467 m_columns = columns;
1468 prePositioning();
1469 emit columnsChanged();
1470}
1471
1472void QQuickGrid::setRows(const int rows)
1473{
1474 if (rows == m_rows)
1475 return;
1476 m_rows = rows;
1477 prePositioning();
1478 emit rowsChanged();
1479}
1480
1481/*!
1482 \qmlproperty enumeration QtQuick::Grid::flow
1483 This property holds the flow of the layout.
1484
1485 Possible values are:
1486
1487 \list
1488 \li Grid.LeftToRight (default) - Items are positioned next to
1489 each other in the \l layoutDirection, then wrapped to the next line.
1490 \li Grid.TopToBottom - Items are positioned next to each
1491 other from top to bottom, then wrapped to the next column.
1492 \endlist
1493*/
1494QQuickGrid::Flow QQuickGrid::flow() const
1495{
1496 return m_flow;
1497}
1498
1499void QQuickGrid::setFlow(Flow flow)
1500{
1501 if (m_flow != flow) {
1502 m_flow = flow;
1503 prePositioning();
1504 emit flowChanged();
1505 }
1506}
1507
1508/*!
1509 \qmlproperty real QtQuick::Grid::rowSpacing
1510
1511 This property holds the spacing in pixels between rows.
1512
1513 If this property is not set, then spacing is used for the row spacing.
1514
1515 By default this property is not set.
1516
1517 \sa columnSpacing
1518 \since 5.0
1519*/
1520void QQuickGrid::setRowSpacing(const qreal rowSpacing)
1521{
1522 if (rowSpacing == m_rowSpacing)
1523 return;
1524 m_rowSpacing = rowSpacing;
1525 m_useRowSpacing = true;
1526 prePositioning();
1527 emit rowSpacingChanged();
1528}
1529
1530/*!
1531 \qmlproperty real QtQuick::Grid::columnSpacing
1532
1533 This property holds the spacing in pixels between columns.
1534
1535 If this property is not set, then spacing is used for the column spacing.
1536
1537 By default this property is not set.
1538
1539 \sa rowSpacing
1540 \since 5.0
1541*/
1542void QQuickGrid::setColumnSpacing(const qreal columnSpacing)
1543{
1544 if (columnSpacing == m_columnSpacing)
1545 return;
1546 m_columnSpacing = columnSpacing;
1547 m_useColumnSpacing = true;
1548 prePositioning();
1549 emit columnSpacingChanged();
1550}
1551
1552/*!
1553 \qmlproperty enumeration QtQuick::Grid::layoutDirection
1554
1555 This property holds the layout direction of the layout.
1556
1557 Possible values are:
1558
1559 \list
1560 \li Qt.LeftToRight (default) - Items are positioned from the top to bottom,
1561 and left to right. The flow direction is dependent on the
1562 \l Grid::flow property.
1563 \li Qt.RightToLeft - Items are positioned from the top to bottom,
1564 and right to left. The flow direction is dependent on the
1565 \l Grid::flow property.
1566 \endlist
1567
1568 \sa Flow::layoutDirection, Row::layoutDirection
1569*/
1570Qt::LayoutDirection QQuickGrid::layoutDirection() const
1571{
1572 return QQuickBasePositionerPrivate::getLayoutDirection(this);
1573}
1574
1575void QQuickGrid::setLayoutDirection(Qt::LayoutDirection layoutDirection)
1576{
1577 QQuickBasePositionerPrivate *d = static_cast<QQuickBasePositionerPrivate*>(QQuickBasePositionerPrivate::get(this));
1578 if (d->layoutDirection != layoutDirection) {
1579 d->layoutDirection = layoutDirection;
1580 emit layoutDirectionChanged();
1581 d->effectiveLayoutDirectionChange();
1582 }
1583}
1584
1585/*!
1586 \qmlproperty enumeration QtQuick::Grid::effectiveLayoutDirection
1587 This property holds the effective layout direction of the grid.
1588
1589 When using the attached property \l {LayoutMirroring::enabled}{LayoutMirroring::enabled} for locale layouts,
1590 the visual layout direction of the grid positioner will be mirrored. However, the
1591 property \l {Grid::layoutDirection}{layoutDirection} will remain unchanged.
1592
1593 \sa Grid::layoutDirection, {LayoutMirroring}{LayoutMirroring}
1594*/
1595Qt::LayoutDirection QQuickGrid::effectiveLayoutDirection() const
1596{
1597 return QQuickBasePositionerPrivate::getEffectiveLayoutDirection(this);
1598}
1599
1600/*!
1601 \qmlproperty enumeration QtQuick::Grid::horizontalItemAlignment
1602 \qmlproperty enumeration QtQuick::Grid::verticalItemAlignment
1603 \qmlproperty enumeration QtQuick::Grid::effectiveHorizontalItemAlignment
1604 \since 5.1
1605
1606 Sets the horizontal and vertical alignment of items in the Grid. By default,
1607 the items are vertically aligned to the top. Horizontal
1608 alignment follows the layoutDirection of the Grid, for example when having a layoutDirection
1609 from LeftToRight, the items will be aligned on the left.
1610
1611 The valid values for \c horizontalItemAlignment are, \c Grid.AlignLeft, \c Grid.AlignRight and
1612 \c Grid.AlignHCenter.
1613
1614 The valid values for \c verticalItemAlignment are \c Grid.AlignTop, \c Grid.AlignBottom
1615 and \c Grid.AlignVCenter.
1616
1617 The below images show three examples of how to align items.
1618
1619 \table
1620 \row
1621 \li
1622 \li \inlineimage gridLayout_aligntopleft.png
1623 {Colored rectangles aligned top-left in grid cells}
1624 \li \inlineimage gridLayout_aligntop.png
1625 {Colored rectangles aligned top-center in grid cells}
1626 \li \inlineimage gridLayout_aligncenter.png
1627 {Colored rectangles centered in grid cells}
1628 \row
1629 \li Horizontal alignment
1630 \li AlignLeft
1631 \li AlignHCenter
1632 \li AlignHCenter
1633 \row
1634 \li Vertical alignment
1635 \li AlignTop
1636 \li AlignTop
1637 \li AlignVCenter
1638 \endtable
1639
1640
1641 When mirroring the layout using either the attached property LayoutMirroring::enabled or
1642 by setting the layoutDirection, the horizontal alignment of items will be mirrored as well.
1643 However, the property \c horizontalItemAlignment will remain unchanged.
1644 To query the effective horizontal alignment of items, use the read-only property
1645 \c effectiveHorizontalItemAlignment.
1646
1647 \sa Grid::layoutDirection, {LayoutMirroring}{LayoutMirroring}
1648*/
1649QQuickGrid::HAlignment QQuickGrid::hItemAlign() const
1650{
1651 return m_hItemAlign;
1652}
1653void QQuickGrid::setHItemAlign(HAlignment align)
1654{
1655 if (m_hItemAlign != align) {
1656 m_hItemAlign = align;
1657 prePositioning();
1658 emit horizontalAlignmentChanged(align);
1659 emit effectiveHorizontalAlignmentChanged(effectiveHAlign());
1660 }
1661}
1662
1663QQuickGrid::HAlignment QQuickGrid::effectiveHAlign() const
1664{
1665 HAlignment effectiveAlignment = m_hItemAlign;
1666 if (effectiveLayoutDirection() == Qt::RightToLeft) {
1667 switch (hItemAlign()) {
1668 case AlignLeft:
1669 effectiveAlignment = AlignRight;
1670 break;
1671 case AlignRight:
1672 effectiveAlignment = AlignLeft;
1673 break;
1674 default:
1675 break;
1676 }
1677 }
1678 return effectiveAlignment;
1679}
1680
1681
1682QQuickGrid::VAlignment QQuickGrid::vItemAlign() const
1683{
1684 return m_vItemAlign;
1685}
1686void QQuickGrid::setVItemAlign(VAlignment align)
1687{
1688 if (m_vItemAlign != align) {
1689 m_vItemAlign = align;
1690 prePositioning();
1691 emit verticalAlignmentChanged(align);
1692 }
1693}
1694
1695void QQuickGrid::doPositioning(QSizeF *contentSize)
1696{
1697 //Precondition: All items in the positioned list have a valid item pointer and should be positioned
1698 QQuickBasePositionerPrivate *d = static_cast<QQuickBasePositionerPrivate*>(QQuickBasePositionerPrivate::get(this));
1699 int c = m_columns;
1700 int r = m_rows;
1701 const int numVisible = int(positionedItems.size());
1702
1703 if (m_columns <= 0 && m_rows <= 0) {
1704 c = 4;
1705 r = (numVisible+3)/4;
1706 } else if (m_rows <= 0) {
1707 r = (numVisible+(m_columns-1))/m_columns;
1708 } else if (m_columns <= 0) {
1709 c = (numVisible+(m_rows-1))/m_rows;
1710 }
1711
1712 if (r == 0 || c == 0) {
1713 contentSize->setHeight(topPadding() + bottomPadding());
1714 contentSize->setWidth(leftPadding() + rightPadding());
1715 return; //Nothing else to do
1716 }
1717
1718 if (numVisible > r * c) {
1719 qmlWarning(this) << "Grid contains more visible items (" << numVisible << ") than rows*columns (" << r * c << ")";
1720 }
1721
1722 QList<qreal> maxColWidth;
1723 QList<qreal> maxRowHeight;
1724 int childIndex =0;
1725 if (m_flow == LeftToRight) {
1726 for (int i = 0; i < r; i++) {
1727 for (int j = 0; j < c; j++) {
1728 if (j == 0)
1729 maxRowHeight << 0;
1730 if (i == 0)
1731 maxColWidth << 0;
1732
1733 if (childIndex == numVisible)
1734 break;
1735
1736 const PositionedItem &child = positionedItems[childIndex++];
1737 if (child.item->width() > maxColWidth[j])
1738 maxColWidth[j] = child.item->width();
1739 if (child.item->height() > maxRowHeight[i])
1740 maxRowHeight[i] = child.item->height();
1741 }
1742 }
1743 } else {
1744 for (int j = 0; j < c; j++) {
1745 for (int i = 0; i < r; i++) {
1746 if (j == 0)
1747 maxRowHeight << 0;
1748 if (i == 0)
1749 maxColWidth << 0;
1750
1751 if (childIndex == numVisible)
1752 break;
1753
1754 const PositionedItem &child = positionedItems[childIndex++];
1755 if (child.item->width() > maxColWidth[j])
1756 maxColWidth[j] = child.item->width();
1757 if (child.item->height() > maxRowHeight[i])
1758 maxRowHeight[i] = child.item->height();
1759 }
1760 }
1761 }
1762
1763 qreal columnSpacing = m_useColumnSpacing ? m_columnSpacing : spacing();
1764 qreal rowSpacing = m_useRowSpacing ? m_rowSpacing : spacing();
1765
1766 qreal widthSum = 0;
1767 for (int j = 0; j < maxColWidth.size(); j++) {
1768 if (j)
1769 widthSum += columnSpacing;
1770 widthSum += maxColWidth[j];
1771 }
1772 widthSum += leftPadding() + rightPadding();
1773
1774 qreal heightSum = 0;
1775 for (int i = 0; i < maxRowHeight.size(); i++) {
1776 if (i)
1777 heightSum += rowSpacing;
1778 heightSum += maxRowHeight[i];
1779 }
1780 heightSum += topPadding() + bottomPadding();
1781
1782 contentSize->setHeight(heightSum);
1783 contentSize->setWidth(widthSum);
1784
1785 int end = 0;
1786 if (widthValid())
1787 end = width();
1788 else
1789 end = widthSum;
1790
1791 qreal xoffset = leftPadding();
1792 if (!d->isLeftToRight())
1793 xoffset = end - rightPadding();
1794 qreal yoffset = topPadding();
1795 int curRow =0;
1796 int curCol =0;
1797 for (PositionedItem &child : positionedItems) {
1798 qreal childXOffset = xoffset;
1799
1800 if (effectiveHAlign() == AlignRight)
1801 childXOffset += maxColWidth[curCol] - child.item->width();
1802 else if (hItemAlign() == AlignHCenter)
1803 childXOffset += (maxColWidth[curCol] - child.item->width())/2.0;
1804
1805 if (!d->isLeftToRight())
1806 childXOffset -= maxColWidth[curCol];
1807
1808 qreal alignYOffset = yoffset;
1809 if (m_vItemAlign == AlignVCenter)
1810 alignYOffset += (maxRowHeight[curRow] - child.item->height())/2.0;
1811 else if (m_vItemAlign == AlignBottom)
1812 alignYOffset += maxRowHeight[curRow] - child.item->height();
1813
1814 positionItem(childXOffset, alignYOffset, &child);
1815 child.updatePadding(leftPadding(), topPadding(), rightPadding(), bottomPadding());
1816
1817 if (m_flow == LeftToRight) {
1818 if (d->isLeftToRight())
1819 xoffset += maxColWidth[curCol]+columnSpacing;
1820 else
1821 xoffset -= maxColWidth[curCol]+columnSpacing;
1822 curCol++;
1823 curCol %= c;
1824 if (!curCol) {
1825 yoffset += maxRowHeight[curRow]+rowSpacing;
1826 if (d->isLeftToRight())
1827 xoffset = leftPadding();
1828 else
1829 xoffset = end - rightPadding();
1830 curRow++;
1831 if (curRow>=r)
1832 break;
1833 }
1834 } else {
1835 yoffset += maxRowHeight[curRow]+rowSpacing;
1836 curRow++;
1837 curRow %= r;
1838 if (!curRow) {
1839 if (d->isLeftToRight())
1840 xoffset += maxColWidth[curCol]+columnSpacing;
1841 else
1842 xoffset -= maxColWidth[curCol]+columnSpacing;
1843 yoffset = topPadding();
1844 curCol++;
1845 if (curCol>=c)
1846 break;
1847 }
1848 }
1849 }
1850}
1851
1852void QQuickGrid::reportConflictingAnchors()
1853{
1854 QQuickBasePositionerPrivate *d = static_cast<QQuickBasePositionerPrivate*>(QQuickBasePositionerPrivate::get(this));
1855 for (const PositionedItem &child : positionedItems) {
1856 if (child.item) {
1857 QQuickAnchors *anchors = QQuickItemPrivate::get(static_cast<QQuickItem *>(child.item))->_anchors;
1858 if (anchors && (anchors->usedAnchors() || anchors->fill() || anchors->centerIn())) {
1859 d->anchorConflict = true;
1860 break;
1861 }
1862 }
1863 }
1864 if (d->anchorConflict)
1865 qmlWarning(this) << "Cannot specify anchors for items inside Grid." << " Grid will not function.";
1866}
1867
1868/*!
1869 \qmltype Flow
1870 \nativetype QQuickFlow
1871 \inqmlmodule QtQuick
1872 \inherits Item
1873 \ingroup qtquick-positioners
1874 \brief Positions its children side by side, wrapping as necessary.
1875
1876 The Flow item positions its child items like words on a page, wrapping them
1877 to create rows or columns of items.
1878
1879 Below is a Flow that contains various \l Text items:
1880
1881 \snippet qml/flow.qml flow item
1882
1883 The Flow item automatically positions the child \l Text items side by
1884 side, wrapping as necessary:
1885
1886 \image qml-flow-snippet.png {Text items wrapped like words on a page
1887 within a Flow positioner}
1888
1889 If an item within a Flow is not \l {Item::}{visible}, or if it has a width or
1890 height of 0, the item will not be laid out and it will not be visible within the
1891 Flow. Also, since a Flow automatically positions its children, a child
1892 item within a Flow should not set its \l {Item::x}{x} or \l {Item::y}{y} positions
1893 or anchor itself with any of the \l {Item::anchors}{anchor} properties.
1894
1895 For more information on using Flow and other related positioner-types, see
1896 \l{Item Positioners}.
1897
1898 \sa Column, Row, Grid, Positioner, {Qt Quick Examples - Positioners}
1899*/
1900/*!
1901 \since 5.6
1902 \qmlproperty real QtQuick::Flow::padding
1903 \qmlproperty real QtQuick::Flow::topPadding
1904 \qmlproperty real QtQuick::Flow::leftPadding
1905 \qmlproperty real QtQuick::Flow::bottomPadding
1906 \qmlproperty real QtQuick::Flow::rightPadding
1907
1908 These properties hold the padding around the content.
1909*/
1910/*!
1911 \qmlproperty Transition QtQuick::Flow::populate
1912
1913 This property holds the transition to be run for items that are part of
1914 this positioner at the time of its creation. The transition is run when the positioner
1915 is first created.
1916
1917 The transition can use the \l ViewTransition property to access more details about
1918 the item that is being added. See the \l ViewTransition documentation for more details
1919 and examples on using these transitions.
1920
1921 \sa add, ViewTransition, {Qt Quick Examples - Positioners}
1922*/
1923/*!
1924 \qmlproperty Transition QtQuick::Flow::add
1925
1926 This property holds the transition to be run for items that are added to this
1927 positioner. For a positioner, this applies to:
1928
1929 \list
1930 \li Items that are created or reparented as a child of the positioner after the
1931 positioner has been created
1932 \li Child items that change their \l Item::visible property from false to true, and thus
1933 are now visible
1934 \endlist
1935
1936 The transition can use the \l ViewTransition property to access more details about
1937 the item that is being added. See the \l ViewTransition documentation for more details
1938 and examples on using these transitions.
1939
1940 \note This transition is not applied to the items that are already part of the positioner
1941 at the time of its creation. In this case, the \l populate transition is applied instead.
1942
1943 \sa populate, ViewTransition, {Qt Quick Examples - Positioners}
1944*/
1945/*!
1946 \qmlproperty Transition QtQuick::Flow::move
1947
1948 This property holds the transition to run for items that have moved within the
1949 positioner. For a positioner, this applies to:
1950
1951 \list
1952 \li Child items that move when they are displaced due to the addition, removal or
1953 rearrangement of other items in the positioner
1954 \li Child items that are repositioned due to the resizing of other items in the positioner
1955 \endlist
1956
1957 The transition can use the \l ViewTransition property to access more details about
1958 the item that is being moved. Note, however, that for this move transition, the
1959 ViewTransition.targetIndexes and ViewTransition.targetItems lists are only set when
1960 this transition is triggered by the addition of other items in the positioner; in other
1961 cases, these lists will be empty. See the \l ViewTransition documentation for more details
1962 and examples on using these transitions.
1963
1964 \sa add, populate, ViewTransition, {Qt Quick Examples - Positioners}
1965*/
1966/*!
1967 \qmlproperty real QtQuick::Flow::spacing
1968
1969 spacing is the amount in pixels left empty between each adjacent
1970 item, and defaults to 0.
1971
1972 \sa Grid::spacing
1973*/
1974/*!
1975 \qmlmethod void QtQuick::Flow::forceLayout()
1976 \since 5.9
1977
1978 Flow typically positions its children once per frame. This means that
1979 inside script blocks it is possible for the underlying children to have changed,
1980 but the Flow to have not yet been updated accordingly.
1981
1982 This method forces the Flow to immediately respond to any outstanding
1983 changes in its children.
1984
1985
1986 \b Note: methods in general should only be called after the Component has completed.
1987*/
1988/*!
1989 \qmlsignal QtQuick::Flow::positioningComplete()
1990 \since 5.9
1991
1992 This signal is emitted when positioning has been completed.
1993*/
1994
1996{
1997 Q_DECLARE_PUBLIC(QQuickFlow)
1998
1999public:
2003
2005 {
2006 Q_Q(QQuickFlow);
2007 // Don't postpone, as it might be the only trigger for visible changes.
2008 q->prePositioning();
2010 }
2011
2013};
2014
2015QQuickFlow::QQuickFlow(QQuickItem *parent)
2016: QQuickBasePositioner(*(new QQuickFlowPrivate), Both, parent)
2017{
2018 Q_D(QQuickFlow);
2019 // Flow layout requires relayout if its own size changes too.
2020 d->addItemChangeListener(d, QQuickItemPrivate::Geometry);
2021}
2022
2023/*!
2024 \qmlproperty enumeration QtQuick::Flow::flow
2025 This property holds the flow of the layout.
2026
2027 Possible values are:
2028
2029 \list
2030 \li Flow.LeftToRight (default) - Items are positioned next to
2031 to each other according to the \l layoutDirection until the width of the Flow
2032 is exceeded, then wrapped to the next line.
2033 \li Flow.TopToBottom - Items are positioned next to each
2034 other from top to bottom until the height of the Flow is exceeded,
2035 then wrapped to the next column.
2036 \endlist
2037*/
2038QQuickFlow::Flow QQuickFlow::flow() const
2039{
2040 Q_D(const QQuickFlow);
2041 return d->flow;
2042}
2043
2044void QQuickFlow::setFlow(Flow flow)
2045{
2046 Q_D(QQuickFlow);
2047 if (d->flow != flow) {
2048 d->flow = flow;
2049 prePositioning();
2050 emit flowChanged();
2051 }
2052}
2053
2054/*!
2055 \qmlproperty enumeration QtQuick::Flow::layoutDirection
2056
2057 This property holds the layout direction of the layout.
2058
2059 Possible values are:
2060
2061 \list
2062 \li Qt.LeftToRight (default) - Items are positioned from the top to bottom,
2063 and left to right. The flow direction is dependent on the
2064 \l Flow::flow property.
2065 \li Qt.RightToLeft - Items are positioned from the top to bottom,
2066 and right to left. The flow direction is dependent on the
2067 \l Flow::flow property.
2068 \endlist
2069
2070 \sa Grid::layoutDirection, Row::layoutDirection
2071*/
2072
2073Qt::LayoutDirection QQuickFlow::layoutDirection() const
2074{
2075 Q_D(const QQuickFlow);
2076 return d->layoutDirection;
2077}
2078
2079void QQuickFlow::setLayoutDirection(Qt::LayoutDirection layoutDirection)
2080{
2081 Q_D(QQuickFlow);
2082 if (d->layoutDirection != layoutDirection) {
2083 d->layoutDirection = layoutDirection;
2084 emit layoutDirectionChanged();
2085 d->effectiveLayoutDirectionChange();
2086 }
2087}
2088
2089/*!
2090 \qmlproperty enumeration QtQuick::Flow::effectiveLayoutDirection
2091 This property holds the effective layout direction of the flow.
2092
2093 When using the attached property \l {LayoutMirroring::enabled}{LayoutMirroring::enabled} for locale layouts,
2094 the visual layout direction of the grid positioner will be mirrored. However, the
2095 property \l {Flow::layoutDirection}{layoutDirection} will remain unchanged.
2096
2097 \sa Flow::layoutDirection, {LayoutMirroring}{LayoutMirroring}
2098*/
2099
2100Qt::LayoutDirection QQuickFlow::effectiveLayoutDirection() const
2101{
2102 return QQuickBasePositionerPrivate::getEffectiveLayoutDirection(this);
2103}
2104
2105void QQuickFlow::doPositioning(QSizeF *contentSize)
2106{
2107 //Precondition: All items in the positioned list have a valid item pointer and should be positioned
2108 Q_D(QQuickFlow);
2109
2110 qreal hoffset1 = leftPadding();
2111 qreal hoffset2 = rightPadding();
2112 if (!d->isLeftToRight())
2113 qSwap(hoffset1, hoffset2);
2114 qreal hoffset = hoffset1;
2115 const qreal voffset1 = topPadding();
2116 qreal voffset = voffset1;
2117 qreal linemax = 0;
2118 QList<qreal> hoffsets;
2119 contentSize->setWidth(qMax(contentSize->width(), hoffset1 + hoffset2));
2120 contentSize->setHeight(qMax(contentSize->height(), voffset + bottomPadding()));
2121
2122 for (PositionedItem &child : positionedItems) {
2123 if (d->flow == LeftToRight) {
2124 if (widthValid() && hoffset != hoffset1 && hoffset + child.item->width() + hoffset2 > width()) {
2125 hoffset = hoffset1;
2126 voffset += linemax + spacing();
2127 linemax = 0;
2128 }
2129 } else {
2130 if (heightValid() && voffset != voffset1 && voffset + child.item->height() + bottomPadding() > height()) {
2131 voffset = voffset1;
2132 hoffset += linemax + spacing();
2133 linemax = 0;
2134 }
2135 }
2136
2137 if (d->isLeftToRight()) {
2138 positionItem(hoffset, voffset, &child);
2139 child.updatePadding(leftPadding(), topPadding(), rightPadding(), bottomPadding());
2140 } else {
2141 hoffsets << hoffset;
2142 positionItemY(voffset, &child);
2143 child.topPadding = topPadding();
2144 child.bottomPadding = bottomPadding();
2145 }
2146
2147 contentSize->setWidth(qMax(contentSize->width(), hoffset + child.item->width() + hoffset2));
2148 contentSize->setHeight(qMax(contentSize->height(), voffset + child.item->height() + bottomPadding()));
2149
2150 if (d->flow == LeftToRight) {
2151 hoffset += child.item->width();
2152 hoffset += spacing();
2153 linemax = qMax(linemax, child.item->height());
2154 } else {
2155 voffset += child.item->height();
2156 voffset += spacing();
2157 linemax = qMax(linemax, child.item->width());
2158 }
2159 }
2160
2161 if (d->isLeftToRight())
2162 return;
2163
2164 qreal end;
2165 if (widthValid())
2166 end = width();
2167 else
2168 end = contentSize->width();
2169 int acc = 0;
2170 for (PositionedItem &child : positionedItems) {
2171 hoffset = end - hoffsets[acc++] - child.item->width();
2172 positionItemX(hoffset, &child);
2173 child.leftPadding = leftPadding();
2174 child.rightPadding = rightPadding();
2175 }
2176}
2177
2178void QQuickFlow::reportConflictingAnchors()
2179{
2180 Q_D(QQuickFlow);
2181 for (const PositionedItem &child : positionedItems) {
2182 if (child.item) {
2183 QQuickAnchors *anchors = QQuickItemPrivate::get(static_cast<QQuickItem *>(child.item))->_anchors;
2184 if (anchors && (anchors->usedAnchors() || anchors->fill() || anchors->centerIn())) {
2185 d->anchorConflict = true;
2186 break;
2187 }
2188 }
2189 }
2190 if (d->anchorConflict)
2191 qmlWarning(this) << "Cannot specify anchors for items inside Flow." << " Flow will not function.";
2192}
2193
2194QT_END_NAMESPACE
2195
2196#include "moc_qquickpositioners_p.cpp"
void watchChanges(QQuickItem *other)
void setLeftPadding(qreal value, bool reset=false)
void setBottomPadding(qreal value, bool reset=false)
void setRightPadding(qreal value, bool reset=false)
void setTopPadding(qreal value, bool reset=false)
void unwatchChanges(QQuickItem *other)
\qmltype Flow \nativetype QQuickFlow \inqmlmodule QtQuick \inherits Item
\qmltype Grid \nativetype QQuickGrid \inqmlmodule QtQuick \inherits Item
void setIsFirstItem(bool isFirstItem)
\qmlattachedproperty bool QtQuick::Positioner::isFirstItem \qmlattachedproperty bool QtQuick::Positio...
void setIsLastItem(bool isLastItem)
\qmltype Row \nativetype QQuickRow \inqmlmodule QtQuick \inherits Item
Combined button and popup list for selecting options.
static QT_BEGIN_NAMESPACE const QQuickItemPrivate::ChangeTypes positionerWatchedChanges