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

source code of qtdeclarative/src/quicklayouts/qquicklayout.cpp