aboutsummaryrefslogtreecommitdiffstats
path: root/tests/auto/quick/qquicklayouts/data/tst_rowlayout.qml
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/quick/qquicklayouts/data/tst_rowlayout.qml')
-rw-r--r--tests/auto/quick/qquicklayouts/data/tst_rowlayout.qml766
1 files changed, 696 insertions, 70 deletions
diff --git a/tests/auto/quick/qquicklayouts/data/tst_rowlayout.qml b/tests/auto/quick/qquicklayouts/data/tst_rowlayout.qml
index 87e0a01df2..d31a0b0fb8 100644
--- a/tests/auto/quick/qquicklayouts/data/tst_rowlayout.qml
+++ b/tests/auto/quick/qquicklayouts/data/tst_rowlayout.qml
@@ -1,56 +1,13 @@
-/****************************************************************************
-**
-** Copyright (C) 2020 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:BSD$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** BSD License Usage
-** Alternatively, you may use this file under the terms of the BSD license
-** as follows:
-**
-** "Redistribution and use in source and binary forms, with or without
-** modification, are permitted provided that the following conditions are
-** met:
-** * Redistributions of source code must retain the above copyright
-** notice, this list of conditions and the following disclaimer.
-** * Redistributions in binary form must reproduce the above copyright
-** notice, this list of conditions and the following disclaimer in
-** the documentation and/or other materials provided with the
-** distribution.
-** * Neither the name of The Qt Company Ltd nor the names of its
-** contributors may be used to endorse or promote products derived
-** from this software without specific prior written permission.
-**
-**
-** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-import QtQuick 2.2
-import QtTest 1.0
-import QtQuick.Layouts 1.0
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+import QtQuick
+import QtTest
+import QtQuick.Controls
+import QtQuick.Layouts
+import "LayoutHelperLibrary.js" as LayoutHelpers
+
+import org.qtproject.Test
Item {
id: container
@@ -68,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 {
@@ -77,6 +41,18 @@ Item {
}
Component {
+ id: layout_rowLayout_Component
+ RowLayout {
+ }
+ }
+
+ Component {
+ id: layout_columnLayout_Component
+ ColumnLayout {
+ }
+ }
+
+ Component {
id: itemsWithAnchorsLayout_Component
RowLayout {
spacing: 2
@@ -126,7 +102,7 @@ Item {
function test_warnAboutLayoutItemsWithAnchors()
{
- var regex = new RegExp("QML Item: Detected anchors on an item that is managed by a layout. "
+ var regex = new RegExp(".*: Detected anchors on an item that is managed by a layout. "
+ "This is undefined behavior; use Layout.alignment instead.")
for (var i = 0; i < 7; ++i) {
ignoreWarning(regex)
@@ -322,11 +298,12 @@ Item {
compare(row.implicitHeight, 6);
var r2 = row.children[2]
r2.implicitWidth = 20
- verify(waitForRendering(row))
+ waitForItemPolished(row)
compare(row.implicitWidth, 50 + 10 + 20)
var r3 = rectangle_Component.createObject(container)
r3.implicitWidth = 30
r3.parent = row
+ waitForItemPolished(row)
compare(row.implicitWidth, 50 + 10 + 20 + 30)
row.destroy()
}
@@ -443,12 +420,14 @@ Item {
compare(layout.implicitHeight, 0)
var rect0 = layoutItem_Component.createObject(layout)
+ waitForItemPolished(layout)
compare(layout.implicitWidth, 20)
compare(layout.implicitHeight, 20)
var rect1 = layoutItem_Component.createObject(layout)
rect1.Layout.preferredWidth = 30;
rect1.Layout.preferredHeight = 30;
+ waitForItemPolished(layout)
compare(layout.implicitWidth, 50)
compare(layout.implicitHeight, 30)
@@ -458,25 +437,30 @@ Item {
var rect3 = layoutItem_Component.createObject(col)
rect3.Layout.fillHeight = true
+ waitForItemPolished(layout)
compare(layout.implicitWidth, 70)
compare(col.implicitHeight, 40)
compare(layout.implicitHeight, 40)
rect3.destroy()
wait(0) // this will hopefully effectuate the destruction of the object
+ waitForItemPolished(layout)
col.destroy()
wait(0)
+ waitForItemPolished(layout)
compare(layout.implicitWidth, 50)
compare(layout.implicitHeight, 30)
rect0.destroy()
wait(0)
+ waitForItemPolished(layout)
compare(layout.implicitWidth, 30)
compare(layout.implicitHeight, 30)
rect1.destroy()
wait(0)
+ waitForItemPolished(layout)
compare(layout.implicitWidth, 0)
compare(layout.implicitHeight, 0)
}
@@ -523,7 +507,7 @@ Item {
var layout = layout_alignment_Component.createObject(container);
layout.width = 100;
layout.height = 40;
-
+ waitForItemPolished(layout)
compare(itemRect(layout.children[0]), [ 0, 0, 20, 40]);
compare(itemRect(layout.children[1]), [20, 10, 20, 20]);
compare(itemRect(layout.children[2]), [40, 0, 20, 20]);
@@ -532,6 +516,102 @@ Item {
layout.destroy();
}
+
+ function buildLayout(layout, arrLayoutData) {
+ for (let i = 0; i < arrLayoutData.length; i++) {
+ let layoutItemDesc = arrLayoutData[i]
+ let rect = layoutItem_Component.createObject(layout)
+ for (let keyName in layoutItemDesc) {
+ rect.Layout[keyName] = layoutItemDesc[keyName]
+ }
+ }
+ }
+
+ function test_dynamicAlignment_data()
+ {
+ return [
+ {
+ tag: "simple",
+
+ layout: {
+ type: "RowLayout",
+ items: [
+ {preferredWidth: 30, preferredHeight: 20, fillHeight: true},
+ {preferredWidth: 30, preferredHeight: 20},
+ ]
+ },
+ expectedGeometries: [
+ [ 0, 0, 30, 60],
+ [30, 20, 30, 20]
+ ]
+ },{
+ tag: "valign",
+ layout: {
+ type: "RowLayout",
+ items: [
+ {preferredWidth: 12, preferredHeight: 20, fillHeight: true},
+ {preferredWidth: 12, preferredHeight: 20},
+ {preferredWidth: 12, preferredHeight: 20, alignment: Qt.AlignTop},
+ {preferredWidth: 12, preferredHeight: 20, alignment: Qt.AlignVCenter},
+ {preferredWidth: 12, preferredHeight: 20, alignment: Qt.AlignBottom}
+ ]
+ },
+ expectedGeometries: [
+ [ 0, 0, 12, 60],
+ [12, 20, 12, 20],
+ [24, 0, 12, 20],
+ [36, 20, 12, 20],
+ [48, 40, 12, 20]
+ ]
+ },{
+ tag: "halign",
+ layout: {
+ type: "ColumnLayout",
+ items: [
+ {preferredWidth: 20, preferredHeight: 12, fillWidth: true},
+ {preferredWidth: 20, preferredHeight: 12},
+ {preferredWidth: 20, preferredHeight: 12, alignment: Qt.AlignLeft},
+ {preferredWidth: 20, preferredHeight: 12, alignment: Qt.AlignHCenter},
+ {preferredWidth: 20, preferredHeight: 12, alignment: Qt.AlignRight}
+ ]
+ },
+ expectedGeometries: [
+ [ 0, 0, 60, 12],
+ [ 0, 12, 20, 12],
+ [ 0, 24, 20, 12],
+ [20, 36, 20, 12],
+ [40, 48, 20, 12]
+ ]
+ }
+ ]
+ }
+
+ function test_dynamicAlignment(data)
+ {
+ let layout
+ switch (data.layout.type) {
+ case "RowLayout":
+ layout = createTemporaryObject(layout_rowLayout_Component, container)
+ break
+ case "ColumnLayout":
+ layout = createTemporaryObject(layout_columnLayout_Component, container)
+ break
+ default:
+ console.log("data.layout.type not recognized(" + data.layout.type + ")")
+ }
+ layout.spacing = 0
+ buildLayout(layout, data.layout.items)
+ layout.width = 60
+ layout.height = 60 // divides in 1/2/3/4/5/6
+ waitForItemPolished(layout)
+
+ for (let i = 0; i < layout.children.length; ++i) {
+ let itm = layout.children[i]
+ compare(itemRect(itm), data.expectedGeometries[i])
+ }
+ }
+
+
Component {
id: layout_sizeHintNormalization_Component
GridLayout {
@@ -580,7 +660,7 @@ Item {
layout.children[0].Layout.minimumWidth = data.widthHints[0];
layout.children[0].Layout.preferredWidth = data.widthHints[1];
layout.children[0].Layout.maximumWidth = data.widthHints[2];
- wait(0); // Trigger processEvents() (allow LayoutRequest to be processed)
+ waitForItemPolished(layout)
var normalizedResult = [layout.Layout.minimumWidth, layout.implicitWidth, layout.Layout.maximumWidth]
compare(normalizedResult, data.expected);
layout.destroy();
@@ -667,6 +747,7 @@ Item {
child.Layout.preferredWidth = data.childHints[1]
child.Layout.maximumWidth = data.childHints[2]
+ waitForItemPolished(layout)
var effectiveSizeHintResult = [layout.Layout.minimumWidth, layout.implicitWidth, layout.Layout.maximumWidth]
compare(effectiveSizeHintResult, data.expected)
layout.destroy()
@@ -677,38 +758,49 @@ Item {
var child = layout.children[0].children[0]
child.Layout.minimumWidth = -1
+ waitForItemPolished(layout)
compare(itemSizeHints(layout), [0, 2, 3])
child.Layout.preferredWidth = -1
+ waitForItemPolished(layout)
compare(itemSizeHints(layout), [0, 1, 3])
child.Layout.maximumWidth = -1
+ waitForItemPolished(layout)
compare(itemSizeHints(layout), [0, 1, Number.POSITIVE_INFINITY])
layout.Layout.maximumWidth = 1000
+ waitForItemPolished(layout)
compare(itemSizeHints(layout), [0, 1, 1000])
layout.Layout.maximumWidth = -1
+ waitForItemPolished(layout)
compare(itemSizeHints(layout), [0, 1, Number.POSITIVE_INFINITY])
layout.implicitWidthChangedCount = 0
child.Layout.minimumWidth = 10
+ waitForItemPolished(layout)
compare(itemSizeHints(layout), [10, 10, Number.POSITIVE_INFINITY])
compare(layout.implicitWidthChangedCount, 1)
child.Layout.preferredWidth = 20
+ waitForItemPolished(layout)
compare(itemSizeHints(layout), [10, 20, Number.POSITIVE_INFINITY])
compare(layout.implicitWidthChangedCount, 2)
child.Layout.maximumWidth = 30
+ waitForItemPolished(layout)
compare(itemSizeHints(layout), [10, 20, 30])
compare(layout.implicitWidthChangedCount, 2)
child.Layout.maximumWidth = 15
+ waitForItemPolished(layout)
compare(itemSizeHints(layout), [10, 15, 15])
compare(layout.implicitWidthChangedCount, 3)
child.Layout.maximumWidth = 30
+ waitForItemPolished(layout)
compare(itemSizeHints(layout), [10, 20, 30])
compare(layout.implicitWidthChangedCount, 4)
layout.Layout.maximumWidth = 29
+ waitForItemPolished(layout)
compare(layout.Layout.maximumWidth, 29)
layout.Layout.maximumWidth = -1
compare(layout.Layout.maximumWidth, 30)
@@ -769,19 +861,13 @@ Item {
var r = layout.children[0]
r.Layout.preferredWidth = 20
r.Layout.preferredHeight = 30
+ waitForItemPolished(layout)
compare(layout.implicitWidth, 20)
compare(layout.implicitHeight, 30)
layout.destroy();
}
-
- Component {
- id: layout_rowLayout_Component
- RowLayout {
- }
- }
-
function test_stretchItem_data()
{
return [
@@ -816,7 +902,7 @@ Item {
r.Layout.minimumWidth = data.minimumWidth
if (data.maximumWidth !== undefined)
r.Layout.maximumWidth = data.maximumWidth
-
+ waitForItemPolished(layout)
layout.width = 100
compare(r.width, data.expectedWidth)
@@ -824,6 +910,215 @@ Item {
layout.destroy();
}
+ function test_distribution_data()
+ {
+ return [
+ {
+ tag: "one",
+ layout: {
+ type: "RowLayout",
+ items: [
+ {minimumWidth: 1, preferredWidth: 10, maximumWidth: 20, fillWidth: true},
+ {minimumWidth: 1, preferredWidth: 4, maximumWidth: 10, fillWidth: true},
+ ]
+ },
+ layoutWidth: 28,
+ expectedWidths: [20, 8]
+ },{
+ tag: "two",
+ layout: {
+ type: "RowLayout",
+ items: [
+ {minimumWidth: 1, preferredWidth: 10, horizontalStretchFactor: 4, fillWidth: true},
+ {minimumWidth: 1, preferredWidth: 4, horizontalStretchFactor: 1, fillWidth: true},
+ ]
+ },
+ 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).
+ }
+ ];
+ }
+
+ function test_distribution(data)
+ {
+ var layout = layout_rowLayout_Component.createObject(container)
+ layout.spacing = 0
+ buildLayout(layout, data.layout.items)
+ waitForPolish(layout)
+ layout.width = data.layoutWidth
+
+ let actualWidths = []
+ for (let i = 0; i < layout.children.length; i++) {
+ actualWidths.push(layout.children[i].width)
+ }
+ compare(actualWidths, data.expectedWidths)
+ 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 {
@@ -994,16 +1289,21 @@ Item {
compare(grid.visible, true) // LAYOUT SHOWN
compare(grid.implicitWidth, 2);
child.visible = false
+ waitForItemPolished(layout)
compare(grid.implicitWidth, 0);
child.visible = true
+ waitForItemPolished(layout)
compare(grid.implicitWidth, 2);
grid.visible = false // LAYOUT HIDDEN
+ waitForItemPolished(layout)
compare(grid.implicitWidth, 2);
child.visible = false
expectFail('', 'If GridLayout is hidden, GridLayout is not notified when child is explicitly hidden')
+ waitForItemPolished(grid)
compare(grid.implicitWidth, 0);
child.visible = true
+ waitForItemPolished(grid)
compare(grid.implicitWidth, 2);
layout.destroy();
@@ -1041,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
@@ -1207,6 +1579,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
@@ -1262,13 +1677,224 @@ Item {
function test_dependentWidth_QTBUG_87253()
{
- var warningMsg = new RegExp("Qt Quick Layouts: Detected recursive rearrange. "
- + "Aborting after two iterations.")
- for (var i = 0; i < 10; ++i) {
- ignoreWarning(warningMsg)
- }
var layout = createTemporaryObject(layout_dependentWidth_QTBUG_87253_Component, container)
+ // Do not crash
waitForRendering(layout)
}
+
+ //---------------------------
+ Component {
+ id: rowlayoutWithRectangle_Component
+ RowLayout {
+ property alias spy : signalSpy
+ Rectangle {
+ color: "red"
+ implicitWidth: 10
+ implicitHeight: 10
+ }
+ SignalSpy {
+ id: signalSpy
+ target: parent
+ signalName: "implicitWidthChanged"
+ }
+ }
+ }
+
+ // QTBUG-93988
+ function test_ensurePolished() {
+ var layout = createTemporaryObject(rowlayoutWithRectangle_Component, container)
+ compare(layout.spy.count, 1)
+ waitForRendering(layout)
+ compare(layout.implicitWidth, 10)
+ var r0 = layout.children[0]
+
+ r0.implicitWidth = 42
+ compare(layout.spy.count, 1) // Not yet updated, awaiting PolishEvent...
+ layout.ensurePolished()
+ compare(layout.spy.count, 2)
+ compare(layout.implicitWidth, 42)
+ }
+
+ //---------------------------
+ Component {
+ id: rowlayoutCausesBindingLoop_Component
+ Item {
+ id: root
+ width: 100
+ height: 100
+ property real maxWidth : Math.max(header.implicitWidth, content.implicitWidth)
+
+ RowLayout {
+ id: header
+ y: 0
+
+ Rectangle {
+ color: "red"
+ implicitWidth: 10
+ implicitHeight: 10
+ }
+ }
+ Rectangle {
+ id: content
+ y: 10
+ implicitWidth: 42
+ implicitHeight: 10
+ color: Qt.rgba(root.maxWidth/66, 0, 1, 1)
+ }
+ }
+ }
+ function test_bindingLoop() {
+ var rootItem = createTemporaryObject(rowlayoutCausesBindingLoop_Component, container)
+ waitForRendering(rootItem)
+ var header = rootItem.children[0]
+ var content = rootItem.children[1]
+ var rect = header.children[0]
+ rect.implicitWidth = 20
+ content.implicitWidth = 66
+ waitForItemPolished(header)
+ compare(rootItem.maxWidth, 66)
+
+ // Should not trigger a binding loop
+ 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()
+ }
}
}