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