Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
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
6
7#include <QtQml/qqml.h>
8#include <QtQml/qqmlinfo.h>
9#include <QtCore/qcoreapplication.h>
10
11#include <QtQuick/private/qquicktransition_p.h>
12
14
15static const QQuickItemPrivate::ChangeTypes positionerWatchedChanges
20
22{
24 otherPrivate->addItemChangeListener(this, positionerWatchedChanges);
25}
26
28{
30 otherPrivate->removeItemChangeListener(this, positionerWatchedChanges);
31}
32
33
35 : item(i)
36#if QT_CONFIG(quick_viewtransitions)
37 , transitionableItem(nullptr)
38#endif
39 , index(-1)
40 , isNew(false)
41 , isVisible(true)
42 , topPadding(0)
43 , leftPadding(0)
44 , rightPadding(0)
45 , bottomPadding(0)
46{
47}
48
50{
51#if QT_CONFIG(quick_viewtransitions)
52 delete transitionableItem;
53#endif
54}
55
57{
58 return
59#if QT_CONFIG(quick_viewtransitions)
60 transitionableItem ? transitionableItem->itemX() :
61#endif
62 item->x();
63}
64
66{
67 return
68#if QT_CONFIG(quick_viewtransitions)
69 transitionableItem ? transitionableItem->itemY() :
70#endif
71 item->y();
72}
73
75{
76#if QT_CONFIG(quick_viewtransitions)
77 if (transitionableItem)
78 transitionableItem->moveTo(pos);
79 else
80#endif
81 item->setPosition(pos);
82}
83
84#if QT_CONFIG(quick_viewtransitions)
85void QQuickBasePositioner::PositionedItem::transitionNextReposition(QQuickItemViewTransitioner *transitioner, QQuickItemViewTransitioner::TransitionType type, bool asTarget)
86{
87 if (!transitioner)
88 return;
89 if (!transitionableItem)
90 transitionableItem = new QQuickItemViewTransitionableItem(item);
91 transitioner->transitionNextReposition(transitionableItem, type, asTarget);
92}
93
94bool QQuickBasePositioner::PositionedItem::prepareTransition(QQuickItemViewTransitioner *transitioner, const QRectF &viewBounds)
95{
96 return transitionableItem ? transitionableItem->prepareTransition(transitioner, index, viewBounds) : false;
97}
98
99void QQuickBasePositioner::PositionedItem::startTransition(QQuickItemViewTransitioner *transitioner)
100{
101 if (transitionableItem)
102 transitionableItem->startTransition(transitioner, index);
103}
104#endif
105
113
147
149{
151#if QT_CONFIG(quick_viewtransitions)
152 delete d->transitioner;
153#endif
154 for (int i = 0; i < positionedItems.count(); ++i)
155 d->unwatchChanges(positionedItems.at(i).item);
156 for (int i = 0; i < unpositionedItems.count(); ++i)
157 d->unwatchChanges(unpositionedItems.at(i).item);
160}
161
163{
165 if (d->positioningDirty)
167}
168
170{
171 Q_D(const QQuickBasePositioner);
172 return d->spacing;
173}
174
176{
178 if (s == d->spacing)
179 return;
180 d->spacing = s;
181 d->setPositioningDirty();
183}
184
185#if QT_CONFIG(quick_viewtransitions)
186QQuickTransition *QQuickBasePositioner::populate() const
187{
188 Q_D(const QQuickBasePositioner);
189 return d->transitioner ? d->transitioner->populateTransition : nullptr;
190}
191
192void QQuickBasePositioner::setPopulate(QQuickTransition *transition)
193{
195 if (!d->transitioner)
196 d->transitioner = new QQuickItemViewTransitioner;
197 if (d->transitioner->populateTransition != transition) {
198 d->transitioner->populateTransition = transition;
200 }
201}
202
203QQuickTransition *QQuickBasePositioner::move() const
204{
205 Q_D(const QQuickBasePositioner);
206 return d->transitioner ? d->transitioner->displacedTransition : nullptr;
207}
208
209void QQuickBasePositioner::setMove(QQuickTransition *mt)
210{
212 if (!d->transitioner)
213 d->transitioner = new QQuickItemViewTransitioner;
214 if (mt == d->transitioner->displacedTransition)
215 return;
216
217 d->transitioner->displacedTransition = mt;
219}
220
221QQuickTransition *QQuickBasePositioner::add() const
222{
223 Q_D(const QQuickBasePositioner);
224 return d->transitioner ? d->transitioner->addTransition : nullptr;
225}
226
227void QQuickBasePositioner::setAdd(QQuickTransition *add)
228{
230 if (!d->transitioner)
231 d->transitioner = new QQuickItemViewTransitioner;
232 if (add == d->transitioner->addTransition)
233 return;
234
235 d->transitioner->addTransition = add;
237}
238#endif
239
241{
242#if QT_CONFIG(quick_viewtransitions)
244#endif
246#if QT_CONFIG(quick_viewtransitions)
247 if (d->transitioner)
248 d->transitioner->setPopulateTransitionEnabled(true);
249#endif
250 positionedItems.reserve(childItems().size());
252#if QT_CONFIG(quick_viewtransitions)
253 if (d->transitioner)
254 d->transitioner->setPopulateTransitionEnabled(false);
255#endif
256}
257
259{
261 if (change == ItemChildAddedChange) {
262 d->setPositioningDirty();
263 } else if (change == ItemChildRemovedChange) {
264 QQuickItem *child = value.item;
266 int idx = positionedItems.find(posItem);
267 if (idx >= 0) {
268 d->unwatchChanges(child);
270 } else if ((idx = unpositionedItems.find(posItem)) >= 0) {
271 d->unwatchChanges(child);
273 }
274 d->setPositioningDirty();
275 }
276
278}
279
280void QQuickBasePositioner::forceLayout()
281{
282 updatePolish();
283}
284
286{
288 if (!isComponentComplete())
289 return;
290
291 if (d->doingPositioning)
292 return;
293
294 d->positioningDirty = false;
295 d->doingPositioning = true;
296 //Need to order children by creation order modified by stacking order
297 QList<QQuickItem *> children = childItems();
298
299 QPODVector<PositionedItem,8> oldItems;
300 positionedItems.copyAndClear(oldItems);
301 for (int ii = 0; ii < unpositionedItems.count(); ii++)
302 oldItems.append(unpositionedItems[ii]);
303 unpositionedItems.clear();
304#if QT_CONFIG(quick_viewtransitions)
305 int addedIndex = -1;
306#endif
307
308 for (int ii = 0; ii < children.size(); ++ii) {
310 if (QQuickItemPrivate::get(child)->isTransparentForPositioner())
311 continue;
313 PositionedItem posItem(child);
314 int wIdx = oldItems.find(posItem);
315 if (wIdx < 0) {
316 d->watchChanges(child);
317 posItem.isNew = true;
318 if (!childPrivate->explicitVisible || !child->width() || !child->height()) {
319 posItem.isVisible = false;
320 posItem.index = -1;
321 unpositionedItems.append(posItem);
322 } else {
323 posItem.index = positionedItems.count();
324 positionedItems.append(posItem);
325
326#if QT_CONFIG(quick_viewtransitions)
327 if (d->transitioner) {
328 if (addedIndex < 0)
329 addedIndex = posItem.index;
330 PositionedItem *theItem = &positionedItems[positionedItems.count()-1];
331 if (d->transitioner->canTransition(QQuickItemViewTransitioner::PopulateTransition, true))
332 theItem->transitionNextReposition(d->transitioner, QQuickItemViewTransitioner::PopulateTransition, true);
333 else if (!d->transitioner->populateTransitionEnabled())
334 theItem->transitionNextReposition(d->transitioner, QQuickItemViewTransitioner::AddTransition, true);
335 }
336#endif
337 }
338 } else {
339 PositionedItem *item = &oldItems[wIdx];
340 // Items are only omitted from positioning if they are explicitly hidden
341 // i.e. their positioning is not affected if an ancestor is hidden.
342 if (!childPrivate->explicitVisible || !child->width() || !child->height()) {
343 item->isVisible = false;
344 item->index = -1;
345 unpositionedItems.append(*item);
346 } else if (!item->isVisible) {
347 // item changed from non-visible to visible, treat it as a "new" item
348 item->isVisible = true;
349 item->isNew = true;
350 item->index = positionedItems.count();
351 positionedItems.append(*item);
352
353#if QT_CONFIG(quick_viewtransitions)
354 if (d->transitioner) {
355 if (addedIndex < 0)
356 addedIndex = item->index;
357 positionedItems[positionedItems.count()-1].transitionNextReposition(d->transitioner, QQuickItemViewTransitioner::AddTransition, true);
358 }
359#endif
360 } else {
361 item->isNew = false;
362 item->index = positionedItems.count();
363 positionedItems.append(*item);
364 }
365 }
366 }
367
368#if QT_CONFIG(quick_viewtransitions)
369 if (d->transitioner) {
370 for (int i=0; i<positionedItems.count(); i++) {
371 if (!positionedItems[i].isNew) {
372 if (addedIndex >= 0) {
373 positionedItems[i].transitionNextReposition(d->transitioner, QQuickItemViewTransitioner::AddTransition, false);
374 } else {
375 // just queue the item for a move-type displace - if the item hasn't
376 // moved anywhere, it won't be transitioned anyway
377 positionedItems[i].transitionNextReposition(d->transitioner, QQuickItemViewTransitioner::MoveTransition, false);
378 }
379 }
380 }
381 }
382#endif
383
384 QSizeF contentSize(0,0);
386 if (!d->anchorConflict) {
387 doPositioning(&contentSize);
389 }
390
391#if QT_CONFIG(quick_viewtransitions)
392 if (d->transitioner) {
393 QRectF viewBounds(QPointF(), contentSize);
394 for (int i=0; i<positionedItems.count(); i++)
395 positionedItems[i].prepareTransition(d->transitioner, viewBounds);
396 for (int i=0; i<positionedItems.count(); i++)
397 positionedItems[i].startTransition(d->transitioner);
398 d->transitioner->resetTargetLists();
399 }
400#endif
401
402 d->doingPositioning = false;
403
404 //Set implicit size to the size of its children
405 setImplicitSize(contentSize.width(), contentSize.height());
406
407 emit positioningComplete();
408}
409
411{
412 if ( target->itemX() != x || target->itemY() != y )
413 target->moveTo(QPointF(x, y));
414}
415
417{
419 if (target->itemX() != x
420 && (d->type == Horizontal || d->type == Both)) {
421 target->moveTo(QPointF(x, target->itemY()));
422 }
423}
424
426{
428 if (target->itemY() != y
429 && (d->type == Vertical || d->type == Both)) {
430 target->moveTo(QPointF(target->itemX(), y));
431 }
432}
433
434/*
435 Since PositionedItem values are stored by value, their internal transitionableItem pointers
436 must be cleaned up when a PositionedItem is removed from a QPODVector, otherwise the pointer
437 is never deleted since QPODVector doesn't invoke the destructor.
438 */
439void QQuickBasePositioner::removePositionedItem(QPODVector<PositionedItem,8> *items, int index)
440{
441 Q_ASSERT(index >= 0 && index < items->count());
442#if QT_CONFIG(quick_viewtransitions)
443 delete items->at(index).transitionableItem;
444#endif
446}
447void QQuickBasePositioner::clearPositionedItems(QPODVector<PositionedItem,8> *items)
448{
449#if QT_CONFIG(quick_viewtransitions)
450 for (int i=0; i<items->count(); i++)
451 delete items->at(i).transitionableItem;
452#endif
453 items->clear();
454}
455
460
461void QQuickBasePositioner::updateAttachedProperties(QQuickPositionerAttached *specificProperty, QQuickItem *specificPropertyOwner) const
462{
463 // If this function is deemed too expensive or shows up in profiles, it could
464 // be changed to run only when there are attached properties present. This
465 // could be a flag in the positioner that is set by the attached property
466 // constructor.
467 QQuickPositionerAttached *prevLastProperty = nullptr;
468 QQuickPositionerAttached *lastProperty = nullptr;
469
470 for (int ii = 0; ii < positionedItems.count(); ++ii) {
471 const PositionedItem &child = positionedItems.at(ii);
472 if (!child.item)
473 continue;
474
475 QQuickPositionerAttached *property = nullptr;
476
477 if (specificProperty) {
478 if (specificPropertyOwner == child.item) {
479 property = specificProperty;
480 }
481 } else {
482 property = static_cast<QQuickPositionerAttached *>(qmlAttachedPropertiesObject<QQuickBasePositioner>(child.item, false));
483 }
484
485 if (property) {
486 property->setIndex(ii);
487 property->setIsFirstItem(ii == 0);
488
489 if (property->isLastItem()) {
490 if (prevLastProperty)
491 prevLastProperty->setIsLastItem(false); // there can be only one last property
492 prevLastProperty = property;
493 }
494 }
495
496 lastProperty = property;
497 }
498
499 if (prevLastProperty && prevLastProperty != lastProperty)
500 prevLastProperty->setIsLastItem(false);
501 if (lastProperty)
502 lastProperty->setIsLastItem(true);
503
504 // clear attached properties for unpositioned items
505 for (int ii = 0; ii < unpositionedItems.count(); ++ii) {
506 const PositionedItem &child = unpositionedItems.at(ii);
507 if (!child.item)
508 continue;
509
510 QQuickPositionerAttached *property = nullptr;
511
512 if (specificProperty) {
513 if (specificPropertyOwner == child.item) {
514 property = specificProperty;
515 }
516 } else {
517 property = static_cast<QQuickPositionerAttached *>(qmlAttachedPropertiesObject<QQuickBasePositioner>(child.item, false));
518 }
519
520 if (property) {
521 property->setIndex(-1);
522 property->setIsFirstItem(false);
523 property->setIsLastItem(false);
524 }
525 }
526}
527
529{
530 Q_D(const QQuickBasePositioner);
531 return d->padding();
532}
533
535{
537 if (qFuzzyCompare(d->padding(), padding))
538 return;
539
540 d->extra.value().padding = padding;
541 d->setPositioningDirty();
542 emit paddingChanged();
543 if (!d->extra.isAllocated() || !d->extra->explicitTopPadding)
544 emit topPaddingChanged();
545 if (!d->extra.isAllocated() || !d->extra->explicitLeftPadding)
546 emit leftPaddingChanged();
547 if (!d->extra.isAllocated() || !d->extra->explicitRightPadding)
548 emit rightPaddingChanged();
549 if (!d->extra.isAllocated() || !d->extra->explicitBottomPadding)
550 emit bottomPaddingChanged();
551}
552
557
559{
560 Q_D(const QQuickBasePositioner);
561 if (d->extra.isAllocated() && d->extra->explicitTopPadding)
562 return d->extra->topPadding;
563 return d->padding();
564}
565
567{
569 d->setTopPadding(padding);
570}
571
573{
575 d->setTopPadding(0, true);
576}
577
579{
580 Q_D(const QQuickBasePositioner);
581 if (d->extra.isAllocated() && d->extra->explicitLeftPadding)
582 return d->extra->leftPadding;
583 return d->padding();
584}
585
587{
589 d->setLeftPadding(padding);
590}
591
593{
595 d->setLeftPadding(0, true);
596}
597
599{
600 Q_D(const QQuickBasePositioner);
601 if (d->extra.isAllocated() && d->extra->explicitRightPadding)
602 return d->extra->rightPadding;
603 return d->padding();
604}
605
607{
609 d->setRightPadding(padding);
610}
611
613{
615 d->setRightPadding(0, true);
616}
617
619{
620 Q_D(const QQuickBasePositioner);
621 if (d->extra.isAllocated() && d->extra->explicitBottomPadding)
622 return d->extra->bottomPadding;
623 return d->padding();
624}
625
627{
629 d->setBottomPadding(padding);
630}
631
633{
635 d->setBottomPadding(0, true);
636}
637
639 : padding(0)
640 , topPadding(0)
641 , leftPadding(0)
642 , rightPadding(0)
643 , bottomPadding(0)
644 , explicitTopPadding(false)
645 , explicitLeftPadding(false)
646 , explicitRightPadding(false)
647 , explicitBottomPadding(false)
648{
649}
650
652{
654 qreal oldPadding = q->topPadding();
655 if (!reset || extra.isAllocated()) {
656 extra.value().topPadding = value;
657 extra.value().explicitTopPadding = !reset;
658 }
659 if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) {
661 emit q->topPaddingChanged();
662 }
663}
664
666{
668 qreal oldPadding = q->leftPadding();
669 if (!reset || extra.isAllocated()) {
670 extra.value().leftPadding = value;
671 extra.value().explicitLeftPadding = !reset;
672 }
673 if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) {
675 emit q->leftPaddingChanged();
676 }
677}
678
680{
682 qreal oldPadding = q->rightPadding();
683 if (!reset || extra.isAllocated()) {
684 extra.value().rightPadding = value;
685 extra.value().explicitRightPadding = !reset;
686 }
687 if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) {
689 emit q->rightPaddingChanged();
690 }
691}
692
694{
696 qreal oldPadding = q->bottomPadding();
697 if (!reset || extra.isAllocated()) {
698 extra.value().bottomPadding = value;
699 extra.value().explicitBottomPadding = !reset;
700 }
701 if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) {
703 emit q->bottomPaddingChanged();
704 }
705}
706
743{
745 if (attachedItem) {
746 QQuickBasePositioner *positioner = qobject_cast<QQuickBasePositioner *>(attachedItem->parent());
747 if (positioner) {
748 positioner->updateAttachedProperties(this, attachedItem);
749 }
750 }
751}
752
760{
761 if (m_index == index)
762 return;
763 m_index = index;
765}
766
775{
776 if (m_isFirstItem == isFirstItem)
777 return;
778 m_isFirstItem = isFirstItem;
780}
781
783{
784 if (m_isLastItem == isLastItem)
785 return;
786 m_isLastItem = isLastItem;
788}
789
938: QQuickBasePositioner(Vertical, parent)
939{
940}
941
943{
944 //Precondition: All items in the positioned list have a valid item pointer and should be positioned
945 qreal voffset = topPadding();
947 contentSize->setWidth(qMax(contentSize->width(), padding));
948
949 for (int ii = 0; ii < positionedItems.count(); ++ii) {
951 positionItem(child.itemX() + leftPadding() - child.leftPadding, voffset, &child);
952 child.updatePadding(leftPadding(), topPadding(), rightPadding(), bottomPadding());
953 contentSize->setWidth(qMax(contentSize->width(), child.item->width() + padding));
954
955 voffset += child.item->height();
956 voffset += spacing();
957 }
958
959 if (voffset - topPadding() != 0)//If we positioned any items, undo the spacing from the last item
960 voffset -= spacing();
961 contentSize->setHeight(voffset + bottomPadding());
962}
963
965{
967 for (int ii = 0; ii < positionedItems.count(); ++ii) {
968 const PositionedItem &child = positionedItems.at(ii);
969 if (child.item) {
970 QQuickAnchors *anchors = QQuickItemPrivate::get(static_cast<QQuickItem *>(child.item))->_anchors;
971 if (anchors) {
972 QQuickAnchors::Anchors usedAnchors = anchors->usedAnchors();
973 if (usedAnchors & QQuickAnchors::TopAnchor ||
974 usedAnchors & QQuickAnchors::BottomAnchor ||
975 usedAnchors & QQuickAnchors::VCenterAnchor ||
976 anchors->fill() || anchors->centerIn()) {
977 d->anchorConflict = true;
978 break;
979 }
980 }
981 }
982 }
983 if (d->anchorConflict) {
984 qmlWarning(this) << "Cannot specify top, bottom, verticalCenter, fill or centerIn anchors for items inside Column."
985 << " Column will not function.";
986 }
987}
1121{
1122 Q_DECLARE_PUBLIC(QQuickRow)
1123
1124public:
1128
1130 {
1131 Q_Q(QQuickRow);
1132 // For RTL layout the positioning changes when the width changes.
1135 else
1137 // Don't postpone, as it might be the only trigger for visible changes.
1138 q->prePositioning();
1139 emit q->effectiveLayoutDirectionChanged();
1140 }
1141};
1142
1144: QQuickBasePositioner(*new QQuickRowPrivate, Horizontal, parent)
1145{
1146}
1166
1168{
1170 if (d->layoutDirection != layoutDirection) {
1173 d->effectiveLayoutDirectionChange();
1174 }
1175}
1191
1193{
1194 //Precondition: All items in the positioned list have a valid item pointer and should be positioned
1196 qreal hoffset1 = leftPadding();
1197 qreal hoffset2 = rightPadding();
1198 if (!d->isLeftToRight())
1199 qSwap(hoffset1, hoffset2);
1200 qreal hoffset = hoffset1;
1201 const qreal padding = topPadding() + bottomPadding();
1202 contentSize->setHeight(qMax(contentSize->height(), padding));
1203
1204 QList<qreal> hoffsets;
1205 for (int ii = 0; ii < positionedItems.count(); ++ii) {
1207
1208 if (d->isLeftToRight()) {
1209 positionItem(hoffset, child.itemY() + topPadding() - child.topPadding, &child);
1210 child.updatePadding(leftPadding(), topPadding(), rightPadding(), bottomPadding());
1211 } else {
1212 hoffsets << hoffset;
1213 }
1214
1215 contentSize->setHeight(qMax(contentSize->height(), child.item->height() + padding));
1216
1217 hoffset += child.item->width();
1218 hoffset += spacing();
1219 }
1220
1221 if (hoffset - hoffset1 != 0)//If we positioned any items, undo the extra spacing from the last item
1222 hoffset -= spacing();
1223 contentSize->setWidth(hoffset + hoffset2);
1224
1225 if (d->isLeftToRight())
1226 return;
1227
1228 //Right to Left layout
1229 qreal end = 0;
1230 if (!widthValid())
1231 end = contentSize->width();
1232 else
1233 end = width();
1234
1235 int acc = 0;
1236 for (int ii = 0; ii < positionedItems.count(); ++ii) {
1238 hoffset = end - hoffsets[acc++] - child.item->width();
1239 positionItem(hoffset, child.itemY() + topPadding() - child.topPadding, &child);
1240 child.updatePadding(leftPadding(), topPadding(), rightPadding(), bottomPadding());
1241 }
1242}
1243
1245{
1247 for (int ii = 0; ii < positionedItems.count(); ++ii) {
1248 const PositionedItem &child = positionedItems.at(ii);
1249 if (child.item) {
1250 QQuickAnchors *anchors = QQuickItemPrivate::get(static_cast<QQuickItem *>(child.item))->_anchors;
1251 if (anchors) {
1252 QQuickAnchors::Anchors usedAnchors = anchors->usedAnchors();
1253 if (usedAnchors & QQuickAnchors::LeftAnchor ||
1254 usedAnchors & QQuickAnchors::RightAnchor ||
1255 usedAnchors & QQuickAnchors::HCenterAnchor ||
1256 anchors->fill() || anchors->centerIn()) {
1257 d->anchorConflict = true;
1258 break;
1259 }
1260 }
1261 }
1262 }
1263 if (d->anchorConflict)
1264 qmlWarning(this) << "Cannot specify left, right, horizontalCenter, fill or centerIn anchors for items inside Row."
1265 << " Row will not function.";
1266}
1267
1412{
1413 Q_DECLARE_PUBLIC(QQuickGrid)
1414
1415public:
1419
1421 {
1422 Q_Q(QQuickGrid);
1423 // For RTL layout the positioning changes when the width changes.
1426 else
1428 // Don't postpone, as it might be the only trigger for visible changes.
1429 q->prePositioning();
1430 emit q->effectiveLayoutDirectionChanged();
1431 emit q->effectiveHorizontalAlignmentChanged(q->effectiveHAlign());
1432 }
1433};
1434
1436 : QQuickBasePositioner(*new QQuickGridPrivate, Both, parent)
1437 , m_rows(-1)
1438 , m_columns(-1)
1439 , m_rowSpacing(-1)
1440 , m_columnSpacing(-1)
1441 , m_useRowSpacing(false)
1442 , m_useColumnSpacing(false)
1443 , m_flow(LeftToRight)
1444 , m_hItemAlign(AlignLeft)
1445 , m_vItemAlign(AlignTop)
1446{
1447}
1448
1467void QQuickGrid::setColumns(const int columns)
1468{
1469 if (columns == m_columns)
1470 return;
1471 m_columns = columns;
1474}
1475
1476void QQuickGrid::setRows(const int rows)
1477{
1478 if (rows == m_rows)
1479 return;
1480 m_rows = rows;
1482 emit rowsChanged();
1483}
1484
1499{
1500 return m_flow;
1501}
1502
1504{
1505 if (m_flow != flow) {
1506 m_flow = flow;
1508 emit flowChanged();
1509 }
1510}
1511
1524void QQuickGrid::setRowSpacing(const qreal rowSpacing)
1525{
1526 if (rowSpacing == m_rowSpacing)
1527 return;
1528 m_rowSpacing = rowSpacing;
1529 m_useRowSpacing = true;
1532}
1533
1546void QQuickGrid::setColumnSpacing(const qreal columnSpacing)
1547{
1548 if (columnSpacing == m_columnSpacing)
1549 return;
1550 m_columnSpacing = columnSpacing;
1551 m_useColumnSpacing = true;
1554}
1555
1578
1580{
1582 if (d->layoutDirection != layoutDirection) {
1585 d->effectiveLayoutDirectionChange();
1586 }
1587}
1588
1603
1651{
1652 return m_hItemAlign;
1653}
1655{
1656 if (m_hItemAlign != align) {
1657 m_hItemAlign = align;
1659 emit horizontalAlignmentChanged(align);
1660 emit effectiveHorizontalAlignmentChanged(effectiveHAlign());
1661 }
1662}
1663
1665{
1666 HAlignment effectiveAlignment = m_hItemAlign;
1668 switch (hItemAlign()) {
1669 case AlignLeft:
1670 effectiveAlignment = AlignRight;
1671 break;
1672 case AlignRight:
1673 effectiveAlignment = AlignLeft;
1674 break;
1675 default:
1676 break;
1677 }
1678 }
1679 return effectiveAlignment;
1680}
1681
1682
1684{
1685 return m_vItemAlign;
1686}
1688{
1689 if (m_vItemAlign != align) {
1690 m_vItemAlign = align;
1692 emit verticalAlignmentChanged(align);
1693 }
1694}
1695
1697{
1698 //Precondition: All items in the positioned list have a valid item pointer and should be positioned
1700 int c = m_columns;
1701 int r = m_rows;
1702 const int numVisible = positionedItems.count();
1703
1704 if (m_columns <= 0 && m_rows <= 0) {
1705 c = 4;
1706 r = (numVisible+3)/4;
1707 } else if (m_rows <= 0) {
1708 r = (numVisible+(m_columns-1))/m_columns;
1709 } else if (m_columns <= 0) {
1710 c = (numVisible+(m_rows-1))/m_rows;
1711 }
1712
1713 if (r == 0 || c == 0) {
1714 contentSize->setHeight(topPadding() + bottomPadding());
1715 contentSize->setWidth(leftPadding() + rightPadding());
1716 return; //Nothing else to do
1717 }
1718
1719 if (numVisible > r * c) {
1720 qmlWarning(this) << "Grid contains more visible items (" << numVisible << ") than rows*columns (" << r * c << ")";
1721 }
1722
1723 QList<qreal> maxColWidth;
1724 QList<qreal> maxRowHeight;
1725 int childIndex =0;
1726 if (m_flow == LeftToRight) {
1727 for (int i = 0; i < r; i++) {
1728 for (int j = 0; j < c; j++) {
1729 if (j == 0)
1730 maxRowHeight << 0;
1731 if (i == 0)
1732 maxColWidth << 0;
1733
1734 if (childIndex == numVisible)
1735 break;
1736
1737 const PositionedItem &child = positionedItems.at(childIndex++);
1738 if (child.item->width() > maxColWidth[j])
1739 maxColWidth[j] = child.item->width();
1740 if (child.item->height() > maxRowHeight[i])
1741 maxRowHeight[i] = child.item->height();
1742 }
1743 }
1744 } else {
1745 for (int j = 0; j < c; j++) {
1746 for (int i = 0; i < r; i++) {
1747 if (j == 0)
1748 maxRowHeight << 0;
1749 if (i == 0)
1750 maxColWidth << 0;
1751
1752 if (childIndex == numVisible)
1753 break;
1754
1755 const PositionedItem &child = positionedItems.at(childIndex++);
1756 if (child.item->width() > maxColWidth[j])
1757 maxColWidth[j] = child.item->width();
1758 if (child.item->height() > maxRowHeight[i])
1759 maxRowHeight[i] = child.item->height();
1760 }
1761 }
1762 }
1763
1764 qreal columnSpacing = m_useColumnSpacing ? m_columnSpacing : spacing();
1765 qreal rowSpacing = m_useRowSpacing ? m_rowSpacing : spacing();
1766
1767 qreal widthSum = 0;
1768 for (int j = 0; j < maxColWidth.size(); j++) {
1769 if (j)
1770 widthSum += columnSpacing;
1771 widthSum += maxColWidth[j];
1772 }
1773 widthSum += leftPadding() + rightPadding();
1774
1775 qreal heightSum = 0;
1776 for (int i = 0; i < maxRowHeight.size(); i++) {
1777 if (i)
1778 heightSum += rowSpacing;
1779 heightSum += maxRowHeight[i];
1780 }
1781 heightSum += topPadding() + bottomPadding();
1782
1783 contentSize->setHeight(heightSum);
1784 contentSize->setWidth(widthSum);
1785
1786 int end = 0;
1787 if (widthValid())
1788 end = width();
1789 else
1790 end = widthSum;
1791
1793 if (!d->isLeftToRight())
1794 xoffset = end - rightPadding();
1796 int curRow =0;
1797 int curCol =0;
1798 for (int i = 0; i < positionedItems.count(); ++i) {
1800 qreal childXOffset = xoffset;
1801
1802 if (effectiveHAlign() == AlignRight)
1803 childXOffset += maxColWidth[curCol] - child.item->width();
1804 else if (hItemAlign() == AlignHCenter)
1805 childXOffset += (maxColWidth[curCol] - child.item->width())/2.0;
1806
1807 if (!d->isLeftToRight())
1808 childXOffset -= maxColWidth[curCol];
1809
1810 qreal alignYOffset = yoffset;
1811 if (m_vItemAlign == AlignVCenter)
1812 alignYOffset += (maxRowHeight[curRow] - child.item->height())/2.0;
1813 else if (m_vItemAlign == AlignBottom)
1814 alignYOffset += maxRowHeight[curRow] - child.item->height();
1815
1816 positionItem(childXOffset, alignYOffset, &child);
1817 child.updatePadding(leftPadding(), topPadding(), rightPadding(), bottomPadding());
1818
1819 if (m_flow == LeftToRight) {
1820 if (d->isLeftToRight())
1821 xoffset += maxColWidth[curCol]+columnSpacing;
1822 else
1823 xoffset -= maxColWidth[curCol]+columnSpacing;
1824 curCol++;
1825 curCol %= c;
1826 if (!curCol) {
1827 yoffset += maxRowHeight[curRow]+rowSpacing;
1828 if (d->isLeftToRight())
1829 xoffset = leftPadding();
1830 else
1831 xoffset = end - rightPadding();
1832 curRow++;
1833 if (curRow>=r)
1834 break;
1835 }
1836 } else {
1837 yoffset += maxRowHeight[curRow]+rowSpacing;
1838 curRow++;
1839 curRow %= r;
1840 if (!curRow) {
1841 if (d->isLeftToRight())
1842 xoffset += maxColWidth[curCol]+columnSpacing;
1843 else
1844 xoffset -= maxColWidth[curCol]+columnSpacing;
1845 yoffset = topPadding();
1846 curCol++;
1847 if (curCol>=c)
1848 break;
1849 }
1850 }
1851 }
1852}
1853
1855{
1857 for (int ii = 0; ii < positionedItems.count(); ++ii) {
1858 const PositionedItem &child = positionedItems.at(ii);
1859 if (child.item) {
1860 QQuickAnchors *anchors = QQuickItemPrivate::get(static_cast<QQuickItem *>(child.item))->_anchors;
1861 if (anchors && (anchors->usedAnchors() || anchors->fill() || anchors->centerIn())) {
1862 d->anchorConflict = true;
1863 break;
1864 }
1865 }
1866 }
1867 if (d->anchorConflict)
1868 qmlWarning(this) << "Cannot specify anchors for items inside Grid." << " Grid will not function.";
1869}
1870
1998{
1999 Q_DECLARE_PUBLIC(QQuickFlow)
2000
2001public:
2005
2007 {
2008 Q_Q(QQuickFlow);
2009 // Don't postpone, as it might be the only trigger for visible changes.
2010 q->prePositioning();
2011 emit q->effectiveLayoutDirectionChanged();
2012 }
2013
2015};
2016
2018: QQuickBasePositioner(*(new QQuickFlowPrivate), Both, parent)
2019{
2020 Q_D(QQuickFlow);
2021 // Flow layout requires relayout if its own size changes too.
2022 d->addItemChangeListener(d, QQuickItemPrivate::Geometry);
2023}
2024
2041{
2042 Q_D(const QQuickFlow);
2043 return d->flow;
2044}
2045
2047{
2048 Q_D(QQuickFlow);
2049 if (d->flow != flow) {
2050 d->flow = flow;
2052 emit flowChanged();
2053 }
2054}
2055
2076{
2077 Q_D(const QQuickFlow);
2078 return d->layoutDirection;
2079}
2080
2082{
2083 Q_D(QQuickFlow);
2084 if (d->layoutDirection != layoutDirection) {
2085 d->layoutDirection = layoutDirection;
2087 d->effectiveLayoutDirectionChange();
2088 }
2089}
2090
2106
2108{
2109 //Precondition: All items in the positioned list have a valid item pointer and should be positioned
2110 Q_D(QQuickFlow);
2111
2112 qreal hoffset1 = leftPadding();
2113 qreal hoffset2 = rightPadding();
2114 if (!d->isLeftToRight())
2115 qSwap(hoffset1, hoffset2);
2116 qreal hoffset = hoffset1;
2117 const qreal voffset1 = topPadding();
2118 qreal voffset = voffset1;
2119 qreal linemax = 0;
2120 QList<qreal> hoffsets;
2121 contentSize->setWidth(qMax(contentSize->width(), hoffset1 + hoffset2));
2122 contentSize->setHeight(qMax(contentSize->height(), voffset + bottomPadding()));
2123
2124 for (int i = 0; i < positionedItems.count(); ++i) {
2126
2127 if (d->flow == LeftToRight) {
2128 if (widthValid() && hoffset != hoffset1 && hoffset + child.item->width() + hoffset2 > width()) {
2129 hoffset = hoffset1;
2130 voffset += linemax + spacing();
2131 linemax = 0;
2132 }
2133 } else {
2134 if (heightValid() && voffset != voffset1 && voffset + child.item->height() + bottomPadding() > height()) {
2135 voffset = voffset1;
2136 hoffset += linemax + spacing();
2137 linemax = 0;
2138 }
2139 }
2140
2141 if (d->isLeftToRight()) {
2142 positionItem(hoffset, voffset, &child);
2143 child.updatePadding(leftPadding(), topPadding(), rightPadding(), bottomPadding());
2144 } else {
2145 hoffsets << hoffset;
2146 positionItemY(voffset, &child);
2147 child.topPadding = topPadding();
2148 child.bottomPadding = bottomPadding();
2149 }
2150
2151 contentSize->setWidth(qMax(contentSize->width(), hoffset + child.item->width() + hoffset2));
2152 contentSize->setHeight(qMax(contentSize->height(), voffset + child.item->height() + bottomPadding()));
2153
2154 if (d->flow == LeftToRight) {
2155 hoffset += child.item->width();
2156 hoffset += spacing();
2157 linemax = qMax(linemax, child.item->height());
2158 } else {
2159 voffset += child.item->height();
2160 voffset += spacing();
2161 linemax = qMax(linemax, child.item->width());
2162 }
2163 }
2164
2165 if (d->isLeftToRight())
2166 return;
2167
2168 qreal end;
2169 if (widthValid())
2170 end = width();
2171 else
2172 end = contentSize->width();
2173 int acc = 0;
2174 for (int i = 0; i < positionedItems.count(); ++i) {
2176 hoffset = end - hoffsets[acc++] - child.item->width();
2177 positionItemX(hoffset, &child);
2178 child.leftPadding = leftPadding();
2179 child.rightPadding = rightPadding();
2180 }
2181}
2182
2184{
2185 Q_D(QQuickFlow);
2186 for (int ii = 0; ii < positionedItems.count(); ++ii) {
2187 const PositionedItem &child = positionedItems.at(ii);
2188 if (child.item) {
2189 QQuickAnchors *anchors = QQuickItemPrivate::get(static_cast<QQuickItem *>(child.item))->_anchors;
2190 if (anchors && (anchors->usedAnchors() || anchors->fill() || anchors->centerIn())) {
2191 d->anchorConflict = true;
2192 break;
2193 }
2194 }
2195 }
2196 if (d->anchorConflict)
2197 qmlWarning(this) << "Cannot specify anchors for items inside Flow." << " Flow will not function.";
2198}
2199
2201
2202#include "moc_qquickpositioners_p.cpp"
qreal y() const
This convenience function is equivalent to calling pos().y().
qreal x() const
This convenience function is equivalent to calling pos().x().
bool isVisible() const
Returns true if the item is visible; otherwise, false is returned.
qsizetype size() const noexcept
Definition qlist.h:397
const_reference at(qsizetype i) const noexcept
Definition qlist.h:446
void remove(qsizetype i, qsizetype n=1)
Definition qlist.h:794
qsizetype count() const noexcept
Definition qlist.h:398
void clear()
Definition qlist.h:434
QObject * parent
Definition qobject.h:73
static QObjectPrivate * get(QObject *o)
Definition qobject_p.h:150
\inmodule QtCore
Definition qobject.h:103
const QObjectList & children() const
Returns a list of child objects.
Definition qobject.h:201
QObject * parent() const
Returns a pointer to the parent object.
Definition qobject.h:346
\inmodule QtCore\reentrant
Definition qpoint.h:217
QQuickItem * fill
QQuickItem * centerIn
Anchors usedAnchors() const
void watchChanges(QQuickItem *other)
void setLeftPadding(qreal value, bool reset=false)
static Qt::LayoutDirection getEffectiveLayoutDirection(const QQuickBasePositioner *positioner)
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)
QLazilyAllocated< ExtraData > extra
static Qt::LayoutDirection getLayoutDirection(const QQuickBasePositioner *positioner)
void updatePadding(qreal lp, qreal tp, qreal rp, qreal bp)
For specifying a base for QQuickGraphics layouts.
void setBottomPadding(qreal padding)
virtual void reportConflictingAnchors()=0
QQuickBasePositioner(PositionerType, QQuickItem *parent)
void setRightPadding(qreal padding)
void positionItemY(qreal, PositionedItem *target)
void setLeftPadding(qreal padding)
QPODVector< PositionedItem, 8 > positionedItems
void updateAttachedProperties(QQuickPositionerAttached *specificProperty=nullptr, QQuickItem *specificPropertyOwner=nullptr) const
void setTopPadding(qreal padding)
void updatePolish() override
This function should perform any layout as required for this item.
static QQuickPositionerAttached * qmlAttachedProperties(QObject *obj)
virtual void doPositioning(QSizeF *contentSize)=0
void itemChange(ItemChange, const ItemChangeData &) override
Called when change occurs for this item.
void positionItemX(qreal, PositionedItem *target)
void componentComplete() override
Invoked after the root component that caused this instantiation has completed construction.
void removePositionedItem(QPODVector< PositionedItem, 8 > *items, int index)
void positionItem(qreal x, qreal y, PositionedItem *target)
void clearPositionedItems(QPODVector< PositionedItem, 8 > *items)
void setPadding(qreal padding)
QPODVector< PositionedItem, 8 > unpositionedItems
void reportConflictingAnchors() override
void doPositioning(QSizeF *contentSize) override
QQuickColumn(QQuickItem *parent=nullptr)
\qmltype Column \instantiates QQuickColumn \inqmlmodule QtQuick \inherits Item
\qmltype Flow \instantiates QQuickFlow \inqmlmodule QtQuick \inherits Item
void effectiveLayoutDirectionChange() override
void flowChanged()
void layoutDirectionChanged()
void doPositioning(QSizeF *contentSize) override
Qt::LayoutDirection layoutDirection
void reportConflictingAnchors() override
void setLayoutDirection(Qt::LayoutDirection)
QQuickFlow(QQuickItem *parent=nullptr)
Qt::LayoutDirection effectiveLayoutDirection
\qmltype Grid \instantiates QQuickGrid \inqmlmodule QtQuick \inherits Item
void effectiveLayoutDirectionChange() override
void reportConflictingAnchors() override
void setColumns(const int columns)
\qmlproperty int QtQuick::Grid::columns
void columnSpacingChanged()
void rowSpacingChanged()
void columnsChanged()
void setRows(const int rows)
HAlignment effectiveHAlign() const
Qt::LayoutDirection layoutDirection
VAlignment vItemAlign() const
void setColumnSpacing(qreal)
\qmlproperty qreal QtQuick::Grid::columnSpacing
QQuickGrid(QQuickItem *parent=nullptr)
void rowsChanged()
void setHItemAlign(HAlignment align)
void doPositioning(QSizeF *contentSize) override
void setVItemAlign(VAlignment align)
void setLayoutDirection(Qt::LayoutDirection)
Qt::LayoutDirection effectiveLayoutDirection
void layoutDirectionChanged()
void setRowSpacing(qreal)
\qmlproperty qreal QtQuick::Grid::rowSpacing
void flowChanged()
HAlignment hItemAlign() const
\qmlproperty enumeration QtQuick::Grid::horizontalItemAlignment \qmlproperty enumeration QtQuick::Gri...
void removeItemChangeListener(QQuickItemChangeListener *, ChangeTypes types)
void addItemChangeListener(QQuickItemChangeListener *listener, ChangeTypes types)
static QQuickItemPrivate * get(QQuickItem *item)
The QQuickItem class provides the most basic of all visual items in \l {Qt Quick}.
Definition qquickitem.h:63
QList< QQuickItem * > childItems() const
Returns the children of this item.
void componentComplete() override
\reimp Derived classes should call the base class method before adding their own actions to perform a...
QSizeF size() const
qreal width
This property holds the width of this item.
Definition qquickitem.h:75
virtual void itemChange(ItemChange, const ItemChangeData &)
Called when change occurs for this item.
bool isComponentComplete() const
Returns true if construction of the QML component is complete; otherwise returns false.
QQuickItem * parent
\qmlproperty Item QtQuick::Item::parent This property holds the visual parent of the item.
Definition qquickitem.h:67
bool heightValid() const
Returns whether the height property has been set explicitly.
bool widthValid() const
Returns whether the width property has been set explicitly.
qreal height
This property holds the height of this item.
Definition qquickitem.h:76
ItemChange
Used in conjunction with QQuickItem::itemChange() to notify the item about certain types of changes.
Definition qquickitem.h:144
@ ItemChildAddedChange
Definition qquickitem.h:145
@ ItemChildRemovedChange
Definition qquickitem.h:146
void setImplicitSize(qreal, qreal)
void setIndex(int index)
\qmlattachedproperty int QtQuick::Positioner::index
QQuickPositionerAttached(QObject *parent)
\qmltype Positioner \instantiates QQuickPositionerAttached \inqmlmodule QtQuick
void setIsFirstItem(bool isFirstItem)
\qmlattachedproperty bool QtQuick::Positioner::isFirstItem \qmlattachedproperty bool QtQuick::Positio...
void setIsLastItem(bool isLastItem)
\qmltype Row \instantiates QQuickRow \inqmlmodule QtQuick \inherits Item
void effectiveLayoutDirectionChange() override
Qt::LayoutDirection effectiveLayoutDirection
void reportConflictingAnchors() override
void setLayoutDirection(Qt::LayoutDirection)
QQuickRow(QQuickItem *parent=nullptr)
Qt::LayoutDirection layoutDirection
void layoutDirectionChanged()
void doPositioning(QSizeF *contentSize) override
\inmodule QtCore\reentrant
Definition qrect.h:484
\inmodule QtCore
Definition qsize.h:208
constexpr void setHeight(qreal h) noexcept
Sets the height to the given finite height.
Definition qsize.h:341
constexpr void setWidth(qreal w) noexcept
Sets the width to the given finite width.
Definition qsize.h:338
constexpr qreal width() const noexcept
Returns the width.
Definition qsize.h:332
constexpr qreal height() const noexcept
Returns the height.
Definition qsize.h:335
Combined button and popup list for selecting options.
LayoutDirection
@ RightToLeft
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
bool qFuzzyCompare(qfloat16 p1, qfloat16 p2) noexcept
Definition qfloat16.h:333
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:42
GLint GLint GLint GLint GLint x
[0]
GLuint index
[2]
GLboolean r
[2]
GLuint GLuint end
GLenum GLenum GLsizei count
GLint GLint GLint yoffset
GLint GLsizei width
GLenum type
GLenum target
GLint GLint xoffset
GLint y
GLhandleARB obj
[2]
GLdouble s
[6]
Definition qopenglext.h:235
GLboolean reset
const GLubyte * c
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
static void add(QPainterPath &path, const QWingedEdge &list, int edge, QPathEdge::Traversal traversal)
Q_QML_EXPORT QQmlInfo qmlWarning(const QObject *me)
QQuickAnchors * anchors(QQuickItem *item)
static QList< QQuickStateAction > prepareTransition(QQuickDrawer *drawer, QQuickTransition *transition, qreal to)
QQuickItem * qobject_cast< QQuickItem * >(QObject *o)
Definition qquickitem.h:492
static QT_BEGIN_NAMESPACE const QQuickItemPrivate::ChangeTypes positionerWatchedChanges
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
QT_BEGIN_NAMESPACE constexpr void qSwap(T &value1, T &value2) noexcept(std::is_nothrow_swappable_v< T >)
Definition qswap.h:20
#define QT_CONFIG(feature)
#define emit
double qreal
Definition qtypes.h:187
const char property[13]
Definition qwizard.cpp:101
if(qFloatDistance(a, b)<(1<< 7))
[0]
QObject::connect nullptr
QSharedPointer< T > other(t)
[5]
QGraphicsItem * item
edit isVisible()
QList< QTreeWidgetItem * > items
QLayoutItem * child
[0]
QAction * at
\inmodule QtQuick
Definition qquickitem.h:159