1
/****************************************************************************
3
** Copyright (C) 2016 The Qt Company Ltd.
4
** Contact: https://www.qt.io/licensing/
6
** This file is part of the QtWidgets module of the Qt Toolkit.
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.
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.
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.
38
****************************************************************************/
42
#include "qapplication.h"
43
#include "qlayoutengine_p.h"
49
#include "qwidget_p.h"
53
inline static QRect fromLayoutItemRect(QWidgetPrivate *priv, const QRect &rect)
55
return rect.adjusted(priv->leftLayoutItemMargin, priv->topLayoutItemMargin,
56
-priv->rightLayoutItemMargin, -priv->bottomLayoutItemMargin);
59
inline static QSize fromLayoutItemSize(QWidgetPrivate *priv, const QSize &size)
61
return fromLayoutItemRect(priv, QRect(QPoint(0, 0), size)).size();
64
inline static QRect toLayoutItemRect(QWidgetPrivate *priv, const QRect &rect)
66
return rect.adjusted(-priv->leftLayoutItemMargin, -priv->topLayoutItemMargin,
67
priv->rightLayoutItemMargin, priv->bottomLayoutItemMargin);
70
inline static QSize toLayoutItemSize(QWidgetPrivate *priv, const QSize &size)
72
return toLayoutItemRect(priv, QRect(QPoint(0, 0), size)).size();
77
\brief The QLayoutItem class provides an abstract item that a
80
\ingroup geomanagement
83
This is used by custom layouts.
85
Pure virtual functions are provided to return information about
86
the layout, including, sizeHint(), minimumSize(), maximumSize()
89
The layout's geometry can be set and retrieved with setGeometry()
90
and geometry(), and its alignment with setAlignment() and
93
isEmpty() returns whether the layout item is empty. If the
94
concrete item is a QWidget, it can be retrieved using widget().
95
Similarly for layout() and spacerItem().
97
Some layouts have width and height interdependencies. These can
98
be expressed using hasHeightForWidth(), heightForWidth(), and
99
minimumHeightForWidth(). For more explanation see the \e{Qt
101
\l{http://doc.qt.io/archives/qq/qq04-height-for-width.html}{Trading
109
\ingroup geomanagement
110
\brief The QSpacerItem class provides blank space in a layout.
114
Normally, you don't need to use this class directly. Qt's
115
built-in layout managers provide the following functions for
116
manipulating empty space in layouts:
122
\li \l{QBoxLayout::addSpacing()}{addSpacing()},
123
\l{QBoxLayout::addStretch()}{addStretch()},
124
\l{QBoxLayout::insertSpacing()}{insertSpacing()},
125
\l{QBoxLayout::insertStretch()}{insertStretch()}
127
\li \l{QGridLayout::setRowMinimumHeight()}{setRowMinimumHeight()},
128
\l{QGridLayout::setRowStretch()}{setRowStretch()},
129
\l{QGridLayout::setColumnMinimumWidth()}{setColumnMinimumWidth()},
130
\l{QGridLayout::setColumnStretch()}{setColumnStretch()}
133
\sa QLayout, QWidgetItem, QLayoutItem::spacerItem()
138
\ingroup geomanagement
139
\brief The QWidgetItem class is a layout item that represents a widget.
143
Normally, you don't need to use this class directly. Qt's
144
built-in layout managers provide the following functions for
145
manipulating widgets in layouts:
151
\li \l{QBoxLayout::addWidget()}{addWidget()},
152
\l{QBoxLayout::insertWidget()}{insertWidget()},
153
\l{QBoxLayout::setStretchFactor()}{setStretchFactor()}
155
\li \l{QGridLayout::addWidget()}{addWidget()}
156
\row \li QStackedLayout
157
\li \l{QStackedLayout::addWidget()}{addWidget()},
158
\l{QStackedLayout::insertWidget()}{insertWidget()},
159
\l{QStackedLayout::currentWidget()}{currentWidget()},
160
\l{QStackedLayout::setCurrentWidget()}{setCurrentWidget()},
161
\l{QStackedLayout::widget()}{widget()}
164
\sa QLayout, QSpacerItem, QLayoutItem::widget()
168
\fn QLayoutItem::QLayoutItem(Qt::Alignment alignment)
170
Constructs a layout item with an \a alignment.
171
Not all subclasses support alignment.
175
\fn Qt::Alignment QLayoutItem::alignment() const
177
Returns the alignment of this item.
181
Sets the alignment of this item to \a alignment.
183
\b{Note:} Item alignment is only supported by QLayoutItem subclasses
184
where it would have a visual effect. Except for QSpacerItem, which provides
185
blank space for layouts, all public Qt classes that inherit QLayoutItem
186
support item alignment.
188
void QLayoutItem::setAlignment(Qt::Alignment alignment)
194
\fn QSize QLayoutItem::maximumSize() const
196
Implemented in subclasses to return the maximum size of this item.
200
\fn QSize QLayoutItem::minimumSize() const
202
Implemented in subclasses to return the minimum size of this item.
206
\fn QSize QLayoutItem::sizeHint() const
208
Implemented in subclasses to return the preferred size of this item.
212
\fn Qt::Orientations QLayoutItem::expandingDirections() const
214
Returns whether this layout item can make use of more space than
215
sizeHint(). A value of Qt::Vertical or Qt::Horizontal means that
216
it wants to grow in only one dimension, whereas Qt::Vertical |
217
Qt::Horizontal means that it wants to grow in both dimensions.
221
\fn void QLayoutItem::setGeometry(const QRect &r)
223
Implemented in subclasses to set this item's geometry to \a r.
229
\fn QRect QLayoutItem::geometry() const
231
Returns the rectangle covered by this layout item.
237
\fn virtual bool QLayoutItem::isEmpty() const
239
Implemented in subclasses to return whether this item is empty,
240
i.e. whether it contains any widgets.
244
\fn QSpacerItem::QSpacerItem(int w, int h, QSizePolicy::Policy hPolicy, QSizePolicy::Policy vPolicy)
246
Constructs a spacer item with preferred width \a w, preferred
247
height \a h, horizontal size policy \a hPolicy and vertical size
250
The default values provide a gap that is able to stretch if
251
nothing else wants the space.
257
QSpacerItem::~QSpacerItem() {}
260
Changes this spacer item to have preferred width \a w, preferred
261
height \a h, horizontal size policy \a hPolicy and vertical size
264
The default values provide a gap that is able to stretch if
265
nothing else wants the space.
267
Note that if changeSize() is called after the spacer item has been added
268
to a layout, it is necessary to invalidate the layout in order for the
269
spacer item's new size to take effect.
271
\sa QSpacerItem::invalidate()
273
void QSpacerItem::changeSize(int w, int h, QSizePolicy::Policy hPolicy,
274
QSizePolicy::Policy vPolicy)
278
sizeP = QSizePolicy(hPolicy, vPolicy);
282
\fn QWidgetItem::QWidgetItem(QWidget *widget)
284
Creates an item containing the given \a widget.
290
QWidgetItem::~QWidgetItem() {}
293
Destroys the QLayoutItem.
295
QLayoutItem::~QLayoutItem()
300
Invalidates any cached information in this layout item.
302
void QLayoutItem::invalidate()
307
If this item is a QLayout, it is returned as a QLayout; otherwise
308
0 is returned. This function provides type-safe casting.
310
\sa spacerItem(), widget()
312
QLayout * QLayoutItem::layout()
318
If this item is a QSpacerItem, it is returned as a QSpacerItem;
319
otherwise 0 is returned. This function provides type-safe casting.
321
\sa layout(), widget()
323
QSpacerItem * QLayoutItem::spacerItem()
331
QLayout * QLayout::layout()
337
Returns a pointer to this object.
339
QSpacerItem * QSpacerItem::spacerItem()
345
\fn QSizePolicy QSpacerItem::sizePolicy() const
348
Returns the size policy of this item.
352
If this item manages a QWidget, returns that widget. Otherwise,
353
\c nullptr is returned.
355
\note While the functions layout() and spacerItem() perform casts, this
356
function returns another object: QLayout and QSpacerItem inherit QLayoutItem,
357
while QWidget does not.
359
\sa layout(), spacerItem()
361
QWidget * QLayoutItem::widget()
367
Returns the widget managed by this item.
369
QWidget *QWidgetItem::widget()
375
Returns \c true if this layout's preferred height depends on its
376
width; otherwise returns \c false. The default implementation returns
379
Reimplement this function in layout managers that support height
382
\sa heightForWidth(), QWidget::heightForWidth()
384
bool QLayoutItem::hasHeightForWidth() const
390
Returns the minimum height this widget needs for the given width,
391
\a w. The default implementation simply returns heightForWidth(\a
394
int QLayoutItem::minimumHeightForWidth(int w) const
396
return heightForWidth(w);
401
Returns the preferred height for this layout item, given the width
404
The default implementation returns -1, indicating that the
405
preferred height is independent of the width of the item. Using
406
the function hasHeightForWidth() will typically be much faster
407
than calling this function and testing for -1.
409
Reimplement this function in layout managers that support height
410
for width. A typical implementation will look like this:
411
\snippet code/src_gui_kernel_qlayoutitem.cpp 0
413
Caching is strongly recommended; without it layout will take
416
\sa hasHeightForWidth()
418
int QLayoutItem::heightForWidth(int /* w */) const
424
Returns the control type(s) for the layout item. For a
425
QWidgetItem, the control type comes from the widget's size
426
policy; for a QLayoutItem, the control types is derived from the
429
\sa QSizePolicy::controlType()
431
QSizePolicy::ControlTypes QLayoutItem::controlTypes() const
433
return QSizePolicy::DefaultType;
439
void QSpacerItem::setGeometry(const QRect &r)
447
void QWidgetItem::setGeometry(const QRect &rect)
452
QRect r = !wid->testAttribute(Qt::WA_LayoutUsesWidgetRect)
453
? fromLayoutItemRect(wid->d_func(), rect)
455
const QSize widgetRectSurplus = r.size() - rect.size();
458
For historical reasons, this code is done using widget rect
459
coordinates, not layout item rect coordinates. However,
460
QWidgetItem's sizeHint(), maximumSize(), and heightForWidth()
461
all work in terms of layout item rect coordinates, so we have to
462
add or subtract widgetRectSurplus here and there. The code could
463
be much simpler if we did everything using layout item rect
464
coordinates and did the conversion right before the call to
465
QWidget::setGeometry().
468
QSize s = r.size().boundedTo(maximumSize() + widgetRectSurplus);
471
if (align & (Qt::AlignHorizontal_Mask | Qt::AlignVertical_Mask)) {
472
QSize pref(sizeHint());
473
QSizePolicy sp = wid->sizePolicy();
474
if (sp.horizontalPolicy() == QSizePolicy::Ignored)
475
pref.setWidth(wid->sizeHint().expandedTo(wid->minimumSize()).width());
476
if (sp.verticalPolicy() == QSizePolicy::Ignored)
477
pref.setHeight(wid->sizeHint().expandedTo(wid->minimumSize()).height());
478
pref += widgetRectSurplus;
479
if (align & Qt::AlignHorizontal_Mask)
480
s.setWidth(qMin(s.width(), pref.width()));
481
if (align & Qt::AlignVertical_Mask) {
482
if (hasHeightForWidth())
483
s.setHeight(qMin(s.height(),
484
heightForWidth(s.width() - widgetRectSurplus.width())
485
+ widgetRectSurplus.height()));
487
s.setHeight(qMin(s.height(), pref.height()));
490
Qt::Alignment alignHoriz = QStyle::visualAlignment(wid->layoutDirection(), align);
491
if (alignHoriz & Qt::AlignRight)
492
x = x + (r.width() - s.width());
493
else if (!(alignHoriz & Qt::AlignLeft))
494
x = x + (r.width() - s.width()) / 2;
496
if (align & Qt::AlignBottom)
497
y = y + (r.height() - s.height());
498
else if (!(align & Qt::AlignTop))
499
y = y + (r.height() - s.height()) / 2;
501
wid->setGeometry(x, y, s.width(), s.height());
507
QRect QSpacerItem::geometry() const
515
QRect QWidgetItem::geometry() const
517
return !wid->testAttribute(Qt::WA_LayoutUsesWidgetRect)
518
? toLayoutItemRect(wid->d_func(), wid->geometry())
526
bool QWidgetItem::hasHeightForWidth() const
530
return wid->hasHeightForWidth();
536
int QWidgetItem::heightForWidth(int w) const
541
w = !wid->testAttribute(Qt::WA_LayoutUsesWidgetRect)
542
? fromLayoutItemSize(wid->d_func(), QSize(w, 0)).width()
547
hfw = wid->layout()->totalHeightForWidth(w);
549
hfw = wid->heightForWidth(w);
551
if (hfw > wid->maximumHeight())
552
hfw = wid->maximumHeight();
553
if (hfw < wid->minimumHeight())
554
hfw = wid->minimumHeight();
556
hfw = !wid->testAttribute(Qt::WA_LayoutUsesWidgetRect)
557
? toLayoutItemSize(wid->d_func(), QSize(0, hfw)).height()
568
Qt::Orientations QSpacerItem::expandingDirections() const
570
return sizeP.expandingDirections();
576
Qt::Orientations QWidgetItem::expandingDirections() const
579
return Qt::Orientations(0);
581
Qt::Orientations e = wid->sizePolicy().expandingDirections();
583
If the layout is expanding, we make the widget expanding, even if
584
its own size policy isn't expanding.
587
if (wid->sizePolicy().horizontalPolicy() & QSizePolicy::GrowFlag
588
&& (wid->layout()->expandingDirections() & Qt::Horizontal))
590
if (wid->sizePolicy().verticalPolicy() & QSizePolicy::GrowFlag
591
&& (wid->layout()->expandingDirections() & Qt::Vertical))
595
if (align & Qt::AlignHorizontal_Mask)
596
e &= ~Qt::Horizontal;
597
if (align & Qt::AlignVertical_Mask)
605
QSize QSpacerItem::minimumSize() const
607
return QSize(sizeP.horizontalPolicy() & QSizePolicy::ShrinkFlag ? 0 : width,
608
sizeP.verticalPolicy() & QSizePolicy::ShrinkFlag ? 0 : height);
614
QSize QWidgetItem::minimumSize() const
618
return !wid->testAttribute(Qt::WA_LayoutUsesWidgetRect)
619
? toLayoutItemSize(wid->d_func(), qSmartMinSize(this))
620
: qSmartMinSize(this);
626
QSize QSpacerItem::maximumSize() const
628
return QSize(sizeP.horizontalPolicy() & QSizePolicy::GrowFlag ? QLAYOUTSIZE_MAX : width,
629
sizeP.verticalPolicy() & QSizePolicy::GrowFlag ? QLAYOUTSIZE_MAX : height);
635
QSize QWidgetItem::maximumSize() const
640
return !wid->testAttribute(Qt::WA_LayoutUsesWidgetRect)
641
? toLayoutItemSize(wid->d_func(), qSmartMaxSize(this, align))
642
: qSmartMaxSize(this, align);
649
QSize QSpacerItem::sizeHint() const
651
return QSize(width, height);
657
QSize QWidgetItem::sizeHint() const
661
s = wid->sizeHint().expandedTo(wid->minimumSizeHint());
662
s = s.boundedTo(wid->maximumSize())
663
.expandedTo(wid->minimumSize());
664
s = !wid->testAttribute(Qt::WA_LayoutUsesWidgetRect)
665
? toLayoutItemSize(wid->d_func(), s)
668
if (wid->sizePolicy().horizontalPolicy() == QSizePolicy::Ignored)
670
if (wid->sizePolicy().verticalPolicy() == QSizePolicy::Ignored)
679
bool QSpacerItem::isEmpty() const
685
Returns \c true if the widget is hidden; otherwise returns \c false.
687
\sa QWidget::isHidden()
689
bool QWidgetItem::isEmpty() const
691
return (wid->isHidden() && !wid->sizePolicy().retainSizeWhenHidden()) || wid->isWindow();
695
Returns the control type associated with the widget for which
696
this size policy applies.
698
\sa QSizePolicy::controlType()
700
QSizePolicy::ControlTypes QWidgetItem::controlTypes() const
702
return wid->sizePolicy().controlType();
710
inline bool QWidgetItemV2::useSizeCache() const
712
return wid->d_func()->widgetItem == this;
715
void QWidgetItemV2::updateCacheIfNecessary() const
717
if (q_cachedMinimumSize.width() != Dirty)
720
const QSize sizeHint(wid->sizeHint());
721
const QSize minimumSizeHint(wid->minimumSizeHint());
722
const QSize minimumSize(wid->minimumSize());
723
const QSize maximumSize(wid->maximumSize());
724
const QSizePolicy sizePolicy(wid->sizePolicy());
725
const QSize expandedSizeHint(sizeHint.expandedTo(minimumSizeHint));
727
const QSize smartMinSize(qSmartMinSize(sizeHint, minimumSizeHint, minimumSize, maximumSize, sizePolicy));
728
const QSize smartMaxSize(qSmartMaxSize(expandedSizeHint, minimumSize, maximumSize, sizePolicy, align));
730
const bool useLayoutItemRect = !wid->testAttribute(Qt::WA_LayoutUsesWidgetRect);
732
q_cachedMinimumSize = useLayoutItemRect
733
? toLayoutItemSize(wid->d_func(), smartMinSize)
736
q_cachedSizeHint = expandedSizeHint;
737
q_cachedSizeHint = q_cachedSizeHint.boundedTo(maximumSize)
738
.expandedTo(minimumSize);
739
q_cachedSizeHint = useLayoutItemRect
740
? toLayoutItemSize(wid->d_func(), q_cachedSizeHint)
743
if (wid->sizePolicy().horizontalPolicy() == QSizePolicy::Ignored)
744
q_cachedSizeHint.setWidth(0);
745
if (wid->sizePolicy().verticalPolicy() == QSizePolicy::Ignored)
746
q_cachedSizeHint.setHeight(0);
748
q_cachedMaximumSize = useLayoutItemRect
749
? toLayoutItemSize(wid->d_func(), smartMaxSize)
753
QWidgetItemV2::QWidgetItemV2(QWidget *widget)
754
: QWidgetItem(widget),
755
q_cachedMinimumSize(Dirty, Dirty),
756
q_cachedSizeHint(Dirty, Dirty),
757
q_cachedMaximumSize(Dirty, Dirty),
762
QWidgetPrivate *wd = wid->d_func();
764
wd->widgetItem = this;
767
QWidgetItemV2::~QWidgetItemV2()
770
QWidgetPrivate *wd = wid->d_func();
771
if (wd->widgetItem == this)
776
QSize QWidgetItemV2::sizeHint() const
781
if (useSizeCache()) {
782
updateCacheIfNecessary();
783
return q_cachedSizeHint;
785
return QWidgetItem::sizeHint();
789
QSize QWidgetItemV2::minimumSize() const
794
if (useSizeCache()) {
795
updateCacheIfNecessary();
796
return q_cachedMinimumSize;
798
return QWidgetItem::minimumSize();
802
QSize QWidgetItemV2::maximumSize() const
807
if (useSizeCache()) {
808
updateCacheIfNecessary();
809
return q_cachedMaximumSize;
811
return QWidgetItem::maximumSize();
816
The height-for-width cache is organized as a circular buffer. The entries
818
q_hfwCachedHfws[q_firstCachedHfw],
820
q_hfwCachedHfws[(q_firstCachedHfw + q_hfwCacheSize - 1) % HfwCacheMaxSize]
822
contain the last cached values. When the cache is full, the first entry to
823
be erased is the entry before q_hfwCachedHfws[q_firstCachedHfw]. When
824
values are looked up, we try to move q_firstCachedHfw to point to that new
825
entry (unless the cache is not full, in which case it would leave the cache
826
in a broken state), so that the most recently used entry is also the last
830
int QWidgetItemV2::heightForWidth(int width) const
835
for (int i = 0; i < q_hfwCacheSize; ++i) {
836
int offset = q_firstCachedHfw + i;
837
const QSize &size = q_cachedHfws[offset % HfwCacheMaxSize];
838
if (size.width() == width) {
839
if (q_hfwCacheSize == HfwCacheMaxSize)
840
q_firstCachedHfw = offset;
841
return size.height();
845
if (q_hfwCacheSize < HfwCacheMaxSize)
847
q_firstCachedHfw = (q_firstCachedHfw + HfwCacheMaxSize - 1) % HfwCacheMaxSize;
849
int height = QWidgetItem::heightForWidth(width);
850
q_cachedHfws[q_firstCachedHfw] = QSize(width, height);