/**************************************************************************** | |
** | |
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). | |
** All rights reserved. | |
** Contact: Nokia Corporation (qt-info@nokia.com) | |
** | |
** This file is part of the QtGui module of the Qt Toolkit. | |
** | |
** $QT_BEGIN_LICENSE:LGPL$ | |
** GNU Lesser General Public License Usage | |
** This file may be used under the terms of the GNU Lesser General Public | |
** License version 2.1 as published by the Free Software Foundation and | |
** appearing in the file LICENSE.LGPL included in the packaging of this | |
** file. Please review the following information to ensure the GNU Lesser | |
** General Public License version 2.1 requirements will be met: | |
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. | |
** | |
** In addition, as a special exception, Nokia gives you certain additional | |
** rights. These rights are described in the Nokia Qt LGPL Exception | |
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. | |
** | |
** GNU General Public License Usage | |
** Alternatively, this file may be used under the terms of the GNU General | |
** Public License version 3.0 as published by the Free Software Foundation | |
** and appearing in the file LICENSE.GPL included in the packaging of this | |
** file. Please review the following information to ensure the GNU General | |
** Public License version 3.0 requirements will be met: | |
** http://www.gnu.org/copyleft/gpl.html. | |
** | |
** Other Usage | |
** Alternatively, this file may be used in accordance with the terms and | |
** conditions contained in a signed written agreement between you and Nokia. | |
** | |
** | |
** | |
** | |
** | |
** $QT_END_LICENSE$ | |
** | |
****************************************************************************/ | |
#include "qlayout.h" | |
#include "qapplication.h" | |
#include "qlayoutengine_p.h" | |
#include "qmenubar.h" | |
#include "qtoolbar.h" | |
#include "qevent.h" | |
#include "qstyle.h" | |
#include "qvariant.h" | |
#include "qwidget_p.h" | |
QT_BEGIN_NAMESPACE | |
inline static QRect fromLayoutItemRect(QWidgetPrivate *priv, const QRect &rect) | |
{ | |
return rect.adjusted(priv->leftLayoutItemMargin, priv->topLayoutItemMargin, | |
-priv->rightLayoutItemMargin, -priv->bottomLayoutItemMargin); | |
} | |
inline static QSize fromLayoutItemSize(QWidgetPrivate *priv, const QSize &size) | |
{ | |
return fromLayoutItemRect(priv, QRect(QPoint(0, 0), size)).size(); | |
} | |
inline static QRect toLayoutItemRect(QWidgetPrivate *priv, const QRect &rect) | |
{ | |
return rect.adjusted(-priv->leftLayoutItemMargin, -priv->topLayoutItemMargin, | |
priv->rightLayoutItemMargin, priv->bottomLayoutItemMargin); | |
} | |
inline static QSize toLayoutItemSize(QWidgetPrivate *priv, const QSize &size) | |
{ | |
return toLayoutItemRect(priv, QRect(QPoint(0, 0), size)).size(); | |
} | |
/*! | |
Returns a QVariant storing this QSizePolicy. | |
*/ | |
QSizePolicy::operator QVariant() const | |
{ | |
return QVariant(QVariant::SizePolicy, this); | |
} | |
/*! | |
\class QLayoutItem | |
\brief The QLayoutItem class provides an abstract item that a | |
QLayout manipulates. | |
\ingroup geomanagement | |
This is used by custom layouts. | |
Pure virtual functions are provided to return information about | |
the layout, including, sizeHint(), minimumSize(), maximumSize() | |
and expanding(). | |
The layout's geometry can be set and retrieved with setGeometry() | |
and geometry(), and its alignment with setAlignment() and | |
alignment(). | |
isEmpty() returns whether the layout item is empty. If the | |
concrete item is a QWidget, it can be retrieved using widget(). | |
Similarly for layout() and spacerItem(). | |
Some layouts have width and height interdependencies. These can | |
be expressed using hasHeightForWidth(), heightForWidth(), and | |
minimumHeightForWidth(). For more explanation see the \e{Qt | |
Quarterly} article | |
\l{http://qt.nokia.com/doc/qq/qq04-height-for-width.html}{Trading | |
Height for Width}. | |
\sa QLayout | |
*/ | |
/*! | |
\class QSpacerItem | |
\ingroup geomanagement | |
\brief The QSpacerItem class provides blank space in a layout. | |
Normally, you don't need to use this class directly. Qt's | |
built-in layout managers provide the following functions for | |
manipulating empty space in layouts: | |
\table | |
\header \o Class | |
\o Functions | |
\row \o QHBoxLayout | |
\o \l{QBoxLayout::addSpacing()}{addSpacing()}, | |
\l{QBoxLayout::addStretch()}{addStretch()}, | |
\l{QBoxLayout::insertSpacing()}{insertSpacing()}, | |
\l{QBoxLayout::insertStretch()}{insertStretch()} | |
\row \o QGridLayout | |
\o \l{QGridLayout::setRowMinimumHeight()}{setRowMinimumHeight()}, | |
\l{QGridLayout::setRowStretch()}{setRowStretch()}, | |
\l{QGridLayout::setColumnMinimumWidth()}{setColumnMinimumWidth()}, | |
\l{QGridLayout::setColumnStretch()}{setColumnStretch()} | |
\endtable | |
\sa QLayout, QWidgetItem, QLayoutItem::spacerItem() | |
*/ | |
/*! | |
\class QWidgetItem | |
\ingroup geomanagement | |
\brief The QWidgetItem class is a layout item that represents a widget. | |
Normally, you don't need to use this class directly. Qt's | |
built-in layout managers provide the following functions for | |
manipulating widgets in layouts: | |
\table | |
\header \o Class | |
\o Functions | |
\row \o QBoxLayout | |
\o \l{QBoxLayout::addWidget()}{addWidget()}, | |
\l{QBoxLayout::insertWidget()}{insertWidget()}, | |
\l{QBoxLayout::setStretchFactor()}{setStretchFactor()} | |
\row \o QGridLayout | |
\o \l{QGridLayout::addWidget()}{addWidget()} | |
\row \o QStackedLayout | |
\o \l{QStackedLayout::addWidget()}{addWidget()}, | |
\l{QStackedLayout::insertWidget()}{insertWidget()}, | |
\l{QStackedLayout::currentWidget()}{currentWidget()}, | |
\l{QStackedLayout::setCurrentWidget()}{setCurrentWidget()}, | |
\l{QStackedLayout::widget()}{widget()} | |
\endtable | |
\sa QLayout, QSpacerItem, QLayoutItem::widget() | |
*/ | |
/*! | |
\fn QLayoutItem::QLayoutItem(Qt::Alignment alignment) | |
Constructs a layout item with an \a alignment. | |
Not all subclasses support alignment. | |
*/ | |
/*! | |
\fn Qt::Alignment QLayoutItem::alignment() const | |
Returns the alignment of this item. | |
*/ | |
/*! | |
Sets the alignment of this item to \a alignment. | |
\bold{Note:} Item alignment is only supported by QLayoutItem subclasses | |
where it would have a visual effect. Except for QSpacerItem, which provides | |
blank space for layouts, all public Qt classes that inherit QLayoutItem | |
support item alignment. | |
*/ | |
void QLayoutItem::setAlignment(Qt::Alignment alignment) | |
{ | |
align = alignment; | |
} | |
/*! | |
\fn QSize QLayoutItem::maximumSize() const | |
Implemented in subclasses to return the maximum size of this item. | |
*/ | |
/*! | |
\fn QSize QLayoutItem::minimumSize() const | |
Implemented in subclasses to return the minimum size of this item. | |
*/ | |
/*! | |
\fn QSize QLayoutItem::sizeHint() const | |
Implemented in subclasses to return the preferred size of this item. | |
*/ | |
/*! | |
\fn Qt::Orientations QLayoutItem::expandingDirections() const | |
Returns whether this layout item can make use of more space than | |
sizeHint(). A value of Qt::Vertical or Qt::Horizontal means that | |
it wants to grow in only one dimension, whereas Qt::Vertical | | |
Qt::Horizontal means that it wants to grow in both dimensions. | |
*/ | |
/*! | |
\fn void QLayoutItem::setGeometry(const QRect &r) | |
Implemented in subclasses to set this item's geometry to \a r. | |
\sa geometry() | |
*/ | |
/*! | |
\fn QRect QLayoutItem::geometry() const | |
Returns the rectangle covered by this layout item. | |
\sa setGeometry() | |
*/ | |
/*! | |
\fn virtual bool QLayoutItem::isEmpty() const | |
Implemented in subclasses to return whether this item is empty, | |
i.e. whether it contains any widgets. | |
*/ | |
/*! | |
\fn QSpacerItem::QSpacerItem(int w, int h, QSizePolicy::Policy hPolicy, QSizePolicy::Policy vPolicy) | |
Constructs a spacer item with preferred width \a w, preferred | |
height \a h, horizontal size policy \a hPolicy and vertical size | |
policy \a vPolicy. | |
The default values provide a gap that is able to stretch if | |
nothing else wants the space. | |
*/ | |
/*! | |
Changes this spacer item to have preferred width \a w, preferred | |
height \a h, horizontal size policy \a hPolicy and vertical size | |
policy \a vPolicy. | |
The default values provide a gap that is able to stretch if | |
nothing else wants the space. | |
Note that if changeSize() is called after the spacer item has been added | |
to a layout, it is necessary to invalidate the layout in order for the | |
spacer item's new size to take effect. | |
\sa QSpacerItem::invalidate() | |
*/ | |
void QSpacerItem::changeSize(int w, int h, QSizePolicy::Policy hPolicy, | |
QSizePolicy::Policy vPolicy) | |
{ | |
width = w; | |
height = h; | |
sizeP = QSizePolicy(hPolicy, vPolicy); | |
} | |
/*! | |
\fn QWidgetItem::QWidgetItem(QWidget *widget) | |
Creates an item containing the given \a widget. | |
*/ | |
/*! | |
Destroys the QLayoutItem. | |
*/ | |
QLayoutItem::~QLayoutItem() | |
{ | |
} | |
/*! | |
Invalidates any cached information in this layout item. | |
*/ | |
void QLayoutItem::invalidate() | |
{ | |
} | |
/*! | |
If this item is a QLayout, it is returned as a QLayout; otherwise | |
0 is returned. This function provides type-safe casting. | |
*/ | |
QLayout * QLayoutItem::layout() | |
{ | |
return 0; | |
} | |
/*! | |
If this item is a QSpacerItem, it is returned as a QSpacerItem; | |
otherwise 0 is returned. This function provides type-safe casting. | |
*/ | |
QSpacerItem * QLayoutItem::spacerItem() | |
{ | |
return 0; | |
} | |
/*! | |
\reimp | |
*/ | |
QLayout * QLayout::layout() | |
{ | |
return this; | |
} | |
/*! | |
Returns a pointer to this object. | |
*/ | |
QSpacerItem * QSpacerItem::spacerItem() | |
{ | |
return this; | |
} | |
/*! | |
If this item is a QWidget, it is returned as a QWidget; otherwise | |
0 is returned. This function provides type-safe casting. | |
*/ | |
QWidget * QLayoutItem::widget() | |
{ | |
return 0; | |
} | |
/*! | |
Returns the widget managed by this item. | |
*/ | |
QWidget *QWidgetItem::widget() | |
{ | |
return wid; | |
} | |
/*! | |
Returns true if this layout's preferred height depends on its | |
width; otherwise returns false. The default implementation returns | |
false. | |
Reimplement this function in layout managers that support height | |
for width. | |
\sa heightForWidth(), QWidget::heightForWidth() | |
*/ | |
bool QLayoutItem::hasHeightForWidth() const | |
{ | |
return false; | |
} | |
/*! | |
Returns the minimum height this widget needs for the given width, | |
\a w. The default implementation simply returns heightForWidth(\a | |
w). | |
*/ | |
int QLayoutItem::minimumHeightForWidth(int w) const | |
{ | |
return heightForWidth(w); | |
} | |
/*! | |
Returns the preferred height for this layout item, given the width | |
\a w. | |
The default implementation returns -1, indicating that the | |
preferred height is independent of the width of the item. Using | |
the function hasHeightForWidth() will typically be much faster | |
than calling this function and testing for -1. | |
Reimplement this function in layout managers that support height | |
for width. A typical implementation will look like this: | |
\snippet doc/src/snippets/code/src_gui_kernel_qlayoutitem.cpp 0 | |
Caching is strongly recommended; without it layout will take | |
exponential time. | |
\sa hasHeightForWidth() | |
*/ | |
int QLayoutItem::heightForWidth(int /* w */) const | |
{ | |
return -1; | |
} | |
/*! | |
Returns the control type(s) for the layout item. For a | |
QWidgetItem, the control type comes from the widget's size | |
policy; for a QLayoutItem, the control types is derived from the | |
layout's contents. | |
\sa QSizePolicy::controlType() | |
*/ | |
QSizePolicy::ControlTypes QLayoutItem::controlTypes() const | |
{ | |
// ### Qt 5: This function should probably be virtual instead | |
if (const QWidget *widget = const_cast<QLayoutItem*>(this)->widget()) { | |
return widget->sizePolicy().controlType(); | |
} else if (const QLayout *layout = const_cast<QLayoutItem*>(this)->layout()) { | |
if (layout->count() == 0) | |
return QSizePolicy::DefaultType; | |
QSizePolicy::ControlTypes types; | |
for (int i = layout->count() - 1; i >= 0; --i) | |
types |= layout->itemAt(i)->controlTypes(); | |
return types; | |
} | |
return QSizePolicy::DefaultType; | |
} | |
/*! | |
\reimp | |
*/ | |
void QSpacerItem::setGeometry(const QRect &r) | |
{ | |
rect = r; | |
} | |
/*! | |
\reimp | |
*/ | |
void QWidgetItem::setGeometry(const QRect &rect) | |
{ | |
if (isEmpty()) | |
return; | |
QRect r = !wid->testAttribute(Qt::WA_LayoutUsesWidgetRect) | |
? fromLayoutItemRect(wid->d_func(), rect) | |
: rect; | |
const QSize widgetRectSurplus = r.size() - rect.size(); | |
/* | |
For historical reasons, this code is done using widget rect | |
coordinates, not layout item rect coordinates. However, | |
QWidgetItem's sizeHint(), maximumSize(), and heightForWidth() | |
all work in terms of layout item rect coordinates, so we have to | |
add or subtract widgetRectSurplus here and there. The code could | |
be much simpler if we did everything using layout item rect | |
coordinates and did the conversion right before the call to | |
QWidget::setGeometry(). | |
*/ | |
QSize s = r.size().boundedTo(maximumSize() + widgetRectSurplus); | |
int x = r.x(); | |
int y = r.y(); | |
if (align & (Qt::AlignHorizontal_Mask | Qt::AlignVertical_Mask)) { | |
QSize pref(sizeHint()); | |
QSizePolicy sp = wid->sizePolicy(); | |
if (sp.horizontalPolicy() == QSizePolicy::Ignored) | |
pref.setWidth(wid->sizeHint().expandedTo(wid->minimumSize()).width()); | |
if (sp.verticalPolicy() == QSizePolicy::Ignored) | |
pref.setHeight(wid->sizeHint().expandedTo(wid->minimumSize()).height()); | |
pref += widgetRectSurplus; | |
if (align & Qt::AlignHorizontal_Mask) | |
s.setWidth(qMin(s.width(), pref.width())); | |
if (align & Qt::AlignVertical_Mask) { | |
if (hasHeightForWidth()) | |
s.setHeight(qMin(s.height(), | |
heightForWidth(s.width() - widgetRectSurplus.width()) | |
+ widgetRectSurplus.height())); | |
else | |
s.setHeight(qMin(s.height(), pref.height())); | |
} | |
} | |
Qt::Alignment alignHoriz = QStyle::visualAlignment(wid->layoutDirection(), align); | |
if (alignHoriz & Qt::AlignRight) | |
x = x + (r.width() - s.width()); | |
else if (!(alignHoriz & Qt::AlignLeft)) | |
x = x + (r.width() - s.width()) / 2; | |
if (align & Qt::AlignBottom) | |
y = y + (r.height() - s.height()); | |
else if (!(align & Qt::AlignTop)) | |
y = y + (r.height() - s.height()) / 2; | |
wid->setGeometry(x, y, s.width(), s.height()); | |
} | |
/*! | |
\reimp | |
*/ | |
QRect QSpacerItem::geometry() const | |
{ | |
return rect; | |
} | |
/*! | |
\reimp | |
*/ | |
QRect QWidgetItem::geometry() const | |
{ | |
return !wid->testAttribute(Qt::WA_LayoutUsesWidgetRect) | |
? toLayoutItemRect(wid->d_func(), wid->geometry()) | |
: wid->geometry(); | |
} | |
/*! | |
\reimp | |
*/ | |
bool QWidgetItem::hasHeightForWidth() const | |
{ | |
if (isEmpty()) | |
return false; | |
if (wid->layout()) | |
return wid->layout()->hasHeightForWidth(); | |
return wid->sizePolicy().hasHeightForWidth(); | |
} | |
/*! | |
\reimp | |
*/ | |
int QWidgetItem::heightForWidth(int w) const | |
{ | |
if (isEmpty()) | |
return -1; | |
w = !wid->testAttribute(Qt::WA_LayoutUsesWidgetRect) | |
? fromLayoutItemSize(wid->d_func(), QSize(w, 0)).width() | |
: w; | |
int hfw; | |
if (wid->layout()) | |
hfw = wid->layout()->totalHeightForWidth(w); | |
else | |
hfw = wid->heightForWidth(w); | |
if (hfw > wid->maximumHeight()) | |
hfw = wid->maximumHeight(); | |
if (hfw < wid->minimumHeight()) | |
hfw = wid->minimumHeight(); | |
hfw = !wid->testAttribute(Qt::WA_LayoutUsesWidgetRect) | |
? toLayoutItemSize(wid->d_func(), QSize(0, hfw)).height() | |
: hfw; | |
if (hfw < 0) | |
hfw = 0; | |
return hfw; | |
} | |
/*! | |
\reimp | |
*/ | |
Qt::Orientations QSpacerItem::expandingDirections() const | |
{ | |
return sizeP.expandingDirections(); | |
} | |
/*! | |
\reimp | |
*/ | |
Qt::Orientations QWidgetItem::expandingDirections() const | |
{ | |
if (isEmpty()) | |
return Qt::Orientations(0); | |
Qt::Orientations e = wid->sizePolicy().expandingDirections(); | |
/* | |
### Qt 4.0: | |
If the layout is expanding, we make the widget expanding, even if | |
its own size policy isn't expanding. This behavior should be | |
reconsidered. | |
*/ | |
if (wid->layout()) { | |
if (wid->sizePolicy().horizontalPolicy() & QSizePolicy::GrowFlag | |
&& (wid->layout()->expandingDirections() & Qt::Horizontal)) | |
e |= Qt::Horizontal; | |
if (wid->sizePolicy().verticalPolicy() & QSizePolicy::GrowFlag | |
&& (wid->layout()->expandingDirections() & Qt::Vertical)) | |
e |= Qt::Vertical; | |
} | |
if (align & Qt::AlignHorizontal_Mask) | |
e &= ~Qt::Horizontal; | |
if (align & Qt::AlignVertical_Mask) | |
e &= ~Qt::Vertical; | |
return e; | |
} | |
/*! | |
\reimp | |
*/ | |
QSize QSpacerItem::minimumSize() const | |
{ | |
return QSize(sizeP.horizontalPolicy() & QSizePolicy::ShrinkFlag ? 0 : width, | |
sizeP.verticalPolicy() & QSizePolicy::ShrinkFlag ? 0 : height); | |
} | |
/*! | |
\reimp | |
*/ | |
QSize QWidgetItem::minimumSize() const | |
{ | |
if (isEmpty()) | |
return QSize(0, 0); | |
return !wid->testAttribute(Qt::WA_LayoutUsesWidgetRect) | |
? toLayoutItemSize(wid->d_func(), qSmartMinSize(this)) | |
: qSmartMinSize(this); | |
} | |
/*! | |
\reimp | |
*/ | |
QSize QSpacerItem::maximumSize() const | |
{ | |
return QSize(sizeP.horizontalPolicy() & QSizePolicy::GrowFlag ? QLAYOUTSIZE_MAX : width, | |
sizeP.verticalPolicy() & QSizePolicy::GrowFlag ? QLAYOUTSIZE_MAX : height); | |
} | |
/*! | |
\reimp | |
*/ | |
QSize QWidgetItem::maximumSize() const | |
{ | |
if (isEmpty()) { | |
return QSize(0, 0); | |
} else { | |
return !wid->testAttribute(Qt::WA_LayoutUsesWidgetRect) | |
? toLayoutItemSize(wid->d_func(), qSmartMaxSize(this, align)) | |
: qSmartMaxSize(this, align); | |
} | |
} | |
/*! | |
\reimp | |
*/ | |
QSize QSpacerItem::sizeHint() const | |
{ | |
return QSize(width, height); | |
} | |
/*! | |
\reimp | |
*/ | |
QSize QWidgetItem::sizeHint() const | |
{ | |
QSize s(0, 0); | |
if (!isEmpty()) { | |
s = wid->sizeHint().expandedTo(wid->minimumSizeHint()); | |
s = s.boundedTo(wid->maximumSize()) | |
.expandedTo(wid->minimumSize()); | |
s = !wid->testAttribute(Qt::WA_LayoutUsesWidgetRect) | |
? toLayoutItemSize(wid->d_func(), s) | |
: s; | |
if (wid->sizePolicy().horizontalPolicy() == QSizePolicy::Ignored) | |
s.setWidth(0); | |
if (wid->sizePolicy().verticalPolicy() == QSizePolicy::Ignored) | |
s.setHeight(0); | |
} | |
return s; | |
} | |
/*! | |
Returns true. | |
*/ | |
bool QSpacerItem::isEmpty() const | |
{ | |
return true; | |
} | |
/*! | |
Returns true if the widget is hidden; otherwise returns false. | |
\sa QWidget::isHidden() | |
*/ | |
bool QWidgetItem::isEmpty() const | |
{ | |
return wid->isHidden() || wid->isWindow(); | |
} | |
/*! | |
\class QWidgetItemV2 | |
\internal | |
*/ | |
inline bool QWidgetItemV2::useSizeCache() const | |
{ | |
return wid->d_func()->widgetItem == this; | |
} | |
void QWidgetItemV2::updateCacheIfNecessary() const | |
{ | |
if (q_cachedMinimumSize.width() != Dirty) | |
return; | |
const QSize sizeHint(wid->sizeHint()); | |
const QSize minimumSizeHint(wid->minimumSizeHint()); | |
const QSize minimumSize(wid->minimumSize()); | |
const QSize maximumSize(wid->maximumSize()); | |
const QSizePolicy sizePolicy(wid->sizePolicy()); | |
const QSize expandedSizeHint(sizeHint.expandedTo(minimumSizeHint)); | |
const QSize smartMinSize(qSmartMinSize(sizeHint, minimumSizeHint, minimumSize, maximumSize, sizePolicy)); | |
const QSize smartMaxSize(qSmartMaxSize(expandedSizeHint, minimumSize, maximumSize, sizePolicy, align)); | |
const bool useLayoutItemRect = !wid->testAttribute(Qt::WA_LayoutUsesWidgetRect); | |
q_cachedMinimumSize = useLayoutItemRect | |
? toLayoutItemSize(wid->d_func(), smartMinSize) | |
: smartMinSize; | |
q_cachedSizeHint = expandedSizeHint; | |
q_cachedSizeHint = q_cachedSizeHint.boundedTo(maximumSize) | |
.expandedTo(minimumSize); | |
q_cachedSizeHint = useLayoutItemRect | |
? toLayoutItemSize(wid->d_func(), q_cachedSizeHint) | |
: q_cachedSizeHint; | |
if (wid->sizePolicy().horizontalPolicy() == QSizePolicy::Ignored) | |
q_cachedSizeHint.setWidth(0); | |
if (wid->sizePolicy().verticalPolicy() == QSizePolicy::Ignored) | |
q_cachedSizeHint.setHeight(0); | |
q_cachedMaximumSize = useLayoutItemRect | |
? toLayoutItemSize(wid->d_func(), smartMaxSize) | |
: smartMaxSize; | |
} | |
QWidgetItemV2::QWidgetItemV2(QWidget *widget) | |
: QWidgetItem(widget), | |
q_cachedMinimumSize(Dirty, Dirty), | |
q_cachedSizeHint(Dirty, Dirty), | |
q_cachedMaximumSize(Dirty, Dirty), | |
q_firstCachedHfw(0), | |
q_hfwCacheSize(0), | |
d(0) | |
{ | |
QWidgetPrivate *wd = wid->d_func(); | |
if (!wd->widgetItem) | |
wd->widgetItem = this; | |
} | |
QWidgetItemV2::~QWidgetItemV2() | |
{ | |
if (wid) { | |
QWidgetPrivate *wd = wid->d_func(); | |
if (wd->widgetItem == this) | |
wd->widgetItem = 0; | |
} | |
} | |
QSize QWidgetItemV2::sizeHint() const | |
{ | |
if (isEmpty()) | |
return QSize(0, 0); | |
if (useSizeCache()) { | |
updateCacheIfNecessary(); | |
return q_cachedSizeHint; | |
} else { | |
return QWidgetItem::sizeHint(); | |
} | |
} | |
QSize QWidgetItemV2::minimumSize() const | |
{ | |
if (isEmpty()) | |
return QSize(0, 0); | |
if (useSizeCache()) { | |
updateCacheIfNecessary(); | |
return q_cachedMinimumSize; | |
} else { | |
return QWidgetItem::minimumSize(); | |
} | |
} | |
QSize QWidgetItemV2::maximumSize() const | |
{ | |
if (isEmpty()) | |
return QSize(0, 0); | |
if (useSizeCache()) { | |
updateCacheIfNecessary(); | |
return q_cachedMaximumSize; | |
} else { | |
return QWidgetItem::maximumSize(); | |
} | |
} | |
/* | |
The height-for-width cache is organized as a circular buffer. The entries | |
q_hfwCachedHfws[q_firstCachedHfw], | |
..., | |
q_hfwCachedHfws[(q_firstCachedHfw + q_hfwCacheSize - 1) % HfwCacheMaxSize] | |
contain the last cached values. When the cache is full, the first entry to | |
be erased is the entry before q_hfwCachedHfws[q_firstCachedHfw]. When | |
values are looked up, we try to move q_firstCachedHfw to point to that new | |
entry (unless the cache is not full, in which case it would leave the cache | |
in a broken state), so that the most recently used entry is also the last | |
to be erased. | |
*/ | |
int QWidgetItemV2::heightForWidth(int width) const | |
{ | |
if (isEmpty()) | |
return -1; | |
for (int i = 0; i < q_hfwCacheSize; ++i) { | |
int offset = q_firstCachedHfw + i; | |
const QSize &size = q_cachedHfws[offset % HfwCacheMaxSize]; | |
if (size.width() == width) { | |
if (q_hfwCacheSize == HfwCacheMaxSize) | |
q_firstCachedHfw = offset; | |
return size.height(); | |
} | |
} | |
if (q_hfwCacheSize < HfwCacheMaxSize) | |
++q_hfwCacheSize; | |
q_firstCachedHfw = (q_firstCachedHfw + HfwCacheMaxSize - 1) % HfwCacheMaxSize; | |
int height = QWidgetItem::heightForWidth(width); | |
q_cachedHfws[q_firstCachedHfw] = QSize(width, height); | |
return height; | |
} | |
QT_END_NAMESPACE |