diff --git a/src/DockWidgetBase.cpp b/src/DockWidgetBase.cpp index ad995366..13967981 100644 --- a/src/DockWidgetBase.cpp +++ b/src/DockWidgetBase.cpp @@ -226,6 +226,7 @@ void DockWidgetBase::setWidget(QWidget *w) qCDebug(addwidget) << Q_FUNC_INFO << w; d->widget = w; + setSizePolicy(w->sizePolicy()); Q_EMIT widgetChanged(w); setWindowTitle(uniqueName()); } diff --git a/src/private/Frame.cpp b/src/private/Frame.cpp index 783d8427..a6223cfe 100644 --- a/src/private/Frame.cpp +++ b/src/private/Frame.cpp @@ -626,17 +626,17 @@ QSize Frame::biggestDockWidgetMaxSize() const { QSize size = Layouting::Item::hardcodedMaximumSize; for (DockWidgetBase *dw : dockWidgets()) { + const QSize dwMax = widgetMaxSize(dw); if (size == Layouting::Item::hardcodedMaximumSize) { - size = dw->maximumSize(); + size = dwMax; continue; } - const bool hasMaxSize = dw->maximumSize() != Layouting::Item::hardcodedMaximumSize; + const bool hasMaxSize = dwMax != Layouting::Item::hardcodedMaximumSize; if (hasMaxSize) size = dw->maximumSize().expandedTo(size); } - // Interpret 0 max-size as not having one too. if (size.width() == 0) size.setWidth(Layouting::Item::hardcodedMaximumSize.width()); diff --git a/src/private/multisplitter/CMakeLists.txt b/src/private/multisplitter/CMakeLists.txt index a27aa550..31fd2a35 100644 --- a/src/private/multisplitter/CMakeLists.txt +++ b/src/private/multisplitter/CMakeLists.txt @@ -7,6 +7,7 @@ set(MULTISPLITTER_SRCS MultiSplitterConfig.h Separator.cpp Separator_p.h + Widget.cpp Widget.h multisplitter_export.h ) diff --git a/src/private/multisplitter/Widget.cpp b/src/private/multisplitter/Widget.cpp new file mode 100644 index 00000000..ff0dba58 --- /dev/null +++ b/src/private/multisplitter/Widget.cpp @@ -0,0 +1,44 @@ +/* + This file is part of KDDockWidgets. + + Copyright (C) 2018-2020 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com + Author: Sérgio Martins + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "Widget.h" +#include "Item_p.h" + +using namespace Layouting; + +Widget::~Widget() +{ +} + +QSize Widget::boundedMaxSize(QSize min, QSize max) +{ + // Max should be bigger than min, but not bigger than the hardcoded max + max = max.boundedTo(QSize(KDDOCKWIDGETS_MAX_WIDTH, KDDOCKWIDGETS_MAX_HEIGHT)); + + // 0 interpreted as not having max + if (max.width() <= 0) + max.setWidth(KDDOCKWIDGETS_MAX_WIDTH); + if (max.height() <= 0) + max.setHeight(KDDOCKWIDGETS_MAX_HEIGHT); + + max = max.expandedTo(min); + + return max; +} diff --git a/src/private/multisplitter/Widget.h b/src/private/multisplitter/Widget.h index 10c7ca23..f696e083 100644 --- a/src/private/multisplitter/Widget.h +++ b/src/private/multisplitter/Widget.h @@ -55,13 +55,14 @@ public: explicit Widget(QObject *thisObj) : m_thisObj(thisObj) {} - virtual ~Widget() {} + virtual ~Widget(); virtual void setLayoutItem(Item *) = 0; // Not strickly necessary, but it's nice conveniance for kddw which is widget based. virtual QWidget *asQWidget() const { return nullptr; }; + virtual QSize sizeHint() const { return {}; } virtual QSize minSize() const = 0; virtual QSize maxSizeHint() const = 0; virtual QRect geometry() const = 0; @@ -102,6 +103,9 @@ public: return obj == m_thisObj; } +protected: + static QSize boundedMaxSize(QSize min, QSize max); + private: QObject *const m_thisObj; Q_DISABLE_COPY(Widget) diff --git a/src/private/multisplitter/Widget_qwidget.cpp b/src/private/multisplitter/Widget_qwidget.cpp index a1bb737e..1ccc2ede 100644 --- a/src/private/multisplitter/Widget_qwidget.cpp +++ b/src/private/multisplitter/Widget_qwidget.cpp @@ -29,6 +29,11 @@ Widget_qwidget::~Widget_qwidget() { } +QSize Widget_qwidget::sizeHint() const +{ + return m_thisWidget->sizeHint(); +} + QSize Widget_qwidget::minSize() const { return widgetMinSize(m_thisWidget); @@ -36,7 +41,7 @@ QSize Widget_qwidget::minSize() const QSize Widget_qwidget::maxSizeHint() const { - return m_thisWidget->maximumSize(); + return widgetMaxSize(m_thisWidget); } QRect Widget_qwidget::geometry() const @@ -128,6 +133,26 @@ QSize Widget_qwidget::widgetMinSize(const QWidget *w) return QSize(minW, minH).expandedTo(Item::hardcodedMinimumSize); } +QSize Widget_qwidget::widgetMaxSize(const QWidget *w) +{ + // The max size is usually QWidget::maximumSize(), but we also honour the QSizePolicy::Fixed+sizeHint() case + // as widgets don't need to have QWidget::maximumSize() to have a max size honoured + + const QSize min = widgetMinSize(w); + QSize max = w->maximumSize(); + max = boundedMaxSize(min, max); // for safety against weird values + + const QSizePolicy policy = w->sizePolicy(); + + if (policy.verticalPolicy() == QSizePolicy::Fixed) + max.setHeight(qMin(max.height(), w->sizeHint().height())); + if (policy.horizontalPolicy() == QSizePolicy::Fixed) + max.setWidth(qMin(max.width(), w->sizeHint().width())); + + max = boundedMaxSize(min, max); // for safety against weird values + return max; +} + void Widget_qwidget::setSize(int width, int height) { m_thisWidget->resize(QSize(width, height)); diff --git a/src/private/multisplitter/Widget_qwidget.h b/src/private/multisplitter/Widget_qwidget.h index fa5f63af..c8196b76 100644 --- a/src/private/multisplitter/Widget_qwidget.h +++ b/src/private/multisplitter/Widget_qwidget.h @@ -46,6 +46,7 @@ public: return m_thisWidget; } + QSize sizeHint() const override; QSize minSize() const override; QSize maxSizeHint() const override; QRect geometry() const override; @@ -64,7 +65,7 @@ public: void setHeight(int height) override; static QSize widgetMinSize(const QWidget *w); - + static QSize widgetMaxSize(const QWidget *w); private: QWidget *const m_thisWidget; Q_DISABLE_COPY(Widget_qwidget) diff --git a/tests/tst_docks.cpp b/tests/tst_docks.cpp index 7752cbe4..55930c76 100644 --- a/tests/tst_docks.cpp +++ b/tests/tst_docks.cpp @@ -356,6 +356,7 @@ private Q_SLOTS: void tst_moreTitleBarCornerCases(); void tst_maxSizePropagates(); void tst_maxSizeHonouredWhenDropped(); + void tst_fixedSizePolicy(); private: std::unique_ptr createMultiSplitterFromSetup(MultiSplitterSetup setup, QHash &frameMap) const; @@ -5385,6 +5386,30 @@ void TestDocks::tst_maxSizeHonouredWhenDropped() QCOMPARE(dock2->frame()->width(), droppedWidth); } +void TestDocks::tst_fixedSizePolicy() +{ + // tests that KDDW also takes into account QSizePolicy::Fixed for calculating the max size hint. + // Since QPushButton for example doesn't set QWidget::maximumSize(), but instead uses sizeHint() + // + QSizePolicy::Fixed. + EnsureTopLevelsDeleted e; + auto button = new QPushButton("one"); + auto dock1 = createDockWidget("dock1", button); + Frame *frame = dock1->frame(); + + // Just a precondition from the test. If QPushButton ever changes, replace with a QWidget and set fixed size policy + QCOMPARE(button->sizePolicy().verticalPolicy(), QSizePolicy::Fixed); + + const int buttonMaxHeight = button->sizeHint().height(); + + QCOMPARE(dock1->sizeHint(), button->sizeHint()); + QCOMPARE(dock1->sizePolicy().verticalPolicy(), button->sizePolicy().verticalPolicy()); + QCOMPARE(dock1->sizePolicy().horizontalPolicy(), button->sizePolicy().horizontalPolicy()); + + QCOMPARE(frame->maxSizeHint().height(), qMax(buttonMaxHeight, KDDOCKWIDGETS_MIN_HEIGHT)); + + delete dock1->window(); +} + int main(int argc, char *argv[]) { if (!qpaPassedAsArgument(argc, argv)) {