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
735*/
736
737QQuickPositionerAttached::QQuickPositionerAttached(QObject *parent) : QObject(parent), m_index(-1), m_isFirstItem(false), m_isLastItem(false)
738{
739 QQuickItem *attachedItem = qobject_cast<QQuickItem *>(parent);
740 if (attachedItem) {
741 QQuickBasePositioner *positioner = qobject_cast<QQuickBasePositioner *>(attachedItem->parent());
742 if (positioner) {
743 positioner->updateAttachedProperties(this, attachedItem);
744 }
745 }
746}
747
748/*!
749 \qmlattachedproperty int QtQuick::Positioner::index
750
751 This property allows the item to determine
752 its index within the positioner.
753*/
754void QQuickPositionerAttached::setIndex(int index)
755{
756 if (m_index == index)
757 return;
758 m_index = index;
759 emit indexChanged();
760}
761
762/*!
763 \qmlattachedproperty bool QtQuick::Positioner::isFirstItem
764 \qmlattachedproperty bool QtQuick::Positioner::isLastItem
765
766 These properties allow the item to determine if it
767 is the first or last item in the positioner, respectively.
768*/
770{
771 if (m_isFirstItem == isFirstItem)
772 return;
773 m_isFirstItem = isFirstItem;
774 emit isFirstItemChanged();
775}
776
778{
779 if (m_isLastItem == isLastItem)
780 return;
781 m_isLastItem = isLastItem;
782 emit isLastItemChanged();
783}
784
785/*!
786 \qmltype Column
787 \nativetype QQuickColumn
788 \inqmlmodule QtQuick
789 \inherits Item
790 \ingroup qtquick-positioners
791 \brief Positions its children in a column.
792
793 Column is a type that positions its child items along a single column.
794 It can be used as a convenient way to vertically position a series of items without
795 using \l {Positioning with Anchors}{anchors}.
796
797 Below is a Column that contains three rectangles of various sizes:
798
799 \snippet qml/column/vertical-positioner.qml document
800
801 The Column automatically positions these items in a vertical formation, like this:
802
803 \image verticalpositioner_example.png
804
805 If an item within a Column is not \l {Item::}{visible}, or if it has a width or
806 height of 0, the item will not be laid out and it will not be visible within the
807 column. Also, since a Column automatically positions its children vertically, a child
808 item within a Column should not set its \l {Item::y}{y} position or vertically
809 anchor itself using the \l {Item::anchors.top}{top}, \l {Item::anchors.bottom}{bottom},
810 \l {Item::anchors.verticalCenter}{anchors.verticalCenter}, \l {Item::anchors.fill}{fill}
811 or \l {Item::anchors.centerIn}{centerIn} anchors. If you need to perform these actions,
812 consider positioning the items without the use of a Column.
813
814 Note that items in a Column can use the \l Positioner attached property to access
815 more information about its position within the Column.
816
817 For more information on using Column and other related positioner-types, see
818 \l{Item Positioners}.
819
820
821 \section1 Using Transitions
822
823 A Column animate items using specific transitions when items are added to or moved
824 within a Column.
825
826 For example, the Column below sets the \l move property to a specific \l Transition:
827
828 \snippet qml/column/column-transitions.qml document
829
830 When the Space key is pressed, the \l {Item::visible}{visible} value of the green
831 \l Rectangle is toggled. As it appears and disappears, the blue \l Rectangle moves within
832 the Column, and the \l move transition is automatically applied to the blue \l Rectangle:
833
834 \image verticalpositioner_transition.gif
835
836 \sa Row, Grid, Flow, Positioner, ColumnLayout, {Qt Quick Examples - Positioners}
837*/
838/*!
839 \since 5.6
840 \qmlproperty real QtQuick::Column::padding
841 \qmlproperty real QtQuick::Column::topPadding
842 \qmlproperty real QtQuick::Column::leftPadding
843 \qmlproperty real QtQuick::Column::bottomPadding
844 \qmlproperty real QtQuick::Column::rightPadding
845
846 These properties hold the padding around the content.
847*/
848/*!
849 \qmlproperty Transition QtQuick::Column::populate
850
851 This property holds the transition to be run for items that are part of
852 this positioner at the time of its creation. The transition is run when the positioner
853 is first created.
854
855 The transition can use the \l ViewTransition property to access more details about
856 the item that is being added. See the \l ViewTransition documentation for more details
857 and examples on using these transitions.
858
859 \sa add, ViewTransition, {Qt Quick Examples - Positioners}
860*/
861/*!
862 \qmlproperty Transition QtQuick::Column::add
863
864 This property holds the transition to be run for items that are added to this
865 positioner. For a positioner, this applies to:
866
867 \list
868 \li Items that are created or reparented as a child of the positioner after the
869 positioner has been created
870 \li Child items that change their \l Item::visible property from false to true, and thus
871 are now visible
872 \endlist
873
874 The transition can use the \l ViewTransition property to access more details about
875 the item that is being added. See the \l ViewTransition documentation for more details
876 and examples on using these transitions.
877
878 \note This transition is not applied to the items that are already part of the positioner
879 at the time of its creation. In this case, the \l populate transition is applied instead.
880
881 \sa populate, ViewTransition, {Qt Quick Examples - Positioners}
882*/
883/*!
884 \qmlproperty Transition QtQuick::Column::move
885
886 This property holds the transition to run for items that have moved within the
887 positioner. For a positioner, this applies to:
888
889 \list
890 \li Child items that move when they are displaced due to the addition, removal or
891 rearrangement of other items in the positioner
892 \li Child items that are repositioned due to the resizing of other items in the positioner
893 \endlist
894
895 The transition can use the \l ViewTransition property to access more details about
896 the item that is being moved. Note, however, that for this move transition, the
897 ViewTransition.targetIndexes and ViewTransition.targetItems lists are only set when
898 this transition is triggered by the addition of other items in the positioner; in other
899 cases, these lists will be empty. See the \l ViewTransition documentation for more details
900 and examples on using these transitions.
901
902 \sa add, populate, ViewTransition, {Qt Quick Examples - Positioners}
903*/
904/*!
905 \qmlproperty real QtQuick::Column::spacing
906
907 The spacing is the amount in pixels left empty between adjacent
908 items. The default spacing is 0.
909
910 \sa Grid::spacing
911*/
912/*!
913 \qmlmethod QtQuick::Column::forceLayout()
914 \since 5.9
915
916 Column typically positions its children once per frame. This means that
917 inside script blocks it is possible for the underlying children to have changed,
918 but the Column to have not yet been updated accordingly.
919
920 This method forces the Column to immediately respond to any outstanding
921 changes in its children.
922
923 \b Note: methods in general should only be called after the Component has completed.
924*/
925/*!
926 \qmlsignal QtQuick::Column::positioningComplete()
927 \since 5.9
928
929 This signal is emitted when positioning has been completed.
930*/
931
932QQuickColumn::QQuickColumn(QQuickItem *parent)
933: QQuickBasePositioner(Vertical, parent)
934{
935}
936
937void QQuickColumn::doPositioning(QSizeF *contentSize)
938{
939 //Precondition: All items in the positioned list have a valid item pointer and should be positioned
940 qreal voffset = topPadding();
941 const qreal padding = leftPadding() + rightPadding();
942 contentSize->setWidth(qMax(contentSize->width(), padding));
943
944 for (PositionedItem &child : positionedItems) {
945 positionItem(child.itemX() + leftPadding() - child.leftPadding, voffset, &child);
946 child.updatePadding(leftPadding(), topPadding(), rightPadding(), bottomPadding());
947 contentSize->setWidth(qMax(contentSize->width(), child.item->width() + padding));
948
949 voffset += child.item->height();
950 voffset += spacing();
951 }
952
953 if (voffset - topPadding() != 0)//If we positioned any items, undo the spacing from the last item
954 voffset -= spacing();
955 contentSize->setHeight(voffset + bottomPadding());
956}
957
958void QQuickColumn::reportConflictingAnchors()
959{
960 QQuickBasePositionerPrivate *d = static_cast<QQuickBasePositionerPrivate*>(QQuickBasePositionerPrivate::get(this));
961 for (const PositionedItem &child : positionedItems) {
962 if (child.item) {
963 QQuickAnchors *anchors = QQuickItemPrivate::get(static_cast<QQuickItem *>(child.item))->_anchors;
964 if (anchors) {
965 QQuickAnchors::Anchors usedAnchors = anchors->usedAnchors();
966 if (usedAnchors & QQuickAnchors::TopAnchor ||
967 usedAnchors & QQuickAnchors::BottomAnchor ||
968 usedAnchors & QQuickAnchors::VCenterAnchor ||
969 anchors->fill() || anchors->centerIn()) {
970 d->anchorConflict = true;
971 break;
972 }
973 }
974 }
975 }
976 if (d->anchorConflict) {
977 qmlWarning(this) << "Cannot specify top, bottom, verticalCenter, fill or centerIn anchors for items inside Column."
978 << " Column will not function.";
979 }
980}
981/*!
982 \qmltype Row
983 \nativetype QQuickRow
984 \inqmlmodule QtQuick
985 \inherits Item
986 \ingroup qtquick-positioners
987 \brief Positions its children in a row.
988
989 Row is a type that positions its child items along a single row.
990 It can be used as a convenient way to horizontally position a series of items without
991 using \l {Positioning with Anchors}{anchors}.
992
993 Below is a Row that contains three rectangles of various sizes:
994
995 \snippet qml/row/row.qml document
996
997 The Row automatically positions these items in a horizontal formation, like this:
998
999 \image horizontalpositioner_example.png
1000
1001 If an item within a Row is not \l {Item::}{visible}, or if it has a width or
1002 height of 0, the item will not be laid out and it will not be visible within the
1003 row. Also, since a Row automatically positions its children horizontally, a child
1004 item within a Row should not set its \l {Item::x}{x} position or horizontally
1005 anchor itself using the \l {Item::anchors.left}{left}, \l {Item::anchors.right}{right},
1006 \l {Item::anchors.horizontalCenter}{anchors.horizontalCenter}, \l {Item::anchors.fill}{fill}
1007 or \l {Item::anchors.centerIn}{centerIn} anchors. If you need to perform these actions,
1008 consider positioning the items without the use of a Row.
1009
1010 Note that items in a Row can use the \l Positioner attached property to access
1011 more information about its position within the Row.
1012
1013 For more information on using Row and other related positioner-types, see
1014 \l{Item Positioners}.
1015
1016
1017 \sa Column, Grid, Flow, Positioner, RowLayout, {Qt Quick Examples - Positioners}
1018*/
1019/*!
1020 \since 5.6
1021 \qmlproperty real QtQuick::Row::padding
1022 \qmlproperty real QtQuick::Row::topPadding
1023 \qmlproperty real QtQuick::Row::leftPadding
1024 \qmlproperty real QtQuick::Row::bottomPadding
1025 \qmlproperty real QtQuick::Row::rightPadding
1026
1027 These properties hold the padding around the content.
1028*/
1029/*!
1030 \qmlproperty Transition QtQuick::Row::populate
1031
1032 This property holds the transition to be run for items that are part of
1033 this positioner at the time of its creation. The transition is run when the positioner
1034 is first created.
1035
1036 The transition can use the \l ViewTransition property to access more details about
1037 the item that is being added. See the \l ViewTransition documentation for more details
1038 and examples on using these transitions.
1039
1040 \sa add, ViewTransition, {Qt Quick Examples - Positioners}
1041*/
1042/*!
1043 \qmlproperty Transition QtQuick::Row::add
1044
1045 This property holds the transition to be run for items that are added to this
1046 positioner. For a positioner, this applies to:
1047
1048 \list
1049 \li Items that are created or reparented as a child of the positioner after the
1050 positioner has been created
1051 \li Child items that change their \l Item::visible property from false to true, and thus
1052 are now visible
1053 \endlist
1054
1055 The transition can use the \l ViewTransition property to access more details about
1056 the item that is being added. See the \l ViewTransition documentation for more details
1057 and examples on using these transitions.
1058
1059 \note This transition is not applied to the items that are already part of the positioner
1060 at the time of its creation. In this case, the \l populate transition is applied instead.
1061
1062 \sa populate, ViewTransition, {Qt Quick Examples - Positioners}
1063*/
1064/*!
1065 \qmlproperty Transition QtQuick::Row::move
1066
1067 This property holds the transition to run for items that have moved within the
1068 positioner. For a positioner, this applies to:
1069
1070 \list
1071 \li Child items that move when they are displaced due to the addition, removal or
1072 rearrangement of other items in the positioner
1073 \li Child items that are repositioned due to the resizing of other items in the positioner
1074 \endlist
1075
1076 The transition can use the \l ViewTransition property to access more details about
1077 the item that is being moved. Note, however, that for this move transition, the
1078 ViewTransition.targetIndexes and ViewTransition.targetItems lists are only set when
1079 this transition is triggered by the addition of other items in the positioner; in other
1080 cases, these lists will be empty. See the \l ViewTransition documentation for more details
1081 and examples on using these transitions.
1082
1083 \sa add, populate, ViewTransition, {Qt Quick Examples - Positioners}
1084*/
1085/*!
1086 \qmlproperty real QtQuick::Row::spacing
1087
1088 The spacing is the amount in pixels left empty between adjacent
1089 items. The default spacing is 0.
1090
1091 \sa Grid::spacing
1092*/
1093/*!
1094 \qmlmethod QtQuick::Row::forceLayout()
1095 \since 5.9
1096
1097 Row typically positions its children once per frame. This means that
1098 inside script blocks it is possible for the underlying children to have changed,
1099 but the Row to have not yet been updated accordingly.
1100
1101 This method forces the Row to immediately respond to any outstanding
1102 changes in its children.
1103
1104 \b Note: methods in general should only be called after the Component has completed.
1105*/
1106/*!
1107 \qmlsignal QtQuick::Row::positioningComplete()
1108 \since 5.9
1109
1110 This signal is emitted when positioning has been completed.
1111*/
1112
1114{
1115 Q_DECLARE_PUBLIC(QQuickRow)
1116
1117public:
1121
1123 {
1124 Q_Q(QQuickRow);
1125 // For RTL layout the positioning changes when the width changes.
1128 else
1130 // Don't postpone, as it might be the only trigger for visible changes.
1131 q->prePositioning();
1133 }
1134};
1135
1136QQuickRow::QQuickRow(QQuickItem *parent)
1137: QQuickBasePositioner(*new QQuickRowPrivate, Horizontal, parent)
1138{
1139}
1140/*!
1141 \qmlproperty enumeration QtQuick::Row::layoutDirection
1142
1143 This property holds the layoutDirection of the row.
1144
1145 Possible values:
1146
1147 \value Qt.LeftToRight (default) Items are laid out from left to right. If the width of the row is
1148 explicitly set, the left anchor remains to the left of the row.
1149 \value Qt.RightToLeft Items are laid out from right to left. If the width of the row is
1150 explicitly set, the right anchor remains to the right of the row.
1151
1152 \sa Grid::layoutDirection, Flow::layoutDirection
1153*/
1154
1155Qt::LayoutDirection QQuickRow::layoutDirection() const
1156{
1157 return QQuickBasePositionerPrivate::getLayoutDirection(this);
1158}
1159
1160void QQuickRow::setLayoutDirection(Qt::LayoutDirection layoutDirection)
1161{
1162 QQuickBasePositionerPrivate *d = static_cast<QQuickBasePositionerPrivate* >(QQuickBasePositionerPrivate::get(this));
1163 if (d->layoutDirection != layoutDirection) {
1164 d->layoutDirection = layoutDirection;
1165 emit layoutDirectionChanged();
1166 d->effectiveLayoutDirectionChange();
1167 }
1168}
1169/*!
1170 \qmlproperty enumeration QtQuick::Row::effectiveLayoutDirection
1171 This property holds the effective layout direction of the row.
1172
1173 When using the attached property \l {LayoutMirroring::enabled}{LayoutMirroring::enabled} for locale layouts,
1174 the visual layout direction of the row positioner will be mirrored. However, the
1175 property \l {Row::layoutDirection}{layoutDirection} will remain unchanged.
1176
1177 \sa Row::layoutDirection, {LayoutMirroring}{LayoutMirroring}
1178*/
1179
1180Qt::LayoutDirection QQuickRow::effectiveLayoutDirection() const
1181{
1182 return QQuickBasePositionerPrivate::getEffectiveLayoutDirection(this);
1183}
1184
1185void QQuickRow::doPositioning(QSizeF *contentSize)
1186{
1187 //Precondition: All items in the positioned list have a valid item pointer and should be positioned
1188 QQuickBasePositionerPrivate *d = static_cast<QQuickBasePositionerPrivate* >(QQuickBasePositionerPrivate::get(this));
1189 qreal hoffset1 = leftPadding();
1190 qreal hoffset2 = rightPadding();
1191 if (!d->isLeftToRight())
1192 qSwap(hoffset1, hoffset2);
1193 qreal hoffset = hoffset1;
1194 const qreal padding = topPadding() + bottomPadding();
1195 contentSize->setHeight(qMax(contentSize->height(), padding));
1196
1197 QList<qreal> hoffsets;
1198 for (PositionedItem &child : positionedItems) {
1199 if (d->isLeftToRight()) {
1200 positionItem(hoffset, child.itemY() + topPadding() - child.topPadding, &child);
1201 child.updatePadding(leftPadding(), topPadding(), rightPadding(), bottomPadding());
1202 } else {
1203 hoffsets << hoffset;
1204 }
1205
1206 contentSize->setHeight(qMax(contentSize->height(), child.item->height() + padding));
1207
1208 hoffset += child.item->width();
1209 hoffset += spacing();
1210 }
1211
1212 if (hoffset - hoffset1 != 0)//If we positioned any items, undo the extra spacing from the last item
1213 hoffset -= spacing();
1214 contentSize->setWidth(hoffset + hoffset2);
1215
1216 if (d->isLeftToRight())
1217 return;
1218
1219 //Right to Left layout
1220 qreal end = 0;
1221 if (!widthValid())
1222 end = contentSize->width();
1223 else
1224 end = width();
1225
1226 int acc = 0;
1227 for (PositionedItem &child : positionedItems) {
1228 hoffset = end - hoffsets[acc++] - child.item->width();
1229 positionItem(hoffset, child.itemY() + topPadding() - child.topPadding, &child);
1230 child.updatePadding(leftPadding(), topPadding(), rightPadding(), bottomPadding());
1231 }
1232}
1233
1234void QQuickRow::reportConflictingAnchors()
1235{
1236 QQuickBasePositionerPrivate *d = static_cast<QQuickBasePositionerPrivate*>(QQuickBasePositionerPrivate::get(this));
1237 for (const PositionedItem &child : positionedItems) {
1238 if (child.item) {
1239 QQuickAnchors *anchors = QQuickItemPrivate::get(static_cast<QQuickItem *>(child.item))->_anchors;
1240 if (anchors) {
1241 QQuickAnchors::Anchors usedAnchors = anchors->usedAnchors();
1242 if (usedAnchors & QQuickAnchors::LeftAnchor ||
1243 usedAnchors & QQuickAnchors::RightAnchor ||
1244 usedAnchors & QQuickAnchors::HCenterAnchor ||
1245 anchors->fill() || anchors->centerIn()) {
1246 d->anchorConflict = true;
1247 break;
1248 }
1249 }
1250 }
1251 }
1252 if (d->anchorConflict)
1253 qmlWarning(this) << "Cannot specify left, right, horizontalCenter, fill or centerIn anchors for items inside Row."
1254 << " Row will not function.";
1255}
1256
1257/*!
1258 \qmltype Grid
1259 \nativetype QQuickGrid
1260 \inqmlmodule QtQuick
1261 \inherits Item
1262 \ingroup qtquick-positioners
1263 \brief Positions its children in grid formation.
1264
1265 Grid is a type that positions its child items in grid formation.
1266
1267 A Grid creates a grid of cells that is large enough to hold all of its
1268 child items, and places these items in the cells from left to right
1269 and top to bottom. Each item is positioned at the top-left corner of its
1270 cell with position (0, 0).
1271
1272 A Grid defaults to four columns, and creates as many rows as are necessary to
1273 fit all of its child items. The number of rows and columns can be constrained
1274 by setting the \l rows and \l columns properties.
1275
1276 For example, below is a Grid that contains five rectangles of various sizes:
1277
1278 \snippet qml/grid/grid.qml document
1279
1280 The Grid automatically positions the child items in a grid formation:
1281
1282 \image gridLayout_example.png
1283
1284 If an item within a Grid is not \l {Item::}{visible}, or if it has a width or
1285 height of 0, the item will not be laid out and it will not be visible within the
1286 column. Also, since a Grid automatically positions its children, a child
1287 item within a Grid should not set its \l {Item::x}{x} or \l {Item::y}{y} positions
1288 or anchor itself with any of the \l {Item::anchors}{anchor} properties.
1289
1290 For more information on using Grid and other related positioner-types, see
1291 \l{Item Positioners}.
1292
1293
1294 \sa Flow, Row, Column, Positioner, GridLayout, {Qt Quick Examples - Positioners}
1295*/
1296/*!
1297 \since 5.6
1298 \qmlproperty real QtQuick::Grid::padding
1299 \qmlproperty real QtQuick::Grid::topPadding
1300 \qmlproperty real QtQuick::Grid::leftPadding
1301 \qmlproperty real QtQuick::Grid::bottomPadding
1302 \qmlproperty real QtQuick::Grid::rightPadding
1303
1304 These properties hold the padding around the content.
1305*/
1306/*!
1307 \qmlproperty Transition QtQuick::Grid::populate
1308
1309 This property holds the transition to be run for items that are part of
1310 this positioner at the time of its creation. The transition is run when the positioner
1311 is first created.
1312
1313 The transition can use the \l ViewTransition property to access more details about
1314 the item that is being added. See the \l ViewTransition documentation for more details
1315 and examples on using these transitions.
1316
1317 \sa add, ViewTransition, {Qt Quick Examples - Positioners}
1318*/
1319/*!
1320 \qmlproperty Transition QtQuick::Grid::add
1321
1322 This property holds the transition to be run for items that are added to this
1323 positioner. For a positioner, this applies to:
1324
1325 \list
1326 \li Items that are created or reparented as a child of the positioner after the
1327 positioner has been created
1328 \li Child items that change their \l Item::visible property from false to true, and thus
1329 are now visible
1330 \endlist
1331
1332 The transition can use the \l ViewTransition property to access more details about
1333 the item that is being added. See the \l ViewTransition documentation for more details
1334 and examples on using these transitions.
1335
1336 \note This transition is not applied to the items that are already part of the positioner
1337 at the time of its creation. In this case, the \l populate transition is applied instead.
1338
1339 \sa populate, ViewTransition, {Qt Quick Examples - Positioners}
1340*/
1341/*!
1342 \qmlproperty Transition QtQuick::Grid::move
1343
1344 This property holds the transition to run for items that have moved within the
1345 positioner. For a positioner, this applies to:
1346
1347 \list
1348 \li Child items that move when they are displaced due to the addition, removal or
1349 rearrangement of other items in the positioner
1350 \li Child items that are repositioned due to the resizing of other items in the positioner
1351 \endlist
1352
1353 The transition can use the \l ViewTransition property to access more details about
1354 the item that is being moved. Note, however, that for this move transition, the
1355 ViewTransition.targetIndexes and ViewTransition.targetItems lists are only set when
1356 this transition is triggered by the addition of other items in the positioner; in other
1357 cases, these lists will be empty. See the \l ViewTransition documentation for more details
1358 and examples on using these transitions.
1359
1360 \sa add, populate, ViewTransition, {Qt Quick Examples - Positioners}
1361*/
1362/*!
1363 \qmlproperty real QtQuick::Grid::spacing
1364
1365 The spacing is the amount in pixels left empty between adjacent
1366 items. The amount of spacing applied will be the same in the
1367 horizontal and vertical directions. The default spacing is 0.
1368
1369 The below example places a Grid containing a red, a blue and a
1370 green rectangle on a gray background. The area the grid positioner
1371 occupies is colored white. The positioner on the left has the
1372 no spacing (the default), and the positioner on the right has
1373 a spacing of 6.
1374
1375 \inlineimage qml-grid-no-spacing.png
1376 \inlineimage qml-grid-spacing.png
1377
1378 \sa rows, columns
1379*/
1380/*!
1381 \qmlmethod QtQuick::Grid::forceLayout()
1382 \since 5.9
1383
1384 Grid typically positions its children once per frame. This means that
1385 inside script blocks it is possible for the underlying children to have changed,
1386 but the Grid to have not yet been updated accordingly.
1387
1388 This method forces the Grid to immediately respond to any outstanding
1389 changes in its children.
1390
1391 \b Note: methods in general should only be called after the Component has completed.
1392*/
1393/*!
1394 \qmlsignal QtQuick::Grid::positioningComplete()
1395 \since 5.9
1396
1397 This signal is emitted when positioning has been completed.
1398*/
1399
1401{
1402 Q_DECLARE_PUBLIC(QQuickGrid)
1403
1404public:
1408
1410 {
1411 Q_Q(QQuickGrid);
1412 // For RTL layout the positioning changes when the width changes.
1415 else
1417 // Don't postpone, as it might be the only trigger for visible changes.
1418 q->prePositioning();
1421 }
1422};
1423
1424QQuickGrid::QQuickGrid(QQuickItem *parent)
1425 : QQuickBasePositioner(*new QQuickGridPrivate, Both, parent)
1426 , m_rows(-1)
1427 , m_columns(-1)
1428 , m_rowSpacing(-1)
1429 , m_columnSpacing(-1)
1430 , m_useRowSpacing(false)
1431 , m_useColumnSpacing(false)
1432 , m_flow(LeftToRight)
1433 , m_hItemAlign(AlignLeft)
1434 , m_vItemAlign(AlignTop)
1435{
1436}
1437
1438/*!
1439 \qmlproperty int QtQuick::Grid::columns
1440
1441 This property holds the number of columns in the grid. The default
1442 number of columns is 4.
1443
1444 If the grid does not have enough items to fill the specified
1445 number of columns, some columns will be of zero width.
1446*/
1447
1448/*!
1449 \qmlproperty int QtQuick::Grid::rows
1450 This property holds the number of rows in the grid.
1451
1452 If the grid does not have enough items to fill the specified
1453 number of rows, some rows will be of zero width.
1454*/
1455
1456void QQuickGrid::setColumns(const int columns)
1457{
1458 if (columns == m_columns)
1459 return;
1460 m_columns = columns;
1461 prePositioning();
1462 emit columnsChanged();
1463}
1464
1465void QQuickGrid::setRows(const int rows)
1466{
1467 if (rows == m_rows)
1468 return;
1469 m_rows = rows;
1470 prePositioning();
1471 emit rowsChanged();
1472}
1473
1474/*!
1475 \qmlproperty enumeration QtQuick::Grid::flow
1476 This property holds the flow of the layout.
1477
1478 Possible values are:
1479
1480 \list
1481 \li Grid.LeftToRight (default) - Items are positioned next to
1482 each other in the \l layoutDirection, then wrapped to the next line.
1483 \li Grid.TopToBottom - Items are positioned next to each
1484 other from top to bottom, then wrapped to the next column.
1485 \endlist
1486*/
1487QQuickGrid::Flow QQuickGrid::flow() const
1488{
1489 return m_flow;
1490}
1491
1492void QQuickGrid::setFlow(Flow flow)
1493{
1494 if (m_flow != flow) {
1495 m_flow = flow;
1496 prePositioning();
1497 emit flowChanged();
1498 }
1499}
1500
1501/*!
1502 \qmlproperty real QtQuick::Grid::rowSpacing
1503
1504 This property holds the spacing in pixels between rows.
1505
1506 If this property is not set, then spacing is used for the row spacing.
1507
1508 By default this property is not set.
1509
1510 \sa columnSpacing
1511 \since 5.0
1512*/
1513void QQuickGrid::setRowSpacing(const qreal rowSpacing)
1514{
1515 if (rowSpacing == m_rowSpacing)
1516 return;
1517 m_rowSpacing = rowSpacing;
1518 m_useRowSpacing = true;
1519 prePositioning();
1520 emit rowSpacingChanged();
1521}
1522
1523/*!
1524 \qmlproperty real QtQuick::Grid::columnSpacing
1525
1526 This property holds the spacing in pixels between columns.
1527
1528 If this property is not set, then spacing is used for the column spacing.
1529
1530 By default this property is not set.
1531
1532 \sa rowSpacing
1533 \since 5.0
1534*/
1535void QQuickGrid::setColumnSpacing(const qreal columnSpacing)
1536{
1537 if (columnSpacing == m_columnSpacing)
1538 return;
1539 m_columnSpacing = columnSpacing;
1540 m_useColumnSpacing = true;
1541 prePositioning();
1542 emit columnSpacingChanged();
1543}
1544
1545/*!
1546 \qmlproperty enumeration QtQuick::Grid::layoutDirection
1547
1548 This property holds the layout direction of the layout.
1549
1550 Possible values are:
1551
1552 \list
1553 \li Qt.LeftToRight (default) - Items are positioned from the top to bottom,
1554 and left to right. The flow direction is dependent on the
1555 \l Grid::flow property.
1556 \li Qt.RightToLeft - Items are positioned from the top to bottom,
1557 and right to left. The flow direction is dependent on the
1558 \l Grid::flow property.
1559 \endlist
1560
1561 \sa Flow::layoutDirection, Row::layoutDirection
1562*/
1563Qt::LayoutDirection QQuickGrid::layoutDirection() const
1564{
1565 return QQuickBasePositionerPrivate::getLayoutDirection(this);
1566}
1567
1568void QQuickGrid::setLayoutDirection(Qt::LayoutDirection layoutDirection)
1569{
1570 QQuickBasePositionerPrivate *d = static_cast<QQuickBasePositionerPrivate*>(QQuickBasePositionerPrivate::get(this));
1571 if (d->layoutDirection != layoutDirection) {
1572 d->layoutDirection = layoutDirection;
1573 emit layoutDirectionChanged();
1574 d->effectiveLayoutDirectionChange();
1575 }
1576}
1577
1578/*!
1579 \qmlproperty enumeration QtQuick::Grid::effectiveLayoutDirection
1580 This property holds the effective layout direction of the grid.
1581
1582 When using the attached property \l {LayoutMirroring::enabled}{LayoutMirroring::enabled} for locale layouts,
1583 the visual layout direction of the grid positioner will be mirrored. However, the
1584 property \l {Grid::layoutDirection}{layoutDirection} will remain unchanged.
1585
1586 \sa Grid::layoutDirection, {LayoutMirroring}{LayoutMirroring}
1587*/
1588Qt::LayoutDirection QQuickGrid::effectiveLayoutDirection() const
1589{
1590 return QQuickBasePositionerPrivate::getEffectiveLayoutDirection(this);
1591}
1592
1593/*!
1594 \qmlproperty enumeration QtQuick::Grid::horizontalItemAlignment
1595 \qmlproperty enumeration QtQuick::Grid::verticalItemAlignment
1596 \qmlproperty enumeration QtQuick::Grid::effectiveHorizontalItemAlignment
1597 \since 5.1
1598
1599 Sets the horizontal and vertical alignment of items in the Grid. By default,
1600 the items are vertically aligned to the top. Horizontal
1601 alignment follows the layoutDirection of the Grid, for example when having a layoutDirection
1602 from LeftToRight, the items will be aligned on the left.
1603
1604 The valid values for \c horizontalItemAlignment are, \c Grid.AlignLeft, \c Grid.AlignRight and
1605 \c Grid.AlignHCenter.
1606
1607 The valid values for \c verticalItemAlignment are \c Grid.AlignTop, \c Grid.AlignBottom
1608 and \c Grid.AlignVCenter.
1609
1610 The below images show three examples of how to align items.
1611
1612 \table
1613 \row
1614 \li
1615 \li \inlineimage gridLayout_aligntopleft.png
1616 \li \inlineimage gridLayout_aligntop.png
1617 \li \inlineimage gridLayout_aligncenter.png
1618 \row
1619 \li Horizontal alignment
1620 \li AlignLeft
1621 \li AlignHCenter
1622 \li AlignHCenter
1623 \row
1624 \li Vertical alignment
1625 \li AlignTop
1626 \li AlignTop
1627 \li AlignVCenter
1628 \endtable
1629
1630
1631 When mirroring the layout using either the attached property LayoutMirroring::enabled or
1632 by setting the layoutDirection, the horizontal alignment of items will be mirrored as well.
1633 However, the property \c horizontalItemAlignment will remain unchanged.
1634 To query the effective horizontal alignment of items, use the read-only property
1635 \c effectiveHorizontalItemAlignment.
1636
1637 \sa Grid::layoutDirection, {LayoutMirroring}{LayoutMirroring}
1638*/
1639QQuickGrid::HAlignment QQuickGrid::hItemAlign() const
1640{
1641 return m_hItemAlign;
1642}
1643void QQuickGrid::setHItemAlign(HAlignment align)
1644{
1645 if (m_hItemAlign != align) {
1646 m_hItemAlign = align;
1647 prePositioning();
1648 emit horizontalAlignmentChanged(align);
1649 emit effectiveHorizontalAlignmentChanged(effectiveHAlign());
1650 }
1651}
1652
1653QQuickGrid::HAlignment QQuickGrid::effectiveHAlign() const
1654{
1655 HAlignment effectiveAlignment = m_hItemAlign;
1656 if (effectiveLayoutDirection() == Qt::RightToLeft) {
1657 switch (hItemAlign()) {
1658 case AlignLeft:
1659 effectiveAlignment = AlignRight;
1660 break;
1661 case AlignRight:
1662 effectiveAlignment = AlignLeft;
1663 break;
1664 default:
1665 break;
1666 }
1667 }
1668 return effectiveAlignment;
1669}
1670
1671
1672QQuickGrid::VAlignment QQuickGrid::vItemAlign() const
1673{
1674 return m_vItemAlign;
1675}
1676void QQuickGrid::setVItemAlign(VAlignment align)
1677{
1678 if (m_vItemAlign != align) {
1679 m_vItemAlign = align;
1680 prePositioning();
1681 emit verticalAlignmentChanged(align);
1682 }
1683}
1684
1685void QQuickGrid::doPositioning(QSizeF *contentSize)
1686{
1687 //Precondition: All items in the positioned list have a valid item pointer and should be positioned
1688 QQuickBasePositionerPrivate *d = static_cast<QQuickBasePositionerPrivate*>(QQuickBasePositionerPrivate::get(this));
1689 int c = m_columns;
1690 int r = m_rows;
1691 const int numVisible = int(positionedItems.size());
1692
1693 if (m_columns <= 0 && m_rows <= 0) {
1694 c = 4;
1695 r = (numVisible+3)/4;
1696 } else if (m_rows <= 0) {
1697 r = (numVisible+(m_columns-1))/m_columns;
1698 } else if (m_columns <= 0) {
1699 c = (numVisible+(m_rows-1))/m_rows;
1700 }
1701
1702 if (r == 0 || c == 0) {
1703 contentSize->setHeight(topPadding() + bottomPadding());
1704 contentSize->setWidth(leftPadding() + rightPadding());
1705 return; //Nothing else to do
1706 }
1707
1708 if (numVisible > r * c) {
1709 qmlWarning(this) << "Grid contains more visible items (" << numVisible << ") than rows*columns (" << r * c << ")";
1710 }
1711
1712 QList<qreal> maxColWidth;
1713 QList<qreal> maxRowHeight;
1714 int childIndex =0;
1715 if (m_flow == LeftToRight) {
1716 for (int i = 0; i < r; i++) {
1717 for (int j = 0; j < c; j++) {
1718 if (j == 0)
1719 maxRowHeight << 0;
1720 if (i == 0)
1721 maxColWidth << 0;
1722
1723 if (childIndex == numVisible)
1724 break;
1725
1726 const PositionedItem &child = positionedItems[childIndex++];
1727 if (child.item->width() > maxColWidth[j])
1728 maxColWidth[j] = child.item->width();
1729 if (child.item->height() > maxRowHeight[i])
1730 maxRowHeight[i] = child.item->height();
1731 }
1732 }
1733 } else {
1734 for (int j = 0; j < c; j++) {
1735 for (int i = 0; i < r; i++) {
1736 if (j == 0)
1737 maxRowHeight << 0;
1738 if (i == 0)
1739 maxColWidth << 0;
1740
1741 if (childIndex == numVisible)
1742 break;
1743
1744 const PositionedItem &child = positionedItems[childIndex++];
1745 if (child.item->width() > maxColWidth[j])
1746 maxColWidth[j] = child.item->width();
1747 if (child.item->height() > maxRowHeight[i])
1748 maxRowHeight[i] = child.item->height();
1749 }
1750 }
1751 }
1752
1753 qreal columnSpacing = m_useColumnSpacing ? m_columnSpacing : spacing();
1754 qreal rowSpacing = m_useRowSpacing ? m_rowSpacing : spacing();
1755
1756 qreal widthSum = 0;
1757 for (int j = 0; j < maxColWidth.size(); j++) {
1758 if (j)
1759 widthSum += columnSpacing;
1760 widthSum += maxColWidth[j];
1761 }
1762 widthSum += leftPadding() + rightPadding();
1763
1764 qreal heightSum = 0;
1765 for (int i = 0; i < maxRowHeight.size(); i++) {
1766 if (i)
1767 heightSum += rowSpacing;
1768 heightSum += maxRowHeight[i];
1769 }
1770 heightSum += topPadding() + bottomPadding();
1771
1772 contentSize->setHeight(heightSum);
1773 contentSize->setWidth(widthSum);
1774
1775 int end = 0;
1776 if (widthValid())
1777 end = width();
1778 else
1779 end = widthSum;
1780
1781 qreal xoffset = leftPadding();
1782 if (!d->isLeftToRight())
1783 xoffset = end - rightPadding();
1784 qreal yoffset = topPadding();
1785 int curRow =0;
1786 int curCol =0;
1787 for (PositionedItem &child : positionedItems) {
1788 qreal childXOffset = xoffset;
1789
1790 if (effectiveHAlign() == AlignRight)
1791 childXOffset += maxColWidth[curCol] - child.item->width();
1792 else if (hItemAlign() == AlignHCenter)
1793 childXOffset += (maxColWidth[curCol] - child.item->width())/2.0;
1794
1795 if (!d->isLeftToRight())
1796 childXOffset -= maxColWidth[curCol];
1797
1798 qreal alignYOffset = yoffset;
1799 if (m_vItemAlign == AlignVCenter)
1800 alignYOffset += (maxRowHeight[curRow] - child.item->height())/2.0;
1801 else if (m_vItemAlign == AlignBottom)
1802 alignYOffset += maxRowHeight[curRow] - child.item->height();
1803
1804 positionItem(childXOffset, alignYOffset, &child);
1805 child.updatePadding(leftPadding(), topPadding(), rightPadding(), bottomPadding());
1806
1807 if (m_flow == LeftToRight) {
1808 if (d->isLeftToRight())
1809 xoffset += maxColWidth[curCol]+columnSpacing;
1810 else
1811 xoffset -= maxColWidth[curCol]+columnSpacing;
1812 curCol++;
1813 curCol %= c;
1814 if (!curCol) {
1815 yoffset += maxRowHeight[curRow]+rowSpacing;
1816 if (d->isLeftToRight())
1817 xoffset = leftPadding();
1818 else
1819 xoffset = end - rightPadding();
1820 curRow++;
1821 if (curRow>=r)
1822 break;
1823 }
1824 } else {
1825 yoffset += maxRowHeight[curRow]+rowSpacing;
1826 curRow++;
1827 curRow %= r;
1828 if (!curRow) {
1829 if (d->isLeftToRight())
1830 xoffset += maxColWidth[curCol]+columnSpacing;
1831 else
1832 xoffset -= maxColWidth[curCol]+columnSpacing;
1833 yoffset = topPadding();
1834 curCol++;
1835 if (curCol>=c)
1836 break;
1837 }
1838 }
1839 }
1840}
1841
1842void QQuickGrid::reportConflictingAnchors()
1843{
1844 QQuickBasePositionerPrivate *d = static_cast<QQuickBasePositionerPrivate*>(QQuickBasePositionerPrivate::get(this));
1845 for (const PositionedItem &child : positionedItems) {
1846 if (child.item) {
1847 QQuickAnchors *anchors = QQuickItemPrivate::get(static_cast<QQuickItem *>(child.item))->_anchors;
1848 if (anchors && (anchors->usedAnchors() || anchors->fill() || anchors->centerIn())) {
1849 d->anchorConflict = true;
1850 break;
1851 }
1852 }
1853 }
1854 if (d->anchorConflict)
1855 qmlWarning(this) << "Cannot specify anchors for items inside Grid." << " Grid will not function.";
1856}
1857
1858/*!
1859 \qmltype Flow
1860 \nativetype QQuickFlow
1861 \inqmlmodule QtQuick
1862 \inherits Item
1863 \ingroup qtquick-positioners
1864 \brief Positions its children side by side, wrapping as necessary.
1865
1866 The Flow item positions its child items like words on a page, wrapping them
1867 to create rows or columns of items.
1868
1869 Below is a Flow that contains various \l Text items:
1870
1871 \snippet qml/flow.qml flow item
1872
1873 The Flow item automatically positions the child \l Text items side by
1874 side, wrapping as necessary:
1875
1876 \image qml-flow-snippet.png
1877
1878 If an item within a Flow is not \l {Item::}{visible}, or if it has a width or
1879 height of 0, the item will not be laid out and it will not be visible within the
1880 Flow. Also, since a Flow automatically positions its children, a child
1881 item within a Flow should not set its \l {Item::x}{x} or \l {Item::y}{y} positions
1882 or anchor itself with any of the \l {Item::anchors}{anchor} properties.
1883
1884 For more information on using Flow and other related positioner-types, see
1885 \l{Item Positioners}.
1886
1887 \sa Column, Row, Grid, Positioner, {Qt Quick Examples - Positioners}
1888*/
1889/*!
1890 \since 5.6
1891 \qmlproperty real QtQuick::Flow::padding
1892 \qmlproperty real QtQuick::Flow::topPadding
1893 \qmlproperty real QtQuick::Flow::leftPadding
1894 \qmlproperty real QtQuick::Flow::bottomPadding
1895 \qmlproperty real QtQuick::Flow::rightPadding
1896
1897 These properties hold the padding around the content.
1898*/
1899/*!
1900 \qmlproperty Transition QtQuick::Flow::populate
1901
1902 This property holds the transition to be run for items that are part of
1903 this positioner at the time of its creation. The transition is run when the positioner
1904 is first created.
1905
1906 The transition can use the \l ViewTransition property to access more details about
1907 the item that is being added. See the \l ViewTransition documentation for more details
1908 and examples on using these transitions.
1909
1910 \sa add, ViewTransition, {Qt Quick Examples - Positioners}
1911*/
1912/*!
1913 \qmlproperty Transition QtQuick::Flow::add
1914
1915 This property holds the transition to be run for items that are added to this
1916 positioner. For a positioner, this applies to:
1917
1918 \list
1919 \li Items that are created or reparented as a child of the positioner after the
1920 positioner has been created
1921 \li Child items that change their \l Item::visible property from false to true, and thus
1922 are now visible
1923 \endlist
1924
1925 The transition can use the \l ViewTransition property to access more details about
1926 the item that is being added. See the \l ViewTransition documentation for more details
1927 and examples on using these transitions.
1928
1929 \note This transition is not applied to the items that are already part of the positioner
1930 at the time of its creation. In this case, the \l populate transition is applied instead.
1931
1932 \sa populate, ViewTransition, {Qt Quick Examples - Positioners}
1933*/
1934/*!
1935 \qmlproperty Transition QtQuick::Flow::move
1936
1937 This property holds the transition to run for items that have moved within the
1938 positioner. For a positioner, this applies to:
1939
1940 \list
1941 \li Child items that move when they are displaced due to the addition, removal or
1942 rearrangement of other items in the positioner
1943 \li Child items that are repositioned due to the resizing of other items in the positioner
1944 \endlist
1945
1946 The transition can use the \l ViewTransition property to access more details about
1947 the item that is being moved. Note, however, that for this move transition, the
1948 ViewTransition.targetIndexes and ViewTransition.targetItems lists are only set when
1949 this transition is triggered by the addition of other items in the positioner; in other
1950 cases, these lists will be empty. See the \l ViewTransition documentation for more details
1951 and examples on using these transitions.
1952
1953 \sa add, populate, ViewTransition, {Qt Quick Examples - Positioners}
1954*/
1955/*!
1956 \qmlproperty real QtQuick::Flow::spacing
1957
1958 spacing is the amount in pixels left empty between each adjacent
1959 item, and defaults to 0.
1960
1961 \sa Grid::spacing
1962*/
1963/*!
1964 \qmlmethod QtQuick::Flow::forceLayout()
1965 \since 5.9
1966
1967 Flow typically positions its children once per frame. This means that
1968 inside script blocks it is possible for the underlying children to have changed,
1969 but the Flow to have not yet been updated accordingly.
1970
1971 This method forces the Flow to immediately respond to any outstanding
1972 changes in its children.
1973
1974
1975 \b Note: methods in general should only be called after the Component has completed.
1976*/
1977/*!
1978 \qmlsignal QtQuick::Flow::positioningComplete()
1979 \since 5.9
1980
1981 This signal is emitted when positioning has been completed.
1982*/
1983
1985{
1986 Q_DECLARE_PUBLIC(QQuickFlow)
1987
1988public:
1992
1994 {
1995 Q_Q(QQuickFlow);
1996 // Don't postpone, as it might be the only trigger for visible changes.
1997 q->prePositioning();
1999 }
2000
2002};
2003
2004QQuickFlow::QQuickFlow(QQuickItem *parent)
2005: QQuickBasePositioner(*(new QQuickFlowPrivate), Both, parent)
2006{
2007 Q_D(QQuickFlow);
2008 // Flow layout requires relayout if its own size changes too.
2009 d->addItemChangeListener(d, QQuickItemPrivate::Geometry);
2010}
2011
2012/*!
2013 \qmlproperty enumeration QtQuick::Flow::flow
2014 This property holds the flow of the layout.
2015
2016 Possible values are:
2017
2018 \list
2019 \li Flow.LeftToRight (default) - Items are positioned next to
2020 to each other according to the \l layoutDirection until the width of the Flow
2021 is exceeded, then wrapped to the next line.
2022 \li Flow.TopToBottom - Items are positioned next to each
2023 other from top to bottom until the height of the Flow is exceeded,
2024 then wrapped to the next column.
2025 \endlist
2026*/
2027QQuickFlow::Flow QQuickFlow::flow() const
2028{
2029 Q_D(const QQuickFlow);
2030 return d->flow;
2031}
2032
2033void QQuickFlow::setFlow(Flow flow)
2034{
2035 Q_D(QQuickFlow);
2036 if (d->flow != flow) {
2037 d->flow = flow;
2038 prePositioning();
2039 emit flowChanged();
2040 }
2041}
2042
2043/*!
2044 \qmlproperty enumeration QtQuick::Flow::layoutDirection
2045
2046 This property holds the layout direction of the layout.
2047
2048 Possible values are:
2049
2050 \list
2051 \li Qt.LeftToRight (default) - Items are positioned from the top to bottom,
2052 and left to right. The flow direction is dependent on the
2053 \l Flow::flow property.
2054 \li Qt.RightToLeft - Items are positioned from the top to bottom,
2055 and right to left. The flow direction is dependent on the
2056 \l Flow::flow property.
2057 \endlist
2058
2059 \sa Grid::layoutDirection, Row::layoutDirection
2060*/
2061
2062Qt::LayoutDirection QQuickFlow::layoutDirection() const
2063{
2064 Q_D(const QQuickFlow);
2065 return d->layoutDirection;
2066}
2067
2068void QQuickFlow::setLayoutDirection(Qt::LayoutDirection layoutDirection)
2069{
2070 Q_D(QQuickFlow);
2071 if (d->layoutDirection != layoutDirection) {
2072 d->layoutDirection = layoutDirection;
2073 emit layoutDirectionChanged();
2074 d->effectiveLayoutDirectionChange();
2075 }
2076}
2077
2078/*!
2079 \qmlproperty enumeration QtQuick::Flow::effectiveLayoutDirection
2080 This property holds the effective layout direction of the flow.
2081
2082 When using the attached property \l {LayoutMirroring::enabled}{LayoutMirroring::enabled} for locale layouts,
2083 the visual layout direction of the grid positioner will be mirrored. However, the
2084 property \l {Flow::layoutDirection}{layoutDirection} will remain unchanged.
2085
2086 \sa Flow::layoutDirection, {LayoutMirroring}{LayoutMirroring}
2087*/
2088
2089Qt::LayoutDirection QQuickFlow::effectiveLayoutDirection() const
2090{
2091 return QQuickBasePositionerPrivate::getEffectiveLayoutDirection(this);
2092}
2093
2094void QQuickFlow::doPositioning(QSizeF *contentSize)
2095{
2096 //Precondition: All items in the positioned list have a valid item pointer and should be positioned
2097 Q_D(QQuickFlow);
2098
2099 qreal hoffset1 = leftPadding();
2100 qreal hoffset2 = rightPadding();
2101 if (!d->isLeftToRight())
2102 qSwap(hoffset1, hoffset2);
2103 qreal hoffset = hoffset1;
2104 const qreal voffset1 = topPadding();
2105 qreal voffset = voffset1;
2106 qreal linemax = 0;
2107 QList<qreal> hoffsets;
2108 contentSize->setWidth(qMax(contentSize->width(), hoffset1 + hoffset2));
2109 contentSize->setHeight(qMax(contentSize->height(), voffset + bottomPadding()));
2110
2111 for (PositionedItem &child : positionedItems) {
2112 if (d->flow == LeftToRight) {
2113 if (widthValid() && hoffset != hoffset1 && hoffset + child.item->width() + hoffset2 > width()) {
2114 hoffset = hoffset1;
2115 voffset += linemax + spacing();
2116 linemax = 0;
2117 }
2118 } else {
2119 if (heightValid() && voffset != voffset1 && voffset + child.item->height() + bottomPadding() > height()) {
2120 voffset = voffset1;
2121 hoffset += linemax + spacing();
2122 linemax = 0;
2123 }
2124 }
2125
2126 if (d->isLeftToRight()) {
2127 positionItem(hoffset, voffset, &child);
2128 child.updatePadding(leftPadding(), topPadding(), rightPadding(), bottomPadding());
2129 } else {
2130 hoffsets << hoffset;
2131 positionItemY(voffset, &child);
2132 child.topPadding = topPadding();
2133 child.bottomPadding = bottomPadding();
2134 }
2135
2136 contentSize->setWidth(qMax(contentSize->width(), hoffset + child.item->width() + hoffset2));
2137 contentSize->setHeight(qMax(contentSize->height(), voffset + child.item->height() + bottomPadding()));
2138
2139 if (d->flow == LeftToRight) {
2140 hoffset += child.item->width();
2141 hoffset += spacing();
2142 linemax = qMax(linemax, child.item->height());
2143 } else {
2144 voffset += child.item->height();
2145 voffset += spacing();
2146 linemax = qMax(linemax, child.item->width());
2147 }
2148 }
2149
2150 if (d->isLeftToRight())
2151 return;
2152
2153 qreal end;
2154 if (widthValid())
2155 end = width();
2156 else
2157 end = contentSize->width();
2158 int acc = 0;
2159 for (PositionedItem &child : positionedItems) {
2160 hoffset = end - hoffsets[acc++] - child.item->width();
2161 positionItemX(hoffset, &child);
2162 child.leftPadding = leftPadding();
2163 child.rightPadding = rightPadding();
2164 }
2165}
2166
2167void QQuickFlow::reportConflictingAnchors()
2168{
2169 Q_D(QQuickFlow);
2170 for (const PositionedItem &child : positionedItems) {
2171 if (child.item) {
2172 QQuickAnchors *anchors = QQuickItemPrivate::get(static_cast<QQuickItem *>(child.item))->_anchors;
2173 if (anchors && (anchors->usedAnchors() || anchors->fill() || anchors->centerIn())) {
2174 d->anchorConflict = true;
2175 break;
2176 }
2177 }
2178 }
2179 if (d->anchorConflict)
2180 qmlWarning(this) << "Cannot specify anchors for items inside Flow." << " Flow will not function.";
2181}
2182
2183QT_END_NAMESPACE
2184
2185#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
static QT_BEGIN_NAMESPACE const QQuickItemPrivate::ChangeTypes positionerWatchedChanges