diff --git a/src/private/multisplitter/Item.cpp b/src/private/multisplitter/Item.cpp index 9de49974..f893cdc1 100644 --- a/src/private/multisplitter/Item.cpp +++ b/src/private/multisplitter/Item.cpp @@ -562,6 +562,11 @@ int Item::minLength(Qt::Orientation o) const return Layouting::length(minSize(), o); } +int Item::maxLengthHint(Qt::Orientation o) const +{ + return Layouting::length(maxSizeHint(), o); +} + void Item::setLength(int length, Qt::Orientation o) { Q_ASSERT(length > 0); @@ -833,6 +838,8 @@ void Item::onWidgetLayoutRequested() if (w->minSize() != minSize()) { setMinSize(m_guest->minSize()); } + + setMaxSizeHint(w->maxSizeHint()); } } @@ -1797,8 +1804,8 @@ QSize ItemContainer::minSize() const QSize ItemContainer::maxSizeHint() const { - int maxW = 0; - int maxH = 0; + int maxW = KDDOCKWIDGETS_MAX_WIDTH; + int maxH = KDDOCKWIDGETS_MAX_HEIGHT; if (!isEmpty()) { const Item::List visibleChildren = this->visibleChildren(); @@ -1819,7 +1826,7 @@ QSize ItemContainer::maxSizeHint() const maxW += separatorWaste; } - return { maxW, maxH }; + return QSize(maxW, maxH).expandedTo(minSize()); } void ItemContainer::Private::resizeChildren(QSize oldSize, QSize newSize, SizingInfo::List &childSizes, @@ -2087,7 +2094,7 @@ void ItemContainer::restoreChild(Item *item, NeighbourSqueezeStrategy neighbourS const int available = availableOnSide(item, Side1) + availableOnSide(item, Side2) - Item::separatorThickness; - const int max = available; + const int max = qMin(available, item->maxLengthHint(d->m_orientation)); const int min = item->minLength(d->m_orientation); const int proposed = Layouting::length(item->size(), d->m_orientation); const int newLength = qBound(min, proposed, max); @@ -2289,7 +2296,7 @@ void ItemContainer::layoutEqually(SizingInfo::List &sizes) const int newItemLenght = qBound(size.minLength(d->m_orientation), size.length(d->m_orientation) + suggestedToGive, - size.maxLength(d->m_orientation)); + size.maxLengthHint(d->m_orientation)); const int toGive = newItemLenght - size.length(d->m_orientation); if (toGive == 0) { diff --git a/src/private/multisplitter/Item_p.h b/src/private/multisplitter/Item_p.h index 3134f144..0dc29f22 100644 --- a/src/private/multisplitter/Item_p.h +++ b/src/private/multisplitter/Item_p.h @@ -138,8 +138,8 @@ struct SizingInfo { return Layouting::length(minSize, o); } - int maxLength(Qt::Orientation o) const { - return Layouting::length(maxSizeHint, o); + int maxLengthHint(Qt::Orientation o) const { + return qMax(minLength(o), Layouting::length(maxSizeHint, o)); } int availableLength(Qt::Orientation o) const { @@ -193,7 +193,7 @@ struct SizingInfo { } int availableToGrow(Qt::Orientation o) const { - return maxLength(o) - length(o); + return maxLengthHint(o) - length(o); } QVariantMap toVariantMap() const; @@ -294,6 +294,7 @@ public: int refCount() const; int minLength(Qt::Orientation) const; + int maxLengthHint(Qt::Orientation) const; QObject *host() const; Widget *hostWidget() const; diff --git a/src/private/multisplitter/tests/tst_multisplitter.cpp b/src/private/multisplitter/tests/tst_multisplitter.cpp index d89d56ea..13191941 100644 --- a/src/private/multisplitter/tests/tst_multisplitter.cpp +++ b/src/private/multisplitter/tests/tst_multisplitter.cpp @@ -69,6 +69,19 @@ public: } } + void setMaxSize(QSize sz) + { + if (sz != m_maxSize) { + m_maxSize = sz; + Q_EMIT layoutInvalidated(); + } + } + + + QSize maxSizeHint() const override { + return m_maxSize; + } + void resizeEvent(QResizeEvent *ev) override { QWidget::resizeEvent(ev); @@ -97,6 +110,7 @@ Q_SIGNALS: void layoutInvalidated(); private: QSize m_minSize = QSize(200, 200); + QSize m_maxSize = QSize(KDDOCKWIDGETS_MAX_WIDTH, KDDOCKWIDGETS_MAX_HEIGHT); }; static void fatalWarningsMessageHandler(QtMsgType t, const QMessageLogContext &context, const QString &msg) @@ -181,6 +195,7 @@ private Q_SLOTS: void tst_closeAndRestorePreservesPosition(); void tst_minSizeChangedBeforeRestore(); void tst_separatorMoveCrash(); + void tst_maxSizeHonoured1(); }; class MyHostWidget : public QWidget @@ -1528,6 +1543,24 @@ void TestMultiSplitter::tst_separatorMoveCrash() c->requestSeparatorMove(separator, available5 + 10); } +void TestMultiSplitter::tst_maxSizeHonoured1() +{ + // Tests that the suggested rect honours max size when adding an item to a layout. + + auto root = createRoot(); + auto item1 = createItem(); + auto item2 = createItem(); + root->insertItem(item1, Item::Location_OnTop); + root->setSize_recursive(QSize(3000, 3000)); + + auto guest2 = static_cast(item2->guestWidget()); + const int maxHeight = 250; + guest2->setMaxSize(QSize(250, maxHeight)); + + root->insertItem(item2, Item::Location_OnBottom); + QCOMPARE(item2->height(), maxHeight); +} + int main(int argc, char *argv[]) { bool qpaPassed = false; diff --git a/tests/tst_docks.cpp b/tests/tst_docks.cpp index 16ebeefc..969bcb86 100644 --- a/tests/tst_docks.cpp +++ b/tests/tst_docks.cpp @@ -355,6 +355,7 @@ private Q_SLOTS: void tst_lastFloatingPositionIsRestored(); void tst_moreTitleBarCornerCases(); void tst_maxSizePropagates(); + void tst_maxSizeHonouredWhenDropped(); private: std::unique_ptr createMultiSplitterFromSetup(MultiSplitterSetup setup, QHash &frameMap) const; @@ -5332,34 +5333,55 @@ void TestDocks::tst_moreTitleBarCornerCases() void TestDocks::tst_maxSizePropagates() { - { - // Tests that the DockWidget gets the min and max size of its guest widget + // Tests that the DockWidget gets the min and max size of its guest widget + EnsureTopLevelsDeleted e; + auto dock1 = new DockWidget("dock1"); - auto dock1 = new DockWidget("dock1"); + auto w = new QWidget(); + w->setMinimumSize(120, 120); + w->setMaximumSize(500, 500); + dock1->setWidget(w); + dock1->show(); - auto w = new QWidget(); - w->setMinimumSize(120, 120); - w->setMaximumSize(500, 500); - dock1->setWidget(w); - dock1->show(); + QCOMPARE(Widget_qwidget::widgetMinSize(dock1), Widget_qwidget::widgetMinSize(w)); + QCOMPARE(dock1->maximumSize(), w->maximumSize()); - QCOMPARE(Widget_qwidget::widgetMinSize(dock1), Widget_qwidget::widgetMinSize(w)); - QCOMPARE(dock1->maximumSize(), w->maximumSize()); + w->setMinimumSize(121, 121); + w->setMaximumSize(501, 501); - w->setMinimumSize(121, 121); - w->setMaximumSize(501, 501); + Testing::waitForEvent(w, QEvent::LayoutRequest); - Testing::waitForEvent(w, QEvent::LayoutRequest); + QCOMPARE(Widget_qwidget::widgetMinSize(dock1), Widget_qwidget::widgetMinSize(w)); + QCOMPARE(dock1->maximumSize(), w->maximumSize()); - QCOMPARE(Widget_qwidget::widgetMinSize(dock1), Widget_qwidget::widgetMinSize(w)); - QCOMPARE(dock1->maximumSize(), w->maximumSize()); + // Now let's see if our Frame also has proper size-constraints + Frame *frame = dock1->frame(); + QCOMPARE(frame->maximumSize().expandedTo(w->maximumSize()), frame->maximumSize()); - // Now let's see if our Frame also has proper size-constraints - Frame *frame = dock1->frame(); - QCOMPARE(frame->maximumSize().expandedTo(w->maximumSize()), frame->maximumSize()); + delete dock1->window(); +} - delete dock1->window(); - } +void TestDocks::tst_maxSizeHonouredWhenDropped() +{ + EnsureTopLevelsDeleted e; + auto m1 = createMainWindow(); + auto dock1 = new DockWidget("dock1"); + auto dock2 = new DockWidget("dock2"); + m1->addDockWidget(dock1, Location_OnTop); + m1->resize(2000, 2000); + + dock2->setWidget(new QWidget); + const int maxWidth = 200; + dock2->widget()->setMaximumSize(maxWidth, 200); + m1->addDockWidget(dock2, Location_OnLeft); + const int droppedWidth = dock2->frame()->width(); + QVERIFY(droppedWidth < maxWidth + 50); // +50 to cover any margins and waste by QTabWidget + + // Try again, but now dropping a multisplitter + dock2->setFloating(true); + auto fw = qobject_cast(dock2->window()); + m1->dropArea()->drop(fw, Location_OnLeft, nullptr); + QCOMPARE(dock2->frame()->width(), droppedWidth); } int main(int argc, char *argv[])