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
qquicklayout.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
6#include <QEvent>
7#include <QtCore/qcoreapplication.h>
8#include <QtCore/private/qnumeric_p.h>
9#include <QtCore/qstack.h>
10#include <QtCore/qmath.h>
11#include <QtQml/qqmlinfo.h>
12#include <limits>
13
14/*!
15 \qmltype Layout
16 //! \nativetype QQuickLayoutAttached
17 \inqmlmodule QtQuick.Layouts
18 \ingroup layouts
19 \brief Provides attached properties for items pushed onto a \l GridLayout,
20 \l RowLayout or \l ColumnLayout.
21
22 An object of type Layout is attached to children of the layout to provide layout specific
23 information about the item.
24 The properties of the attached object influence how the layout will arrange the items.
25
26 For instance, you can specify \l minimumWidth, \l preferredWidth, and
27 \l maximumWidth if the default values are not satisfactory.
28
29 When a layout is resized, items may grow or shrink. Due to this, items have a
30 \l{Layout::minimumWidth}{minimum size}, \l{Layout::preferredWidth}{preferred size} and a
31 \l{Layout::maximumWidth}{maximum size}.
32
33 If minimum size has not been explicitly specified on an item, the size is set to \c 0.
34 If maximum size has not been explicitly specified on an item, the size is set to
35 \c Number.POSITIVE_INFINITY.
36
37 For layouts, the implicit minimum and maximum sizes depend on the content of the layouts.
38
39 The \l fillWidth and \l fillHeight properties can either be \c true or \c false. If they are \c
40 false, the item's size will be fixed to its preferred size. Otherwise, it will grow or shrink
41 between its minimum and maximum size as the layout is resized. If there are multiple items
42 with \l fillWidth (or \l fillHeight) set to \c true, the layout will grow or shrink the items
43 relative to the ratio of their preferred size.
44
45 For more details on the layout algorithm, see also the \l {Qt Quick Layouts Overview}.
46
47 \note Do not bind to the x, y, width, or height properties of items in a layout,
48 as this would conflict with the goals of Layout, and can also cause binding loops.
49 The width and height properties are used by the layout engine to store the current
50 size of items as calculated from the minimum/preferred/maximum attached properties,
51 and can be ovewritten each time the items are laid out. Use
52 \l {Layout.preferredWidth} and \l {Layout.preferredHeight}, or \l {Item::}{implicitWidth}
53 and \l {Item::}{implicitHeight} to specify the preferred size of items.
54
55 \sa GridLayout
56 \sa RowLayout
57 \sa ColumnLayout
58*/
59
61
62Q_LOGGING_CATEGORY(lcQuickLayouts, "qt.quick.layouts")
63
64QQuickLayoutAttached::QQuickLayoutAttached(QObject *parent)
65 : QObject(parent),
66 m_minimumWidth(0),
67 m_minimumHeight(0),
68 m_preferredWidth(-1),
69 m_preferredHeight(-1),
70 m_maximumWidth(std::numeric_limits<qreal>::infinity()),
71 m_maximumHeight(std::numeric_limits<qreal>::infinity()),
72 m_defaultMargins(0),
73 m_fallbackWidth(-1),
74 m_fallbackHeight(-1),
75 m_row(-1),
76 m_column(-1),
77 m_rowSpan(1),
78 m_columnSpan(1),
79 m_fillWidth(false),
80 m_fillHeight(false),
81 m_isFillWidthSet(false),
82 m_isFillHeightSet(false),
83 m_isUseDefaultSizePolicySet(false),
84 m_useDefaultSizePolicy(QQuickLayout::SizePolicyExplicit),
85 m_isMinimumWidthSet(false),
86 m_isMinimumHeightSet(false),
87 m_isMaximumWidthSet(false),
88 m_isMaximumHeightSet(false),
89 m_changesNotificationEnabled(true),
90 m_isMarginsSet(false),
91 m_isLeftMarginSet(false),
92 m_isTopMarginSet(false),
93 m_isRightMarginSet(false),
94 m_isBottomMarginSet(false),
95 m_isAlignmentSet(false),
96 m_horizontalStretch(-1),
97 m_verticalStretch(-1)
98{
99
100}
101
102/*!
103 \qmlattachedproperty real Layout::minimumWidth
104
105 This property holds the minimum width of an item in a layout.
106 The default value is the item's implicit minimum width.
107
108 If the item is a layout, the implicit minimum width will be the minimum width the layout can
109 have without any of its items shrinking below their minimum width.
110 The implicit minimum width for any other item is \c 0.
111
112 Setting this value to -1 will reset the width back to its implicit minimum width.
113
114
115 \sa preferredWidth
116 \sa maximumWidth
117*/
118void QQuickLayoutAttached::setMinimumWidth(qreal width)
119{
120 if (qt_is_nan(width))
121 return;
122 m_isMinimumWidthSet = width >= 0;
123 if (m_minimumWidth == width)
124 return;
125
126 m_minimumWidth = width;
127 invalidateItem();
128 emit minimumWidthChanged();
129}
130
131/*!
132 \qmlattachedproperty real Layout::minimumHeight
133
134 This property holds the minimum height of an item in a layout.
135 The default value is the item's implicit minimum height.
136
137 If the item is a layout, the implicit minimum height will be the minimum height the layout can
138 have without any of its items shrinking below their minimum height.
139 The implicit minimum height for any other item is \c 0.
140
141 Setting this value to -1 will reset the height back to its implicit minimum height.
142
143 \sa preferredHeight
144 \sa maximumHeight
145*/
146void QQuickLayoutAttached::setMinimumHeight(qreal height)
147{
148 if (qt_is_nan(height))
149 return;
150 m_isMinimumHeightSet = height >= 0;
151 if (m_minimumHeight == height)
152 return;
153
154 m_minimumHeight = height;
155 invalidateItem();
156 emit minimumHeightChanged();
157}
158
159/*!
160 \qmlattachedproperty real Layout::preferredWidth
161
162 This property holds the preferred width of an item in a layout.
163 If the preferred width is \c -1 it will be ignored, and the layout
164 will use \l{Item::implicitWidth}{implicitWidth} instead.
165 The default is \c -1.
166
167 \sa minimumWidth
168 \sa maximumWidth
169*/
170void QQuickLayoutAttached::setPreferredWidth(qreal width)
171{
172 if (qt_is_nan(width) || m_preferredWidth == width)
173 return;
174
175 m_preferredWidth = width;
176 invalidateItem();
177 emit preferredWidthChanged();
178}
179
180/*!
181 \qmlattachedproperty real Layout::preferredHeight
182
183 This property holds the preferred height of an item in a layout.
184 If the preferred height is \c -1 it will be ignored, and the layout
185 will use \l{Item::implicitHeight}{implicitHeight} instead.
186 The default is \c -1.
187
188 \sa minimumHeight
189 \sa maximumHeight
190*/
191void QQuickLayoutAttached::setPreferredHeight(qreal height)
192{
193 if (qt_is_nan(height) || m_preferredHeight == height)
194 return;
195
196 m_preferredHeight = height;
197 invalidateItem();
198 emit preferredHeightChanged();
199}
200
201/*!
202 \qmlattachedproperty real Layout::maximumWidth
203
204 This property holds the maximum width of an item in a layout.
205 The default value is the item's implicit maximum width.
206
207 If the item is a layout, the implicit maximum width will be the maximum width the layout can
208 have without any of its items growing beyond their maximum width.
209 The implicit maximum width for any other item is \c Number.POSITIVE_INFINITY.
210
211 Setting this value to \c -1 will reset the width back to its implicit maximum width.
212
213 \sa minimumWidth
214 \sa preferredWidth
215*/
216void QQuickLayoutAttached::setMaximumWidth(qreal width)
217{
218 if (qt_is_nan(width))
219 return;
220 m_isMaximumWidthSet = width >= 0;
221 if (m_maximumWidth == width)
222 return;
223
224 m_maximumWidth = width;
225 invalidateItem();
226 emit maximumWidthChanged();
227}
228
229/*!
230 \qmlattachedproperty real Layout::maximumHeight
231
232 The default value is the item's implicit maximum height.
233
234 If the item is a layout, the implicit maximum height will be the maximum height the layout can
235 have without any of its items growing beyond their maximum height.
236 The implicit maximum height for any other item is \c Number.POSITIVE_INFINITY.
237
238 Setting this value to \c -1 will reset the height back to its implicit maximum height.
239
240 \sa minimumHeight
241 \sa preferredHeight
242*/
243void QQuickLayoutAttached::setMaximumHeight(qreal height)
244{
245 if (qt_is_nan(height))
246 return;
247 m_isMaximumHeightSet = height >= 0;
248 if (m_maximumHeight == height)
249 return;
250
251 m_maximumHeight = height;
252 invalidateItem();
253 emit maximumHeightChanged();
254}
255
256void QQuickLayoutAttached::setMinimumImplicitSize(const QSizeF &sz)
257{
258 bool emitWidthChanged = false;
259 bool emitHeightChanged = false;
260 if (!m_isMinimumWidthSet && m_minimumWidth != sz.width()) {
261 m_minimumWidth = sz.width();
262 emitWidthChanged = true;
263 }
264 if (!m_isMinimumHeightSet && m_minimumHeight != sz.height()) {
265 m_minimumHeight = sz.height();
266 emitHeightChanged = true;
267 }
268 // Only invalidate the item once, and make sure we emit signal changed after the call to
269 // invalidateItem()
270 if (emitWidthChanged || emitHeightChanged) {
271 invalidateItem();
272 if (emitWidthChanged)
273 emit minimumWidthChanged();
274 if (emitHeightChanged)
275 emit minimumHeightChanged();
276 }
277}
278
279void QQuickLayoutAttached::setMaximumImplicitSize(const QSizeF &sz)
280{
281 bool emitWidthChanged = false;
282 bool emitHeightChanged = false;
283 if (!m_isMaximumWidthSet && m_maximumWidth != sz.width()) {
284 m_maximumWidth = sz.width();
285 emitWidthChanged = true;
286 }
287 if (!m_isMaximumHeightSet && m_maximumHeight != sz.height()) {
288 m_maximumHeight = sz.height();
289 emitHeightChanged = true;
290 }
291 // Only invalidate the item once, and make sure we emit changed signal after the call to
292 // invalidateItem()
293 if (emitWidthChanged || emitHeightChanged) {
294 invalidateItem();
295 if (emitWidthChanged)
296 emit maximumWidthChanged();
297 if (emitHeightChanged)
298 emit maximumHeightChanged();
299 }
300}
301
302/*!
303 \qmlattachedproperty bool Layout::fillWidth
304
305 If this property is \c true, the item will be as wide as possible while respecting
306 the given constraints. If the property is \c false, the item will have a fixed width
307 set to the preferred width.
308 The default depends on implicit (built-in) size policy of item.
309
310 \note By default, this property is \c true for layouts.
311
312 \sa fillHeight
313*/
314void QQuickLayoutAttached::setFillWidth(bool fill)
315{
316 bool oldFillWidth = fillWidth();
317 m_isFillWidthSet = true;
318 m_fillWidth = fill;
319 if (oldFillWidth != fill) {
320 invalidateItem();
321 emit fillWidthChanged();
322 }
323}
324
325/*!
326 \qmlattachedproperty bool Layout::fillHeight
327
328 If this property is \c true, the item will be as tall as possible while respecting
329 the given constraints. If the property is \c false, the item will have a fixed height
330 set to the preferred height.
331 The default depends on implicit (built-in) size policy of the item.
332
333 \note By default, this property is \c true for layouts.
334
335 \sa fillWidth
336*/
337void QQuickLayoutAttached::setFillHeight(bool fill)
338{
339 bool oldFillHeight = fillHeight();
340 m_isFillHeightSet = true;
341 m_fillHeight = fill;
342 if (oldFillHeight != fill) {
343 invalidateItem();
344 emit fillHeightChanged();
345 }
346}
347
348/*!
349 \qmlattachedproperty enumeration Layout::useDefaultSizePolicy
350 \since 6.8
351
352 This property allows the user to configure the layout size policy at the component
353 level.
354
355 The default value will be inherited by querying the application attribute
356 \l Qt::AA_QtQuickUseDefaultSizePolicy. You can use this property to override that value.
357
358 \value Layout.SizePolicyImplicit
359 The item in the layout uses implicit or built-in size policy
360 \value Layout.SizePolicyExplicit
361 The item in the layout doesn't use implicit size policies.
362*/
363void QQuickLayoutAttached::setUseDefaultSizePolicy(QQuickLayout::SizePolicy sizePolicy)
364{
365 m_isUseDefaultSizePolicySet = true;
366 if (m_useDefaultSizePolicy != sizePolicy) {
367 m_useDefaultSizePolicy = sizePolicy;
368 emit useDefaultSizePolicyChanged();
369 }
370}
371
372/*!
373 \qmlattachedproperty int Layout::row
374
375 This property allows you to specify the row position of an item in a \l GridLayout.
376
377 If both \l column and this property are not set, it is up to the layout to assign a cell to the item.
378
379 The default value is \c 0.
380
381 \sa column
382 \sa rowSpan
383*/
384void QQuickLayoutAttached::setRow(int row)
385{
386 if (row >= 0 && row != m_row) {
387 m_row = row;
388 invalidateItem();
389 emit rowChanged();
390 }
391}
392
393/*!
394 \qmlattachedproperty int Layout::column
395
396 This property allows you to specify the column position of an item in a \l GridLayout.
397
398 If both \l row and this property are not set, it is up to the layout to assign a cell to the item.
399
400 The default value is \c 0.
401
402 \sa row
403 \sa columnSpan
404*/
405void QQuickLayoutAttached::setColumn(int column)
406{
407 if (column >= 0 && column != m_column) {
408 m_column = column;
409 invalidateItem();
410 emit columnChanged();
411 }
412}
413
414
415/*!
416 \qmlattachedproperty Qt.Alignment Layout::alignment
417
418 This property allows you to specify the alignment of an item within the cell(s) it occupies.
419
420 The default value is \c 0, which means it will be \c{Qt.AlignVCenter | Qt.AlignLeft}.
421 These defaults also apply if only a horizontal or vertical flag is specified:
422 if only a horizontal flag is specified, the default vertical flag will be
423 \c Qt.AlignVCenter, and if only a vertical flag is specified, the default
424 horizontal flag will be \c Qt.AlignLeft.
425
426 A valid alignment is a combination of the following flags:
427 \list
428 \li Qt::AlignLeft
429 \li Qt::AlignHCenter
430 \li Qt::AlignRight
431 \li Qt::AlignTop
432 \li Qt::AlignVCenter
433 \li Qt::AlignBottom
434 \li Qt::AlignBaseline
435 \endlist
436
437*/
438void QQuickLayoutAttached::setAlignment(Qt::Alignment align)
439{
440 m_isAlignmentSet = true;
441 if (align != m_alignment) {
442 m_alignment = align;
443 if (QQuickLayout *layout = parentLayout()) {
444 layout->setAlignment(item(), align);
445 invalidateItem();
446 }
447 emit alignmentChanged();
448 }
449}
450
451/*!
452 \qmlattachedproperty int Layout::horizontalStretchFactor
453
454 This property allows you to specify the horizontal stretch factor. By default, two identical
455 items arranged in a linear layout will have the same size, but if the first item has a
456 stretch factor of 1 and the second item has a stretch factor of 2, the first item will \e
457 aim to get 1/3 of the available space, and the second will \e aim to get 2/3 of the available
458 space. Note that, whether they become exactly 1/3 and 2/3 of the available space depends on
459 their size hints. This is because when e.g a horizontal layout is shown in its minimum width
460 all its child items will consequently also have their minimum width.
461
462 Likewise, when a horizontal layout has its preferred width, all child items will have their
463 preferred widths, and when a horizontal layout has its maximum width, all child items will have
464 their maximum widths. This strategy is applied regardless of what the individual stretch
465 factors are. As a consequence of this, stretch factors will only determine the growth rate of
466 child items \e between the preferredWidth and maximumWidth range.
467
468 The default value is \c -1, which means that no stretch factor is applied.
469
470 \note This requires that Layout::fillWidth is set to true
471
472 \since Qt 6.5
473
474 \sa verticalStretchFactor
475*/
476void QQuickLayoutAttached::setHorizontalStretchFactor(int factor)
477{
478 if (factor != m_horizontalStretch) {
479 m_horizontalStretch = factor;
480 if (QQuickLayout *layout = parentLayout()) {
481 layout->setStretchFactor(item(), factor, Qt::Horizontal);
482 invalidateItem();
483 }
484 emit horizontalStretchFactorChanged();
485 }
486}
487
488/*!
489 \qmlattachedproperty int Layout::verticalStretchFactor
490
491 This property allows you to specify the vertical stretch factor. By default, two identical
492 items arranged in a linear layout will have the same size, but if the first item has a
493 stretch factor of 1 and the second item has a stretch factor of 2, the first item will \e
494 aim to get 1/3 of the available space, and the second will \e aim to get 2/3 of the available
495 space. Note that, whether they become exactly 1/3 and 2/3 of the available space depends on
496 their size hints. This is because when e.g a vertical layout is shown in its minimum height
497 all its child items will consequently also have their minimum height.
498
499 Likewise, when a vertical layout has its preferred height, all child items will have their
500 preferred heights, and when a vertical layout has its maximum height, all child items will have
501 their maximum heights. This strategy is applied regardless of what the individual stretch
502 factors are. As a consequence of this, stretch factors will only determine the growth rate of
503 child items \e between the preferredHeight and maximumHeight range.
504
505 The default value is \c -1, which means that no stretch factor is applied.
506
507 \note This requires that Layout::fillHeight is set to true
508
509 \since Qt 6.5
510
511 \sa horizontalStretchFactor
512*/
513void QQuickLayoutAttached::setVerticalStretchFactor(int factor)
514{
515 if (factor != m_verticalStretch) {
516 m_verticalStretch = factor;
517 if (QQuickLayout *layout = parentLayout()) {
518 layout->setStretchFactor(item(), factor, Qt::Vertical);
519 invalidateItem();
520 }
521 emit verticalStretchFactorChanged();
522 }
523}
524
525/*!
526 \qmlattachedproperty real Layout::margins
527
528 Sets the margins outside of an item to all have the same value. The item
529 itself does not evaluate its own margins. It is the parent's responsibility
530 to decide if it wants to evaluate the margins.
531
532 Specifically, margins are only evaluated by ColumnLayout, RowLayout,
533 GridLayout, and other layout-like containers, such as SplitView, where the
534 effective cell size of an item will be increased as the margins are
535 increased.
536
537 Therefore, if an item with margins is a child of another \c Item, its
538 position, size and implicit size will remain unchanged.
539
540 Combining margins with alignment will align the item \e including its
541 margins. For instance, a vertically-centered Item with a top margin of \c 1
542 and a bottom margin of \c 9 will cause the Items effective alignment within
543 the cell to be 4 pixels above the center.
544
545 The default value is \c 0.
546
547 \sa leftMargin
548 \sa topMargin
549 \sa rightMargin
550 \sa bottomMargin
551
552 \since QtQuick.Layouts 1.2
553*/
554void QQuickLayoutAttached::setMargins(qreal m)
555{
556 m_isMarginsSet = true;
557 if (m == m_defaultMargins)
558 return;
559
560 m_defaultMargins = m;
561 invalidateItem();
562 if (!m_isLeftMarginSet && m_margins.left() != m)
563 emit leftMarginChanged();
564 if (!m_isTopMarginSet && m_margins.top() != m)
565 emit topMarginChanged();
566 if (!m_isRightMarginSet && m_margins.right() != m)
567 emit rightMarginChanged();
568 if (!m_isBottomMarginSet && m_margins.bottom() != m)
569 emit bottomMarginChanged();
570 emit marginsChanged();
571}
572
573/*!
574 \qmlattachedproperty real Layout::leftMargin
575
576 Specifies the left margin outside of an item.
577 If the value is not set, it will use the value from \l margins.
578
579 \sa margins
580
581 \since QtQuick.Layouts 1.2
582*/
583void QQuickLayoutAttached::setLeftMargin(qreal m)
584{
585 const bool changed = leftMargin() != m;
586 m_margins.setLeft(m);
587 m_isLeftMarginSet = true;
588 if (changed) {
589 invalidateItem();
590 emit leftMarginChanged();
591 }
592}
593
594void QQuickLayoutAttached::resetLeftMargin()
595{
596 const bool changed = m_isLeftMarginSet && (m_defaultMargins != m_margins.left());
597 m_isLeftMarginSet = false;
598 if (changed) {
599 invalidateItem();
600 emit leftMarginChanged();
601 }
602}
603
604/*!
605 \qmlattachedproperty real Layout::topMargin
606
607 Specifies the top margin outside of an item.
608 If the value is not set, it will use the value from \l margins.
609
610 \sa margins
611
612 \since QtQuick.Layouts 1.2
613*/
614void QQuickLayoutAttached::setTopMargin(qreal m)
615{
616 const bool changed = topMargin() != m;
617 m_margins.setTop(m);
618 m_isTopMarginSet = true;
619 if (changed) {
620 invalidateItem();
621 emit topMarginChanged();
622 }
623}
624
625void QQuickLayoutAttached::resetTopMargin()
626{
627 const bool changed = m_isTopMarginSet && (m_defaultMargins != m_margins.top());
628 m_isTopMarginSet = false;
629 if (changed) {
630 invalidateItem();
631 emit topMarginChanged();
632 }
633}
634
635/*!
636 \qmlattachedproperty real Layout::rightMargin
637
638 Specifies the right margin outside of an item.
639 If the value is not set, it will use the value from \l margins.
640
641 \sa margins
642
643 \since QtQuick.Layouts 1.2
644*/
645void QQuickLayoutAttached::setRightMargin(qreal m)
646{
647 const bool changed = rightMargin() != m;
648 m_margins.setRight(m);
649 m_isRightMarginSet = true;
650 if (changed) {
651 invalidateItem();
652 emit rightMarginChanged();
653 }
654}
655
656void QQuickLayoutAttached::resetRightMargin()
657{
658 const bool changed = m_isRightMarginSet && (m_defaultMargins != m_margins.right());
659 m_isRightMarginSet = false;
660 if (changed) {
661 invalidateItem();
662 emit rightMarginChanged();
663 }
664}
665
666/*!
667 \qmlattachedproperty real Layout::bottomMargin
668
669 Specifies the bottom margin outside of an item.
670 If the value is not set, it will use the value from \l margins.
671
672 \sa margins
673
674 \since QtQuick.Layouts 1.2
675*/
676void QQuickLayoutAttached::setBottomMargin(qreal m)
677{
678 const bool changed = bottomMargin() != m;
679 m_margins.setBottom(m);
680 m_isBottomMarginSet = true;
681 if (changed) {
682 invalidateItem();
683 emit bottomMarginChanged();
684 }
685}
686
687void QQuickLayoutAttached::resetBottomMargin()
688{
689 const bool changed = m_isBottomMarginSet && (m_defaultMargins != m_margins.bottom());
690 m_isBottomMarginSet = false;
691 if (changed) {
692 invalidateItem();
693 emit bottomMarginChanged();
694 }
695}
696
697
698/*!
699 \qmlattachedproperty int Layout::rowSpan
700
701 This property allows you to specify the row span of an item in a \l GridLayout.
702
703 The default value is \c 1.
704
705 \sa columnSpan
706 \sa row
707*/
708void QQuickLayoutAttached::setRowSpan(int span)
709{
710 if (span != m_rowSpan) {
711 m_rowSpan = span;
712 invalidateItem();
713 emit rowSpanChanged();
714 }
715}
716
717
718/*!
719 \qmlattachedproperty int Layout::columnSpan
720
721 This property allows you to specify the column span of an item in a \l GridLayout.
722
723 The default value is \c 1.
724
725 \sa rowSpan
726 \sa column
727*/
728void QQuickLayoutAttached::setColumnSpan(int span)
729{
730 if (span != m_columnSpan) {
731 m_columnSpan = span;
732 invalidateItem();
733 emit columnSpanChanged();
734 }
735}
736
737
738qreal QQuickLayoutAttached::sizeHint(Qt::SizeHint which, Qt::Orientation orientation) const
739{
740 qreal result = 0;
741 if (QQuickLayout *layout = qobject_cast<QQuickLayout *>(item())) {
742 const QSizeF sz = layout->sizeHint(which);
743 result = (orientation == Qt::Horizontal ? sz.width() : sz.height());
744 } else {
745 if (which == Qt::MaximumSize)
746 result = std::numeric_limits<qreal>::infinity();
747 }
748 return result;
749}
750
751void QQuickLayoutAttached::invalidateItem()
752{
753 qCDebug(lcQuickLayouts) << "QQuickLayoutAttached::invalidateItem";
754 if (QQuickLayout *layout = parentLayout()) {
755 layout->invalidate(item());
756 }
757}
758
759QQuickLayout *QQuickLayoutAttached::parentLayout() const
760{
761 QQuickItem *parentItem = item();
762 if (parentItem) {
763 parentItem = parentItem->parentItem();
764 return qobject_cast<QQuickLayout *>(parentItem);
765 } else {
766 qmlWarning(parent()) << "Layout attached property must be attached to an object deriving from Item";
767 }
768 return nullptr;
769}
770
771QQuickItem *QQuickLayoutAttached::item() const
772{
773 return qobject_cast<QQuickItem *>(parent());
774}
775
776void QQuickLayoutPrivate::applySizeHints() const
777{
778 Q_Q(const QQuickLayout);
779
780 QQuickLayout *that = const_cast<QQuickLayout*>(q);
781 QQuickLayoutAttached *info = attachedLayoutObject(that, true);
782
783 const QSizeF min = q->sizeHint(Qt::MinimumSize);
784 const QSizeF max = q->sizeHint(Qt::MaximumSize);
785 const QSizeF pref = q->sizeHint(Qt::PreferredSize);
786 info->setMinimumImplicitSize(min);
787 info->setMaximumImplicitSize(max);
788 that->setImplicitSize(pref.width(), pref.height());
789}
790
791QQuickLayout::QQuickLayout(QQuickLayoutPrivate &dd, QQuickItem *parent)
792 : QQuickItem(dd, parent)
793 , m_inUpdatePolish(false)
794 , m_polishInsideUpdatePolish(0)
795{
796}
797
799 QQuickItemPrivate::SiblingOrder
800 | QQuickItemPrivate::ImplicitWidth
801 | QQuickItemPrivate::ImplicitHeight
802 | QQuickItemPrivate::Destroyed
803 | QQuickItemPrivate::Visibility;
804
805QQuickLayout::~QQuickLayout()
806{
807 d_func()->m_isReady = false;
808
809 const auto childItems = d_func()->childItems;
810 for (QQuickItem *child : childItems)
811 QQuickItemPrivate::get(child)->removeItemChangeListener(this, changeTypes);
812}
813
814QQuickLayoutAttached *QQuickLayout::qmlAttachedProperties(QObject *object)
815{
816 return new QQuickLayoutAttached(object);
817}
818
819void QQuickLayout::updatePolish()
820{
821 qCDebug(lcQuickLayouts) << "updatePolish() ENTERING" << this;
822 m_inUpdatePolish = true;
823
824 // Might have become "undirty" before we reach this updatePolish()
825 // (e.g. if somebody queried for implicitWidth it will immediately
826 // calculate size hints)
827 // Note that we need to call ensureLayoutItemsUpdated() *before* we query width() and height(),
828 // because width()/height() might return their implicitWidth/implicitHeight (e.g. for a layout
829 // with no explicitly specified size, (nor anchors.fill: parent))
830 ensureLayoutItemsUpdated(QQuickLayout::ApplySizeHints | QQuickLayout::Recursive);
831 rearrange(QSizeF(width(), height()));
832 m_inUpdatePolish = false;
833 qCDebug(lcQuickLayouts) << "updatePolish() LEAVING" << this;
834}
835
836void QQuickLayout::componentComplete()
837{
838 Q_D(QQuickLayout);
839 d->m_disableRearrange = true;
840 QQuickItem::componentComplete(); // will call our geometryChange(), (where isComponentComplete() == true)
841 d->m_disableRearrange = false;
842 d->m_isReady = true;
843}
844
845void QQuickLayout::maybeSubscribeToBaseLineOffsetChanges(QQuickItem *item)
846{
847 QQuickLayoutAttached *info = attachedLayoutObject(item, false);
848 if (info) {
849 if (info->alignment() == Qt::AlignBaseline && static_cast<QQuickLayout*>(item->parentItem()) == this) {
850 qmlobject_connect(item, QQuickItem, SIGNAL(baselineOffsetChanged(qreal)), this, QQuickLayout, SLOT(invalidateSenderItem()));
851 } else {
852 qmlobject_disconnect(item, QQuickItem, SIGNAL(baselineOffsetChanged(qreal)), this, QQuickLayout, SLOT(invalidateSenderItem()));
853 }
854 }
855}
856
857void QQuickLayout::invalidate(QQuickItem * /*childItem*/)
858{
859 Q_D(QQuickLayout);
860 if (invalidated())
861 return;
862
863 qCDebug(lcQuickLayouts) << "QQuickLayout::invalidate()" << this;
864 d->m_dirty = true;
865 d->m_dirtyArrangement = true;
866
867 if (!qobject_cast<QQuickLayout *>(parentItem())) {
868 polish();
869
870 if (m_inUpdatePolish) {
871 if (++m_polishInsideUpdatePolish > 2)
872 // allow at most two consecutive loops in order to respond to height-for-width
873 // (e.g QQuickText changes implicitHeight when its width gets changed)
874 qCDebug(lcQuickLayouts) << "Layout polish loop detected for " << this
875 << ". The polish request will still be scheduled.";
876 } else {
877 m_polishInsideUpdatePolish = 0;
878 }
879 }
880}
881
882bool QQuickLayout::shouldIgnoreItem(QQuickItem *child) const
883{
884 QQuickItemPrivate *childPrivate = QQuickItemPrivate::get(child);
885 bool ignoreItem = !childPrivate->explicitVisible;
886 if (!ignoreItem && childPrivate->isTransparentForPositioner())
887 ignoreItem = true;
888 return ignoreItem;
889}
890
891void QQuickLayout::checkAnchors(QQuickItem *item) const
892{
893 QQuickAnchors *anchors = QQuickItemPrivate::get(item)->_anchors;
894 if (anchors && anchors->activeDirections())
895 qmlWarning(item) << "Detected anchors on an item that is managed by a layout. This is undefined behavior; use Layout.alignment instead.";
896}
897
898void QQuickLayout::ensureLayoutItemsUpdated(EnsureLayoutItemsUpdatedOptions options) const
899{
900 Q_D(const QQuickLayout);
901 if (!invalidated())
902 return;
903 qCDebug(lcQuickLayouts) << "ENTER QQuickLayout::ensureLayoutItemsUpdated()" << this << options;
904 QQuickLayoutPrivate *priv = const_cast<QQuickLayoutPrivate*>(d);
905
906 // breadth-first
907 // must update the root first, and continue towards the leaf nodes.
908 // Otherwise, we wouldn't know which children to traverse to
909 const_cast<QQuickLayout*>(this)->updateLayoutItems();
910
911 // make invalidate() return true
912 d->m_dirty = false;
913
914 if (options & Recursive) {
915 for (int i = 0; i < itemCount(); ++i) {
916 QQuickItem *itm = itemAt(i);
917 if (QQuickLayout *lay = qobject_cast<QQuickLayout*>(itm)) {
918 lay->ensureLayoutItemsUpdated(options);
919 }
920 }
921 }
922
923 // size hints are updated depth-first (parent size hints depends on their childrens size hints)
924 if (options & ApplySizeHints)
925 priv->applySizeHints();
926 qCDebug(lcQuickLayouts) << "LEAVE QQuickLayout::ensureLayoutItemsUpdated()" << this;
927}
928
929
930void QQuickLayout::itemChange(ItemChange change, const ItemChangeData &value)
931{
932 if (change == ItemChildAddedChange) {
933 Q_D(QQuickLayout);
934 QQuickItem *item = value.item;
935 maybeSubscribeToBaseLineOffsetChanges(item);
936 QQuickItemPrivate::get(item)->addItemChangeListener(this, changeTypes);
937 d->m_hasItemChangeListeners = true;
938 qCDebug(lcQuickLayouts) << "ChildAdded" << item;
939 if (isReady())
940 invalidate();
941 } else if (change == ItemChildRemovedChange) {
942 QQuickItem *item = value.item;
943 maybeSubscribeToBaseLineOffsetChanges(item);
944 QQuickItemPrivate::get(item)->removeItemChangeListener(this, changeTypes);
945 qCDebug(lcQuickLayouts) << "ChildRemoved" << item;
946 if (isReady())
947 invalidate();
948 }
949 QQuickItem::itemChange(change, value);
950}
951
952void QQuickLayout::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
953{
954 Q_D(QQuickLayout);
955 qCDebug(lcQuickLayouts) << "QQuickLayout::geometryChange"
956 << oldGeometry << "-->" << newGeometry;
957
958 QQuickItem::geometryChange(newGeometry, oldGeometry);
959
960 if ((invalidated() && !qobject_cast<QQuickLayout *>(parentItem())) ||
961 d->m_disableRearrange || !isReady())
962 return;
963
964 // The geometryChange call above might recursively update the
965 // geometry of this layout, via item change listeners, in which
966 // case the recursive call has already rearranged the layout for
967 // the new size. We don't want to rearrange here based on the old
968 // 'new geometry', as that would revert the most up to date layout.
969 const qreal w = d->width.valueBypassingBindings();
970 const qreal h = d->height.valueBypassingBindings();
971 const QSizeF currentSize(w, h);
972 if (currentSize != newGeometry.size()) {
973 qCDebug(lcQuickLayouts) << "QQuickItem::geometryChange resulted"
974 << "in size change from" << newGeometry.size() << "to"
975 << currentSize << "; layout should already be up to date.";
976 return;
977 }
978
979 rearrange(newGeometry.size());
980}
981
982void QQuickLayout::invalidateSenderItem()
983{
984 if (!isReady())
985 return;
986 QQuickItem *item = static_cast<QQuickItem *>(sender());
987 Q_ASSERT(item);
988 invalidate(item);
989}
990
991bool QQuickLayout::isReady() const
992{
993 return d_func()->m_isReady;
994}
995
996/*!
997 * \brief QQuickLayout::deactivateRecur
998 * \internal
999 *
1000 * Call this from the dtor of the top-level layout.
1001 * Otherwise, it will trigger lots of unneeded item change listeners (itemVisibleChanged()) for all its descendants
1002 * that will have its impact thrown away.
1003 */
1004void QQuickLayout::deactivateRecur()
1005{
1006 if (d_func()->m_hasItemChangeListeners) {
1007 ensureLayoutItemsUpdated();
1008 for (int i = 0; i < itemCount(); ++i) {
1009 QQuickItem *item = itemAt(i);
1010 // When deleting a layout with children, there is no reason for the children to inform the layout that their
1011 // e.g. visibility got changed. The layout already knows that all its children will eventually become invisible, so
1012 // we therefore remove its change listener.
1013 QQuickItemPrivate::get(item)->removeItemChangeListener(this, changeTypes);
1014 if (QQuickLayout *layout = qobject_cast<QQuickLayout*>(item))
1015 layout->deactivateRecur();
1016 }
1017 d_func()->m_hasItemChangeListeners = false;
1018 }
1019}
1020
1021bool QQuickLayout::invalidated() const
1022{
1023 return d_func()->m_dirty;
1024}
1025
1026bool QQuickLayout::invalidatedArrangement() const
1027{
1028 return d_func()->m_dirtyArrangement;
1029}
1030
1031bool QQuickLayout::isMirrored() const
1032{
1033 return d_func()->isMirrored();
1034}
1035
1036void QQuickLayout::itemSiblingOrderChanged(QQuickItem *item)
1037{
1038 Q_UNUSED(item);
1039 invalidate();
1040}
1041
1042void QQuickLayout::itemImplicitWidthChanged(QQuickItem *item)
1043{
1044 if (!isReady())
1045 return;
1046 invalidate(item);
1047}
1048
1049void QQuickLayout::itemImplicitHeightChanged(QQuickItem *item)
1050{
1051 if (!isReady())
1052 return;
1053 invalidate(item);
1054}
1055
1056void QQuickLayout::itemDestroyed(QQuickItem *item)
1057{
1058 Q_UNUSED(item);
1059}
1060
1061void QQuickLayout::itemVisibilityChanged(QQuickItem *item)
1062{
1063 Q_UNUSED(item);
1064}
1065
1066void QQuickLayout::rearrange(const QSizeF &/*size*/)
1067{
1068 d_func()->m_dirtyArrangement = false;
1069}
1070
1071
1072/*
1073 The layout engine assumes:
1074 1. minimum <= preferred <= maximum
1075 2. descent is within minimum and maximum bounds (### verify)
1076
1077 This function helps to ensure that by the following rules (in the following order):
1078 1. If minimum > maximum, set minimum = maximum
1079 2. Clamp preferred to be between the [minimum,maximum] range.
1080 3. If descent > minimum, set descent = minimum (### verify if this is correct, it might
1081 need some refinements to multiline texts)
1082
1083 If any values are "not set" (i.e. negative), they will be left untouched, so that we
1084 know which values needs to be fetched from the implicit hints (not user hints).
1085 */
1086static void normalizeHints(qreal &minimum, qreal &preferred, qreal &maximum, qreal &descent)
1087{
1088 if (minimum >= 0 && maximum >= 0 && minimum > maximum)
1089 minimum = maximum;
1090
1091 if (preferred >= 0) {
1092 if (minimum >= 0 && preferred < minimum) {
1093 preferred = minimum;
1094 } else if (maximum >= 0 && preferred > maximum) {
1095 preferred = maximum;
1096 }
1097 }
1098
1099 if (minimum >= 0 && descent > minimum)
1100 descent = minimum;
1101}
1102
1103static void boundSize(QSizeF &result, const QSizeF &size)
1104{
1105 if (size.width() >= 0 && size.width() < result.width())
1106 result.setWidth(size.width());
1107 if (size.height() >= 0 && size.height() < result.height())
1108 result.setHeight(size.height());
1109}
1110
1111static void expandSize(QSizeF &result, const QSizeF &size)
1112{
1113 if (size.width() >= 0 && size.width() > result.width())
1114 result.setWidth(size.width());
1115 if (size.height() >= 0 && size.height() > result.height())
1116 result.setHeight(size.height());
1117}
1118
1119static inline void combineHints(qreal &current, qreal fallbackHint)
1120{
1121 if (current < 0)
1122 current = fallbackHint;
1123}
1124
1125static inline void combineSize(QSizeF &result, const QSizeF &fallbackSize)
1126{
1127 combineHints(result.rwidth(), fallbackSize.width());
1128 combineHints(result.rheight(), fallbackSize.height());
1129}
1130
1131static inline void combineImplicitHints(QQuickLayoutAttached *info, Qt::SizeHint which, QSizeF *size)
1132{
1133 if (!info) return;
1134
1135 Q_ASSERT(which == Qt::MinimumSize || which == Qt::MaximumSize);
1136
1137 const QSizeF constraint(which == Qt::MinimumSize
1138 ? QSizeF(info->minimumWidth(), info->minimumHeight())
1139 : QSizeF(info->maximumWidth(), info->maximumHeight()));
1140
1141 if (!info->isExtentExplicitlySet(Qt::Horizontal, which))
1142 combineHints(size->rwidth(), constraint.width());
1143 if (!info->isExtentExplicitlySet(Qt::Vertical, which))
1144 combineHints(size->rheight(), constraint.height());
1145}
1146
1148
1149/*!
1150 \internal
1151 Note: Can potentially return the attached QQuickLayoutAttached object through \a attachedInfo.
1152
1153 It is like this is because it enables it to be reused.
1154
1155 The goal of this function is to return the effective minimum, preferred and maximum size hints
1156 that the layout will use for this item.
1157 This function takes care of gathering all explicitly set size hints, normalizes them so
1158 that min < pref < max.
1159 Further, the hints _not_explicitly_ set will then be initialized with the implicit size hints,
1160 which is usually derived from the content of the layouts (or items).
1161
1162 The following table illustrates the preference of the properties used for measuring layout
1163 items. If present, the USER properties will be preferred. If USER properties are not present,
1164 the HINT properties will be preferred. Finally, the FALLBACK properties will be used as an
1165 ultimate fallback.
1166
1167 Note that one can query if the value of Layout.minimumWidth or Layout.maximumWidth has been
1168 explicitly or implicitly set with QQuickLayoutAttached::isExtentExplicitlySet(). This
1169 determines if it should be used as a USER or as a HINT value.
1170
1171 Fractional size hints will be ceiled to the closest integer. This is in order to give some
1172 slack when the items are snapped to the pixel grid.
1173
1174 | *Minimum* | *Preferred* | *Maximum* |
1175+----------------+----------------------+-----------------------+--------------------------+
1176|USER (explicit) | Layout.minimumWidth | Layout.preferredWidth | Layout.maximumWidth |
1177|HINT (implicit) | Layout.minimumWidth | implicitWidth | Layout.maximumWidth |
1178|FALLBACK | 0 | width | Number.POSITIVE_INFINITY |
1179+----------------+----------------------+-----------------------+--------------------------+
1180 */
1181void QQuickLayout::effectiveSizeHints_helper(QQuickItem *item, QSizeF *cachedSizeHints, QQuickLayoutAttached **attachedInfo, bool useFallbackToWidthOrHeight)
1182{
1183 for (int i = 0; i < Qt::NSizeHints; ++i)
1184 cachedSizeHints[i] = QSizeF();
1185 QQuickLayoutAttached *info = attachedLayoutObject(item, false);
1186 // First, retrieve the user-specified hints from the attached "Layout." properties
1187 if (info) {
1188 struct Getters {
1189 SizeGetter call[NSizes];
1190 };
1191
1192 static Getters horGetters = {
1193 {&QQuickLayoutAttached::minimumWidth, &QQuickLayoutAttached::preferredWidth, &QQuickLayoutAttached::maximumWidth},
1194 };
1195
1196 static Getters verGetters = {
1197 {&QQuickLayoutAttached::minimumHeight, &QQuickLayoutAttached::preferredHeight, &QQuickLayoutAttached::maximumHeight}
1198 };
1199 for (int i = 0; i < NSizes; ++i) {
1200 SizeGetter getter = horGetters.call[i];
1201 Q_ASSERT(getter);
1202
1203 if (info->isExtentExplicitlySet(Qt::Horizontal, (Qt::SizeHint)i))
1204 cachedSizeHints[i].setWidth((info->*getter)());
1205
1206 getter = verGetters.call[i];
1207 Q_ASSERT(getter);
1208 if (info->isExtentExplicitlySet(Qt::Vertical, (Qt::SizeHint)i))
1209 cachedSizeHints[i].setHeight((info->*getter)());
1210 }
1211 }
1212
1213 QSizeF &minS = cachedSizeHints[Qt::MinimumSize];
1214 QSizeF &prefS = cachedSizeHints[Qt::PreferredSize];
1215 QSizeF &maxS = cachedSizeHints[Qt::MaximumSize];
1216 QSizeF &descentS = cachedSizeHints[Qt::MinimumDescent];
1217
1218 // For instance, will normalize the following user-set hints
1219 // from: [10, 5, 60]
1220 // to: [10, 10, 60]
1221 normalizeHints(minS.rwidth(), prefS.rwidth(), maxS.rwidth(), descentS.rwidth());
1222 normalizeHints(minS.rheight(), prefS.rheight(), maxS.rheight(), descentS.rheight());
1223
1224 // All explicit values gathered, now continue to gather the implicit sizes
1225
1226 //--- GATHER MAXIMUM SIZE HINTS ---
1227 combineImplicitHints(info, Qt::MaximumSize, &maxS);
1228 combineSize(maxS, QSizeF(std::numeric_limits<qreal>::infinity(), std::numeric_limits<qreal>::infinity()));
1229 // implicit max or min sizes should not limit an explicitly set preferred size
1230 expandSize(maxS, prefS);
1231 expandSize(maxS, minS);
1232
1233 //--- GATHER MINIMUM SIZE HINTS ---
1234 combineImplicitHints(info, Qt::MinimumSize, &minS);
1235 expandSize(minS, QSizeF(0,0));
1236 boundSize(minS, prefS);
1237 boundSize(minS, maxS);
1238
1239 //--- GATHER PREFERRED SIZE HINTS ---
1240 // First, from implicitWidth/Height
1241 qreal &prefWidth = prefS.rwidth();
1242 qreal &prefHeight = prefS.rheight();
1243 if (prefWidth < 0 && item->implicitWidth() > 0)
1244 prefWidth = qCeil(item->implicitWidth());
1245 if (prefHeight < 0 && item->implicitHeight() > 0)
1246 prefHeight = qCeil(item->implicitHeight());
1247
1248 // If that fails, make an ultimate fallback to width/height
1249 if (useFallbackToWidthOrHeight && !prefS.isValid()) {
1250 /* If we want to support using width/height as preferred size hints in
1251 layouts, (which we think most people expect), we only want to use the
1252 initial width.
1253 This is because the width will change due to layout rearrangement,
1254 and the preferred width should return the same value, regardless of
1255 the current width.
1256 We therefore store this initial width in the attached layout object
1257 and reuse it if needed rather than querying the width another time.
1258 That means we need to ensure that an Layout attached object is available
1259 by creating one if necessary.
1260 */
1261 if (!info)
1262 info = attachedLayoutObject(item);
1263
1264 auto updatePreferredSizes = [](qreal &cachedSize, qreal &attachedSize, qreal size) {
1265 if (cachedSize < 0) {
1266 if (attachedSize < 0)
1267 attachedSize = size;
1268
1269 cachedSize = attachedSize;
1270 }
1271 };
1272 updatePreferredSizes(prefWidth, info->m_fallbackWidth, item->width());
1273 updatePreferredSizes(prefHeight, info->m_fallbackHeight, item->height());
1274 }
1275
1276 // Normalize again after the implicit hints have been gathered
1277 expandSize(prefS, minS);
1278 boundSize(prefS, maxS);
1279
1280 //--- GATHER DESCENT
1281 // Minimum descent is only applicable for the effective minimum height,
1282 // so we gather the descent last.
1283 const qreal minimumDescent = minS.height() - item->baselineOffset();
1284 descentS.setHeight(minimumDescent);
1285
1286 if (info) {
1287 QMarginsF margins = info->qMargins();
1288 QSizeF extraMargins(margins.left() + margins.right(), margins.top() + margins.bottom());
1289 minS += extraMargins;
1290 prefS += extraMargins;
1291 maxS += extraMargins;
1292 descentS += extraMargins;
1293 }
1294 if (attachedInfo)
1295 *attachedInfo = info;
1296}
1297
1298/*!
1299 \internal
1300
1301 Assumes \a info is set (if the object has an attached property)
1302 */
1303QLayoutPolicy::Policy QQuickLayout::effectiveSizePolicy_helper(QQuickItem *item, Qt::Orientation orientation, QQuickLayoutAttached *info)
1304{
1305 QLayoutPolicy::Policy pol{QLayoutPolicy::Fixed};
1306 bool isSet = false;
1307 if (info) {
1308 if (orientation == Qt::Horizontal) {
1309 isSet = info->isFillWidthSet();
1310 if (isSet && info->fillWidth())
1311 pol = QLayoutPolicy::Preferred;
1312 } else {
1313 isSet = info->isFillHeightSet();
1314 if (isSet && info->fillHeight())
1315 pol = QLayoutPolicy::Preferred;
1316 }
1317 }
1318 if (!isSet && item) {
1319 auto effectiveUseDefaultSizePolicy = [info]() {
1320 return info ? info->useDefaultSizePolicy() == QQuickLayout::SizePolicyImplicit
1321 : QGuiApplication::testAttribute(Qt::AA_QtQuickUseDefaultSizePolicy);
1322 };
1323 if (qobject_cast<QQuickLayout*>(item)) {
1324 pol = QLayoutPolicy::Preferred;
1325 } else if (effectiveUseDefaultSizePolicy()) {
1326 QLayoutPolicy sizePolicy = QQuickItemPrivate::get(item)->sizePolicy();
1327 pol = (orientation == Qt::Horizontal) ? sizePolicy.horizontalPolicy() : sizePolicy.verticalPolicy();
1328 }
1329 }
1330
1331 return pol;
1332}
1333
1334void QQuickLayout::_q_dumpLayoutTree() const
1335{
1336 QString buf;
1337 dumpLayoutTreeRecursive(0, buf);
1338 qDebug("\n%s", qPrintable(buf));
1339}
1340
1341void QQuickLayout::dumpLayoutTreeRecursive(int level, QString &buf) const
1342{
1343 auto formatLine = [&level](const char *fmt) -> QString {
1344 QString ss(level *4, QLatin1Char(' '));
1345 return ss + QLatin1String(fmt) + QLatin1Char('\n');
1346 };
1347
1348 auto f2s = [](qreal f) {
1349 return QString::number(f);
1350 };
1351 auto b2s = [](bool b) {
1352 static const char *strBool[] = {"false", "true"};
1353 return QLatin1String(strBool[int(b)]);
1354 };
1355
1356 buf += formatLine("%1 {").arg(QQmlMetaType::prettyTypeName(this));
1357 ++level;
1358 buf += formatLine("// Effective calculated values:");
1359 buf += formatLine("sizeHintDirty: %2").arg(invalidated());
1360 QSizeF min = sizeHint(Qt::MinimumSize);
1361 buf += formatLine("sizeHint.min : [%1, %2]").arg(f2s(min.width()), 5).arg(min.height(), 5);
1362 QSizeF pref = sizeHint(Qt::PreferredSize);
1363 buf += formatLine("sizeHint.pref: [%1, %2]").arg(pref.width(), 5).arg(pref.height(), 5);
1364 QSizeF max = sizeHint(Qt::MaximumSize);
1365 buf += formatLine("sizeHint.max : [%1, %2]").arg(f2s(max.width()), 5).arg(f2s(max.height()), 5);
1366
1367 for (QQuickItem *item : childItems()) {
1368 buf += QLatin1Char('\n');
1369 if (QQuickLayout *childLayout = qobject_cast<QQuickLayout*>(item)) {
1370 childLayout->dumpLayoutTreeRecursive(level, buf);
1371 } else {
1372 buf += formatLine("%1 {").arg(QQmlMetaType::prettyTypeName(item));
1373 ++level;
1374 if (item->implicitWidth() > 0)
1375 buf += formatLine("implicitWidth: %1").arg(f2s(item->implicitWidth()));
1376 if (item->implicitHeight() > 0)
1377 buf += formatLine("implicitHeight: %1").arg(f2s(item->implicitHeight()));
1378 QSizeF min;
1379 QSizeF pref;
1380 QSizeF max;
1381 QQuickLayoutAttached *info = attachedLayoutObject(item, false);
1382 if (info) {
1383 min = QSizeF(info->minimumWidth(), info->minimumHeight());
1384 pref = QSizeF(info->preferredWidth(), info->preferredHeight());
1385 max = QSizeF(info->maximumWidth(), info->maximumHeight());
1386 if (info->isExtentExplicitlySet(Qt::Horizontal, Qt::MinimumSize))
1387 buf += formatLine("Layout.minimumWidth: %1").arg(f2s(min.width()));
1388 if (info->isExtentExplicitlySet(Qt::Vertical, Qt::MinimumSize))
1389 buf += formatLine("Layout.minimumHeight: %1").arg(f2s(min.height()));
1390 if (pref.width() >= 0)
1391 buf += formatLine("Layout.preferredWidth: %1").arg(f2s(pref.width()));
1392 if (pref.height() >= 0)
1393 buf += formatLine("Layout.preferredHeight: %1").arg(f2s(pref.height()));
1394 if (info->isExtentExplicitlySet(Qt::Horizontal, Qt::MaximumSize))
1395 buf += formatLine("Layout.maximumWidth: %1").arg(f2s(max.width()));
1396 if (info->isExtentExplicitlySet(Qt::Vertical, Qt::MaximumSize))
1397 buf += formatLine("Layout.maximumHeight: %1").arg(f2s(max.height()));
1398
1399 if (info->isFillWidthSet())
1400 buf += formatLine("Layout.fillWidth: %1").arg(b2s(info->fillWidth()));
1401 if (info->isFillHeightSet())
1402 buf += formatLine("Layout.fillHeight: %1").arg(b2s(info->fillHeight()));
1403 }
1404 --level;
1405 buf += formatLine("}");
1406 }
1407 }
1408 --level;
1409 buf += formatLine("}");
1410}
1411
1412QT_END_NAMESPACE
1413
1414#include "moc_qquicklayout_p.cpp"
Q_LOGGING_CATEGORY(lcEventDispatcher, "qt.eventdispatcher")
static QQuickItemPrivate::ChangeTypes changeTypes
static void combineHints(qreal &current, qreal fallbackHint)
static void combineImplicitHints(QQuickLayoutAttached *info, Qt::SizeHint which, QSizeF *size)
static void normalizeHints(qreal &minimum, qreal &preferred, qreal &maximum, qreal &descent)
static void boundSize(QSizeF &result, const QSizeF &size)
qreal(QQuickLayoutAttached::* SizeGetter)() const
static void combineSize(QSizeF &result, const QSizeF &fallbackSize)
static void expandSize(QSizeF &result, const QSizeF &size)