| /**************************************************************************** |
| ** |
| ** Copyright (C) 2016 The Qt Company Ltd. |
| ** Contact: https://www.qt.io/licensing/ |
| ** |
| ** This file is part of the QtWidgets module of the Qt Toolkit. |
| ** |
| ** $QT_BEGIN_LICENSE:LGPL$ |
| ** Commercial License Usage |
| ** Licensees holding valid commercial Qt licenses may use this file in |
| ** accordance with the commercial license agreement provided with the |
| ** Software or, alternatively, in accordance with the terms contained in |
| ** a written agreement between you and The Qt Company. For licensing terms |
| ** and conditions see https://www.qt.io/terms-conditions. For further |
| ** information use the contact form at https://www.qt.io/contact-us. |
| ** |
| ** GNU Lesser General Public License Usage |
| ** Alternatively, this file may be used under the terms of the GNU Lesser |
| ** General Public License version 3 as published by the Free Software |
| ** Foundation and appearing in the file LICENSE.LGPL3 included in the |
| ** packaging of this file. Please review the following information to |
| ** ensure the GNU Lesser General Public License version 3 requirements |
| ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. |
| ** |
| ** GNU General Public License Usage |
| ** Alternatively, this file may be used under the terms of the GNU |
| ** General Public License version 2.0 or (at your option) the GNU General |
| ** Public license version 3 or any later version approved by the KDE Free |
| ** Qt Foundation. The licenses are as published by the Free Software |
| ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 |
| ** included in the packaging of this file. Please review the following |
| ** information to ensure the GNU General Public License requirements will |
| ** be met: https://www.gnu.org/licenses/gpl-2.0.html and |
| ** https://www.gnu.org/licenses/gpl-3.0.html. |
| ** |
| ** $QT_END_LICENSE$ |
| ** |
| ****************************************************************************/ |
| |
| #include "qlayout.h" |
| |
| #include "qapplication.h" |
| #include "qlayoutengine_p.h" |
| #if QT_CONFIG(menubar) |
| #include "qmenubar.h" |
| #endif |
| #if QT_CONFIG(toolbar) |
| #include "qtoolbar.h" |
| #endif |
| #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(); |
| } |
| |
| /*! |
| \class QLayoutItem |
| \brief The QLayoutItem class provides an abstract item that a |
| QLayout manipulates. |
| |
| \ingroup geomanagement |
| \inmodule QtWidgets |
| |
| 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://doc.qt.io/archives/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. |
| |
| \inmodule QtWidgets |
| |
| 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 \li Class |
| \li Functions |
| \row \li QHBoxLayout |
| \li \l{QBoxLayout::addSpacing()}{addSpacing()}, |
| \l{QBoxLayout::addStretch()}{addStretch()}, |
| \l{QBoxLayout::insertSpacing()}{insertSpacing()}, |
| \l{QBoxLayout::insertStretch()}{insertStretch()} |
| \row \li QGridLayout |
| \li \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. |
| |
| \inmodule QtWidgets |
| |
| 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 \li Class |
| \li Functions |
| \row \li QBoxLayout |
| \li \l{QBoxLayout::addWidget()}{addWidget()}, |
| \l{QBoxLayout::insertWidget()}{insertWidget()}, |
| \l{QBoxLayout::setStretchFactor()}{setStretchFactor()} |
| \row \li QGridLayout |
| \li \l{QGridLayout::addWidget()}{addWidget()} |
| \row \li QStackedLayout |
| \li \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. |
| |
| \b{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. |
| */ |
| |
| /*! |
| Destructor. |
| */ |
| QSpacerItem::~QSpacerItem() {} |
| |
| /*! |
| 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. |
| */ |
| |
| /*! |
| Destructor. |
| */ |
| QWidgetItem::~QWidgetItem() = default; |
| |
| /*! |
| Destroys the QLayoutItem. |
| */ |
| QLayoutItem::~QLayoutItem() = default; |
| |
| /*! |
| Invalidates any cached information in this layout item. |
| */ |
| void QLayoutItem::invalidate() |
| { |
| } |
| |
| /*! |
| If this item is a QLayout, it is returned as a QLayout; otherwise |
| \nullptr is returned. This function provides type-safe casting. |
| |
| \sa spacerItem(), widget() |
| */ |
| QLayout *QLayoutItem::layout() |
| { |
| return nullptr; |
| } |
| |
| /*! |
| If this item is a QSpacerItem, it is returned as a QSpacerItem; |
| otherwise \nullptr is returned. This function provides type-safe casting. |
| |
| \sa layout(), widget() |
| */ |
| QSpacerItem *QLayoutItem::spacerItem() |
| { |
| return nullptr; |
| } |
| |
| /*! |
| \reimp |
| */ |
| QLayout * QLayout::layout() |
| { |
| return this; |
| } |
| |
| /*! |
| Returns a pointer to this object. |
| */ |
| QSpacerItem * QSpacerItem::spacerItem() |
| { |
| return this; |
| } |
| |
| /*! |
| \fn QSizePolicy QSpacerItem::sizePolicy() const |
| \since 5.5 |
| |
| Returns the size policy of this item. |
| */ |
| |
| /*! |
| If this item manages a QWidget, returns that widget. Otherwise, |
| \nullptr is returned. |
| |
| \note While the functions layout() and spacerItem() perform casts, this |
| function returns another object: QLayout and QSpacerItem inherit QLayoutItem, |
| while QWidget does not. |
| |
| \sa layout(), spacerItem() |
| */ |
| #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) |
| QWidget *QLayoutItem::widget() |
| #else |
| QWidget *QLayoutItem::widget() const |
| #endif |
| { |
| return nullptr; |
| } |
| |
| /*! |
| Returns the widget managed by this item. |
| */ |
| #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) |
| QWidget *QWidgetItem::widget() |
| #else |
| QWidget *QWidgetItem::widget() const |
| #endif |
| { |
| return wid; |
| } |
| |
| /*! |
| Returns \c true if this layout's preferred height depends on its |
| width; otherwise returns \c 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, which is not used in this default implementation. |
| |
| 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 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 |
| { |
| 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; |
| |
| // Make sure we don't move outside of the parent, e.g when styles demand |
| // surplus space that exceeds the available margins (f.ex macOS with QGroupBox) |
| if (x < 0) { |
| s.rwidth() += x; |
| x = 0; |
| } |
| if (y < 0) { |
| s.rheight() += y; |
| y = 0; |
| } |
| |
| 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; |
| return wid->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 e = wid->sizePolicy().expandingDirections(); |
| /* |
| If the layout is expanding, we make the widget expanding, even if |
| its own size policy isn't expanding. |
| */ |
| 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 \c true. |
| */ |
| bool QSpacerItem::isEmpty() const |
| { |
| return true; |
| } |
| |
| /*! |
| Returns \c true if the widget is hidden; otherwise returns \c false. |
| |
| \sa QWidget::isHidden() |
| */ |
| bool QWidgetItem::isEmpty() const |
| { |
| return (wid->isHidden() && !wid->sizePolicy().retainSizeWhenHidden()) || wid->isWindow(); |
| } |
| |
| /*! |
| Returns the control type associated with the widget for which |
| this size policy applies. |
| |
| \sa QSizePolicy::controlType() |
| */ |
| QSizePolicy::ControlTypes QWidgetItem::controlTypes() const |
| { |
| return wid->sizePolicy().controlType(); |
| } |
| |
| /*! |
| \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(nullptr) |
| { |
| QWidgetPrivate *wd = wid->d_func(); |
| if (!wd->widgetItem) |
| wd->widgetItem = this; |
| } |
| |
| QWidgetItemV2::~QWidgetItemV2() |
| { |
| if (wid) { |
| auto *wd = static_cast<QWidgetPrivate *>(QObjectPrivate::get(wid)); |
| if (wd->widgetItem == this) |
| wd->widgetItem = nullptr; |
| } |
| } |
| |
| 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 % HfwCacheMaxSize; |
| 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 |