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