1635 lines
67 KiB
QML
1635 lines
67 KiB
QML
// Copyright (C) 2020 The Qt Company Ltd.
|
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
|
|
|
import QtQuick 2.2
|
|
import QtTest 1.0
|
|
import QtQuick.Layouts 1.0
|
|
import "LayoutHelperLibrary.js" as LayoutHelpers
|
|
|
|
import org.qtproject.Test
|
|
|
|
Item {
|
|
id: container
|
|
width: 200
|
|
height: 200
|
|
TestCase {
|
|
id: testCase
|
|
name: "Tests_RowLayout"
|
|
when: windowShown
|
|
width: 200
|
|
height: 200
|
|
|
|
function itemRect(item)
|
|
{
|
|
return [item.x, item.y, item.width, item.height];
|
|
}
|
|
|
|
Component {
|
|
id: rectangle_Component
|
|
Rectangle {
|
|
width: 100
|
|
height: 50
|
|
}
|
|
}
|
|
|
|
Component {
|
|
id: layout_rowLayout_Component
|
|
RowLayout {
|
|
}
|
|
}
|
|
|
|
Component {
|
|
id: layout_columnLayout_Component
|
|
ColumnLayout {
|
|
}
|
|
}
|
|
|
|
Component {
|
|
id: itemsWithAnchorsLayout_Component
|
|
RowLayout {
|
|
spacing: 2
|
|
Item {
|
|
anchors.fill: parent
|
|
implicitWidth: 10
|
|
implicitHeight: 10
|
|
}
|
|
Item {
|
|
anchors.centerIn: parent
|
|
implicitWidth: 10
|
|
implicitHeight: 10
|
|
}
|
|
Item {
|
|
anchors.left: parent.left
|
|
implicitWidth: 10
|
|
implicitHeight: 10
|
|
}
|
|
Item {
|
|
anchors.right: parent.right
|
|
implicitWidth: 10
|
|
implicitHeight: 10
|
|
}
|
|
Item {
|
|
anchors.top: parent.top
|
|
implicitWidth: 10
|
|
implicitHeight: 10
|
|
}
|
|
Item {
|
|
anchors.bottom: parent.bottom
|
|
implicitWidth: 10
|
|
implicitHeight: 10
|
|
}
|
|
Item {
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
implicitWidth: 10
|
|
implicitHeight: 10
|
|
}
|
|
Item {
|
|
anchors.margins: 42 // although silly, it should not cause a warning from the Layouts POV
|
|
implicitWidth: 10
|
|
implicitHeight: 10
|
|
}
|
|
}
|
|
}
|
|
|
|
function test_warnAboutLayoutItemsWithAnchors()
|
|
{
|
|
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)
|
|
}
|
|
var layout = itemsWithAnchorsLayout_Component.createObject(container)
|
|
waitForRendering(layout)
|
|
layout.destroy()
|
|
}
|
|
|
|
function test_fixedAndExpanding() {
|
|
var test_layoutStr =
|
|
'import QtQuick 2.2; \
|
|
import QtQuick.Layouts 1.0; \
|
|
RowLayout { \
|
|
id: row; \
|
|
width: 15; \
|
|
spacing: 0; \
|
|
property alias r1: _r1; \
|
|
Rectangle { \
|
|
id: _r1; \
|
|
width: 5; \
|
|
height: 10; \
|
|
color: "#8080ff"; \
|
|
Layout.fillWidth: false \
|
|
} \
|
|
property alias r2: _r2; \
|
|
Rectangle { \
|
|
id: _r2; \
|
|
width: 10; \
|
|
height: 20; \
|
|
color: "#c0c0ff"; \
|
|
Layout.fillWidth: true \
|
|
} \
|
|
} '
|
|
|
|
var lay = Qt.createQmlObject(test_layoutStr, container, '');
|
|
tryCompare(lay, 'implicitWidth', 15);
|
|
compare(lay.implicitHeight, 20);
|
|
compare(lay.height, 20);
|
|
lay.width = 30
|
|
compare(lay.r1.x, 0);
|
|
compare(lay.r1.width, 5);
|
|
compare(lay.r2.x, 5);
|
|
compare(lay.r2.width, 25);
|
|
lay.destroy()
|
|
}
|
|
|
|
function test_allExpanding() {
|
|
var test_layoutStr =
|
|
'import QtQuick 2.2; \
|
|
import QtQuick.Layouts 1.0; \
|
|
RowLayout { \
|
|
id: row; \
|
|
width: 15; \
|
|
spacing: 0; \
|
|
property alias r1: _r1; \
|
|
Rectangle { \
|
|
id: _r1; \
|
|
width: 5; \
|
|
height: 10; \
|
|
color: "#8080ff"; \
|
|
Layout.fillWidth: true \
|
|
} \
|
|
property alias r2: _r2; \
|
|
Rectangle { \
|
|
id: _r2; \
|
|
width: 10; \
|
|
height: 20; \
|
|
color: "#c0c0ff"; \
|
|
Layout.fillWidth: true \
|
|
} \
|
|
} '
|
|
|
|
var tmp = Qt.createQmlObject(test_layoutStr, container, '');
|
|
waitForRendering(tmp)
|
|
compare(tmp.implicitWidth, 15);
|
|
compare(tmp.height, 20);
|
|
tmp.width = 30
|
|
compare(tmp.r1.width, 10);
|
|
compare(tmp.r2.width, 20);
|
|
compare(tmp.Layout.minimumWidth, 0)
|
|
compare(tmp.Layout.maximumWidth, Number.POSITIVE_INFINITY)
|
|
tmp.destroy()
|
|
}
|
|
|
|
function test_initialNestedLayouts() {
|
|
var test_layoutStr =
|
|
'import QtQuick 2.2; \
|
|
import QtQuick.Layouts 1.0; \
|
|
ColumnLayout { \
|
|
id : col; \
|
|
property alias row: _row; \
|
|
objectName: "col"; \
|
|
anchors.fill: parent; \
|
|
RowLayout { \
|
|
id : _row; \
|
|
property alias r1: _r1; \
|
|
property alias r2: _r2; \
|
|
objectName: "row"; \
|
|
spacing: 0; \
|
|
Rectangle { \
|
|
id: _r1; \
|
|
color: "red"; \
|
|
implicitWidth: 50; \
|
|
implicitHeight: 20; \
|
|
} \
|
|
Rectangle { \
|
|
id: _r2; \
|
|
color: "green"; \
|
|
implicitWidth: 50; \
|
|
implicitHeight: 20; \
|
|
Layout.fillWidth: true; \
|
|
} \
|
|
} \
|
|
} '
|
|
var col = Qt.createQmlObject(test_layoutStr, container, '');
|
|
tryCompare(col, 'width', 200);
|
|
tryCompare(col.row, 'width', 200);
|
|
tryCompare(col.row.r1, 'width', 50);
|
|
tryCompare(col.row.r2, 'width', 150);
|
|
col.destroy()
|
|
}
|
|
|
|
Component {
|
|
id: propagateImplicitWidthToParent_Component
|
|
Item {
|
|
width: 200
|
|
height: 20
|
|
|
|
// These might trigger a updateLayoutItems() before its component is completed...
|
|
implicitWidth: row.implicitWidth
|
|
implicitHeight: row.implicitHeight
|
|
RowLayout {
|
|
id : row
|
|
anchors.fill: parent
|
|
property alias r1: _r1
|
|
property alias r2: _r2
|
|
spacing: 0
|
|
Rectangle {
|
|
id: _r1
|
|
color: "red"
|
|
implicitWidth: 50
|
|
implicitHeight: 20
|
|
}
|
|
Rectangle {
|
|
id: _r2
|
|
color: "green"
|
|
implicitWidth: 50
|
|
implicitHeight: 20
|
|
Layout.fillWidth: true
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function test_propagateImplicitWidthToParent() {
|
|
var item = createTemporaryObject(propagateImplicitWidthToParent_Component, container)
|
|
var row = item.children[0]
|
|
compare(row.width, 200)
|
|
compare(itemRect(row.r1), [0, 0, 50, 20])
|
|
compare(itemRect(row.r2), [50, 0, 150, 20])
|
|
}
|
|
|
|
function test_implicitSize() {
|
|
var test_layoutStr =
|
|
'import QtQuick 2.2; \
|
|
import QtQuick.Layouts 1.0; \
|
|
RowLayout { \
|
|
id: row; \
|
|
objectName: "row"; \
|
|
spacing: 0; \
|
|
height: 30; \
|
|
anchors.left: parent.left; \
|
|
anchors.right: parent.right; \
|
|
Rectangle { \
|
|
color: "red"; \
|
|
height: 2; \
|
|
Layout.minimumWidth: 50; \
|
|
} \
|
|
Rectangle { \
|
|
color: "green"; \
|
|
width: 10; \
|
|
Layout.minimumHeight: 4; \
|
|
} \
|
|
Rectangle { \
|
|
implicitWidth: 1000; \
|
|
Layout.maximumWidth: 40; \
|
|
implicitHeight: 6 \
|
|
} \
|
|
} '
|
|
var row = Qt.createQmlObject(test_layoutStr, container, '');
|
|
compare(row.implicitWidth, 50 + 10 + 40);
|
|
compare(row.implicitHeight, 6);
|
|
var r2 = row.children[2]
|
|
r2.implicitWidth = 20
|
|
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()
|
|
}
|
|
|
|
function test_countGeometryChanges() {
|
|
var test_layoutStr =
|
|
'import QtQuick 2.2; \
|
|
import QtQuick.Layouts 1.0; \
|
|
ColumnLayout { \
|
|
id : col; \
|
|
property alias row: _row; \
|
|
objectName: "col"; \
|
|
anchors.fill: parent; \
|
|
RowLayout { \
|
|
id : _row; \
|
|
property alias r1: _r1; \
|
|
property alias r2: _r2; \
|
|
objectName: "row"; \
|
|
spacing: 0; \
|
|
property int counter : 0; \
|
|
onWidthChanged: { ++counter; } \
|
|
Rectangle { \
|
|
id: _r1; \
|
|
color: "red"; \
|
|
implicitWidth: 50; \
|
|
implicitHeight: 20; \
|
|
property int counter : 0; \
|
|
onWidthChanged: { ++counter; } \
|
|
Layout.fillWidth: true; \
|
|
} \
|
|
Rectangle { \
|
|
id: _r2; \
|
|
color: "green"; \
|
|
implicitWidth: 50; \
|
|
implicitHeight: 20; \
|
|
property int counter : 0; \
|
|
onWidthChanged: { ++counter; } \
|
|
Layout.fillWidth: true; \
|
|
} \
|
|
} \
|
|
} '
|
|
var col = Qt.createQmlObject(test_layoutStr, container, '');
|
|
compare(col.width, 200);
|
|
compare(col.row.width, 200);
|
|
compare(col.row.r1.width, 100);
|
|
compare(col.row.r2.width, 100);
|
|
compare(col.row.r1.counter, 1);
|
|
compare(col.row.r2.counter, 1);
|
|
verify(col.row.counter <= 2);
|
|
col.destroy()
|
|
}
|
|
|
|
function test_dynamicSizeAdaptationsForInitiallyInvisibleItemsInLayout() {
|
|
var test_layoutStr =
|
|
'import QtQuick 2.2; \
|
|
import QtQuick.Layouts 1.0; \
|
|
RowLayout { \
|
|
id: row; \
|
|
width: 10; \
|
|
spacing: 0; \
|
|
property alias r1: _r1; \
|
|
Rectangle { \
|
|
id: _r1; \
|
|
visible: false; \
|
|
height: 10; \
|
|
Layout.fillWidth: true; \
|
|
color: "#8080ff"; \
|
|
} \
|
|
property alias r2: _r2; \
|
|
Rectangle { \
|
|
id: _r2; \
|
|
height: 10; \
|
|
Layout.fillWidth: true; \
|
|
color: "#c0c0ff"; \
|
|
} \
|
|
} '
|
|
|
|
var lay = Qt.createQmlObject(test_layoutStr, container, '');
|
|
compare(lay.r1.width, 0)
|
|
compare(lay.r2.width, 10)
|
|
lay.r1.visible = true;
|
|
waitForRendering(lay)
|
|
compare(lay.r1.width, 5)
|
|
compare(lay.r2.width, 5)
|
|
lay.destroy()
|
|
}
|
|
|
|
Component {
|
|
id: layoutItem_Component
|
|
Rectangle {
|
|
implicitWidth: 20
|
|
implicitHeight: 20
|
|
}
|
|
}
|
|
|
|
Component {
|
|
id: columnLayoutItem_Component
|
|
ColumnLayout {
|
|
spacing: 0
|
|
}
|
|
}
|
|
|
|
Component {
|
|
id: layout_addAndRemoveItems_Component
|
|
RowLayout {
|
|
spacing: 0
|
|
}
|
|
}
|
|
|
|
function test_addAndRemoveItems()
|
|
{
|
|
var layout = createTemporaryObject(layout_addAndRemoveItems_Component, container)
|
|
compare(layout.implicitWidth, 0)
|
|
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)
|
|
|
|
var col = columnLayoutItem_Component.createObject(layout)
|
|
var rect2 = layoutItem_Component.createObject(col)
|
|
rect2.Layout.fillHeight = true
|
|
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)
|
|
}
|
|
|
|
Component {
|
|
id: layout_alignment_Component
|
|
RowLayout {
|
|
spacing: 0
|
|
Rectangle {
|
|
color: "red"
|
|
Layout.preferredWidth: 20
|
|
Layout.preferredHeight: 20
|
|
Layout.fillHeight: true
|
|
}
|
|
Rectangle {
|
|
color: "red"
|
|
Layout.preferredWidth: 20
|
|
Layout.preferredHeight: 20
|
|
// use default alignment
|
|
}
|
|
Rectangle {
|
|
color: "red"
|
|
Layout.preferredWidth: 20
|
|
Layout.preferredHeight: 20
|
|
Layout.alignment: Qt.AlignTop
|
|
}
|
|
Rectangle {
|
|
color: "red"
|
|
Layout.preferredWidth: 20
|
|
Layout.preferredHeight: 20
|
|
Layout.alignment: Qt.AlignVCenter
|
|
}
|
|
Rectangle {
|
|
color: "red"
|
|
Layout.preferredWidth: 20
|
|
Layout.preferredHeight: 20
|
|
Layout.alignment: Qt.AlignBottom
|
|
}
|
|
}
|
|
}
|
|
|
|
function test_alignment()
|
|
{
|
|
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]);
|
|
compare(itemRect(layout.children[3]), [60, 10, 20, 20]);
|
|
compare(itemRect(layout.children[4]), [80, 20, 20, 20]);
|
|
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 {
|
|
columnSpacing: 0
|
|
rowSpacing: 0
|
|
Rectangle {
|
|
id: r1
|
|
color: "red"
|
|
Layout.minimumWidth: 1
|
|
Layout.preferredWidth: 2
|
|
Layout.maximumWidth: 3
|
|
|
|
Layout.minimumHeight: 20
|
|
Layout.preferredHeight: 20
|
|
Layout.maximumHeight: 20
|
|
Layout.fillWidth: true
|
|
}
|
|
}
|
|
}
|
|
|
|
function test_sizeHintNormalization_data() {
|
|
return [
|
|
{ tag: "fallbackValues", widthHints: [-1, -1, -1], implicitWidth: 42, expected:[0,42,Number.POSITIVE_INFINITY]},
|
|
{ tag: "acceptZeroWidths", widthHints: [0, 0, 0], implicitWidth: 42, expected:[0,0,0]},
|
|
{ tag: "123", widthHints: [1,2,3], expected:[1,2,3]},
|
|
{ tag: "132", widthHints: [1,3,2], expected:[1,2,2]},
|
|
{ tag: "213", widthHints: [2,1,3], expected:[2,2,3]},
|
|
{ tag: "231", widthHints: [2,3,1], expected:[1,1,1]},
|
|
{ tag: "321", widthHints: [3,2,1], expected:[1,1,1]},
|
|
{ tag: "312", widthHints: [3,1,2], expected:[2,2,2]},
|
|
|
|
{ tag: "1i3", widthHints: [1,-1,3], implicitWidth: 2, expected:[1,2,3]},
|
|
{ tag: "1i2", widthHints: [1,-1,2], implicitWidth: 3, expected:[1,2,2]},
|
|
{ tag: "2i3", widthHints: [2,-1,3], implicitWidth: 1, expected:[2,2,3]},
|
|
{ tag: "2i1", widthHints: [2,-1,1], implicitWidth: 3, expected:[1,1,1]},
|
|
{ tag: "3i1", widthHints: [3,-1,1], implicitWidth: 2, expected:[1,1,1]},
|
|
{ tag: "3i2", widthHints: [3,-1,2], implicitWidth: 1, expected:[2,2,2]},
|
|
];
|
|
}
|
|
|
|
function test_sizeHintNormalization(data) {
|
|
var layout = layout_sizeHintNormalization_Component.createObject(container);
|
|
if (data.implicitWidth !== undefined) {
|
|
layout.children[0].implicitWidth = data.implicitWidth
|
|
}
|
|
layout.children[0].Layout.minimumWidth = data.widthHints[0];
|
|
layout.children[0].Layout.preferredWidth = data.widthHints[1];
|
|
layout.children[0].Layout.maximumWidth = data.widthHints[2];
|
|
waitForItemPolished(layout)
|
|
var normalizedResult = [layout.Layout.minimumWidth, layout.implicitWidth, layout.Layout.maximumWidth]
|
|
compare(normalizedResult, data.expected);
|
|
layout.destroy();
|
|
}
|
|
|
|
Component {
|
|
id: layout_sizeHint_Component
|
|
RowLayout {
|
|
property int implicitWidthChangedCount : 0
|
|
onImplicitWidthChanged: { ++implicitWidthChangedCount }
|
|
GridLayout {
|
|
columnSpacing: 0
|
|
rowSpacing: 0
|
|
Rectangle {
|
|
id: r1
|
|
color: "red"
|
|
implicitWidth: 1
|
|
implicitHeight: 1
|
|
|
|
Layout.minimumWidth: 1
|
|
Layout.preferredWidth: 2
|
|
Layout.maximumWidth: 3
|
|
|
|
Layout.minimumHeight: 20
|
|
Layout.preferredHeight: 20
|
|
Layout.maximumHeight: 20
|
|
Layout.fillWidth: true
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function test_sizeHint_data() {
|
|
return [
|
|
{ tag: "propagateNone", layoutHints: [10, 20, 30], childHints: [11, 21, 31], expected:[10, 20, 30]},
|
|
{ tag: "propagateMinimumWidth", layoutHints: [-1, 20, 30], childHints: [10, 21, 31], expected:[10, 20, 30]},
|
|
{ tag: "propagatePreferredWidth", layoutHints: [10, -1, 30], childHints: [11, 20, 31], expected:[10, 20, 30]},
|
|
{ tag: "propagateMaximumWidth", layoutHints: [10, 20, -1], childHints: [11, 21, 30], expected:[10, 20, 30]},
|
|
{ tag: "propagateAll", layoutHints: [-1, -1, -1], childHints: [10, 20, 30], expected:[10, 20, 30]},
|
|
{ tag: "propagateCrazy", layoutHints: [-1, -1, -1], childHints: [40, 21, 30], expected:[30, 30, 30]},
|
|
{ tag: "expandMinToExplicitPref", layoutHints: [-1, 1, -1], childHints: [11, 21, 31], expected:[ 1, 1, 31]},
|
|
{ tag: "expandMaxToExplicitPref", layoutHints: [-1, 99, -1], childHints: [11, 21, 31], expected:[11, 99, 99]},
|
|
{ tag: "expandAllToExplicitMin", layoutHints: [99, -1, -1], childHints: [11, 21, 31], expected:[99, 99, 99]},
|
|
{ tag: "expandPrefToExplicitMin", layoutHints: [24, -1, -1], childHints: [11, 21, 31], expected:[24, 24, 31]},
|
|
{ tag: "boundPrefToExplicitMax", layoutHints: [-1, -1, 19], childHints: [11, 21, 31], expected:[11, 19, 19]},
|
|
{ tag: "boundAllToExplicitMax", layoutHints: [-1, -1, 9], childHints: [11, 21, 31], expected:[ 9, 9, 9]},
|
|
|
|
/**
|
|
* Test how fractional size hint values are rounded. Some hints are ceiled towards the closest integer.
|
|
* Note some of these tests are not authorative, but are here to demonstrate current behavior.
|
|
* To summarize, it seems to be:
|
|
* - min: always ceiled
|
|
* - pref: Ceils only implicit (!) hints. Might also be ceiled if explicit
|
|
preferred size is less than implicit minimum size, but that's just a
|
|
side-effect of that preferred should never be less than minimum.
|
|
(tag "ceilShrinkMinToPref" below)
|
|
* - max: never ceiled
|
|
*/
|
|
{ tag: "ceilImplicitMin", layoutHints: [ -1, -1, -1], childHints: [ .1, 1.1, 9.1], expected:[ 1, 2, 9.1]},
|
|
{ tag: "ceilExplicitMin", layoutHints: [1.1, -1, -1], childHints: [ .1, 2.1, 9.1], expected:[ 2, 3, 9.1]},
|
|
{ tag: "ceilImplicitMin2", layoutHints: [ -1, 4.1, -1], childHints: [ .1, 1.1, 9.1], expected:[ 1, 4.1, 9.1]},
|
|
{ tag: "ceilShrinkMinToPref", layoutHints: [ -1, 2.1, -1], childHints: [ 5, 6.1, 8.1], expected:[ 3, 3, 8.1]},
|
|
{ tag: "ceilExpandMaxToPref", layoutHints: [ -1, 6.1, -1], childHints: [1.1, 3.1, 3.1], expected:[ 2, 6.1, 6.1]},
|
|
];
|
|
}
|
|
|
|
function itemSizeHints(item) {
|
|
return [item.Layout.minimumWidth, item.implicitWidth, item.Layout.maximumWidth]
|
|
}
|
|
|
|
function test_sizeHint(data) {
|
|
var layout = layout_sizeHint_Component.createObject(container)
|
|
|
|
var grid = layout.children[0]
|
|
grid.Layout.minimumWidth = data.layoutHints[0]
|
|
grid.Layout.preferredWidth = data.layoutHints[1]
|
|
grid.Layout.maximumWidth = data.layoutHints[2]
|
|
|
|
var child = grid.children[0]
|
|
if (data.implicitWidth !== undefined) {
|
|
child.implicitWidth = data.implicitWidth
|
|
}
|
|
child.Layout.minimumWidth = data.childHints[0]
|
|
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()
|
|
}
|
|
|
|
function test_sizeHintPropagationCount() {
|
|
var layout = layout_sizeHint_Component.createObject(container)
|
|
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)
|
|
|
|
layout.destroy()
|
|
}
|
|
|
|
Component {
|
|
id: layout_change_implicitWidth_during_rearrange
|
|
ColumnLayout {
|
|
width: 100
|
|
height: 20
|
|
RowLayout {
|
|
spacing: 0
|
|
Rectangle {
|
|
Layout.fillHeight: true
|
|
Layout.fillWidth: false
|
|
implicitWidth: height
|
|
color: "red"
|
|
}
|
|
Rectangle {
|
|
Layout.fillHeight: true
|
|
Layout.fillWidth: true
|
|
color: "blue"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function test_change_implicitWidth_during_rearrange() {
|
|
var layout = layout_change_implicitWidth_during_rearrange.createObject(container)
|
|
var red = layout.children[0].children[0]
|
|
var blue = layout.children[0].children[1]
|
|
waitForRendering(layout);
|
|
tryCompare(red, 'width', 20)
|
|
tryCompare(blue, 'width', 80)
|
|
layout.height = 40
|
|
tryCompare(red, 'width', 40)
|
|
tryCompare(blue, 'width', 60)
|
|
layout.destroy()
|
|
}
|
|
|
|
Component {
|
|
id: layout_addIgnoredItem_Component
|
|
RowLayout {
|
|
spacing: 0
|
|
Rectangle {
|
|
id: r
|
|
}
|
|
}
|
|
}
|
|
|
|
function test_addIgnoredItem()
|
|
{
|
|
var layout = layout_addIgnoredItem_Component.createObject(container)
|
|
compare(layout.implicitWidth, 0)
|
|
compare(layout.implicitHeight, 0)
|
|
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();
|
|
}
|
|
|
|
function test_stretchItem_data()
|
|
{
|
|
return [
|
|
{ expectedWidth: 0},
|
|
{ preferredWidth: 20, expectedWidth: 20},
|
|
{ preferredWidth: 0, expectedWidth: 0},
|
|
{ preferredWidth: 20, fillWidth: true, expectedWidth: 100},
|
|
{ width: 20, fillWidth: true, expectedWidth: 100},
|
|
{ width: 0, fillWidth: true, expectedWidth: 100},
|
|
{ preferredWidth: 0, fillWidth: true, expectedWidth: 100},
|
|
{ preferredWidth: 1, maximumWidth: 0, fillWidth: true, expectedWidth: 0},
|
|
{ preferredWidth: 0, minimumWidth: 1, expectedWidth: 1},
|
|
];
|
|
}
|
|
|
|
function test_stretchItem(data)
|
|
{
|
|
var layout = layout_rowLayout_Component.createObject(container)
|
|
var r = layoutItem_Component.createObject(layout)
|
|
// Reset previously relevant properties
|
|
r.width = 0
|
|
r.implicitWidth = 0
|
|
compare(layout.implicitWidth, 0)
|
|
|
|
if (data.preferredWidth !== undefined)
|
|
r.Layout.preferredWidth = data.preferredWidth
|
|
if (data.fillWidth !== undefined)
|
|
r.Layout.fillWidth = data.fillWidth
|
|
if (data.width !== undefined)
|
|
r.width = data.width
|
|
if (data.minimumWidth !== undefined)
|
|
r.Layout.minimumWidth = data.minimumWidth
|
|
if (data.maximumWidth !== undefined)
|
|
r.Layout.maximumWidth = data.maximumWidth
|
|
waitForItemPolished(layout)
|
|
layout.width = 100
|
|
|
|
compare(r.width, data.expectedWidth)
|
|
|
|
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]
|
|
}
|
|
];
|
|
}
|
|
|
|
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: layout_alignToPixelGrid_Component
|
|
RowLayout {
|
|
spacing: 2
|
|
Rectangle {
|
|
implicitWidth: 10
|
|
implicitHeight: 10
|
|
Layout.alignment: Qt.AlignVCenter
|
|
}
|
|
Rectangle {
|
|
implicitWidth: 10
|
|
implicitHeight: 10
|
|
Layout.alignment: Qt.AlignVCenter
|
|
}
|
|
}
|
|
}
|
|
function test_alignToPixelGrid()
|
|
{
|
|
var layout = layout_alignToPixelGrid_Component.createObject(container)
|
|
layout.width = 21
|
|
layout.height = 21
|
|
var r0 = layout.children[0]
|
|
compare(r0.x, 0) // 0.0
|
|
compare(r0.y, 6) // 5.5
|
|
var r1 = layout.children[1]
|
|
compare(r1.x, 12) // 11.5
|
|
compare(r1.y, 6) // 5.5
|
|
layout.destroy();
|
|
}
|
|
|
|
Component {
|
|
id: test_distributeToPixelGrid_Component
|
|
RowLayout {
|
|
spacing: 0
|
|
}
|
|
}
|
|
|
|
function test_distributeToPixelGrid_data() {
|
|
return [
|
|
{ tag: "narrow", spacing: 0, width: 60, hints: [{pref: 50}, {pref: 20}, {pref: 70}] },
|
|
{ tag: "belowPreferred", spacing: 0, width: 130, hints: [{pref: 50}, {pref: 20}, {pref: 70}]},
|
|
{ tag: "belowPreferredWithSpacing", spacing: 10, width: 130, hints: [{pref: 50}, {pref: 20}, {pref: 70}]},
|
|
{ tag: "abovePreferred", spacing: 0, width: 150, hints: [{pref: 50}, {pref: 20}, {pref: 70}]},
|
|
{ tag: "stretchSomethingToMaximum", spacing: 0, width: 240, hints: [{pref: 50}, {pref: 20}, {pref: 70}],
|
|
expected: [90, 60, 90] },
|
|
{ tag: "minSizeHasFractions", spacing: 2, width: 33 + 4, hints: [{min: 10+1/3}, {min: 10+1/3}, {min: 10+1/3}],
|
|
/*expected: [11, 11, 11]*/ }, /* verify that nothing gets allocated a size smaller than its minimum */
|
|
{ tag: "maxSizeHasFractions", spacing: 2, width: 271 + 4, hints: [{max: 90+1/3}, {max: 90+1/3}, {max: 90+1/3}],
|
|
/*expected: [90, 90, 90]*/ }, /* verify that nothing gets allocated a size larger than its maximum */
|
|
{ tag: "fixedSizeHasFractions", spacing: 2, width: 31 + 4, hints: [{min: 10+1/3, max: 10+1/3}, {min: 10+1/3, max: 10+1/3}, {min: 10+1/3, max: 10+1/3}],
|
|
/*expected: [11, 11, 11]*/ }, /* verify that nothing gets allocated a size smaller than its minimum */
|
|
{ tag: "481", spacing: 0, width: 481,
|
|
hints: [{min:0, pref:0, max:999}, {min:0, pref:0, max: 999}, {min: 0, pref: 0, max:0}],
|
|
expected: [241, 240, 0] },
|
|
{ tag: "theend", spacing: 1, width: 18,
|
|
hints: [{min: 10, pref: 10, max:10}, {min:3, pref:3.33}, {min:2, pref:2.33}],
|
|
expected: [10, 4, 2] },
|
|
{ tag: "theend2", spacing: 1, width: 18,
|
|
hints: [{min: 10, pref: 10, max:10}, {min:3, pref:3.33}, {min:2.33, pref:2.33}],
|
|
expected: [10, 3, 3] },
|
|
{ tag: "43", spacing: 0, width: 43,
|
|
hints: [{min: 10, pref: 10, max:10}, {min:10, pref:30.33}, {min:2.33, pref:2.33}],
|
|
expected: [10, 30, 3] },
|
|
{ tag: "40", spacing: 0, width: 40,
|
|
hints: [{min: 10, pref: 10, max:10}, {min:10, pref:30.33}, {min:2.33, pref:2.33}],
|
|
expected: [10, 27, 3] },
|
|
{ tag: "roundingAccumulates1", spacing: 0, width: 50,
|
|
hints: [{pref: 10, max:30.3},
|
|
{min:2.3, pref:2.3}, {min:2.3, pref:2.3}, {min:2.3, pref:2.3}, {min:2.3, pref:2.3}, {min:2.3, pref:2.3},
|
|
{min:2.3, pref:2.3}, {min:2.3, pref:2.3}, {min:2.3, pref:2.3}, {min:2.3, pref:2.3}, {min:2.3, pref:2.3},
|
|
{pref: 10, max:30.3}],
|
|
expected: [10, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 10] },
|
|
{ tag: "roundingAccumulates2", spacing: 0, width: 60,
|
|
hints: [{pref: 20, max:30.3},
|
|
{min:2.3, pref:2.3}, {min:2.3, pref:2.3}, {min:2.3, pref:2.3}, {min:2.3, pref:2.3}, {min:2.3, pref:2.3},
|
|
{min:2.3, pref:2.3}, {min:2.3, pref:2.3}, {min:2.3, pref:2.3}, {min:2.3, pref:2.3}, {min:2.3, pref:2.3},
|
|
{pref: 20, max:30.3}],
|
|
expected: [15, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 15] },
|
|
];
|
|
}
|
|
|
|
function test_distributeToPixelGrid(data)
|
|
{
|
|
// CONFIGURATION
|
|
var layout = test_distributeToPixelGrid_Component.createObject(container)
|
|
layout.spacing = data.spacing
|
|
layout.width = data.width
|
|
layout.height = 10
|
|
|
|
var hints = data.hints
|
|
var i;
|
|
var n = hints.length
|
|
for (i = 0; i < n; ++i) {
|
|
var rect = layoutItem_Component.createObject(layout)
|
|
rect.Layout.fillWidth = true
|
|
var h = hints[i]
|
|
rect.Layout.minimumWidth = h.hasOwnProperty('min') ? h.min : 10
|
|
if (h.hasOwnProperty('pref'))
|
|
rect.Layout.preferredWidth = h.pref
|
|
rect.Layout.maximumWidth = h.hasOwnProperty('max') ? h.max : 90
|
|
}
|
|
|
|
var kids = layout.children
|
|
|
|
waitForRendering(layout)
|
|
|
|
var sum = (n - 1) * layout.spacing
|
|
// TEST
|
|
for (i = 0; i < n; ++i) {
|
|
compare(kids[i].x % 1, 0) // checks if position is a whole integer
|
|
// check if width is a whole integer (unless there are constraints preventing it from stretching)
|
|
verify(kids[i].width % 1 == 0
|
|
|| Math.floor(kids[i].Layout.maximumWidth) < kids[i].width
|
|
|| layout.width < layout.Layout.maximumWidth + 1)
|
|
// verify if the items are within the size constraints as specified
|
|
verify(kids[i].width >= kids[i].Layout.minimumWidth)
|
|
verify(kids[i].width <= kids[i].Layout.maximumWidth)
|
|
if (data.hasOwnProperty('expected'))
|
|
compare(kids[i].width, data.expected[i])
|
|
sum += kids[i].width
|
|
}
|
|
fuzzyCompare(sum, layout.width, 1)
|
|
|
|
layout.destroy();
|
|
}
|
|
|
|
|
|
|
|
Component {
|
|
id: layout_deleteLayout
|
|
ColumnLayout {
|
|
property int dummyproperty: 0 // yes really - its needed
|
|
RowLayout {
|
|
Text { text: "label1" } // yes, both are needed
|
|
Text { text: "label2" }
|
|
}
|
|
}
|
|
}
|
|
|
|
function test_destroyLayout()
|
|
{
|
|
var layout = layout_deleteLayout.createObject(container)
|
|
layout.children[0].children[0].visible = true
|
|
layout.visible = false
|
|
layout.destroy() // Do not crash
|
|
}
|
|
|
|
function test_destroyImplicitInvisibleLayout()
|
|
{
|
|
var root = rectangle_Component.createObject(container)
|
|
root.visible = false
|
|
var layout = layout_deleteLayout.createObject(root)
|
|
layout.visible = true
|
|
// at this point the layout is still invisible because root is invisible
|
|
layout.destroy()
|
|
// Do not crash when destructing the layout
|
|
waitForRendering(container) // should ideally call gc(), but does not work
|
|
root.destroy()
|
|
}
|
|
|
|
function test_sizeHintWithHiddenChildren(data) {
|
|
var layout = layout_sizeHint_Component.createObject(container)
|
|
var grid = layout.children[0]
|
|
var child = grid.children[0]
|
|
|
|
// Implicit sizes are not affected by the visibility of the parent layout.
|
|
// This is in order for the layout to know the preferred size it should show itself at.
|
|
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();
|
|
}
|
|
|
|
Component {
|
|
id: row_sizeHint_Component
|
|
Row {
|
|
Rectangle {
|
|
id: r1
|
|
color: "red"
|
|
width: 2
|
|
height: 20
|
|
}
|
|
}
|
|
}
|
|
|
|
function test_sizeHintWithHiddenChildrenForRow(data) {
|
|
var row = row_sizeHint_Component.createObject(container)
|
|
var child = row.children[0]
|
|
compare(row.visible, true) // POSITIONER SHOWN
|
|
compare(row.implicitWidth, 2);
|
|
child.visible = false
|
|
tryCompare(row, 'implicitWidth', 0);
|
|
child.visible = true
|
|
tryCompare(row, 'implicitWidth', 2);
|
|
|
|
row.visible = false // POSITIONER HIDDEN
|
|
compare(row.implicitWidth, 2);
|
|
child.visible = false
|
|
expectFail('', 'If Row is hidden, Row is not notified when child is explicitly hidden')
|
|
compare(row.implicitWidth, 0);
|
|
child.visible = true
|
|
compare(row.implicitWidth, 2);
|
|
}
|
|
|
|
Component {
|
|
id: rearrangeNestedLayouts_Component
|
|
RowLayout {
|
|
id: layout
|
|
anchors.fill: parent
|
|
width: 200
|
|
height: 20
|
|
RowLayout {
|
|
id: row
|
|
spacing: 0
|
|
|
|
Rectangle {
|
|
id: fixed
|
|
color: 'red'
|
|
implicitWidth: 20
|
|
implicitHeight: 20
|
|
}
|
|
Rectangle {
|
|
id: filler
|
|
color: 'grey'
|
|
Layout.fillWidth: true
|
|
implicitHeight: 20
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function test_rearrangeNestedLayouts()
|
|
{
|
|
var layout = rearrangeNestedLayouts_Component.createObject(container)
|
|
var fixed = layout.children[0].children[0]
|
|
var filler = layout.children[0].children[1]
|
|
|
|
compare(itemRect(fixed), [0,0,20,20])
|
|
compare(itemRect(filler), [20,0,180,20])
|
|
|
|
fixed.implicitWidth = 100
|
|
waitForRendering(layout)
|
|
wait(0); // Trigger processEvents() (allow LayoutRequest to be processed)
|
|
compare(itemRect(fixed), [0,0,100,20])
|
|
compare(itemRect(filler), [100,0,100,20])
|
|
}
|
|
|
|
Component {
|
|
id: rearrangeFixedSizeLayout_Component
|
|
RowLayout {
|
|
id: layout
|
|
width: 200
|
|
height: 20
|
|
spacing: 0
|
|
RowLayout {
|
|
id: row
|
|
spacing: 0
|
|
Rectangle {
|
|
id: r0
|
|
color: 'red'
|
|
implicitWidth: 20
|
|
implicitHeight: 20
|
|
}
|
|
Rectangle {
|
|
id: r1
|
|
color: 'grey'
|
|
implicitWidth: 80
|
|
implicitHeight: 20
|
|
}
|
|
}
|
|
ColumnLayout {
|
|
id: row2
|
|
spacing: 0
|
|
Rectangle {
|
|
id: r2_0
|
|
color: 'blue'
|
|
Layout.fillWidth: true
|
|
implicitWidth: 100
|
|
implicitHeight: 20
|
|
}
|
|
}
|
|
}
|
|
}
|
|
function test_rearrangeFixedSizeLayout()
|
|
{
|
|
var layout = createTemporaryObject(rearrangeFixedSizeLayout_Component, testCase)
|
|
var row = layout.children[0]
|
|
var r0 = row.children[0]
|
|
var r1 = row.children[1]
|
|
|
|
waitForRendering(layout)
|
|
compare(itemRect(r0), [0,0,20,20])
|
|
compare(itemRect(r1), [20,0,80,20])
|
|
|
|
// just swap their widths. The layout should keep the same size
|
|
r0.implicitWidth = 80
|
|
r1.implicitWidth = 20
|
|
waitForRendering(layout)
|
|
// even if the layout did not change size, it should rearrange its children
|
|
compare(itemRect(row), [0,0, 100, 20])
|
|
compare(itemRect(r0), [0,0,80,20])
|
|
compare(itemRect(r1), [80,0,20,20])
|
|
}
|
|
|
|
Component {
|
|
id: changeChildrenOfHiddenLayout_Component
|
|
RowLayout {
|
|
property int childCount: 1
|
|
Repeater {
|
|
model: parent.childCount
|
|
Text {
|
|
text: 'Just foo it'
|
|
}
|
|
}
|
|
}
|
|
}
|
|
function test_changeChildrenOfHiddenLayout()
|
|
{
|
|
var layout = changeChildrenOfHiddenLayout_Component.createObject(container)
|
|
var child = layout.children[0]
|
|
waitForRendering(layout)
|
|
layout.visible = false
|
|
waitForRendering(layout)
|
|
// Remove and add children to the hidden layout..
|
|
layout.childCount = 0
|
|
waitForRendering(layout)
|
|
layout.childCount = 1
|
|
waitForRendering(layout)
|
|
layout.destroy()
|
|
}
|
|
|
|
|
|
function test_defaultPropertyAliasCrash() {
|
|
var containerUserComponent = Qt.createComponent("rowlayout/ContainerUser.qml");
|
|
compare(containerUserComponent.status, Component.Ready);
|
|
|
|
var containerUser = containerUserComponent.createObject(testCase);
|
|
verify(containerUser);
|
|
|
|
// Shouldn't crash.
|
|
containerUser.destroy();
|
|
}
|
|
|
|
function test_defaultPropertyAliasCrashAgain() {
|
|
var containerUserComponent = Qt.createComponent("rowlayout/ContainerUser2.qml");
|
|
compare(containerUserComponent.status, Component.Ready);
|
|
|
|
var containerUser = createTemporaryObject(containerUserComponent, testCase);
|
|
verify(containerUser);
|
|
|
|
// Shouldn't crash upon destroying containerUser.
|
|
}
|
|
|
|
/*
|
|
Tests that a layout-managed item that sets layer.enabled to true
|
|
still renders something. This is a simpler test case that only
|
|
reproduces the issue when the layout that manages it is made visible
|
|
after component completion, but QTBUG-63269 has a more complex example
|
|
where this (setting visible to true afterwards) isn't necessary.
|
|
*/
|
|
function test_layerEnabled() {
|
|
var component = Qt.createComponent("rowlayout/LayerEnabled.qml");
|
|
compare(component.status, Component.Ready);
|
|
|
|
var rootRect = createTemporaryObject(component, container);
|
|
verify(rootRect);
|
|
rootRect.layout.visible = true;
|
|
waitForRendering(rootRect.layout)
|
|
compare(rootRect.item1.width, 100)
|
|
}
|
|
|
|
//---------------------------
|
|
Component {
|
|
id: rowlayoutWithTextItems_Component
|
|
RowLayout {
|
|
Text {
|
|
Layout.fillWidth: true
|
|
text: "OneWord"
|
|
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
|
|
}
|
|
Text {
|
|
Layout.fillWidth: true
|
|
text: "OneWord"
|
|
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
|
|
}
|
|
}
|
|
}
|
|
|
|
// QTBUG-73683
|
|
function test_rowlayoutWithTextItems() {
|
|
var layout = createTemporaryObject(rowlayoutWithTextItems_Component, container)
|
|
waitForRendering(layout)
|
|
layout.width = layout.width - 2 // set the size to be smaller than its "minimum size"
|
|
waitForRendering(layout) // do not exit before all warnings have been received
|
|
|
|
// DO NOT CRASH due to stack overflow (or loop endlessly due to updatePolish()/polish() loop)
|
|
}
|
|
|
|
Component {
|
|
id: layout_dependentWidth_QTBUG_87253_Component
|
|
|
|
RowLayout {
|
|
anchors.fill: parent;
|
|
|
|
RowLayout {
|
|
spacing: 10
|
|
|
|
Text {
|
|
id: btnOPE
|
|
text: qsTr("Ok")
|
|
Layout.fillWidth: true
|
|
Layout.preferredWidth: (parent.width - 20) / 2
|
|
}
|
|
|
|
Text {
|
|
id: btnSeeChanged
|
|
text: qsTr("Not Ok");
|
|
Layout.fillWidth: true
|
|
Layout.preferredWidth: (parent.width - 20) / 2
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function test_dependentWidth_QTBUG_87253()
|
|
{
|
|
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(!BindingLoopDetector.bindingLoopDetected, "Detected binding loop")
|
|
BindingLoopDetector.reset()
|
|
}
|
|
|
|
|
|
//---------------------------
|
|
// 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)
|
|
}
|
|
}
|
|
}
|