/**************************************************************************** ** ** Copyright (C) 2016 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 QtQuick.Controls 1.2 import QtQuick.Layouts 1.1 ApplicationWindow { id: window property variant defaultAlignment: Qt.AlignBaseline title: "Layouts with baselines" property int margin: 11 width: mainLayout.implicitWidth + 2 * margin height: mainLayout.implicitHeight + 2 * margin minimumWidth: mainLayout.Layout.minimumWidth + 2 * margin minimumHeight: mainLayout.Layout.minimumHeight + 2 * margin Component { id: visualBaselineComponent Rectangle { height: 1 width: 1 color: 'red' } } Item { id: visualBaselinesContainer width: parent.width z: 1 opacity: 0.5 function setBaselinesVisible(showBaselines) { for (var i = 0; i < visualBaselinesContainer.children.length; ++i) { visualBaselinesContainer.children[i].destroy(); } if (showBaselines) { // assumes mainLayout/GroupBox/Layout/ hierarchy // Iterates over all and gathers their baseline positions, var map_baselines = {} for (var i = 0; i < mainLayout.children.length; ++i) { var grp = mainLayout.children[i] var lay = grp.contentItem.children[0] var y = mainLayout.y + grp.y + grp.contentItem.y + lay.y var x = mainLayout.x + grp.x + grp.contentItem.x + lay.x var w = lay.width for (var j = 0; j < lay.children.length; ++j) { var child = lay.children[j]; if (child.visible && child.baselineOffset > 0) { var baseline = y + child.y + child.baselineOffset map_baselines[baseline] = {x: x, width: w}; } } } for (var key in map_baselines) { var o = map_baselines[key]; var visualBaseline = visualBaselineComponent.createObject(visualBaselinesContainer, o); visualBaseline.y = key; } } } Timer { // This is a kludge to wait until the layout has been rearranged, since that won't // happen until we get a polish event. // This will wait minimum of one full vertical scan (17 milliseconds), which // should usually be enough id: refreshBaselinesTimer running: false interval: 17 onTriggered: { visualBaselinesContainer.setBaselinesVisible(ckShowBaselines.checked); } } } ColumnLayout { id: mainLayout anchors.fill: parent anchors.margins: margin GroupBox { id: rowBoxTools title: "Developer tools" Layout.fillWidth: true RowLayout { anchors.fill: parent CheckBox { id: ckShowBaselines text: "Show baselines" checked: false onCheckedChanged: { visualBaselinesContainer.setBaselinesVisible(checked); } } Label { text: "Alignment:" } ComboBox { model: ListModel { id: cbItems ListElement { text: "Default"; value: 0 } ListElement { text: "Align Left"; value: Qt.AlignLeft } ListElement { text: "Align Right"; value: Qt.AlignRight } ListElement { text: "Align HCenter"; value: Qt.AlignHCenter } ListElement { text: "Align Baseline"; value: Qt.AlignBaseline } ListElement { text: "Align Top"; value: Qt.AlignTop } ListElement { text: "Align Bottom"; value: Qt.AlignBottom } ListElement { text: "Align VCenter"; value: Qt.AlignVCenter } } Component.onCompleted: { for (var i = 0; i < cbItems.count; ++i) { var v = cbItems.get(i).value; if (v == defaultAlignment) { currentIndex = i; break; } } } onCurrentIndexChanged: { // assumes mainLayout/GroupBox/Layout/ hierarchy // Iterates over all and modifies their baseline alignment for (var i = 0; i < mainLayout.children.length; ++i) { var grp = mainLayout.children[i] var lay = grp.contentItem.children[0] for (var j = 0; j < lay.children.length; ++j) { var child = lay.children[j]; child.Layout.alignment = cbItems.get(currentIndex).value } } refreshBaselinesTimer.start(); } } Item { Layout.fillWidth: true Layout.fillHeight: true } } } GroupBox { id: rowBox title: "Row layout" Layout.fillWidth: true RowLayout { id: rowLayout anchors.fill: parent Repeater { model: 3 Text { text: "Typography" font.pixelSize: 10 + 4*index Layout.alignment: defaultAlignment Layout.fillWidth: index == 2 } } } } GroupBox { id: gridBox title: "Grid layout" Layout.fillWidth: true GridLayout { id: gridLayout anchors.fill: parent rows: 2 flow: GridLayout.TopToBottom Repeater { model: 6 Text { text: "Typography" font.pixelSize: 8 + 4*index Layout.alignment: defaultAlignment } } } } GroupBox { id: rowBoxWithControls title: "Row layout with Controls" Layout.fillWidth: true RowLayout { id: rowLayoutWithControls anchors.fill: parent Label { id: rowlabel text: "Typo" Layout.alignment: defaultAlignment } Button { text: "Typo" Layout.alignment: defaultAlignment } CheckBox { text: "Typo" Layout.alignment: defaultAlignment } ComboBox { model: ["Typo"] currentIndex: 0 Layout.alignment: defaultAlignment } RadioButton { text: "Typo" Layout.alignment: defaultAlignment } SpinBox { value: 42 Layout.alignment: defaultAlignment } TextField { text: "Typo" Layout.alignment: defaultAlignment Layout.maximumWidth: 40 } } } GroupBox { id: gridBoxWithControls title: "Grid layout with Controls" Layout.fillWidth: true GridLayout { id: gridLayoutWithControls columns: 3 flow: GridLayout.LeftToRight anchors.fill: parent Label { text: "Typography" Layout.alignment: defaultAlignment } Button { text: "Typography" Layout.alignment: defaultAlignment } CheckBox { text: "Typography" Layout.alignment: defaultAlignment } ComboBox { model: ["Typography"] currentIndex: 0 Layout.alignment: defaultAlignment } RadioButton { text: "Typography" Layout.alignment: defaultAlignment } SpinBox { value: 42 Layout.alignment: defaultAlignment } TextField { id: gridTextField text: "Typography" Layout.alignment: defaultAlignment } } } } }