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

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