diff --git a/Changelog b/Changelog
index 48fde829..e6bd4092 100644
--- a/Changelog
+++ b/Changelog
@@ -6,6 +6,7 @@
as TitleBarWidget already reimplements sizeHint. If you're inheriting directly from TitleBar then make
sure to provide a sizeHint.
- Added MainWindow::closeDockWidgets()
+ - Fixed crash in MainWindow::layoutEqually()
* v1.3.1 (unreleased)
- Improve restoring layout when RestoreOption_RelativeToMainWindow is used (#171)
diff --git a/src/private/multisplitter/Item.cpp b/src/private/multisplitter/Item.cpp
index 72408ac6..fc009a14 100644
--- a/src/private/multisplitter/Item.cpp
+++ b/src/private/multisplitter/Item.cpp
@@ -2384,8 +2384,9 @@ void ItemBoxContainer::layoutEqually(SizingInfo::List &sizes)
auto lengthToGive = length() - (d->m_separators.size() * Item::separatorThickness);
// clear the sizes before we start distributing
- for (SizingInfo &size : sizes)
- size.setLength(0, d->m_orientation);
+ for (SizingInfo &size : sizes) {
+ size.setLength(0, d->m_orientation);
+ }
while (satisfiedIndexes.count() < sizes.count()) {
const auto remainingItems = sizes.count() - satisfiedIndexes.count();
@@ -2403,9 +2404,25 @@ void ItemBoxContainer::layoutEqually(SizingInfo::List &sizes)
continue;
}
- const auto newItemLenght = qBound(size.minLength(d->m_orientation),
- size.length(d->m_orientation) + suggestedToGive,
- size.maxLengthHint(d->m_orientation));
+ // Bound the max length. Our max can't be bigger than the remaining space.
+ // The layout's min length minus our own min length is the amount of space that we
+ // need to guarantee. We can't go larger and overwrite that
+
+ const auto othersMissing = // The size that the others are missing to satisfy their
+ // minimum length
+ std::accumulate(sizes.constBegin(), sizes.constEnd(), 0,
+ [this](size_t sum, const SizingInfo &sz) {
+ return sum + sz.missingLength(d->m_orientation);
+ })
+ - size.missingLength(d->m_orientation);
+
+ const auto maxLength =
+ qMin(size.length(d->m_orientation) + lengthToGive - othersMissing,
+ size.maxLengthHint(d->m_orientation));
+
+ const auto newItemLenght =
+ qBound(size.minLength(d->m_orientation),
+ size.length(d->m_orientation) + suggestedToGive, maxLength);
const auto toGive = newItemLenght - size.length(d->m_orientation);
if (toGive == 0) {
diff --git a/tests/layouts/layoutEquallyCrash.json b/tests/layouts/layoutEquallyCrash.json
new file mode 100644
index 00000000..1824b029
--- /dev/null
+++ b/tests/layouts/layoutEquallyCrash.json
@@ -0,0 +1,279 @@
+{
+ "allDockWidgets": [
+ {
+ "affinities": [
+ "{7829427d-88e3-402e-9120-50c628dfd0bc}"
+ ],
+ "lastPosition": {
+ "lastFloatingGeometry": {
+ "height": 0,
+ "width": 0,
+ "x": 0,
+ "y": 0
+ },
+ "placeholders": [
+ {
+ "isFloatingWindow": false,
+ "itemIndex": 2,
+ "mainWindowUniqueName": "{7829427d-88e3-402e-9120-50c628dfd0bc}"
+ }
+ ],
+ "tabIndex": 0,
+ "wasFloating": false
+ },
+ "uniqueName": "Favorite-481"
+ },
+ {
+ "affinities": [
+ "{7829427d-88e3-402e-9120-50c628dfd0bc}"
+ ],
+ "lastPosition": {
+ "lastFloatingGeometry": {
+ "height": 0,
+ "width": 0,
+ "x": 0,
+ "y": 0
+ },
+ "placeholders": [
+ {
+ "isFloatingWindow": false,
+ "itemIndex": 0,
+ "mainWindowUniqueName": "{7829427d-88e3-402e-9120-50c628dfd0bc}"
+ }
+ ],
+ "tabIndex": 0,
+ "wasFloating": false
+ },
+ "uniqueName": "Favorite-482"
+ },
+ {
+ "affinities": [
+ "{7829427d-88e3-402e-9120-50c628dfd0bc}"
+ ],
+ "lastPosition": {
+ "lastFloatingGeometry": {
+ "height": 0,
+ "width": 0,
+ "x": 0,
+ "y": 0
+ },
+ "placeholders": [
+ {
+ "isFloatingWindow": false,
+ "itemIndex": 1,
+ "mainWindowUniqueName": "{7829427d-88e3-402e-9120-50c628dfd0bc}"
+ }
+ ],
+ "tabIndex": 0,
+ "wasFloating": false
+ },
+ "uniqueName": "Favorite-483"
+ }
+ ],
+ "closedDockWidgets": [
+ ],
+ "floatingWindows": [
+ ],
+ "mainWindows": [
+ {
+ "affinities": [
+ "{7829427d-88e3-402e-9120-50c628dfd0bc}"
+ ],
+ "geometry": {
+ "height": 1228,
+ "width": 1644,
+ "x": 501,
+ "y": 110
+ },
+ "isVisible": true,
+ "multiSplitterLayout": {
+ "frames": {
+ "10": {
+ "currentTabIndex": 0,
+ "dockWidgets": [
+ "Favorite-483"
+ ],
+ "geometry": {
+ "height": 1206,
+ "width": 536,
+ "x": 541,
+ "y": 0
+ },
+ "id": "10",
+ "isNull": false,
+ "objectName": "Favorite-483",
+ "options": 0
+ },
+ "12": {
+ "currentTabIndex": 0,
+ "dockWidgets": [
+ "Favorite-481"
+ ],
+ "geometry": {
+ "height": 1206,
+ "width": 540,
+ "x": 1082,
+ "y": 0
+ },
+ "id": "12",
+ "isNull": false,
+ "objectName": "Favorite-481",
+ "options": 0
+ },
+ "9": {
+ "currentTabIndex": 0,
+ "dockWidgets": [
+ "Favorite-482"
+ ],
+ "geometry": {
+ "height": 1206,
+ "width": 536,
+ "x": 0,
+ "y": 0
+ },
+ "id": "9",
+ "isNull": false,
+ "objectName": "Favorite-482",
+ "options": 0
+ }
+ },
+ "layout": {
+ "children": [
+ {
+ "children": [
+ {
+ "guestId": "9",
+ "isContainer": false,
+ "isVisible": true,
+ "objectName": "Favorite-482",
+ "sizingInfo": {
+ "geometry": {
+ "height": 1206,
+ "width": 536,
+ "x": 0,
+ "y": 0
+ },
+ "maxSize": {
+ "height": 524315,
+ "width": 524432
+ },
+ "minSize": {
+ "height": 118,
+ "width": 233
+ }
+ }
+ },
+ {
+ "guestId": "10",
+ "isContainer": false,
+ "isVisible": true,
+ "objectName": "Favorite-483",
+ "sizingInfo": {
+ "geometry": {
+ "height": 1206,
+ "width": 536,
+ "x": 541,
+ "y": 0
+ },
+ "maxSize": {
+ "height": 524287,
+ "width": 524291
+ },
+ "minSize": {
+ "height": 90,
+ "width": 360
+ }
+ }
+ },
+ {
+ "guestId": "12",
+ "isContainer": false,
+ "isVisible": true,
+ "objectName": "Favorite-481",
+ "sizingInfo": {
+ "geometry": {
+ "height": 1206,
+ "width": 540,
+ "x": 1082,
+ "y": 0
+ },
+ "maxSize": {
+ "height": 524317,
+ "width": 524291
+ },
+ "minSize": {
+ "height": 438,
+ "width": 540
+ }
+ }
+ }
+ ],
+ "isContainer": true,
+ "isVisible": false,
+ "objectName": "",
+ "orientation": 1,
+ "sizingInfo": {
+ "geometry": {
+ "height": 1206,
+ "width": 1622,
+ "x": 0,
+ "y": 0
+ },
+ "maxSize": {
+ "height": 524287,
+ "width": 1048728
+ },
+ "minSize": {
+ "height": 118,
+ "width": 598
+ }
+ }
+ }
+ ],
+ "isContainer": true,
+ "isVisible": false,
+ "objectName": "",
+ "orientation": 2,
+ "sizingInfo": {
+ "geometry": {
+ "height": 1206,
+ "width": 1622,
+ "x": 0,
+ "y": 0
+ },
+ "maxSize": {
+ "height": 16777215,
+ "width": 16777215
+ },
+ "minSize": {
+ "height": 90,
+ "width": 80
+ }
+ }
+ }
+ },
+ "options": 0,
+ "screenIndex": 0,
+ "screenSize": {
+ "height": 1440,
+ "width": 2560
+ },
+ "uniqueName": "{7829427d-88e3-402e-9120-50c628dfd0bc}",
+ "windowState": 0
+ }
+ ],
+ "screenInfo": [
+ {
+ "devicePixelRatio": 1.5,
+ "geometry": {
+ "height": 1440,
+ "width": 2560,
+ "x": 0,
+ "y": 0
+ },
+ "index": 0,
+ "name": "DP-2"
+ }
+ ],
+ "serializationVersion": 3
+}
diff --git a/tests/test_resources.qrc b/tests/test_resources.qrc
index fd8b3525..40578558 100644
--- a/tests/test_resources.qrc
+++ b/tests/test_resources.qrc
@@ -4,6 +4,7 @@
layouts/overlapping-item.json
layouts/unsupported-serialization-version.json
layouts/stuck-separator.json
+ layouts/layoutEquallyCrash.json
main.qml
diff --git a/tests/tst_docks.cpp b/tests/tst_docks.cpp
index 2045efaf..114be322 100644
--- a/tests/tst_docks.cpp
+++ b/tests/tst_docks.cpp
@@ -118,6 +118,7 @@ private Q_SLOTS:
void tst_restoreMaximizedState();
void tst_shutdown();
void tst_closeDockWidgets();
+ void tst_layoutEqually();
void tst_doubleClose();
void tst_dockInternal();
void tst_maximizeAndRestore();
@@ -936,6 +937,30 @@ void TestDocks::tst_closeDockWidgets()
QCOMPARE(m->layoutWidget()->visibleCount(), 0);
}
+void TestDocks::tst_layoutEqually()
+{
+ EnsureTopLevelsDeleted e;
+
+ const QString mainWindowId = "{7829427d-88e3-402e-9120-50c628dfd0bc}";
+ auto m = createMainWindow(QSize(800, 500), MainWindowOption_None, mainWindowId);
+ m->setAffinities({ mainWindowId });
+
+ auto dock1 = createDockWidget("Favorite-481", new MyWidget2(QSize(536, 438)));
+ auto dock2 = createDockWidget("Favorite-482", new MyWidget2(QSize(229, 118)));
+ auto dock3 = createDockWidget("Favorite-483", new MyWidget2(QSize(356, 90)));
+
+ m->setContentsMargins(10, 0, 10, 0);
+
+ dock1->setAffinities({ mainWindowId });
+ dock2->setAffinities({ mainWindowId });
+ dock3->setAffinities({ mainWindowId });
+
+ LayoutSaver restorer;
+ restorer.restoreFromFile(":/layouts/layoutEquallyCrash.json");
+
+ m->layoutEqually();
+}
+
void TestDocks::tst_doubleClose()
{
EnsureTopLevelsDeleted e;