diff options
| author | Thorbjørn Lund Martsum <[email protected]> | 2024-08-19 14:41:55 +0200 |
|---|---|---|
| committer | Thorbjørn Lund Martsum <[email protected]> | 2025-05-15 23:55:03 +0200 |
| commit | 5b33c4e84ce23f1d7720306f4f01e771ac8be2e3 (patch) | |
| tree | d720fc486c84fe0e57bf5483917cc75721f07e59 /src/widgets/kernel/qlayout.cpp | |
| parent | bf38ab9990f30151c148dbff77c8c9bf3982f097 (diff) | |
QLayout - Introduce vertical and horizontal layout constraints
In most situations the simple setSizeConstraint is
sufficient to get the sizeConstaint the user wants.
However in certain other situations the QLayout size constraint
demanding same vertical and horizontal behavior could simply
be extremely annoying.
This patch fixes a design-flaw as it makes perfectly sense
to have a fixed sized or minimum size constraint in one
orientation and having it something else (e.g minMax) in
the another.
Likely the old logic was that the user could use
setMinimumWidth and setMaximumWidth on the widget itself
(and similar for height) to get this behavior, but on 2+ monitor
systems with different DPR that is not really an option
(at least not a good one).
[ChangeLog][QWidgets][QLayout] Introduced a vertical and horizontal
size constraint in layout as the size constraint behavior can depend on
the orientation.
Fixes: QTBUG-17730
Change-Id: I8aefcd2b4df228494604b41e8ab7319e9f599d07
Reviewed-by: Richard Moe Gustavsen <[email protected]>
Diffstat (limited to 'src/widgets/kernel/qlayout.cpp')
| -rw-r--r-- | src/widgets/kernel/qlayout.cpp | 277 |
1 files changed, 215 insertions, 62 deletions
diff --git a/src/widgets/kernel/qlayout.cpp b/src/widgets/kernel/qlayout.cpp index ec28581b041..c8b87540bfc 100644 --- a/src/widgets/kernel/qlayout.cpp +++ b/src/widgets/kernel/qlayout.cpp @@ -109,7 +109,7 @@ QLayout::QLayout(QLayoutPrivate &dd, QLayout *lay, QWidget *w) QLayoutPrivate::QLayoutPrivate() : QObjectPrivate(), insideSpacing(-1), userLeftMargin(-1), userTopMargin(-1), userRightMargin(-1), userBottomMargin(-1), topLevel(false), enabled(true), activated(true), autoNewChild(false), - constraint(QLayout::SetDefaultConstraint), menubar(nullptr) + horizontalConstraint(QLayout::SetDefaultConstraint), verticalConstraint(QLayout::SetDefaultConstraint), menubar(nullptr) { } @@ -841,13 +841,6 @@ void QLayout::addChildWidget(QWidget *w) QMetaObject::invokeMethod(w, "_q_showIfNotHidden", Qt::QueuedConnection); //show later } - - - - - - - /*! Tells the geometry manager to place the menu bar \a widget at the top of parentWidget(), outside QWidget::contentsMargins(). All @@ -987,43 +980,127 @@ bool QLayout::activate() uint explMin = md->extra ? md->extra->explicitMinSize : 0; uint explMax = md->extra ? md->extra->explicitMaxSize : 0; - switch (d->constraint) { - case SetFixedSize: - // will trigger resize - mw->setFixedSize(totalSizeHint()); - break; - case SetMinimumSize: - mw->setMinimumSize(totalMinimumSize()); - break; - case SetMaximumSize: - mw->setMaximumSize(totalMaximumSize()); - break; - case SetMinAndMaxSize: - mw->setMinimumSize(totalMinimumSize()); - mw->setMaximumSize(totalMaximumSize()); - break; - case SetDefaultConstraint: { - bool widthSet = explMin & Qt::Horizontal; - bool heightSet = explMin & Qt::Vertical; - if (mw->isWindow()) { - QSize ms = totalMinimumSize(); - if (widthSet) - ms.setWidth(mw->minimumSize().width()); - if (heightSet) - ms.setHeight(mw->minimumSize().height()); - mw->setMinimumSize(ms); - } else if (!widthSet || !heightSet) { - QSize ms = mw->minimumSize(); - if (!widthSet) - ms.setWidth(0); - if (!heightSet) - ms.setHeight(0); - mw->setMinimumSize(ms); + // Do actual calculation + // Result values (needs to be zero or greater to be considered valid/set) + // We make some illegal values different from each other due a later compare. + // ### In the future we may want minSize(0, 0) and maxSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX) + // ### Also see comment below. + QSize minSize(-1, -1); + QSize maxSize(-2, -2); + + // Potentially cached values to avoid calling the same function more times. + constexpr QSize empty(0, 0); + QSize totalSzH = empty; + QSize totalMinSz = empty; + QSize totalMaxSz = empty; + + switch (d->verticalConstraint) { + case SetFixedSize: + totalSzH = totalSizeHint(); + minSize.setHeight(totalSzH.height()); + maxSize.setHeight(totalSzH.height()); + break; + case SetMinimumSize: + totalMinSz = totalMinimumSize(); + minSize.setHeight(totalMinSz.height()); + break; + case SetMaximumSize: + totalMaxSz = totalMaximumSize(); + maxSize.setHeight(totalMaxSz.height()); + break; + case SetMinAndMaxSize: + totalMinSz = totalMinimumSize(); + totalMaxSz = totalMaximumSize(); + minSize.setHeight(totalMinSz.height()); + maxSize.setHeight(totalMaxSz.height()); + break; + case SetDefaultConstraint: { + bool heightSet = explMin & Qt::Vertical; + if (mw->isWindow()) { + if (!heightSet) { + totalMinSz = totalMinimumSize(); + minSize.setHeight(totalMinSz.height()); + } else { + minSize.setHeight(mw->minimumHeight()); + } + } else { + minSize.setHeight(heightSet ? mw->minimumHeight() : 0); + } + break; } - break; + case SetNoConstraint: + break; } - case SetNoConstraint: - break; + switch (d->horizontalConstraint) { + case SetFixedSize: + if (totalSzH == empty) + totalSzH = totalSizeHint(); + minSize.setWidth(totalSzH.width()); + maxSize.setWidth(totalSzH.width()); + break; + case SetMinimumSize: + if (totalMinSz == empty) + totalMinSz = totalMinimumSize(); + minSize.setWidth(totalMinSz.width()); + break; + case SetMaximumSize: + if (totalMaxSz == empty) + totalMaxSz = totalMaximumSize(); + maxSize.setWidth(totalMaxSz.width()); + break; + case SetMinAndMaxSize: + if (totalMinSz == empty) + totalMinSz = totalMinimumSize(); + if (totalMaxSz == empty) + totalMaxSz = totalMaximumSize(); + + minSize.setWidth(totalMinSz.width()); + maxSize.setWidth(totalMaxSz.width()); + break; + case SetDefaultConstraint: { + const bool widthSet = explMin & Qt::Horizontal; + if (mw->isWindow()) { + if (!widthSet) { + if (totalMinSz == empty) + totalMinSz = totalMinimumSize(); + minSize.setWidth(totalMinSz.width()); + } else { + minSize.setWidth(mw->minimumWidth()); + } + } else { + minSize.setWidth(widthSet ? mw->minimumWidth() : 0); + } + break; + } + case SetNoConstraint: + break; + } + if (minSize == maxSize) { + mw->setFixedSize(minSize); + } + else { + // ### To preserve backward compatibility with behavior prior to introducing separate + // ### horizontal and vertical constraints, we only update the specific size properties + // ### dictated by the constraints. For example, if only minimum width is specified + // ### by the constraint, we leave the minimum height untouched. + // ### Like before we leave unconstrained values unchanged though it can + // ### (unintentionally?) retain stale values. + + // handle min-size + if (minSize.isValid()) + mw->setMinimumSize(minSize); + else if (minSize.width() >= 0) + mw->setMinimumWidth(minSize.width()); + else if (minSize.height() >= 0) + mw->setMinimumHeight(minSize.height()); + + // handle max-size + if (maxSize.isValid()) + mw->setMaximumSize(maxSize); + else if (maxSize.width() >= 0) + mw->setMaximumWidth(maxSize.width()); + else if (maxSize.height() >= 0) + mw->setMaximumHeight(maxSize.height()); } d->doResize(); @@ -1181,51 +1258,127 @@ int QLayout::indexOf(const QLayoutItem *layoutItem) const /*! \enum QLayout::SizeConstraint + Describes how the layout constrains the size of the widget. + + A vertical constraint affects the widget's height, while a horizontal constraint affects its width. The possible values are: - \value SetDefaultConstraint The main widget's minimum size is set - to minimumSize(), unless the widget already has - a minimum size. + \value SetDefaultConstraint + In the constrained orientation(s), the widget’s minimum extent + is set to \l minimumSize(), unless a minimum size has already been set. + + \value SetFixedSize + In the constrained orientation(s), the widget’s extent is set to + \l sizeHint(), and it cannot be resized in that direction. - \value SetFixedSize The main widget's size is set to sizeHint(); it - cannot be resized at all. - \value SetMinimumSize The main widget's minimum size is set to - minimumSize(); it cannot be smaller. + \value SetMinimumSize + In the constrained orientation(s), the widget’s minimum extent + is set to \l minimumSize(). - \value SetMaximumSize The main widget's maximum size is set to - maximumSize(); it cannot be larger. + \value SetMaximumSize + In the constrained orientation(s), the widget’s maximum extent + is set to \l maximumSize(). - \value SetMinAndMaxSize The main widget's minimum size is set to - minimumSize() and its maximum size is set to - maximumSize(). + \value SetMinAndMaxSize + In the constrained orientation(s), the widget’s minimum extent + is set to \l minimumSize(), and the maximum extent is set to \l maximumSize(). - \value SetNoConstraint The widget is not constrained. + \value SetNoConstraint + No size constraints are applied to the widget. - \sa setSizeConstraint() + \sa setSizeConstraint(), setSizeConstraints(), horizontalSizeConstraint(), setHorizontalSizeConstraint(), setVerticalSizeConstraint() */ /*! \property QLayout::sizeConstraint - \brief the resize mode of the layout + \brief the resize mode of the layout. + Setting the size constraint for the dialog. + Setting a vertical or horizontal size constraint will override this. The default mode is \l {QLayout::SetDefaultConstraint} {SetDefaultConstraint}. + + \sa horizontalSizeConstraint(), verticalSizeConstraint() */ + void QLayout::setSizeConstraint(SizeConstraint constraint) { + setSizeConstraints(constraint, constraint); +} + +/*! + * \brief the resize mode of the layout. + * \since 6.10 + * Sets both the \a horizontal and \a vertical size constraint. + * Provided for convenience. + * \sa sizeConstraint(), horizontalSizeConstraint(), verticalSizeConstraint() + */ +void QLayout::setSizeConstraints(SizeConstraint horizontal, SizeConstraint vertical) +{ Q_D(QLayout); - if (constraint == d->constraint) + if (horizontal == d->horizontalConstraint && vertical == d->verticalConstraint) return; - - d->constraint = constraint; + d->horizontalConstraint = horizontal; + d->verticalConstraint = vertical; invalidate(); } QLayout::SizeConstraint QLayout::sizeConstraint() const { Q_D(const QLayout); - return d->constraint; + return d->horizontalConstraint; +} + +/*! + \property QLayout::horizontalSizeConstraint + \since 6.10 + \brief The horizontal size constraint. + + The default mode is \l {QLayout::SetDefaultConstraint} + + \sa verticalSizeConstraint(), sizeConstraint() +*/ + +void QLayout::setHorizontalSizeConstraint(SizeConstraint constraint) +{ + Q_D(QLayout); + if (constraint == d->horizontalConstraint) + return; + d->horizontalConstraint = constraint; + invalidate(); +} + + +QLayout::SizeConstraint QLayout::horizontalSizeConstraint() const +{ + Q_D(const QLayout); + return d->horizontalConstraint; +} + +/*! + \property QLayout::verticalSizeConstraint + \since 6.10 + \brief The vertical size constraint. + + The default mode is \l {QLayout::SetDefaultConstraint} + + \sa horizontalSizeConstraint(), sizeConstraint() +*/ + +void QLayout::setVerticalSizeConstraint(SizeConstraint constraint) +{ + Q_D(QLayout); + if (constraint == d->verticalConstraint) + return; + d->verticalConstraint = constraint; + invalidate(); +} + +QLayout::SizeConstraint QLayout::verticalSizeConstraint() const +{ + Q_D(const QLayout); + return d->verticalConstraint; } /*! |
