aboutsummaryrefslogtreecommitdiffstats
path: root/tests/auto/quick/qquicklayouts/data
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/quick/qquicklayouts/data')
-rw-r--r--tests/auto/quick/qquicklayouts/data/LayoutHelperLibrary.js42
-rw-r--r--tests/auto/quick/qquicklayouts/data/rowlayout/Container.qml2
-rw-r--r--tests/auto/quick/qquicklayouts/data/rowlayout/Container2.qml2
-rw-r--r--tests/auto/quick/qquicklayouts/data/rowlayout/ContainerUser.qml2
-rw-r--r--tests/auto/quick/qquicklayouts/data/rowlayout/ContainerUser2.qml2
-rw-r--r--tests/auto/quick/qquicklayouts/data/rowlayout/LayerEnabled.qml2
-rw-r--r--tests/auto/quick/qquicklayouts/data/tst_gridlayout.qml126
-rw-r--r--tests/auto/quick/qquicklayouts/data/tst_layoutproxy.qml687
-rw-r--r--tests/auto/quick/qquicklayouts/data/tst_rowlayout.qml477
-rw-r--r--tests/auto/quick/qquicklayouts/data/tst_stacklayout.qml142
10 files changed, 1469 insertions, 15 deletions
diff --git a/tests/auto/quick/qquicklayouts/data/LayoutHelperLibrary.js b/tests/auto/quick/qquicklayouts/data/LayoutHelperLibrary.js
new file mode 100644
index 0000000000..7dbbc1ad64
--- /dev/null
+++ b/tests/auto/quick/qquicklayouts/data/LayoutHelperLibrary.js
@@ -0,0 +1,42 @@
+.pragma library
+
+
+function buildLayout(layoutData, parentItem) {
+ let layout = null
+ switch (layoutData.type) {
+ case "GridLayout":
+ case "RowLayout":
+ case "ColumnLayout":
+ layout = Qt.createQmlObject("import QtQuick.Layouts\n" +
+ layoutData.type + " {}", parentItem)
+ break
+ default:
+ console.log("data.layout.type not recognized(" + layoutdata.type + ")")
+ }
+ if (layout) {
+ for (let name in layoutData) {
+ let val = layoutData[name]
+ switch (name) {
+ case "items":
+ let arrLayoutData = layoutData.items
+ for (let i = 0; i < arrLayoutData.length; i++) {
+ let layoutItemDesc = arrLayoutData[i]
+ let strProps = ""
+ for (let keyName in layoutItemDesc) {
+ strProps += "Layout." + keyName + ": " + layoutItemDesc[keyName] + ";"
+ }
+ // For some reason we cannot assign the "Layout." attached properties from
+ // here, so for now we have to serialize them as strings.
+ let rect = Qt.createQmlObject("import QtQuick\nimport QtQuick.Layouts\n\nRectangle { implicitWidth: 20; implicitHeight: 20; " + strProps + "}", layout)
+ }
+ break;
+ case "type":
+ break;
+ default:
+ layout[name] = val
+ break;
+ }
+ }
+ }
+ return layout
+}
diff --git a/tests/auto/quick/qquicklayouts/data/rowlayout/Container.qml b/tests/auto/quick/qquicklayouts/data/rowlayout/Container.qml
index 962bc78580..9a5ae0cc7a 100644
--- a/tests/auto/quick/qquicklayouts/data/rowlayout/Container.qml
+++ b/tests/auto/quick/qquicklayouts/data/rowlayout/Container.qml
@@ -1,5 +1,5 @@
// Copyright (C) 2017 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.7
import QtQuick.Layouts 1.3
diff --git a/tests/auto/quick/qquicklayouts/data/rowlayout/Container2.qml b/tests/auto/quick/qquicklayouts/data/rowlayout/Container2.qml
index a2aa7b93b2..30880e2d91 100644
--- a/tests/auto/quick/qquicklayouts/data/rowlayout/Container2.qml
+++ b/tests/auto/quick/qquicklayouts/data/rowlayout/Container2.qml
@@ -1,5 +1,5 @@
// Copyright (C) 2017 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.9
import QtQuick.Layouts 1.3
diff --git a/tests/auto/quick/qquicklayouts/data/rowlayout/ContainerUser.qml b/tests/auto/quick/qquicklayouts/data/rowlayout/ContainerUser.qml
index c324131ef6..22cf2353da 100644
--- a/tests/auto/quick/qquicklayouts/data/rowlayout/ContainerUser.qml
+++ b/tests/auto/quick/qquicklayouts/data/rowlayout/ContainerUser.qml
@@ -1,5 +1,5 @@
// Copyright (C) 2017 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.6
import QtQuick.Window 2.2
diff --git a/tests/auto/quick/qquicklayouts/data/rowlayout/ContainerUser2.qml b/tests/auto/quick/qquicklayouts/data/rowlayout/ContainerUser2.qml
index 7a5389e81e..46fbae02a0 100644
--- a/tests/auto/quick/qquicklayouts/data/rowlayout/ContainerUser2.qml
+++ b/tests/auto/quick/qquicklayouts/data/rowlayout/ContainerUser2.qml
@@ -1,5 +1,5 @@
// Copyright (C) 2017 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.6
diff --git a/tests/auto/quick/qquicklayouts/data/rowlayout/LayerEnabled.qml b/tests/auto/quick/qquicklayouts/data/rowlayout/LayerEnabled.qml
index d7ad38ffaf..ac12868627 100644
--- a/tests/auto/quick/qquicklayouts/data/rowlayout/LayerEnabled.qml
+++ b/tests/auto/quick/qquicklayouts/data/rowlayout/LayerEnabled.qml
@@ -1,5 +1,5 @@
// Copyright (C) 2018 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.7
import QtQuick.Layouts 1.3
diff --git a/tests/auto/quick/qquicklayouts/data/tst_gridlayout.qml b/tests/auto/quick/qquicklayouts/data/tst_gridlayout.qml
index 261b8a9a8e..f311cc34d6 100644
--- a/tests/auto/quick/qquicklayouts/data/tst_gridlayout.qml
+++ b/tests/auto/quick/qquicklayouts/data/tst_gridlayout.qml
@@ -1,9 +1,10 @@
// Copyright (C) 2020 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.6
import QtTest 1.0
import QtQuick.Layouts 1.1
+import "LayoutHelperLibrary.js" as LayoutHelpers
Item {
id: container
@@ -207,7 +208,7 @@ Item {
}
function test_flowLeftToRightDefaultPositions() {
- ignoreWarning("QGridLayoutEngine::addItem: Cell (1, 0) already taken");
+ ignoreWarning(/QGridLayoutEngine::addItem: Can't add .* at cell \(1, 0\) because it's already taken by .*/);
var layout = createTemporaryObject(layout_flowLeftToRightDefaultPositions_Component, container);
compare(layout.implicitWidth, 40);
compare(layout.children[0].x, 0);
@@ -1255,5 +1256,126 @@ Item {
}
verify(layout.implicitHeight > initialImplicitHeight)
}
+
+ function test_uniformCellSizes_data()
+ {
+ return [
+ {
+ tag: "hor 9/3",
+ layout: {
+ type: "GridLayout",
+ columns: 3,
+ items: [
+ {minimumWidth: 1, preferredWidth: 10, maximumWidth: 20, fillWidth: true},
+ {minimumWidth: 1, preferredWidth: 4, maximumWidth: 10, fillWidth: true},
+ {minimumWidth: 1, preferredWidth: 50, maximumWidth: 99, fillWidth: true}
+ ]
+ },
+ layoutWidth: 9,
+ expectedWidths: [3, 3, 3],
+ expectedPositions: [0, 3, 6]
+ },
+ {
+ tag: "hor 30/3",
+ layout: {
+ type: "GridLayout",
+ columns: 3,
+ items: [
+ {minimumWidth: 1, preferredWidth: 10, maximumWidth: 20, fillWidth: true},
+ {minimumWidth: 1, preferredWidth: 4, maximumWidth: 10, fillWidth: true},
+ {minimumWidth: 1, preferredWidth: 50, maximumWidth: 99, fillWidth: true}
+ ]
+ },
+ layoutWidth: 30,
+ expectedWidths: [10, 10, 10]
+ },
+ {
+ tag: "hor 60/3",
+ layout: {
+ type: "GridLayout",
+ columns: 3,
+ items: [
+ {minimumWidth: 1, preferredWidth: 10, maximumWidth: 20, fillWidth: true},
+ {minimumWidth: 1, preferredWidth: 4, maximumWidth: 10, fillWidth: true},
+ {minimumWidth: 1, preferredWidth: 50, maximumWidth: 99, fillWidth: true}
+ ]
+ },
+ layoutWidth: 60,
+ expectedWidths: [20, 10, 20], // We are beyond the maximumWidth. of the middle item,
+ expectedPositions: [0, 20, 40] // check that *cellSize* is still uniform
+ // (middle item will be left-aligned in the cell by default)
+ },
+ {
+ tag: "hor 66/3",
+ layout: {
+ type: "GridLayout",
+ columns: 3,
+ items: [
+ {minimumWidth: 1, preferredWidth: 10, maximumWidth: 20, fillWidth: true},
+ {minimumWidth: 1, preferredWidth: 4, maximumWidth: 10, fillWidth: true},
+ {minimumWidth: 1, preferredWidth: 50, maximumWidth: 99, fillWidth: true}
+ ]
+ },
+ layoutWidth: 66,
+ expectedWidths: [20, 10, 22],
+ expectedPositions: [0, 22, 44]
+ },
+ {
+ tag: "ver 66/3",
+ layout: {
+ type: "GridLayout",
+ columns: 1,
+ items: [
+ {minimumHeight: 1, preferredHeight: 10, maximumHeight: 20, fillHeight: true},
+ {minimumHeight: 1, preferredHeight: 4, maximumHeight: 10, fillHeight: true},
+ {minimumHeight: 1, preferredHeight: 50, maximumHeight: 99, fillHeight: true}
+ ]
+ },
+ layoutHeight: 66,
+ expectedHeights: [20, 10, 22],
+ // If items are too small to fit the cell, they have a default alignment of
+ // Qt::AlignLeft | Qt::AlignVCenter
+ expectedPositions: [1, 22+6, 44]
+ }
+ ];
+ }
+
+ function test_uniformCellSizes(data)
+ {
+ let layout = LayoutHelpers.buildLayout(data.layout, testCase)
+ let isHorizontal = data.hasOwnProperty("expectedWidths")
+ layout.rowSpacing = 0
+ layout.columnSpacing = 0
+ layout.uniformCellWidths = true
+ layout.uniformCellHeights = true
+ waitForPolish(layout)
+ if (data.hasOwnProperty('layoutWidth')) {
+ layout.width = data.layoutWidth
+ }
+ if (data.hasOwnProperty('layoutHeight')) {
+ layout.height = data.layoutHeight
+ }
+
+ let expectedSizes = isHorizontal ? data.expectedWidths : data.expectedHeights
+ let actualSizes = []
+ let i = 0
+ for (i = 0; i < layout.children.length; i++) {
+ let item = layout.children[i]
+ actualSizes.push(isHorizontal ? item.width : item.height)
+ }
+ compare(actualSizes, expectedSizes)
+
+ if (data.hasOwnProperty('expectedPositions')) {
+ let actualPositions = []
+ // If items are too small to fit the cell, they have a default alignment of
+ // Qt::AlignLeft | Qt::AlignVCenter
+ for (i = 0; i < layout.children.length; i++) {
+ let item = layout.children[i]
+ actualPositions.push(isHorizontal ? item.x : item.y)
+ }
+ compare(actualPositions, data.expectedPositions)
+ }
+ }
+
}
}
diff --git a/tests/auto/quick/qquicklayouts/data/tst_layoutproxy.qml b/tests/auto/quick/qquicklayouts/data/tst_layoutproxy.qml
new file mode 100644
index 0000000000..28b0f9a61c
--- /dev/null
+++ b/tests/auto/quick/qquicklayouts/data/tst_layoutproxy.qml
@@ -0,0 +1,687 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick 2.6
+import QtTest 1.0
+import QtQuick.Layouts
+
+Item {
+ id: container
+ width: 200
+ height: 200
+ TestCase {
+ id: testCase
+ name: "Tests_LayoutProxy"
+ when: windowShown
+ width: parent.width
+ height: parent.height
+
+ Component {
+ id: layout_proxy_Component
+ Item {
+ anchors.fill: container
+
+ property var rect1: Rectangle {
+ id: redRectanlge
+ parent: container
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ Layout.margins: 0
+ property var itemRect: [mapToItem(container, Qt.point(0, 0)).x,
+ mapToItem(container, Qt.point(0, 0)).y,
+ width, height]
+ color: "red"
+ }
+
+
+ property var rect2: Rectangle {
+ id: blueRectanlge
+ parent: container
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ Layout.margins: 0
+ property var itemRect: [mapToItem(container, Qt.point(0, 0)).x,
+ mapToItem(container, Qt.point(0, 0)).y,
+ width, height]
+ color: "blue"
+ }
+
+ property var layout1: RowLayout {
+ parent: container
+ anchors.fill: parent
+ spacing: 0
+ LayoutItemProxy { target: redRectanlge }
+ LayoutItemProxy { target: blueRectanlge }
+ }
+
+ property var layout2: ColumnLayout {
+ parent: container
+ anchors.fill: parent
+ spacing: 0
+ LayoutItemProxy { target: redRectanlge }
+ LayoutItemProxy { target: blueRectanlge }
+ }
+ }
+ }
+
+ function test_Proxy_simple()
+ {
+ var item = createTemporaryObject(layout_proxy_Component, container);
+
+ item.layout2.visible = false
+ item.layout1.visible = true
+
+ tryCompare(item.rect1, "itemRect", [ 0, 0, 100, 200])
+ tryCompare(item.rect2, "itemRect", [ 100, 0, 100, 200])
+
+ item.layout1.visible = false
+ item.layout2.visible = true
+
+ tryCompare(item.rect1, "itemRect", [ 0, 0, 200, 100])
+ tryCompare(item.rect2, "itemRect", [ 0, 100, 200, 100])
+
+ item.layout1.visible = true
+ item.layout2.visible = false
+
+ tryCompare(item.rect1, "itemRect", [ 0, 0, 100, 200])
+ tryCompare(item.rect2, "itemRect", [ 100, 0, 100, 200])
+
+ }
+
+ function test_Proxy_layout_destruction1()
+ {
+ var item = createTemporaryObject(layout_proxy_Component, container);
+
+ item.layout1.visible = true
+ item.layout2.visible = false
+
+ tryCompare(item.rect1, "itemRect", [ 0, 0, 100, 200])
+ tryCompare(item.rect2, "itemRect", [ 100, 0, 100, 200])
+
+ item.layout1.visible = false
+ item.layout2.visible = true
+
+ tryCompare(item.rect1, "itemRect", [ 0, 0, 200, 100])
+ tryCompare(item.rect2, "itemRect", [ 0, 100, 200, 100])
+
+ item.layout2.destroy() //destroy the layout that has control
+ wait(0) // process the scheduled delete and actually invoke the dtor
+ compare(item.layout2, null)
+ item.layout1.visible = true //check that the other one still works
+
+ tryCompare(item.rect1, "itemRect", [ 0, 0, 100, 200])
+ tryCompare(item.rect2, "itemRect", [ 100, 0, 100, 200])
+ }
+
+ function test_Proxy_layout_destruction2()
+ {
+ var item = createTemporaryObject(layout_proxy_Component, container);
+
+ item.layout1.visible = false
+ item.layout2.visible = false
+
+ //destroy both layouts while none has control
+ item.layout1.destroy()
+ item.layout2.destroy()
+ wait(0) // process the scheduled delete and actually invoke the dtor
+ //all layouts should be gone now
+ compare(item.layout1, null)
+ compare(item.layout2, null)
+ //but the rectangles should still be here
+ verify(item.rect1 !== null)
+ verify(item.rect2 !== null)
+ }
+
+ function test_Proxy_layout_destruction3()
+ {
+ var item = createTemporaryObject(layout_proxy_Component, container);
+
+ item.layout1.visible = true
+ item.layout2.visible = true
+
+ //destroy both layouts while both have control
+ item.layout1.destroy()
+ item.layout2.destroy()
+ wait(0) // process the scheduled delete and actually invoke the dtor
+ //all layouts should be gone now
+ compare(item.layout1, null)
+ compare(item.layout2, null)
+ //but the rectangles should still be here
+ verify(item.rect1 !== null)
+ verify(item.rect2 !== null)
+ }
+
+ function test_Proxy_layout_destruction_of_targets()
+ {
+ var item = createTemporaryObject(layout_proxy_Component, container);
+
+ item.layout1.visible = true
+ item.layout2.visible = false
+
+ //destroy a rectangle just to see if the proxy crashes
+ item.rect1.destroy()
+ wait(0) // process the scheduled delete and actually invoke the dtor
+ compare(item.rect1, null)
+
+ //the proxy still has the size of the item and is still there
+ tryCompare(item.layout1.children[0], "x", 0)
+ tryCompare(item.layout1.children[0], "y", 0)
+ tryCompare(item.layout1.children[0], "width", 100)
+ tryCompare(item.layout1.children[0], "height", 200)
+ //the second item is still here
+ tryCompare(item.rect2, "itemRect", [ 100, 0, 100, 200])
+ //the most important thing is that it does not crash
+
+ }
+
+ Component {
+ id: layout_proxy_Component_Three
+ Item {
+ anchors.fill: container
+ property var rect1: Rectangle {
+ id: redRectanlge
+ parent: container
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ Layout.margins: 0
+ property var itemRect: [mapToItem(container, Qt.point(0, 0)).x,
+ mapToItem(container, Qt.point(0, 0)).y,
+ width, height]
+ color: "red"
+ }
+
+ property var rect2: Rectangle {
+ id: blueRectanlge
+ parent: container
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ Layout.margins: 0
+ property var itemRect: [mapToItem(container, Qt.point(0, 0)).x,
+ mapToItem(container, Qt.point(0, 0)).y,
+ width, height]
+ color: "blue"
+ }
+
+ property var layout1: RowLayout {
+ parent: container
+ anchors.fill: parent
+ spacing: 0
+ LayoutItemProxy { target: redRectanlge }
+ LayoutItemProxy { target: blueRectanlge }
+ }
+
+ property var layout2: ColumnLayout {
+ parent: container
+ anchors.fill: parent
+ spacing: 0
+ LayoutItemProxy { target: redRectanlge }
+ LayoutItemProxy { target: blueRectanlge }
+ }
+
+ property var layout3: ColumnLayout {
+ parent: container
+ anchors.fill: parent
+ spacing: 0
+ LayoutItemProxy { target: redRectanlge }
+ LayoutItemProxy { target: blueRectanlge }
+ Rectangle {
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ color: "green"
+ }
+ }
+ }
+ }
+
+ function test_Proxy_native_item()
+ {
+ var item = createTemporaryObject(layout_proxy_Component_Three, container);
+
+ item.layout1.visible = true
+ item.layout2.visible = false
+ item.layout3.visible = false
+
+ tryCompare(item.rect1, "itemRect", [ 0, 0, 100, 200])
+ tryCompare(item.rect2, "itemRect", [ 100, 0, 100, 200])
+
+ item.layout1.visible = false
+ item.layout2.visible = true
+ item.layout3.visible = false
+
+ tryCompare(item.rect1, "itemRect", [ 0, 0, 200, 100])
+ tryCompare(item.rect2, "itemRect", [ 0, 100, 200, 100])
+
+ item.layout1.visible = false
+ item.layout2.visible = false
+ item.layout3.visible = true
+
+ tryCompare(item.rect1, "itemRect", [ 0, 0, 200, 67]) //66.6 = 67
+ tryCompare(item.rect2, "itemRect", [ 0, 67, 200, 66])
+ }
+
+
+ Component {
+ id: layout_proxy_Component_overwrite
+ Item {
+ anchors.fill: container
+ property var rect1: Rectangle {
+ id: redRectanlge
+ parent: container
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ Layout.preferredWidth: 180
+ Layout.preferredHeight: 180
+ Layout.margins: 0
+ property var itemRect: [mapToItem(container, Qt.point(0, 0)).x,
+ mapToItem(container, Qt.point(0, 0)).y,
+ width, height]
+ color: "red"
+ }
+
+ property var rect2: Rectangle {
+ id: blueRectanlge
+ parent: container
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ Layout.preferredWidth: 20
+ Layout.preferredHeight: 20
+ Layout.margins: 0
+ property var itemRect: [mapToItem(container, Qt.point(0, 0)).x,
+ mapToItem(container, Qt.point(0, 0)).y,
+ width, height]
+ color: "blue"
+ }
+
+ property var layout1: RowLayout {
+ parent: container
+ anchors.fill: parent
+ spacing: 0
+ LayoutItemProxy { target: redRectanlge }
+ LayoutItemProxy { target: blueRectanlge }
+ }
+
+ property var layout2: ColumnLayout {
+ parent: container
+ anchors.fill: parent
+ spacing: 0
+ LayoutItemProxy { target: redRectanlge }
+ LayoutItemProxy { target: blueRectanlge }
+ }
+ }
+ }
+
+ function test_Proxy_overwrite_layout_properties()
+ {
+ var item = createTemporaryObject(layout_proxy_Component_overwrite, container);
+
+ item.layout1.visible = true
+ item.layout2.visible = false
+
+ tryCompare(item.rect1, "itemRect", [ 0, 0, 180, 200])
+ tryCompare(item.rect2, "itemRect", [ 180, 0, 20, 200])
+
+ item.layout1.visible = false
+ item.layout2.visible = true
+
+ tryCompare(item.rect1, "itemRect", [ 0, 0, 200, 180])
+ tryCompare(item.rect2, "itemRect", [ 0, 180, 200, 20])
+
+ //should overwrite the rectangles preferences
+ item.layout1.children[0].Layout.preferredWidth = 100
+ item.layout1.children[0].Layout.preferredHeight = 100
+ item.layout1.children[1].Layout.preferredWidth = 100
+ item.layout1.children[1].Layout.preferredHeight = 100
+
+ item.layout1.visible = true
+ item.layout2.visible = false
+
+ tryCompare(item.rect1, "itemRect", [ 0, 0, 100, 200])
+ tryCompare(item.rect2, "itemRect", [ 100, 0, 100, 200])
+ }
+
+ Component {
+ id: layout_proxy_Component_overwrite_declarative
+ Item {
+ anchors.fill: container
+ property var rect1: Rectangle {
+ id: redRectanlge
+ parent: container
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ Layout.minimumWidth: 1
+ Layout.minimumHeight: 1
+ Layout.maximumWidth: 3
+ Layout.maximumHeight: 3
+ Layout.preferredWidth: 2
+ Layout.preferredHeight: 2
+ Layout.margins: 1
+ Layout.leftMargin: 2
+ Layout.topMargin: 3
+ Layout.rightMargin: 4
+ Layout.bottomMargin: 5
+ Layout.alignment: Qt.AlignBottom
+ property var itemRect: [mapToItem(container, Qt.point(0, 0)).x,
+ mapToItem(container, Qt.point(0, 0)).y,
+ width, height]
+ color: "red"
+ }
+
+
+ property var layout1: RowLayout {
+ parent: container
+ anchors.fill: parent
+ spacing: 0
+ LayoutItemProxy { target: redRectanlge
+ Layout.fillWidth: false
+ Layout.fillHeight: false
+ Layout.minimumWidth: 100
+ Layout.minimumHeight: 100
+ Layout.maximumWidth: 300
+ Layout.maximumHeight: 300
+ Layout.preferredWidth: 200
+ Layout.preferredHeight: 200
+ Layout.margins: 100
+ Layout.leftMargin: 200
+ Layout.topMargin: 300
+ Layout.rightMargin: 400
+ Layout.bottomMargin: 500
+ Layout.alignment: Qt.AlignTop
+ }
+ }
+
+ property var layout2: RowLayout {
+ parent: container
+ anchors.fill: parent
+ spacing: 0
+ LayoutItemProxy { target: redRectanlge }
+ }
+ }
+ }
+
+ function test_Proxy_overwrite_layout_properties_declarative()
+ {
+ var item = createTemporaryObject(layout_proxy_Component_overwrite_declarative, container);
+
+ compare(item.layout2.children[0].Layout.fillWidth, item.rect1.Layout.fillWidth)
+ compare(item.layout2.children[0].Layout.fillHeight, item.rect1.Layout.fillHeight)
+ compare(item.layout2.children[0].Layout.minimumWidth, item.rect1.Layout.minimumWidth)
+ compare(item.layout2.children[0].Layout.minimumHeight, item.rect1.Layout.minimumHeight)
+ compare(item.layout2.children[0].Layout.maximumWidth, item.rect1.Layout.maximumWidth)
+ compare(item.layout2.children[0].Layout.maximumHeight, item.rect1.Layout.maximumHeight)
+ compare(item.layout2.children[0].Layout.preferredWidth, item.rect1.Layout.preferredWidth)
+ compare(item.layout2.children[0].Layout.preferredHeight, item.rect1.Layout.preferredHeight)
+ compare(item.layout2.children[0].Layout.margins, item.rect1.Layout.margins)
+ compare(item.layout2.children[0].Layout.leftMargin, item.rect1.Layout.leftMargin)
+ compare(item.layout2.children[0].Layout.topMargin, item.rect1.Layout.topMargin)
+ compare(item.layout2.children[0].Layout.rightMargin, item.rect1.Layout.rightMargin)
+ compare(item.layout2.children[0].Layout.bottomMargin, item.rect1.Layout.bottomMargin)
+ compare(item.layout2.children[0].Layout.alignment, item.rect1.Layout.alignment)
+
+ verify(item.layout1.children[0].Layout.fillWidth != item.rect1.Layout.fillWidth)
+ verify(item.layout1.children[0].Layout.fillHeight != item.rect1.Layout.fillHeight)
+ verify(item.layout1.children[0].Layout.minimumWidth != item.rect1.Layout.minimumWidth)
+ verify(item.layout1.children[0].Layout.minimumHeight != item.rect1.Layout.minimumHeight)
+ verify(item.layout1.children[0].Layout.maximumWidth != item.rect1.Layout.maximumWidth)
+ verify(item.layout1.children[0].Layout.maximumHeight != item.rect1.Layout.maximumHeight)
+ verify(item.layout1.children[0].Layout.preferredWidth != item.rect1.Layout.preferredWidth)
+ verify(item.layout1.children[0].Layout.preferredHeight != item.rect1.Layout.preferredHeight)
+ verify(item.layout1.children[0].Layout.margins != item.rect1.Layout.margins)
+ verify(item.layout1.children[0].Layout.leftMargin != item.rect1.Layout.leftMargin)
+ verify(item.layout1.children[0].Layout.topMargin != item.rect1.Layout.topMargin)
+ verify(item.layout1.children[0].Layout.rightMargin != item.rect1.Layout.rightMargin)
+ verify(item.layout1.children[0].Layout.bottomMargin != item.rect1.Layout.bottomMargin)
+ verify(item.layout1.children[0].Layout.alignment != item.rect1.alignment)
+
+ compare(item.layout1.children[0].Layout.fillWidth, false)
+ compare(item.layout1.children[0].Layout.fillHeight, false)
+ compare(item.layout1.children[0].Layout.minimumWidth, item.rect1.Layout.minimumWidth * 100)
+ compare(item.layout1.children[0].Layout.minimumHeight, item.rect1.Layout.minimumHeight * 100)
+ compare(item.layout1.children[0].Layout.maximumWidth, item.rect1.Layout.maximumWidth * 100)
+ compare(item.layout1.children[0].Layout.maximumHeight, item.rect1.Layout.maximumHeight * 100)
+ compare(item.layout1.children[0].Layout.preferredWidth, item.rect1.Layout.preferredWidth * 100)
+ compare(item.layout1.children[0].Layout.preferredHeight, item.rect1.Layout.preferredHeight * 100)
+ compare(item.layout1.children[0].Layout.margins, item.rect1.Layout.margins * 100)
+ compare(item.layout1.children[0].Layout.leftMargin, item.rect1.Layout.leftMargin * 100)
+ compare(item.layout1.children[0].Layout.topMargin, item.rect1.Layout.topMargin * 100)
+ compare(item.layout1.children[0].Layout.rightMargin, item.rect1.Layout.rightMargin * 100)
+ compare(item.layout1.children[0].Layout.bottomMargin, item.rect1.Layout.bottomMargin * 100)
+ compare(item.layout1.children[0].Layout.alignment, Qt.AlignTop)
+ }
+
+ Component {
+ id: layout_proxy_Component_nesting
+ Item {
+ anchors.fill: container
+
+ property var rect1: Rectangle {
+ id: redRectanlge
+ parent: container
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ Layout.margins: 0
+ property var itemRect: [parent ? parent.mapToItem(container, Qt.point(x, y)).x : 0,
+ parent ? parent.mapToItem(container, Qt.point(x, y)).y : 0,
+ width, height]
+ color: "red"
+ }
+
+
+ property var rect2: Rectangle {
+ id: blueRectanlge
+ parent: container
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ Layout.margins: 0
+ property var itemRect: [parent ? parent.mapToItem(container, Qt.point(x, y)).x : 0,
+ parent ? parent.mapToItem(container, Qt.point(x, y)).y : 0,
+ width, height]
+ color: "blue"
+ }
+
+ property var rect3: Rectangle {
+ id: greenRectanlge
+ parent: container
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ Layout.margins: 0
+ property var itemRect: [parent ? parent.mapToItem(container, Qt.point(x, y)).x : 0,
+ parent ? parent.mapToItem(container, Qt.point(x, y)).y : 0,
+ width, height]
+ color: "green"
+ }
+
+ property var layout1: RowLayout {
+ parent: container
+ anchors.fill: parent
+ spacing: 0
+ LayoutItemProxy { target: redRectanlge }
+ ColumnLayout {
+ spacing: 0
+ LayoutItemProxy { target: blueRectanlge }
+ LayoutItemProxy { target: greenRectanlge }
+ }
+ }
+
+ property var layout2: ColumnLayout {
+ parent: container
+ anchors.fill: parent
+ spacing: 0
+ LayoutItemProxy { target: redRectanlge }
+ RowLayout {
+ spacing: 0
+ LayoutItemProxy { target: blueRectanlge }
+ LayoutItemProxy { target: greenRectanlge }
+ }
+ }
+ }
+ }
+
+ function test_Proxy_nesting()
+ {
+ var item = createTemporaryObject(layout_proxy_Component_nesting, container);
+
+ item.layout2.visible = false
+ item.layout1.visible = true
+
+ tryCompare(item.rect1, "itemRect", [ 0, 0, 100, 200])
+ tryCompare(item.rect2, "itemRect", [ 100, 0, 100, 100])
+ tryCompare(item.rect3, "itemRect", [ 100, 100, 100, 100])
+
+ item.layout1.visible = false
+ item.layout2.visible = true
+
+ tryCompare(item.rect1, "itemRect", [ 0, 0, 200, 100])
+ tryCompare(item.rect2, "itemRect", [ 0, 100, 100, 100])
+ tryCompare(item.rect3, "itemRect", [ 100, 100, 100, 100])
+
+ item.layout1.visible = true
+ item.layout2.visible = false
+
+ tryCompare(item.rect1, "itemRect", [ 0, 0, 100, 200])
+ tryCompare(item.rect2, "itemRect", [ 100, 0, 100, 100])
+ tryCompare(item.rect3, "itemRect", [ 100, 100, 100, 100])
+ }
+
+
+
+ Component {
+ id: layout_proxy_Component_nesting_item
+ Item {
+ anchors.fill: container
+
+ property var rect1: Rectangle {
+ id: redRectanlge
+ parent: container
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ Layout.margins: 0
+ property var itemRect: [parent ? parent.mapToItem(container, Qt.point(x, y)).x : 0,
+ parent ? parent.mapToItem(container, Qt.point(x, y)).y : 0,
+ width, height]
+ color: "red"
+ }
+
+ property var rect2: Rectangle {
+ id: blueRectanlge
+ parent: container
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ Layout.margins: 0
+ property var itemRect: [parent ? parent.mapToItem(container, Qt.point(x, y)).x : 0,
+ parent ? parent.mapToItem(container, Qt.point(x, y)).y : 0,
+ width, height]
+ color: "blue"
+ }
+
+ property var rect3: Rectangle {
+ id: greenRectanlge
+ parent: container
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ Layout.margins: 0
+ property var itemRect: [parent ? parent.mapToItem(container, Qt.point(x, y)).x : 0,
+ parent ? parent.mapToItem(container, Qt.point(x, y)).y : 0,
+ width, height]
+ color: "green"
+ }
+
+ property var rect4: Rectangle {
+ id: yellowRectangle
+ parent: container
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ Layout.margins: 0
+ property var itemRect: [parent ? parent.mapToItem(container, Qt.point(x, y)).x : 0,
+ parent ? parent.mapToItem(container, Qt.point(x, y)).y : 0,
+ width, height]
+ color: "yellow"
+ }
+
+ property var rect5: Rectangle {
+ id: brownRectangle
+ parent: container
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ Layout.margins: 0
+ property var itemRect: [parent ? parent.mapToItem(container, Qt.point(x, y)).x : 0,
+ parent ? parent.mapToItem(container, Qt.point(x, y)).y : 0,
+ width, height]
+ color: "brown"
+ }
+
+ property var layout1: RowLayout {
+ parent: container
+ anchors.fill: parent
+ spacing: 0
+ LayoutItemProxy { target: redRectanlge }
+ ColumnLayout {
+ spacing: 0
+ LayoutItemProxy { target: blueRectanlge }
+ LayoutItemProxy { target: greenRectanlge }
+ Item {
+ implicitWidth: rll.implicitWidth
+ implicitHeight: rll.implicitHeight
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ RowLayout {
+ id: rll
+ anchors.fill: parent
+ spacing: 0
+ LayoutItemProxy { target: yellowRectangle }
+ LayoutItemProxy { target: brownRectangle }
+ }
+ }
+ }
+ }
+
+ property var layout2: ColumnLayout {
+ parent: container
+ anchors.fill: parent
+ spacing: 0
+ LayoutItemProxy { target: redRectanlge }
+ RowLayout {
+ spacing: 0
+ LayoutItemProxy { target: blueRectanlge }
+ LayoutItemProxy { target: greenRectanlge }
+ Item {
+ implicitWidth: cll.implicitWidth
+ implicitHeight: cll.implicitHeight
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ ColumnLayout {
+ id: cll
+ anchors.fill: parent
+ spacing: 0
+ LayoutItemProxy { target: yellowRectangle }
+ LayoutItemProxy { target: brownRectangle }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ function test_Proxy_nesting_item()
+ {
+ var item = createTemporaryObject(layout_proxy_Component_nesting_item, container);
+
+ item.layout1.visible = true
+ item.layout2.visible = false
+
+ tryCompare(item.rect1, "itemRect", [ 0, 0, 100, 200])
+ tryCompare(item.rect2, "itemRect", [ 100, 0, 100, 67])
+ tryCompare(item.rect3, "itemRect", [ 100, 67, 100, 66])
+ tryCompare(item.rect4, "itemRect", [ 100, 133, 50, 67])
+ tryCompare(item.rect5, "itemRect", [ 150, 133, 50, 67])
+
+ item.layout2.visible = true
+ item.layout1.visible = false
+
+ tryCompare(item.rect1, "itemRect", [ 0, 0, 200, 100])
+ tryCompare(item.rect2, "itemRect", [ 0, 100, 67, 100])
+ tryCompare(item.rect3, "itemRect", [ 67, 100, 66, 100])
+ tryCompare(item.rect4, "itemRect", [ 133, 100, 67, 50])
+ tryCompare(item.rect5, "itemRect", [ 133, 150, 67, 50])
+ }
+ }
+}
diff --git a/tests/auto/quick/qquicklayouts/data/tst_rowlayout.qml b/tests/auto/quick/qquicklayouts/data/tst_rowlayout.qml
index 506893b631..56198f0d2e 100644
--- a/tests/auto/quick/qquicklayouts/data/tst_rowlayout.qml
+++ b/tests/auto/quick/qquicklayouts/data/tst_rowlayout.qml
@@ -1,9 +1,11 @@
// Copyright (C) 2020 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
-import QtQuick 2.2
-import QtTest 1.0
-import QtQuick.Layouts 1.0
+import QtQuick
+import QtTest
+import QtQuick.Controls
+import QtQuick.Layouts
+import "LayoutHelperLibrary.js" as LayoutHelpers
import org.qtproject.Test
@@ -23,6 +25,13 @@ Item {
return [item.x, item.y, item.width, item.height];
}
+ function cleanup() {
+ if (LayoutSetup.useDefaultSizePolicy) {
+ LayoutSetup.useDefaultSizePolicy = false
+ compare(LayoutSetup.useDefaultSizePolicy, false)
+ }
+ }
+
Component {
id: rectangle_Component
Rectangle {
@@ -926,6 +935,28 @@ Item {
},
layoutWidth: 28,
expectedWidths: [22, 6]
+ },{
+ tag: "resize_to_0_width",
+ layout: {
+ type: "RowLayout",
+ items: [
+ {preferredWidth: 10, fillWidth: true},
+ ]
+ },
+ layoutWidth: 0,
+ expectedWidths: [0]
+ },{
+ tag: "preferred_infinity", // Do not crash/assert when the preferred size is infinity
+ layout: {
+ type: "RowLayout",
+ items: [
+ {minimumWidth: 10, preferredWidth: Number.POSITIVE_INFINITY, fillWidth: true},
+ {minimumWidth: 20, preferredWidth: Number.POSITIVE_INFINITY, fillWidth: true},
+ ]
+ },
+ layoutWidth: 31, // Important that this is between minimum and preferred width of the layout.
+ expectedWidths: [10, 21] // The result here does not have to be exact. (This
+ // test is mostly concerned about not crashing).
}
];
}
@@ -946,6 +977,148 @@ Item {
layout.destroy();
}
+ function test_uniformCellSizes_data()
+ {
+ return [
+ {
+ tag: "hor 9/3",
+ layout: {
+ type: "RowLayout",
+ items: [
+ {minimumWidth: 1, preferredWidth: 10, maximumWidth: 20, fillWidth: true},
+ {minimumWidth: 1, preferredWidth: 4, maximumWidth: 10, fillWidth: true},
+ {minimumWidth: 1, preferredWidth: 50, maximumWidth: 99, fillWidth: true}
+ ]
+ },
+ layoutWidth: 9,
+ expectedWidths: [3, 3, 3],
+ expectedPositions: [0, 3, 6]
+ },
+ {
+ tag: "hor 30/3",
+ layout: {
+ type: "RowLayout",
+ items: [
+ {minimumWidth: 1, preferredWidth: 10, maximumWidth: 20, fillWidth: true},
+ {minimumWidth: 1, preferredWidth: 4, maximumWidth: 10, fillWidth: true},
+ {minimumWidth: 1, preferredWidth: 50, maximumWidth: 99, fillWidth: true}
+ ]
+ },
+ layoutWidth: 30,
+ expectedWidths: [10, 10, 10]
+ },
+ {
+ tag: "hor 60/3",
+ layout: {
+ type: "RowLayout",
+ items: [
+ {minimumWidth: 1, preferredWidth: 10, maximumWidth: 20, fillWidth: true},
+ {minimumWidth: 1, preferredWidth: 4, maximumWidth: 10, fillWidth: true},
+ {minimumWidth: 1, preferredWidth: 50, maximumWidth: 99, fillWidth: true}
+ ]
+ },
+ layoutWidth: 60,
+ expectedWidths: [20, 10, 20], // We are beyond the maximumWidth. of the middle item,
+ expectedPositions: [0, 20, 40] // check that *cellSize* is still uniform
+ // (middle item will be left-aligned in the cell by default)
+ },
+ {
+ tag: "hor 66/3",
+ layout: {
+ type: "RowLayout",
+ items: [
+ {minimumWidth: 1, preferredWidth: 10, maximumWidth: 20, fillWidth: true},
+ {minimumWidth: 1, preferredWidth: 4, maximumWidth: 10, fillWidth: true},
+ {minimumWidth: 1, preferredWidth: 50, maximumWidth: 99, fillWidth: true}
+ ]
+ },
+ layoutWidth: 66,
+ expectedWidths: [20, 10, 22],
+ expectedPositions: [0, 22, 44]
+ },
+ {
+ tag: "ver 66/3",
+ layout: {
+ type: "ColumnLayout",
+ items: [
+ {minimumHeight: 1, preferredHeight: 10, maximumHeight: 20, fillHeight: true},
+ {minimumHeight: 1, preferredHeight: 4, maximumHeight: 10, fillHeight: true},
+ {minimumHeight: 1, preferredHeight: 50, maximumHeight: 99, fillHeight: true}
+ ]
+ },
+ layoutHeight: 66,
+ expectedHeights: [20, 10, 22],
+ // If items are too small to fit the cell, they have a default alignment of
+ // Qt::AlignLeft | Qt::AlignVCenter
+ expectedPositions: [1, 22+6, 44]
+ }
+ ];
+ }
+
+ function test_uniformCellSizes(data)
+ {
+ let layout = LayoutHelpers.buildLayout(data.layout, testCase)
+ let isHorizontal = data.hasOwnProperty("expectedWidths")
+ layout.spacing = 0
+ layout.uniformCellSizes = true
+ waitForPolish(layout)
+ if (data.hasOwnProperty('layoutWidth')) {
+ layout.width = data.layoutWidth
+ }
+ if (data.hasOwnProperty('layoutHeight')) {
+ layout.height = data.layoutHeight
+ }
+
+ let expectedSizes = (isHorizontal ? data.expectedWidths : data.expectedHeights)
+ let actualSizes = []
+ let i = 0
+ for (i = 0; i < layout.children.length; i++) {
+ let item = layout.children[i]
+ actualSizes.push(isHorizontal ? item.width : item.height)
+ }
+ compare(actualSizes, expectedSizes)
+
+ if (data.hasOwnProperty('expectedPositions')) {
+ let actualPositions = []
+ for (i = 0; i < layout.children.length; i++) {
+ let item = layout.children[i]
+ actualPositions.push(isHorizontal ? item.x : item.y)
+ }
+ compare(actualPositions, data.expectedPositions)
+ }
+ }
+
+ Component {
+ id: uniformCellSizes_QML_Component
+ RowLayout {
+ spacing: 0
+ uniformCellSizes: true
+ Rectangle {
+ implicitWidth: 1
+ Layout.fillHeight: true
+ Layout.fillWidth: true
+ color: "red"
+ }
+ Rectangle {
+ implicitWidth: 2
+ Layout.fillHeight: true
+ Layout.fillWidth: true
+ color: "blue"
+ }
+ }
+ }
+
+ function test_uniformCellSizes_QML(data)
+ {
+ var layout = createTemporaryObject(uniformCellSizes_QML_Component, testCase)
+ layout.width = 40
+ layout.height = 20
+ let expectedWidths = [20, 20]
+ let actualWidths = [layout.children[0].width, layout.children[1].width]
+ compare(actualWidths, expectedWidths)
+ }
+
+
Component {
id: layout_alignToPixelGrid_Component
RowLayout {
@@ -1168,6 +1341,78 @@ Item {
}
Component {
+ id: sizeHintBindingLoopComp
+ Item {
+ id: root
+ anchors.fill: parent
+ property var customWidth: 100
+ RowLayout {
+ id: col
+ Item {
+ id: item
+ implicitHeight: 80
+ implicitWidth: Math.max(col2.implicitWidth, root.customWidth + 20)
+ ColumnLayout {
+ id: col2
+ width: parent.width
+ Item {
+ id: rect
+ implicitWidth: root.customWidth
+ implicitHeight: 80
+ }
+ }
+ }
+ }
+ }
+ }
+
+ function test_sizeHintBindingLoopIssue() {
+ var item = createTemporaryObject(sizeHintBindingLoopComp, container)
+ waitForRendering(item)
+ item.customWidth += 10
+ waitForRendering(item)
+ verify(!LayoutSetup.bindingLoopDetected, "Detected binding loop")
+ LayoutSetup.resetBindingLoopDetectedFlag()
+ }
+
+ Component {
+ id: polishLayoutItemComp
+ Item {
+ anchors.fill: parent
+ implicitHeight: contentLayout.implicitHeight
+ implicitWidth: contentLayout.implicitWidth
+ property alias textLayout: contentLayout
+ RowLayout {
+ width: parent.width
+ height: parent.height
+ ColumnLayout {
+ id: contentLayout
+ Layout.alignment: Qt.AlignHCenter | Qt.AlignTop
+ Layout.maximumWidth: 200
+ Repeater {
+ model: 2
+ Text {
+ Layout.fillWidth: true
+ text: "This is a long text causing line breaks to show the bug."
+ wrapMode: Text.Wrap
+ }
+ }
+ Item {
+ Layout.fillHeight: true
+ }
+ }
+ }
+ }
+ }
+
+ function test_polishLayoutItemIssue() {
+ var rootItem = createTemporaryObject(polishLayoutItemComp, container)
+ waitForRendering(rootItem)
+ var textItem = rootItem.textLayout.children[1]
+ verify(textItem.y >= rootItem.textLayout.children[0].height)
+ }
+
+ Component {
id: rearrangeNestedLayouts_Component
RowLayout {
id: layout
@@ -1268,6 +1513,44 @@ Item {
}
Component {
+ id: rearrangeInvalidatedChildInNestedLayout
+ ColumnLayout {
+ anchors.fill: parent
+ RowLayout {
+ spacing: 0
+ Text {
+ Layout.preferredWidth: 50
+ text: "Text Text Text"
+ wrapMode: Text.WordWrap
+ }
+ Rectangle {
+ color: "red";
+ Layout.preferredWidth: 50
+ Layout.preferredHeight: 20
+ }
+ Rectangle {
+ color: "green"
+ Layout.preferredHeight: 20
+ Layout.fillWidth: true
+ }
+ }
+ }
+ }
+
+ function test_rearrangeInvalidatedChildInNestedLayout() {
+ let layout = rearrangeInvalidatedChildInNestedLayout.createObject(container)
+ waitForRendering(layout)
+
+ let item1 = layout.children[0].children[0]
+ let item2 = layout.children[0].children[1]
+ let item3 = layout.children[0].children[2]
+
+ compare(item1.width, 50)
+ compare(item2.width, 50)
+ compare(item3.width, 100)
+ }
+
+ Component {
id: changeChildrenOfHiddenLayout_Component
RowLayout {
property int childCount: 1
@@ -1334,6 +1617,49 @@ Item {
compare(rootRect.item1.width, 100)
}
+ //---------------------------
+ // Layout with negative size
+ Component {
+ id: negativeSize_Component
+ Item {
+ id: rootItem
+ width: 0
+ height: 0
+ // default width x height: (0 x 0)
+ RowLayout {
+ spacing: 0
+ anchors.fill: parent
+ anchors.leftMargin: 1 // since parent size == (0 x 0), it causes layout size
+ anchors.bottomMargin: 1 // to become (-1, -1)
+ Item {
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ }
+ }
+ }
+ }
+
+ function test_negativeSize() {
+ let rootItem = createTemporaryObject(negativeSize_Component, container)
+ let rowLayout = rootItem.children[0]
+ let item = rowLayout.children[0]
+
+ const arr = [7, 1, 7, 0]
+ arr.forEach((n) => {
+ rootItem.width = n
+ rootItem.height = n
+
+ // n === 0 is special: It will cause the layout to have a
+ // negative size. In this case it will simply not rearrange its
+ // child (and leave it at its previous size, 6)
+ const expectedItemExtent = n === 0 ? 6 : n - 1
+
+ compare(item.width, expectedItemExtent)
+ compare(item.height, expectedItemExtent)
+ });
+ }
+
+
//---------------------------
Component {
id: rowlayoutWithTextItems_Component
@@ -1467,9 +1793,146 @@ Item {
compare(rootItem.maxWidth, 66)
// Should not trigger a binding loop
- verify(!BindingLoopDetector.bindingLoopDetected, "Detected binding loop")
- BindingLoopDetector.reset()
+ verify(!LayoutSetup.bindingLoopDetected, "Detected binding loop")
+ LayoutSetup.resetBindingLoopDetectedFlag()
}
- }
+
+ //---------------------------
+ // QTBUG-111792
+ Component {
+ id: rowlayoutCrashes_Component
+ RowLayout {
+ spacing: 5
+ Rectangle {
+ color: "red"
+ implicitWidth: 10
+ implicitHeight: 10
+ }
+ Rectangle {
+ color: "green"
+ implicitWidth: 10
+ implicitHeight: 10
+ }
+ }
+ }
+
+ function test_dontCrashAfterDestroyingChildren_data() {
+ return [
+ { tag: "setWidth", func: function (layout) { layout.width = 42 } },
+ { tag: "setHeight", func: function (layout) { layout.height = 42 } },
+ { tag: "getImplicitWidth", func: function (layout) { let x = layout.implicitWidth } },
+ { tag: "getImplicitHeight", func: function (layout) { let x = layout.implicitHeight } },
+ ]
+ }
+
+ function test_dontCrashAfterDestroyingChildren(data) {
+ var layout = createTemporaryObject(rowlayoutCrashes_Component, container)
+ waitForRendering(layout)
+ compare(layout.implicitWidth, 25)
+ layout.children[0].destroy() // deleteLater()
+ wait(0) // process the scheduled delete and actually invoke the dtor
+ data.func(layout) // call a function that might ultimately access the deleted item (but shouldn't)
+ }
+
+ //---------------------------
+ // Default layout size policy
+ Component {
+ id: defaultLayoutComp
+ Item {
+ id: rootItem
+ width: 110
+ height: 100
+ // Check default layout size policy
+ RowLayout {
+ spacing: 0
+ anchors.fill: parent
+ // Rectangle item - SizePolicy { Horizontal: Fixed; Vertical: Fixed }
+ Rectangle {}
+ // Button item - SizePolicy { Horizontal: Preferred; Vertical: Fixed }
+ Button {}
+ // Frame item - SizePolicy { Horizontal: Preferred; Vertical: Preferred }
+ Frame {}
+ }
+ }
+ }
+
+ function test_defaultLayoutSize() {
+ let rootItem = createTemporaryObject(defaultLayoutComp, container)
+ waitForRendering(rootItem)
+
+ let rowLayout = rootItem.children[0]
+
+ // Test default size policy disabled by default
+ compare(LayoutSetup.useDefaultSizePolicy, false)
+
+ let defaultButtonWidth = rowLayout.children[1].width
+ let defaultFrameWidth = rowLayout.children[2].width
+
+ // Enable attached properties for items and check its size
+ {
+ rowLayout.children[0].Layout.fillWidth = true
+ rowLayout.children[0].Layout.fillHeight = true
+ rowLayout.children[1].Layout.fillWidth = true
+ rowLayout.children[1].Layout.fillHeight = true
+ rowLayout.children[2].Layout.fillWidth = true
+ rowLayout.children[2].Layout.fillHeight = true
+ waitForRendering(rowLayout)
+ let isAbovePreferred = rowLayout.width >= rowLayout.implicitWidth
+ // Removing rectangle as width & implicitWidth be zero always, which makes validation of no use
+ for (let i = 1; i < rowLayout.children.length; i++) {
+ compare(rowLayout.children[i].width >= rowLayout.children[i].implicitWidth, isAbovePreferred)
+ compare(rowLayout.children[i].height, rowLayout.height)
+ }
+ }
+
+ // Destroy existing object
+ rootItem.destroy()
+
+ // Enable default size policy
+ LayoutSetup.useDefaultSizePolicy = true
+ compare(LayoutSetup.useDefaultSizePolicy, true)
+ rootItem = createTemporaryObject(defaultLayoutComp, container)
+ waitForRendering(rootItem)
+ rowLayout = rootItem.children[0]
+
+ // The default size policy would stretch button and frame accordingly
+ {
+ verify(Math.abs(rowLayout.width - (rowLayout.children[0].width + rowLayout.children[1].width + rowLayout.children[2].width)) <= 1)
+ compare(rowLayout.children[1].width < rowLayout.children[2].width, rowLayout.children[1].implicitWidth < rowLayout.children[2].implicitWidth)
+ compare(rowLayout.children[1].height, rowLayout.children[1].implicitHeight)
+ compare(rowLayout.children[2].height, rowLayout.height)
+ }
+
+ // Change the width and height of the root item to see layout size change
+ // Since default size policy for button and frame are Preferred, these items should
+ // stretch
+ {
+ let szDefaultButtonWidth = rowLayout.children[1].width
+ let szDefaultFrameWidth = rowLayout.children[2].width
+
+ rootItem.width = 210
+ rootItem.height = 200
+ waitForRendering(rootItem)
+ verify(rowLayout.children[1].width > szDefaultButtonWidth)
+ compare(rowLayout.children[1].height, rowLayout.children[1].implicitHeight)
+ verify(rowLayout.children[2].width > szDefaultFrameWidth)
+ compare(rowLayout.children[2].height, rowLayout.height)
+ }
+
+ // Disable size policies through attached properties and check item size
+ {
+ rowLayout.children[1].Layout.fillWidth = false
+ rowLayout.children[2].Layout.fillWidth = false
+ rowLayout.children[2].Layout.fillHeight = false
+ waitForRendering(rowLayout)
+ compare(rowLayout.children[1].width, defaultButtonWidth)
+ compare(rowLayout.children[2].width, defaultFrameWidth)
+ for (let index = 1; index < rowLayout.children.length; index++)
+ compare(rowLayout.children[index].height, rowLayout.children[index].implicitHeight)
+ }
+
+ rootItem.destroy()
+ }
+ }
}
diff --git a/tests/auto/quick/qquicklayouts/data/tst_stacklayout.qml b/tests/auto/quick/qquicklayouts/data/tst_stacklayout.qml
index e8d311183e..f627a90dfd 100644
--- a/tests/auto/quick/qquicklayouts/data/tst_stacklayout.qml
+++ b/tests/auto/quick/qquicklayouts/data/tst_stacklayout.qml
@@ -1,5 +1,5 @@
// Copyright (C) 2020 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick 2.15
import QtTest 1.15
@@ -724,6 +724,146 @@ Item {
compare(layout.num_onCountChanged, 1)
}
+ // QTBUG-111902
+ Component {
+ id: stackComponent
+ Loader {
+ id: loader
+ asynchronous: true
+ sourceComponent: StackLayout {
+ id: stackLayout
+ Repeater {
+ model: 3
+ Item {
+ required property int index
+ }
+ }
+ }
+ }
+ }
+
+ function test_loadStackLayoutAsynchronously() {
+ var loaderObj = stackComponent.createObject(container)
+ // Check for loader status to be ready
+ tryCompare(loaderObj, 'status', 1)
+ // Get stack layout object
+ var stackLayoutObj = loaderObj.item
+ // Check repeater index of child object
+ compare(stackLayoutObj.children[0].index, 0)
+ compare(stackLayoutObj.children[1].index, 1)
+ compare(stackLayoutObj.children[2].index, 2)
+ // Check stack layout attached property index
+ compare(stackLayoutObj.children[0].StackLayout.index, 0)
+ compare(stackLayoutObj.children[1].StackLayout.index, 1)
+ compare(stackLayoutObj.children[2].StackLayout.index, 2)
+ }
+
+ Component {
+ id: test_repeater_Component
+
+ Item {
+ property alias stackLayout : stackLayout
+ property var model : ListModel {
+ /*
+ * We cannot programmatically reorder siblings (QQuickItem::stackBefore()
+ * and QQuickItem::stackAfter() are not not available to QML, and we cannot
+ * alter the Item::children property to reorder siblings)
+ * Therefore, we have to go through the hoops with a ListModel and Repeater in
+ * order to trigger sibling reordering, just as reported in QTBUG-112691.
+ * Adding an item to a specific index (with model.insert()), will be done in
+ * two steps:
+ * 1. Append an Item to be the last of the siblings
+ * 2. Reorder that Rectangle to be at the correct child index that corresponds
+ * to the index given to model.insert()
+ *
+ * Adding an item to a specific index will therefore test sibling reordering
+ */
+ id: listModel
+ }
+ StackLayout {
+ id: stackLayout
+ anchors.fill: parent
+ Layout.fillHeight: true
+ Layout.fillWidth: true
+ Repeater {
+ id: repeater
+ model:listModel
+ delegate: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 100
+ objectName: model.color
+ color: model.color
+ }
+ }
+ }
+ }
+ }
+
+ function test_repeater() {
+ let item = createTemporaryObject(test_repeater_Component, container)
+ let layout = item.stackLayout
+ let model = item.model
+ function verifyVisibilityOfItems() {
+ for (let i = 0; i < layout.count; ++i) {
+ compare(layout.children[i].visible, layout.currentIndex === i)
+ }
+ }
+
+ compare(layout.currentIndex, -1)
+ compare(layout.count, 0)
+ model.append({ "color": "red" })
+ compare(layout.currentIndex, 0)
+ compare(layout.count, 1)
+ verifyVisibilityOfItems()
+
+ model.append({ "color": "green" })
+ compare(layout.currentIndex, 0)
+ compare(layout.count, 2)
+ verifyVisibilityOfItems()
+
+ model.append({ "color": "blue" })
+ compare(layout.currentIndex, 0)
+ compare(layout.count, 3)
+ verifyVisibilityOfItems()
+
+ model.insert(0, { "color": "black" })
+ compare(layout.currentIndex, 1)
+ compare(layout.count, 4)
+ verifyVisibilityOfItems()
+
+ // An implicit currentIndex will reset back to -1 if
+ // the StackLayout is empty
+ model.clear()
+ compare(layout.currentIndex, -1)
+ compare(layout.count, 0)
+
+ // set explicit index to out of bounds
+ layout.currentIndex = 1
+ compare(layout.currentIndex, 1)
+ compare(layout.count, 0)
+ verifyVisibilityOfItems()
+
+ model.append({ "color": "red" })
+ compare(layout.currentIndex, 1)
+ compare(layout.count, 1)
+ verifyVisibilityOfItems()
+
+ model.append({ "color": "green" })
+ compare(layout.currentIndex, 1)
+ compare(layout.count, 2)
+ verifyVisibilityOfItems()
+
+ model.insert(1, { "color": "brown" })
+ compare(layout.currentIndex, 2)
+ compare(layout.count, 3)
+ verifyVisibilityOfItems()
+
+ // remove red, currentIndex should decrease
+ model.remove(0, 1)
+ compare(layout.currentIndex, 1)
+ compare(layout.count, 2)
+ verifyVisibilityOfItems()
+ }
}
}