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(priv->leftLayoutItemMargin, priv->topLayoutItemMargin,
60 -priv->rightLayoutItemMargin, -priv->bottomLayoutItemMargin);
61}
62
63inline static QSize fromLayoutItemSize(QWidgetPrivate *priv, const QSize &size)
64{
65 return fromLayoutItemRect(priv, QRect(QPoint(0, 0), size)).size();
66}
67
68inline static QRect toLayoutItemRect(QWidgetPrivate *priv, const QRect &rect)
69{
70 return rect.adjusted(-priv->leftLayoutItemMargin, -priv->topLayoutItemMargin,
71 priv->rightLayoutItemMargin, priv->bottomLayoutItemMargin);
72}
73
74inline static QSize toLayoutItemSize(QWidgetPrivate *priv, const QSize &size)
75{
76 return toLayoutItemRect(priv, 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*/
363QWidget *QLayoutItem::widget() const
364{
365 return nullptr;
366}
367
368/*!
369 Returns the widget managed by this item.
370*/
371QWidget *QWidgetItem::widget() const
372{
373 return wid;
374}
375
376/*!
377 Returns \c true if this layout's preferred height depends on its
378 width; otherwise returns \c false. The default implementation returns
379 false.
380
381 Reimplement this function in layout managers that support height
382 for width.
383
384 \sa heightForWidth(), QWidget::heightForWidth()
385*/
386bool QLayoutItem::hasHeightForWidth() const
387{
388 return false;
389}
390
391/*!
392 Returns the minimum height this widget needs for the given width,
393 \a w. The default implementation simply returns heightForWidth(\a
394 w).
395*/
396int QLayoutItem::minimumHeightForWidth(int w) const
397{
398 return heightForWidth(w);
399}
400
401
402/*!
403 Returns the preferred height for this layout item, given the
404 width, which is not used in this default implementation.
405
406 The default implementation returns -1, indicating that the
407 preferred height is independent of the width of the item. Using
408 the function hasHeightForWidth() will typically be much faster
409 than calling this function and testing for -1.
410
411 Reimplement this function in layout managers that support height
412 for width. A typical implementation will look like this:
413 \snippet code/src_gui_kernel_qlayoutitem.cpp 0
414
415 Caching is strongly recommended; without it layout will take
416 exponential time.
417
418 \sa hasHeightForWidth()
419*/
420int QLayoutItem::heightForWidth(int /* w */) const
421{
422 return -1;
423}
424
425/*!
426 Returns the control type(s) for the layout item. For a
427 QWidgetItem, the control type comes from the widget's size
428 policy; for a QLayoutItem, the control types is derived from the
429 layout's contents.
430
431 \sa QSizePolicy::controlType()
432*/
433QSizePolicy::ControlTypes QLayoutItem::controlTypes() const
434{
435 return QSizePolicy::DefaultType;
436}
437
438/*!
439 \reimp
440*/
441void QSpacerItem::setGeometry(const QRect &r)
442{
443 rect = r;
444}
445
446/*!
447 \reimp
448*/
449void QWidgetItem::setGeometry(const QRect &rect)
450{
451 if (isEmpty())
452 return;
453
454 QRect r = !wid->testAttribute(Qt::WA_LayoutUsesWidgetRect)
455 ? fromLayoutItemRect(wid->d_func(), rect)
456 : rect;
457 const QSize widgetRectSurplus = r.size() - rect.size();
458
459 /*
460 For historical reasons, this code is done using widget rect
461 coordinates, not layout item rect coordinates. However,
462 QWidgetItem's sizeHint(), maximumSize(), and heightForWidth()
463 all work in terms of layout item rect coordinates, so we have to
464 add or subtract widgetRectSurplus here and there. The code could
465 be much simpler if we did everything using layout item rect
466 coordinates and did the conversion right before the call to
467 QWidget::setGeometry().
468 */
469
470 QSize s = r.size().boundedTo(maximumSize() + widgetRectSurplus);
471 int x = r.x();
472 int y = r.y();
473 if (align & (Qt::AlignHorizontal_Mask | Qt::AlignVertical_Mask)) {
474 QSize pref(sizeHint());
475 QSizePolicy sp = wid->sizePolicy();
476 if (sp.horizontalPolicy() == QSizePolicy::Ignored)
477 pref.setWidth(wid->sizeHint().expandedTo(wid->minimumSize()).width());
478 if (sp.verticalPolicy() == QSizePolicy::Ignored)
479 pref.setHeight(wid->sizeHint().expandedTo(wid->minimumSize()).height());
480 pref += widgetRectSurplus;
481 if (align & Qt::AlignHorizontal_Mask)
482 s.setWidth(qMin(s.width(), pref.width()));
483 if (align & Qt::AlignVertical_Mask) {
484 if (hasHeightForWidth())
485 s.setHeight(qMin(s.height(),
486 heightForWidth(s.width() - widgetRectSurplus.width())
487 + widgetRectSurplus.height()));
488 else
489 s.setHeight(qMin(s.height(), pref.height()));
490 }
491 }
492 Qt::Alignment alignHoriz = QStyle::visualAlignment(wid->layoutDirection(), align);
493 if (alignHoriz & Qt::AlignRight)
494 x = x + (r.width() - s.width());
495 else if (!(alignHoriz & Qt::AlignLeft))
496 x = x + (r.width() - s.width()) / 2;
497
498 if (align & Qt::AlignBottom)
499 y = y + (r.height() - s.height());
500 else if (!(align & Qt::AlignTop))
501 y = y + (r.height() - s.height()) / 2;
502
503 // Make sure we don't move outside of the parent, e.g when styles demand
504 // surplus space that exceeds the available margins (f.ex macOS with QGroupBox)
505 if (x < 0) {
506 s.rwidth() += x;
507 x = 0;
508 }
509 if (y < 0) {
510 s.rheight() += y;
511 y = 0;
512 }
513
514 wid->setGeometry(x, y, s.width(), s.height());
515}
516
517/*!
518 \reimp
519*/
520QRect QSpacerItem::geometry() const
521{
522 return rect;
523}
524
525/*!
526 \reimp
527*/
528QRect QWidgetItem::geometry() const
529{
530 return !wid->testAttribute(Qt::WA_LayoutUsesWidgetRect)
531 ? toLayoutItemRect(wid->d_func(), wid->geometry())
532 : wid->geometry();
533}
534
535
536/*!
537 \reimp
538*/
539bool QWidgetItem::hasHeightForWidth() const
540{
541 if (isEmpty())
542 return false;
543 return wid->hasHeightForWidth();
544}
545
546/*!
547 \reimp
548*/
549int QWidgetItem::heightForWidth(int w) const
550{
551 if (isEmpty())
552 return -1;
553
554 w = !wid->testAttribute(Qt::WA_LayoutUsesWidgetRect)
555 ? fromLayoutItemSize(wid->d_func(), QSize(w, 0)).width()
556 : w;
557
558 int hfw;
559 if (wid->layout())
560 hfw = wid->layout()->totalHeightForWidth(w);
561 else
562 hfw = wid->heightForWidth(w);
563
564 if (hfw > wid->maximumHeight())
565 hfw = wid->maximumHeight();
566 if (hfw < wid->minimumHeight())
567 hfw = wid->minimumHeight();
568
569 hfw = !wid->testAttribute(Qt::WA_LayoutUsesWidgetRect)
570 ? toLayoutItemSize(wid->d_func(), QSize(0, hfw)).height()
571 : hfw;
572
573 if (hfw < 0)
574 hfw = 0;
575 return hfw;
576}
577
578/*!
579 \reimp
580*/
581Qt::Orientations QSpacerItem::expandingDirections() const
582{
583 return sizeP.expandingDirections();
584}
585
586/*!
587 \reimp
588*/
589Qt::Orientations QWidgetItem::expandingDirections() const
590{
591 if (isEmpty())
592 return {};
593
594 Qt::Orientations e = wid->sizePolicy().expandingDirections();
595 /*
596 If the layout is expanding, we make the widget expanding, even if
597 its own size policy isn't expanding.
598 */
599 if (wid->layout()) {
600 if (wid->sizePolicy().horizontalPolicy() & QSizePolicy::GrowFlag
601 && (wid->layout()->expandingDirections() & Qt::Horizontal))
602 e |= Qt::Horizontal;
603 if (wid->sizePolicy().verticalPolicy() & QSizePolicy::GrowFlag
604 && (wid->layout()->expandingDirections() & Qt::Vertical))
605 e |= Qt::Vertical;
606 }
607
608 if (align & Qt::AlignHorizontal_Mask)
609 e &= ~Qt::Horizontal;
610 if (align & Qt::AlignVertical_Mask)
611 e &= ~Qt::Vertical;
612 return e;
613}
614
615/*!
616 \reimp
617*/
618QSize QSpacerItem::minimumSize() const
619{
620 return QSize(sizeP.horizontalPolicy() & QSizePolicy::ShrinkFlag ? 0 : width,
621 sizeP.verticalPolicy() & QSizePolicy::ShrinkFlag ? 0 : height);
622}
623
624/*!
625 \reimp
626*/
627QSize QWidgetItem::minimumSize() const
628{
629 if (isEmpty())
630 return QSize(0, 0);
631 return !wid->testAttribute(Qt::WA_LayoutUsesWidgetRect)
632 ? toLayoutItemSize(wid->d_func(), qSmartMinSize(this))
633 : qSmartMinSize(this);
634}
635
636/*!
637 \reimp
638*/
639QSize QSpacerItem::maximumSize() const
640{
641 return QSize(sizeP.horizontalPolicy() & QSizePolicy::GrowFlag ? QLAYOUTSIZE_MAX : width,
642 sizeP.verticalPolicy() & QSizePolicy::GrowFlag ? QLAYOUTSIZE_MAX : height);
643}
644
645/*!
646 \reimp
647*/
648QSize QWidgetItem::maximumSize() const
649{
650 if (isEmpty()) {
651 return QSize(0, 0);
652 } else {
653 return !wid->testAttribute(Qt::WA_LayoutUsesWidgetRect)
654 ? toLayoutItemSize(wid->d_func(), qSmartMaxSize(this, align))
655 : qSmartMaxSize(this, align);
656 }
657}
658
659/*!
660 \reimp
661*/
662QSize QSpacerItem::sizeHint() const
663{
664 return QSize(width, height);
665}
666
667/*!
668 \reimp
669*/
670QSize QWidgetItem::sizeHint() const
671{
672 QSize s(0, 0);
673 if (!isEmpty()) {
674 s = wid->sizeHint().expandedTo(wid->minimumSizeHint());
675 s = s.boundedTo(wid->maximumSize())
676 .expandedTo(wid->minimumSize());
677 s = !wid->testAttribute(Qt::WA_LayoutUsesWidgetRect)
678 ? toLayoutItemSize(wid->d_func(), s)
679 : s;
680
681 if (wid->sizePolicy().horizontalPolicy() == QSizePolicy::Ignored)
682 s.setWidth(0);
683 if (wid->sizePolicy().verticalPolicy() == QSizePolicy::Ignored)
684 s.setHeight(0);
685 }
686 return s;
687}
688
689/*!
690 Returns \c true.
691*/
692bool QSpacerItem::isEmpty() const
693{
694 return true;
695}
696
697/*!
698 Returns \c true if the widget is hidden; otherwise returns \c false.
699
700 \sa QWidget::isHidden()
701*/
702bool QWidgetItem::isEmpty() const
703{
704 return (wid->isHidden() && !wid->sizePolicy().retainSizeWhenHidden()) || wid->isWindow();
705}
706
707/*!
708 Returns the control type associated with the widget for which
709 this size policy applies.
710
711 \sa QSizePolicy::controlType()
712 */
713QSizePolicy::ControlTypes QWidgetItem::controlTypes() const
714{
715 return wid->sizePolicy().controlType();
716}
717
718/*!
719 \class QWidgetItemV2
720 \internal
721*/
722
723inline bool QWidgetItemV2::useSizeCache() const
724{
725 return wid->d_func()->widgetItem == this;
726}
727
728void QWidgetItemV2::updateCacheIfNecessary() const
729{
730 if (q_cachedMinimumSize.width() != Dirty)
731 return;
732
733 const QSize sizeHint(wid->sizeHint());
734 const QSize minimumSizeHint(wid->minimumSizeHint());
735 const QSize minimumSize(wid->minimumSize());
736 const QSize maximumSize(wid->maximumSize());
737 const QSizePolicy sizePolicy(wid->sizePolicy());
738 const QSize expandedSizeHint(sizeHint.expandedTo(minimumSizeHint));
739
740 const QSize smartMinSize(qSmartMinSize(sizeHint, minimumSizeHint, minimumSize, maximumSize, sizePolicy));
741 const QSize smartMaxSize(qSmartMaxSize(expandedSizeHint, minimumSize, maximumSize, sizePolicy, align));
742
743 const bool useLayoutItemRect = !wid->testAttribute(Qt::WA_LayoutUsesWidgetRect);
744
745 q_cachedMinimumSize = useLayoutItemRect
746 ? toLayoutItemSize(wid->d_func(), smartMinSize)
747 : smartMinSize;
748
749 q_cachedSizeHint = expandedSizeHint;
750 q_cachedSizeHint = q_cachedSizeHint.boundedTo(maximumSize)
751 .expandedTo(minimumSize);
752 q_cachedSizeHint = useLayoutItemRect
753 ? toLayoutItemSize(wid->d_func(), q_cachedSizeHint)
754 : q_cachedSizeHint;
755
756 if (wid->sizePolicy().horizontalPolicy() == QSizePolicy::Ignored)
757 q_cachedSizeHint.setWidth(0);
758 if (wid->sizePolicy().verticalPolicy() == QSizePolicy::Ignored)
759 q_cachedSizeHint.setHeight(0);
760
761 q_cachedMaximumSize = useLayoutItemRect
762 ? toLayoutItemSize(wid->d_func(), smartMaxSize)
763 : smartMaxSize;
764}
765
766QWidgetItemV2::QWidgetItemV2(QWidget *widget)
767 : QWidgetItem(widget),
768 q_cachedMinimumSize(Dirty, Dirty),
769 q_cachedSizeHint(Dirty, Dirty),
770 q_cachedMaximumSize(Dirty, Dirty),
771 q_firstCachedHfw(0),
772 q_hfwCacheSize(0),
773 d(nullptr)
774{
775 QWidgetPrivate *wd = wid->d_func();
776 if (!wd->widgetItem)
777 wd->widgetItem = this;
778}
779
780QWidgetItemV2::~QWidgetItemV2()
781{
782 if (wid) {
783 auto *wd = static_cast<QWidgetPrivate *>(QObjectPrivate::get(wid));
784 if (wd->widgetItem == this)
785 wd->widgetItem = nullptr;
786 }
787}
788
789QSize QWidgetItemV2::sizeHint() const
790{
791 if (isEmpty())
792 return QSize(0, 0);
793
794 if (useSizeCache()) {
795 updateCacheIfNecessary();
796 return q_cachedSizeHint;
797 } else {
798 return QWidgetItem::sizeHint();
799 }
800}
801
802QSize QWidgetItemV2::minimumSize() const
803{
804 if (isEmpty())
805 return QSize(0, 0);
806
807 if (useSizeCache()) {
808 updateCacheIfNecessary();
809 return q_cachedMinimumSize;
810 } else {
811 return QWidgetItem::minimumSize();
812 }
813}
814
815QSize QWidgetItemV2::maximumSize() const
816{
817 if (isEmpty())
818 return QSize(0, 0);
819
820 if (useSizeCache()) {
821 updateCacheIfNecessary();
822 return q_cachedMaximumSize;
823 } else {
824 return QWidgetItem::maximumSize();
825 }
826}
827
828/*
829 The height-for-width cache is organized as a circular buffer. The entries
830
831 q_hfwCachedHfws[q_firstCachedHfw],
832 ...,
833 q_hfwCachedHfws[(q_firstCachedHfw + q_hfwCacheSize - 1) % HfwCacheMaxSize]
834
835 contain the last cached values. When the cache is full, the first entry to
836 be erased is the entry before q_hfwCachedHfws[q_firstCachedHfw]. When
837 values are looked up, we try to move q_firstCachedHfw to point to that new
838 entry (unless the cache is not full, in which case it would leave the cache
839 in a broken state), so that the most recently used entry is also the last
840 to be erased.
841*/
842
843int QWidgetItemV2::heightForWidth(int width) const
844{
845 if (isEmpty())
846 return -1;
847
848 for (int i = 0; i < q_hfwCacheSize; ++i) {
849 int offset = q_firstCachedHfw + i;
850 const QSize &size = q_cachedHfws[offset % HfwCacheMaxSize];
851 if (size.width() == width) {
852 if (q_hfwCacheSize == HfwCacheMaxSize)
853 q_firstCachedHfw = offset % HfwCacheMaxSize;
854 return size.height();
855 }
856 }
857
858 if (q_hfwCacheSize < HfwCacheMaxSize)
859 ++q_hfwCacheSize;
860 q_firstCachedHfw = (q_firstCachedHfw + HfwCacheMaxSize - 1) % HfwCacheMaxSize;
861
862 int height = QWidgetItem::heightForWidth(width);
863 q_cachedHfws[q_firstCachedHfw] = QSize(width, height);
864 return height;
865}
866
867QT_END_NAMESPACE
868