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 "qlayout.h"
5
6#include "qapplication.h"
7#include "qlayoutengine_p.h"
8#include "qevent.h"
9#include "qstyle.h"
10#include "qvariant.h"
11#include "qwidget_p.h"
12
13QT_BEGIN_NAMESPACE
14
15inline static QRect fromLayoutItemRect(QWidgetPrivate *priv, const QRect &rect)
16{
17 return rect.adjusted(xp1: priv->leftLayoutItemMargin, yp1: priv->topLayoutItemMargin,
18 xp2: -priv->rightLayoutItemMargin, yp2: -priv->bottomLayoutItemMargin);
19}
20
21inline static QSize fromLayoutItemSize(QWidgetPrivate *priv, const QSize &size)
22{
23 return fromLayoutItemRect(priv, rect: QRect(QPoint(0, 0), size)).size();
24}
25
26inline static QRect toLayoutItemRect(QWidgetPrivate *priv, const QRect &rect)
27{
28 return rect.adjusted(xp1: -priv->leftLayoutItemMargin, yp1: -priv->topLayoutItemMargin,
29 xp2: priv->rightLayoutItemMargin, yp2: priv->bottomLayoutItemMargin);
30}
31
32inline static QSize toLayoutItemSize(QWidgetPrivate *priv, const QSize &size)
33{
34 return toLayoutItemRect(priv, rect: QRect(QPoint(0, 0), size)).size();
35}
36
37/*!
38 \class QLayoutItem
39 \brief The QLayoutItem class provides an abstract item that a
40 QLayout manipulates.
41
42 \ingroup geomanagement
43 \inmodule QtWidgets
44
45 This is used by custom layouts.
46
47 Pure virtual functions are provided to return information about
48 the layout, including, sizeHint(), minimumSize(), maximumSize()
49 and expandingDirections().
50
51 The layout's geometry can be set and retrieved with setGeometry()
52 and geometry(), and its alignment with setAlignment() and
53 alignment().
54
55 isEmpty() returns whether the layout item is empty. If the
56 concrete item is a QWidget, it can be retrieved using widget().
57 Similarly for layout() and spacerItem().
58
59 Some layouts have width and height interdependencies. These can
60 be expressed using hasHeightForWidth(), heightForWidth(), and
61 minimumHeightForWidth(). For more explanation see the \e{Qt
62 Quarterly} article
63 \l{http://doc.qt.io/archives/qq/qq04-height-for-width.html}{Trading
64 Height for Width}.
65
66 \sa QLayout
67*/
68
69/*!
70 \class QSpacerItem
71 \ingroup geomanagement
72 \brief The QSpacerItem class provides blank space in a layout.
73
74 \inmodule QtWidgets
75
76 Normally, you don't need to use this class directly. Qt's
77 built-in layout managers provide the following functions for
78 manipulating empty space in layouts:
79
80 \table
81 \header \li Class
82 \li Functions
83 \row \li QHBoxLayout
84 \li \l{QBoxLayout::addSpacing()}{addSpacing()},
85 \l{QBoxLayout::addStretch()}{addStretch()},
86 \l{QBoxLayout::insertSpacing()}{insertSpacing()},
87 \l{QBoxLayout::insertStretch()}{insertStretch()}
88 \row \li QGridLayout
89 \li \l{QGridLayout::setRowMinimumHeight()}{setRowMinimumHeight()},
90 \l{QGridLayout::setRowStretch()}{setRowStretch()},
91 \l{QGridLayout::setColumnMinimumWidth()}{setColumnMinimumWidth()},
92 \l{QGridLayout::setColumnStretch()}{setColumnStretch()}
93 \endtable
94
95 \sa QLayout, QWidgetItem, QLayoutItem::spacerItem()
96*/
97
98/*!
99 \class QWidgetItem
100 \ingroup geomanagement
101 \brief The QWidgetItem class is a layout item that represents a widget.
102
103 \inmodule QtWidgets
104
105 Normally, you don't need to use this class directly. Qt's
106 built-in layout managers provide the following functions for
107 manipulating widgets in layouts:
108
109 \table
110 \header \li Class
111 \li Functions
112 \row \li QBoxLayout
113 \li \l{QBoxLayout::addWidget()}{addWidget()},
114 \l{QBoxLayout::insertWidget()}{insertWidget()},
115 \l{QBoxLayout::setStretchFactor()}{setStretchFactor()}
116 \row \li QGridLayout
117 \li \l{QGridLayout::addWidget()}{addWidget()}
118 \row \li QStackedLayout
119 \li \l{QStackedLayout::addWidget()}{addWidget()},
120 \l{QStackedLayout::insertWidget()}{insertWidget()},
121 \l{QStackedLayout::currentWidget()}{currentWidget()},
122 \l{QStackedLayout::setCurrentWidget()}{setCurrentWidget()},
123 \l{QStackedLayout::widget()}{widget()}
124 \endtable
125
126 \sa QLayout, QSpacerItem, QLayoutItem::widget()
127*/
128
129/*!
130 \fn QLayoutItem::QLayoutItem(Qt::Alignment alignment)
131
132 Constructs a layout item with an \a alignment.
133 Not all subclasses support alignment.
134*/
135
136/*!
137 \fn Qt::Alignment QLayoutItem::alignment() const
138
139 Returns the alignment of this item.
140*/
141
142/*!
143 Sets the alignment of this item to \a alignment.
144
145 \b{Note:} Item alignment is only supported by QLayoutItem subclasses
146 where it would have a visual effect. Except for QSpacerItem, which provides
147 blank space for layouts, all public Qt classes that inherit QLayoutItem
148 support item alignment.
149*/
150void QLayoutItem::setAlignment(Qt::Alignment alignment)
151{
152 align = alignment;
153}
154
155/*!
156 \fn QSize QLayoutItem::maximumSize() const
157
158 Implemented in subclasses to return the maximum size of this item.
159*/
160
161/*!
162 \fn QSize QLayoutItem::minimumSize() const
163
164 Implemented in subclasses to return the minimum size of this item.
165*/
166
167/*!
168 \fn QSize QLayoutItem::sizeHint() const
169
170 Implemented in subclasses to return the preferred size of this item.
171*/
172
173/*!
174 \fn Qt::Orientations QLayoutItem::expandingDirections() const
175
176 Returns whether this layout item can make use of more space than
177 sizeHint(). A value of Qt::Vertical or Qt::Horizontal means that
178 it wants to grow in only one dimension, whereas Qt::Vertical |
179 Qt::Horizontal means that it wants to grow in both dimensions.
180*/
181
182/*!
183 \fn void QLayoutItem::setGeometry(const QRect &r)
184
185 Implemented in subclasses to set this item's geometry to \a r.
186
187 \sa geometry()
188*/
189
190/*!
191 \fn QRect QLayoutItem::geometry() const
192
193 Returns the rectangle covered by this layout item.
194
195 \sa setGeometry()
196*/
197
198/*!
199 \fn virtual bool QLayoutItem::isEmpty() const
200
201 Implemented in subclasses to return whether this item is empty,
202 i.e. whether it contains any widgets.
203*/
204
205/*!
206 \fn QSpacerItem::QSpacerItem(int w, int h, QSizePolicy::Policy hPolicy, QSizePolicy::Policy vPolicy)
207
208 Constructs a spacer item with preferred width \a w, preferred
209 height \a h, horizontal size policy \a hPolicy and vertical size
210 policy \a vPolicy.
211
212 The default values provide a gap that is able to stretch if
213 nothing else wants the space.
214*/
215
216/*!
217 Destructor.
218*/
219QSpacerItem::~QSpacerItem() {}
220
221/*!
222 Changes this spacer item to have preferred width \a w, preferred
223 height \a h, horizontal size policy \a hPolicy and vertical size
224 policy \a vPolicy.
225
226 The default values provide a gap that is able to stretch if
227 nothing else wants the space.
228
229 Note that if changeSize() is called after the spacer item has been added
230 to a layout, it is necessary to invalidate the layout in order for the
231 spacer item's new size to take effect.
232
233 \sa QSpacerItem::invalidate()
234*/
235void QSpacerItem::changeSize(int w, int h, QSizePolicy::Policy hPolicy,
236 QSizePolicy::Policy vPolicy)
237{
238 width = w;
239 height = h;
240 sizeP = QSizePolicy(hPolicy, vPolicy);
241}
242
243/*!
244 \fn QWidgetItem::QWidgetItem(QWidget *widget)
245
246 Creates an item containing the given \a widget.
247*/
248
249/*!
250 Destructor.
251*/
252QWidgetItem::~QWidgetItem() = default;
253
254/*!
255 Destroys the QLayoutItem.
256*/
257QLayoutItem::~QLayoutItem() = default;
258
259/*!
260 Invalidates any cached information in this layout item.
261*/
262void QLayoutItem::invalidate()
263{
264}
265
266/*!
267 If this item is a QLayout, it is returned as a QLayout; otherwise
268 \nullptr is returned. This function provides type-safe casting.
269
270 \sa spacerItem(), widget()
271*/
272QLayout *QLayoutItem::layout()
273{
274 return nullptr;
275}
276
277/*!
278 If this item is a QSpacerItem, it is returned as a QSpacerItem;
279 otherwise \nullptr is returned. This function provides type-safe casting.
280
281 \sa layout(), widget()
282*/
283QSpacerItem *QLayoutItem::spacerItem()
284{
285 return nullptr;
286}
287
288/*!
289 \reimp
290*/
291QLayout * QLayout::layout()
292{
293 return this;
294}
295
296/*!
297 Returns a pointer to this object.
298*/
299QSpacerItem * QSpacerItem::spacerItem()
300{
301 return this;
302}
303
304/*!
305 \fn QSizePolicy QSpacerItem::sizePolicy() const
306 \since 5.5
307
308 Returns the size policy of this item.
309*/
310
311/*!
312 If this item manages a QWidget, returns that widget. Otherwise,
313 \nullptr is returned.
314
315 \note While the functions layout() and spacerItem() perform casts, this
316 function returns another object: QLayout and QSpacerItem inherit QLayoutItem,
317 while QWidget does not.
318
319 \sa layout(), spacerItem()
320*/
321QWidget *QLayoutItem::widget() const
322{
323 return nullptr;
324}
325
326/*!
327 Returns the widget managed by this item.
328*/
329QWidget *QWidgetItem::widget() const
330{
331 return wid;
332}
333
334/*!
335 Returns \c true if this layout's preferred height depends on its
336 width; otherwise returns \c false. The default implementation returns
337 false.
338
339 Reimplement this function in layout managers that support height
340 for width.
341
342 \sa heightForWidth(), QWidget::heightForWidth()
343*/
344bool QLayoutItem::hasHeightForWidth() const
345{
346 return false;
347}
348
349/*!
350 Returns the minimum height this widget needs for the given width,
351 \a w. The default implementation simply returns heightForWidth(\a
352 w).
353*/
354int QLayoutItem::minimumHeightForWidth(int w) const
355{
356 return heightForWidth(w);
357}
358
359
360/*!
361 Returns the preferred height for this layout item, given the
362 width, which is not used in this default implementation.
363
364 The default implementation returns -1, indicating that the
365 preferred height is independent of the width of the item. Using
366 the function hasHeightForWidth() will typically be much faster
367 than calling this function and testing for -1.
368
369 Reimplement this function in layout managers that support height
370 for width. A typical implementation will look like this:
371 \snippet code/src_gui_kernel_qlayoutitem.cpp 0
372
373 Caching is strongly recommended; without it layout will take
374 exponential time.
375
376 \sa hasHeightForWidth()
377*/
378int QLayoutItem::heightForWidth(int /* w */) const
379{
380 return -1;
381}
382
383/*!
384 Returns the control type(s) for the layout item. For a
385 QWidgetItem, the control type comes from the widget's size
386 policy; for a QLayoutItem, the control types is derived from the
387 layout's contents.
388
389 \sa QSizePolicy::controlType()
390*/
391QSizePolicy::ControlTypes QLayoutItem::controlTypes() const
392{
393 return QSizePolicy::DefaultType;
394}
395
396/*!
397 \reimp
398*/
399void QSpacerItem::setGeometry(const QRect &r)
400{
401 rect = r;
402}
403
404/*!
405 \reimp
406*/
407void QWidgetItem::setGeometry(const QRect &rect)
408{
409 if (isEmpty())
410 return;
411
412 QRect r = !wid->testAttribute(attribute: Qt::WA_LayoutUsesWidgetRect)
413 ? fromLayoutItemRect(priv: wid->d_func(), rect)
414 : rect;
415 const QSize widgetRectSurplus = r.size() - rect.size();
416
417 /*
418 For historical reasons, this code is done using widget rect
419 coordinates, not layout item rect coordinates. However,
420 QWidgetItem's sizeHint(), maximumSize(), and heightForWidth()
421 all work in terms of layout item rect coordinates, so we have to
422 add or subtract widgetRectSurplus here and there. The code could
423 be much simpler if we did everything using layout item rect
424 coordinates and did the conversion right before the call to
425 QWidget::setGeometry().
426 */
427
428 QSize s = r.size().boundedTo(otherSize: maximumSize() + widgetRectSurplus);
429 int x = r.x();
430 int y = r.y();
431 if (align & (Qt::AlignHorizontal_Mask | Qt::AlignVertical_Mask)) {
432 QSize pref(sizeHint());
433 QSizePolicy sp = wid->sizePolicy();
434 if (sp.horizontalPolicy() == QSizePolicy::Ignored)
435 pref.setWidth(wid->sizeHint().expandedTo(otherSize: wid->minimumSize()).width());
436 if (sp.verticalPolicy() == QSizePolicy::Ignored)
437 pref.setHeight(wid->sizeHint().expandedTo(otherSize: wid->minimumSize()).height());
438 pref += widgetRectSurplus;
439 if (align & Qt::AlignHorizontal_Mask)
440 s.setWidth(qMin(a: s.width(), b: pref.width()));
441 if (align & Qt::AlignVertical_Mask) {
442 if (hasHeightForWidth())
443 s.setHeight(qMin(a: s.height(),
444 b: heightForWidth(s.width() - widgetRectSurplus.width())
445 + widgetRectSurplus.height()));
446 else
447 s.setHeight(qMin(a: s.height(), b: pref.height()));
448 }
449 }
450 Qt::Alignment alignHoriz = QStyle::visualAlignment(direction: wid->layoutDirection(), alignment: align);
451 if (alignHoriz & Qt::AlignRight)
452 x = x + (r.width() - s.width());
453 else if (!(alignHoriz & Qt::AlignLeft))
454 x = x + (r.width() - s.width()) / 2;
455
456 if (align & Qt::AlignBottom)
457 y = y + (r.height() - s.height());
458 else if (!(align & Qt::AlignTop))
459 y = y + (r.height() - s.height()) / 2;
460
461 // Make sure we don't move outside of the parent, e.g when styles demand
462 // surplus space that exceeds the available margins (f.ex macOS with QGroupBox)
463 if (x < 0) {
464 s.rwidth() += x;
465 x = 0;
466 }
467 if (y < 0) {
468 s.rheight() += y;
469 y = 0;
470 }
471
472 wid->setGeometry(ax: x, ay: y, aw: s.width(), ah: s.height());
473}
474
475/*!
476 \reimp
477*/
478QRect QSpacerItem::geometry() const
479{
480 return rect;
481}
482
483/*!
484 \reimp
485*/
486QRect QWidgetItem::geometry() const
487{
488 return !wid->testAttribute(attribute: Qt::WA_LayoutUsesWidgetRect)
489 ? toLayoutItemRect(priv: wid->d_func(), rect: wid->geometry())
490 : wid->geometry();
491}
492
493
494/*!
495 \reimp
496*/
497bool QWidgetItem::hasHeightForWidth() const
498{
499 if (isEmpty())
500 return false;
501 return wid->hasHeightForWidth();
502}
503
504/*!
505 \reimp
506*/
507int QWidgetItem::heightForWidth(int w) const
508{
509 if (isEmpty())
510 return -1;
511
512 w = !wid->testAttribute(attribute: Qt::WA_LayoutUsesWidgetRect)
513 ? fromLayoutItemSize(priv: wid->d_func(), size: QSize(w, 0)).width()
514 : w;
515
516 int hfw;
517 if (wid->layout())
518 hfw = wid->layout()->totalHeightForWidth(w);
519 else
520 hfw = wid->heightForWidth(w);
521
522 if (hfw > wid->maximumHeight())
523 hfw = wid->maximumHeight();
524 if (hfw < wid->minimumHeight())
525 hfw = wid->minimumHeight();
526
527 hfw = !wid->testAttribute(attribute: Qt::WA_LayoutUsesWidgetRect)
528 ? toLayoutItemSize(priv: wid->d_func(), size: QSize(0, hfw)).height()
529 : hfw;
530
531 if (hfw < 0)
532 hfw = 0;
533 return hfw;
534}
535
536int QWidgetItem::minimumHeightForWidth(int w) const
537{
538 if (isEmpty())
539 return -1;
540
541 w = !wid->testAttribute(attribute: Qt::WA_LayoutUsesWidgetRect)
542 ? fromLayoutItemSize(priv: wid->d_func(), size: QSize(w, 0)).width()
543 : w;
544
545 int hfw;
546 if (wid->layout())
547 hfw = wid->layout()->totalMinimumHeightForWidth(w);
548 else
549 hfw = wid->heightForWidth(w); // QWidget doesn't have minimumHeightForWidth()
550
551 if (hfw > wid->maximumHeight())
552 hfw = wid->maximumHeight();
553 if (hfw < wid->minimumHeight())
554 hfw = wid->minimumHeight();
555
556 hfw = !wid->testAttribute(attribute: Qt::WA_LayoutUsesWidgetRect)
557 ? toLayoutItemSize(priv: wid->d_func(), size: QSize(0, hfw)).height()
558 : hfw;
559
560 if (hfw < 0)
561 hfw = 0;
562 return hfw;
563
564}
565
566/*!
567 \reimp
568*/
569Qt::Orientations QSpacerItem::expandingDirections() const
570{
571 return sizeP.expandingDirections();
572}
573
574/*!
575 \reimp
576*/
577Qt::Orientations QWidgetItem::expandingDirections() const
578{
579 if (isEmpty())
580 return {};
581
582 Qt::Orientations e = wid->sizePolicy().expandingDirections();
583 /*
584 If the layout is expanding, we make the widget expanding, even if
585 its own size policy isn't expanding.
586 */
587 if (wid->layout()) {
588 if (wid->sizePolicy().horizontalPolicy() & QSizePolicy::GrowFlag
589 && (wid->layout()->expandingDirections() & Qt::Horizontal))
590 e |= Qt::Horizontal;
591 if (wid->sizePolicy().verticalPolicy() & QSizePolicy::GrowFlag
592 && (wid->layout()->expandingDirections() & Qt::Vertical))
593 e |= Qt::Vertical;
594 }
595
596 if (align & Qt::AlignHorizontal_Mask)
597 e &= ~Qt::Horizontal;
598 if (align & Qt::AlignVertical_Mask)
599 e &= ~Qt::Vertical;
600 return e;
601}
602
603/*!
604 \reimp
605*/
606QSize QSpacerItem::minimumSize() const
607{
608 return QSize(sizeP.horizontalPolicy() & QSizePolicy::ShrinkFlag ? 0 : width,
609 sizeP.verticalPolicy() & QSizePolicy::ShrinkFlag ? 0 : height);
610}
611
612/*!
613 \reimp
614*/
615QSize QWidgetItem::minimumSize() const
616{
617 if (isEmpty())
618 return QSize(0, 0);
619 return !wid->testAttribute(attribute: Qt::WA_LayoutUsesWidgetRect)
620 ? toLayoutItemSize(priv: wid->d_func(), size: qSmartMinSize(i: this))
621 : qSmartMinSize(i: this);
622}
623
624/*!
625 \reimp
626*/
627QSize QSpacerItem::maximumSize() const
628{
629 return QSize(sizeP.horizontalPolicy() & QSizePolicy::GrowFlag ? QLAYOUTSIZE_MAX : width,
630 sizeP.verticalPolicy() & QSizePolicy::GrowFlag ? QLAYOUTSIZE_MAX : height);
631}
632
633/*!
634 \reimp
635*/
636QSize QWidgetItem::maximumSize() const
637{
638 if (isEmpty()) {
639 return QSize(0, 0);
640 } else {
641 return !wid->testAttribute(attribute: Qt::WA_LayoutUsesWidgetRect)
642 ? toLayoutItemSize(priv: wid->d_func(), size: qSmartMaxSize(i: this, align))
643 : qSmartMaxSize(i: this, align);
644 }
645}
646
647/*!
648 \reimp
649*/
650QSize QSpacerItem::sizeHint() const
651{
652 return QSize(width, height);
653}
654
655/*!
656 \reimp
657*/
658QSize QWidgetItem::sizeHint() const
659{
660 QSize s(0, 0);
661 if (!isEmpty()) {
662 s = wid->sizeHint().expandedTo(otherSize: wid->minimumSizeHint());
663 s = s.boundedTo(otherSize: wid->maximumSize())
664 .expandedTo(otherSize: wid->minimumSize());
665 s = !wid->testAttribute(attribute: Qt::WA_LayoutUsesWidgetRect)
666 ? toLayoutItemSize(priv: wid->d_func(), size: s)
667 : s;
668
669 if (wid->sizePolicy().horizontalPolicy() == QSizePolicy::Ignored)
670 s.setWidth(0);
671 if (wid->sizePolicy().verticalPolicy() == QSizePolicy::Ignored)
672 s.setHeight(0);
673 }
674 return s;
675}
676
677/*!
678 Returns \c true.
679*/
680bool QSpacerItem::isEmpty() const
681{
682 return true;
683}
684
685/*!
686 Returns \c true if the widget is hidden; otherwise returns \c false.
687
688 \sa QWidget::isHidden()
689*/
690bool QWidgetItem::isEmpty() const
691{
692 return (wid->isHidden() && !wid->sizePolicy().retainSizeWhenHidden()) || wid->isWindow();
693}
694
695/*!
696 Returns the control type associated with the widget for which
697 this size policy applies.
698
699 \sa QSizePolicy::controlType()
700 */
701QSizePolicy::ControlTypes QWidgetItem::controlTypes() const
702{
703 return wid->sizePolicy().controlType();
704}
705
706/*!
707 \class QWidgetItemV2
708 \internal
709*/
710
711inline bool QWidgetItemV2::useSizeCache() const
712{
713 return wid->d_func()->widgetItem == this;
714}
715
716void QWidgetItemV2::updateCacheIfNecessary() const
717{
718 if (q_cachedMinimumSize.width() != Dirty)
719 return;
720
721 const QSize sizeHint(wid->sizeHint());
722 const QSize minimumSizeHint(wid->minimumSizeHint());
723 const QSize minimumSize(wid->minimumSize());
724 const QSize maximumSize(wid->maximumSize());
725 const QSizePolicy sizePolicy(wid->sizePolicy());
726 const QSize expandedSizeHint(sizeHint.expandedTo(otherSize: minimumSizeHint));
727
728 const QSize smartMinSize(qSmartMinSize(sizeHint, minSizeHint: minimumSizeHint, minSize: minimumSize, maxSize: maximumSize, sizePolicy));
729 const QSize smartMaxSize(qSmartMaxSize(sizeHint: expandedSizeHint, minSize: minimumSize, maxSize: maximumSize, sizePolicy, align));
730
731 const bool useLayoutItemRect = !wid->testAttribute(attribute: Qt::WA_LayoutUsesWidgetRect);
732
733 q_cachedMinimumSize = useLayoutItemRect
734 ? toLayoutItemSize(priv: wid->d_func(), size: smartMinSize)
735 : smartMinSize;
736
737 q_cachedSizeHint = expandedSizeHint;
738 q_cachedSizeHint = q_cachedSizeHint.boundedTo(otherSize: maximumSize)
739 .expandedTo(otherSize: minimumSize);
740 q_cachedSizeHint = useLayoutItemRect
741 ? toLayoutItemSize(priv: wid->d_func(), size: q_cachedSizeHint)
742 : q_cachedSizeHint;
743
744 if (wid->sizePolicy().horizontalPolicy() == QSizePolicy::Ignored)
745 q_cachedSizeHint.setWidth(0);
746 if (wid->sizePolicy().verticalPolicy() == QSizePolicy::Ignored)
747 q_cachedSizeHint.setHeight(0);
748
749 q_cachedMaximumSize = useLayoutItemRect
750 ? toLayoutItemSize(priv: wid->d_func(), size: smartMaxSize)
751 : smartMaxSize;
752}
753
754QWidgetItemV2::QWidgetItemV2(QWidget *widget)
755 : QWidgetItem(widget),
756 q_cachedMinimumSize(Dirty, Dirty),
757 q_cachedSizeHint(Dirty, Dirty),
758 q_cachedMaximumSize(Dirty, Dirty),
759 q_firstCachedHfw(0),
760 q_hfwCacheSize(0),
761 d(nullptr)
762{
763 QWidgetPrivate *wd = wid->d_func();
764 if (!wd->widgetItem)
765 wd->widgetItem = this;
766}
767
768QWidgetItemV2::~QWidgetItemV2()
769{
770 if (wid) {
771 auto *wd = static_cast<QWidgetPrivate *>(QObjectPrivate::get(o: wid));
772 if (wd->widgetItem == this)
773 wd->widgetItem = nullptr;
774 }
775}
776
777QSize QWidgetItemV2::sizeHint() const
778{
779 if (isEmpty())
780 return QSize(0, 0);
781
782 if (useSizeCache()) {
783 updateCacheIfNecessary();
784 return q_cachedSizeHint;
785 } else {
786 return QWidgetItem::sizeHint();
787 }
788}
789
790QSize QWidgetItemV2::minimumSize() const
791{
792 if (isEmpty())
793 return QSize(0, 0);
794
795 if (useSizeCache()) {
796 updateCacheIfNecessary();
797 return q_cachedMinimumSize;
798 } else {
799 return QWidgetItem::minimumSize();
800 }
801}
802
803QSize QWidgetItemV2::maximumSize() const
804{
805 if (isEmpty())
806 return QSize(0, 0);
807
808 if (useSizeCache()) {
809 updateCacheIfNecessary();
810 return q_cachedMaximumSize;
811 } else {
812 return QWidgetItem::maximumSize();
813 }
814}
815
816/*
817 The height-for-width cache is organized as a circular buffer. The entries
818
819 q_hfwCachedHfws[q_firstCachedHfw],
820 ...,
821 q_hfwCachedHfws[(q_firstCachedHfw + q_hfwCacheSize - 1) % HfwCacheMaxSize]
822
823 contain the last cached values. When the cache is full, the first entry to
824 be erased is the entry before q_hfwCachedHfws[q_firstCachedHfw]. When
825 values are looked up, we try to move q_firstCachedHfw to point to that new
826 entry (unless the cache is not full, in which case it would leave the cache
827 in a broken state), so that the most recently used entry is also the last
828 to be erased.
829*/
830
831int QWidgetItemV2::heightForWidth(int width) const
832{
833 if (isEmpty())
834 return -1;
835
836 for (int i = 0; i < q_hfwCacheSize; ++i) {
837 int offset = q_firstCachedHfw + i;
838 const QSize &size = q_cachedHfws[offset % HfwCacheMaxSize];
839 if (size.width() == width) {
840 if (q_hfwCacheSize == HfwCacheMaxSize)
841 q_firstCachedHfw = offset % HfwCacheMaxSize;
842 return size.height();
843 }
844 }
845
846 if (q_hfwCacheSize < HfwCacheMaxSize)
847 ++q_hfwCacheSize;
848 q_firstCachedHfw = (q_firstCachedHfw + HfwCacheMaxSize - 1) % HfwCacheMaxSize;
849
850 int height = QWidgetItem::heightForWidth(w: width);
851 q_cachedHfws[q_firstCachedHfw] = QSize(width, height);
852 return height;
853}
854
855QT_END_NAMESPACE
856

source code of qtbase/src/widgets/kernel/qlayoutitem.cpp