diff options
-rw-r--r-- | src/controls/ApplicationWindow.qml | 44 | ||||
-rw-r--r-- | src/controls/Private/ContentItem.qml | 109 | ||||
-rw-r--r-- | src/controls/Private/private.pri | 1 | ||||
-rw-r--r-- | src/controls/Private/qmldir | 1 | ||||
-rw-r--r-- | tests/auto/controls/data/tst_applicationwindow.qml | 73 | ||||
-rw-r--r-- | tests/manual/ApplicationWindow/main.qml | 186 |
6 files changed, 413 insertions, 1 deletions
diff --git a/src/controls/ApplicationWindow.qml b/src/controls/ApplicationWindow.qml index 6e0160df2..f54fa8f51 100644 --- a/src/controls/ApplicationWindow.qml +++ b/src/controls/ApplicationWindow.qml @@ -115,6 +115,48 @@ Window { */ property Item statusBar + // The below documentation was supposed to be written as a grouped property, but qdoc would + // not render it correctly due to a bug (https://bugreports.qt-project.org/browse/QTBUG-34206) + /*! + \qmlproperty ApplicationWindow::contentItem + + This group holds the size constraints of the content item. This is the area between the + \l ToolBar and the \l StatusBar. + The \l ApplicationWindow will use this as input when calculating the effective size + constraints of the actual window. + It holds these 6 properties for describing the minimum, implicit and maximum sizes: + \table + \header \li Grouped property \li Description + \row \li contentItem.minimumWidth \li The minimum width of the content item. + \row \li contentItem.minimumHeight \li The minimum height of the content item. + \row \li contentItem.implicitWidth \li The implicit width of the content item. + \row \li contentItem.implicitHeight \li The implicit height of the content item. + \row \li contentItem.maximumWidth \li The maximum width of the content item. + \row \li contentItem.maximumHeight \li The maximum height of the content item. + \endtable + */ + property alias contentItem : contentArea + + /*! \internal */ + property real __topBottomMargins: contentArea.y + statusBarArea.height + /*! \internal + There is a similar macro QWINDOWSIZE_MAX in qwindow_p.h that is used to limit the + range of QWindow::maximum{Width,Height} + However, in case we have a very big number (> 2^31) conversion will fail, and it will be + converted to 0, resulting in that we will call setMaximumWidth(0).... + We therefore need to enforce the limit at a level where we are still operating on + floating point values. + */ + readonly property real __qwindowsize_max: (1 << 24) - 1 + + width: contentArea.__noImplicitWidthGiven ? 0 : Math.min(Math.max(minimumWidth, contentArea.implicitWidth), maximumWidth) + height: contentArea.__noImplicitHeightGiven ? 0 : Math.min(Math.max(minimumHeight, contentArea.implicitHeight + __topBottomMargins), maximumHeight) + + minimumWidth: contentArea.__noMinimumWidthGiven ? 0 : contentArea.minimumWidth + minimumHeight: contentArea.__noMinimumHeightGiven ? 0 : (contentArea.minimumHeight + __topBottomMargins) + + maximumWidth: Math.min(__qwindowsize_max, contentArea.maximumWidth) + maximumHeight: Math.min(__qwindowsize_max, contentArea.maximumHeight + __topBottomMargins) onToolBarChanged: { if (toolBar) { toolBar.parent = toolBarArea } } onStatusBarChanged: { if (statusBar) { statusBar.parent = statusBarArea } } @@ -140,7 +182,7 @@ Window { Keys.forwardTo: menuBar ? [menuBar.__contentItem] : [] - Item { + ContentItem { id: contentArea anchors.top: toolBarArea.bottom anchors.left: parent.left diff --git a/src/controls/Private/ContentItem.qml b/src/controls/Private/ContentItem.qml new file mode 100644 index 000000000..dbb4a50e2 --- /dev/null +++ b/src/controls/Private/ContentItem.qml @@ -0,0 +1,109 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Quick Controls module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** 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 Digia Plc and its Subsidiary(-ies) 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.1 +import QtQuick.Layouts 1.1 + +Item { + id: contentItem + property real minimumWidth: __calcMinimum('Width') + property real minimumHeight: __calcMinimum('Height') + property real maximumWidth: __calcMaximum('Width') + property real maximumHeight: __calcMaximum('Height') + implicitWidth: __calcImplicitWidth() + implicitHeight: __calcImplicitHeight() + + /*! \internal */ + property Item __layoutItem: contentItem.children.length === 1 ? contentItem.children[0] : null + /*! \internal */ + property real __marginsWidth: __layoutItem ? __layoutItem.anchors.leftMargin + __layoutItem.anchors.rightMargin : 0 + /*! \internal */ + property real __marginsHeight: __layoutItem ? __layoutItem.anchors.topMargin + __layoutItem.anchors.bottomMargin : 0 + + /*! \internal */ + property bool __noMinimumWidthGiven : false + /*! \internal */ + property bool __noMinimumHeightGiven : false + /*! \internal */ + property bool __noImplicitWidthGiven : false + /*! \internal */ + property bool __noImplicitHeightGiven : false + + function __calcImplicitWidth() { + if (__layoutItem && __layoutItem.anchors.fill) + return __calcImplicit('Width') + return contentItem.childrenRect.x + contentItem.childrenRect.width + } + + function __calcImplicitHeight() { + if (__layoutItem && __layoutItem.anchors.fill) + return __calcImplicit('Height') + return contentItem.childrenRect.y + contentItem.childrenRect.height + } + + function __calcImplicit(hw) { + var pref = __layoutItem.Layout['preferred' + hw] + if (pref < 0) { + pref = __layoutItem['implicit' + hw] + } + contentItem['__noImplicit' + hw + 'Given'] = (pref === 0 ? true : false) + pref += contentItem['__margins' + hw] + return pref + } + + function __calcMinimum(hw) { // hw is 'Width' or 'Height' + return (__layoutItem && __layoutItem.anchors.fill) ? __calcMinMax('minimum', hw) : 0 + } + + function __calcMaximum(hw) { // hw is 'Width' or 'Height' + return (__layoutItem && __layoutItem.anchors.fill) ? __calcMinMax('maximum', hw) : Number.POSITIVE_INFINITY + } + + function __calcMinMax(minMaxConstraint, hw) { + var attachedPropName = minMaxConstraint + hw + var extent = __layoutItem.Layout[attachedPropName] + + if (minMaxConstraint === 'minimum') + contentItem['__noMinimum' + hw + 'Given'] = (extent === 0 ? true : false) + + extent += contentItem['__margins' + hw] + return extent + } +} diff --git a/src/controls/Private/private.pri b/src/controls/Private/private.pri index 304649745..7852edffb 100644 --- a/src/controls/Private/private.pri +++ b/src/controls/Private/private.pri @@ -45,6 +45,7 @@ PRIVATE_QML_FILES += \ $$PWD/ColumnMenuContent.qml \ $$PWD/MenuContentItem.qml \ $$PWD/MenuContentScroller.qml \ + $$PWD/ContentItem.qml \ $$PWD/qmldir QML_FILES += $$PRIVATE_QML_FILES diff --git a/src/controls/Private/qmldir b/src/controls/Private/qmldir index 351387806..5dc8061cd 100644 --- a/src/controls/Private/qmldir +++ b/src/controls/Private/qmldir @@ -19,4 +19,5 @@ ToolButtonStyle 1.0 ../Styles/Base/ToolButtonStyle.qml MenuContentItem 1.0 MenuContentItem.qml MenuContentScroller 1.0 MenuContentScroller.qml ColumnMenuContent 1.0 ColumnMenuContent.qml +ContentItem 1.0 ContentItem.qml singleton TextSingleton 1.0 TextSingleton.qml diff --git a/tests/auto/controls/data/tst_applicationwindow.qml b/tests/auto/controls/data/tst_applicationwindow.qml index e424cc2d5..590231f45 100644 --- a/tests/auto/controls/data/tst_applicationwindow.qml +++ b/tests/auto/controls/data/tst_applicationwindow.qml @@ -94,5 +94,78 @@ TestCase { verify(contentArea.height < oldHeight) window.destroy() } + + + function test_defaultContentItemConstraints_data() { + return [ + { tag: "height", + input: {height: 100}, + expected: {implicitHeight: 100} }, + { tag: "height_y", + input: {height: 100, y: 10}, + expected: {implicitHeight: 110} }, + { tag: "height_implicitHeight_anchorsFill", + input: {height: 100, implicitHeight: 10, anchorsFill: true}, + expected: {implicitHeight: 10} }, + { tag: "height_implicitHeight_anchorsFill_margins", + input: {height: 100, implicitHeight: 10, anchorsFill: true, anchors_margins: 20}, + expected: {implicitHeight: 50} }, + { tag: "height_anchorsFill_margins", + input: {height: 100, anchorsFill: true, anchors_margins: 20}, + expected: {implicitHeight: 40} }, + { tag: "anchorsFill_margins", //Rectangle { anchors.fill: parent; anchors.margins: 20 } + input: {anchorsFill: true, anchors_margins: 20}, + expected: {implicitHeight: 40} }, + { tag: "anchorsFill_margins0", //Rectangle { anchors.fill: parent; anchors.margins: 0 } + input: {anchorsFill: true, anchors_margins: 0}, + expected: {implicitHeight: 0} }, + { tag: "minimum_implicit_maximum_anchorsFill", + input: {anchorsFill: true, Layout_minimumHeight: 10, implicitHeight: 100, Layout_maximumHeight: 150}, + expected: {minimumHeight: 10, implicitHeight: 100, maximumHeight: 150} }, + { tag: "minimum_implicit_maximum_anchorsFill_margins", + input: {anchorsFill: true, anchors_margins: 20, Layout_minimumHeight: 10, implicitHeight: 100, Layout_maximumHeight: 150}, + expected: {minimumHeight: 50, implicitHeight: 140, maximumHeight: 190} }, + { tag: "minimum_height_maximum_anchorsFill", + input: {anchorsFill: true, Layout_minimumHeight: 0, height: 100, Layout_maximumHeight: 150}, + expected: {minimumHeight: 0, implicitHeight: 0, maximumHeight: 150} }, + ]; + } + function test_defaultContentItemConstraints(data) { + var input = data.input + var expected = data.expected + + var str = '' + // serialize.... + for (var varName in input) { + var realName = varName.replace('_', '.') + // anchorsFill is special... + if (realName === 'anchorsFill') { + str += 'anchors.fill:parent;' + } else if (input[varName] !== undefined) { + // serialize the other properties... + str += realName + ':' + input[varName] +';' + } + } + + var test_control = 'import QtQuick 2.1; \ + import QtQuick.Controls 1.1; \ + import QtQuick.Layouts 1.1; \ + ApplicationWindow { \ + id: window; \ + Rectangle { \ + id: rect; \ + color: \'red\'; \ + ' + str + '\ + } \ + } ' + + var window = Qt.createQmlObject(test_control, container, '') + wait(0) + + for (var propName in expected) { + compare(window.contentItem[propName], expected[propName]) + } + } + } } diff --git a/tests/manual/ApplicationWindow/main.qml b/tests/manual/ApplicationWindow/main.qml new file mode 100644 index 000000000..a9a64ac54 --- /dev/null +++ b/tests/manual/ApplicationWindow/main.qml @@ -0,0 +1,186 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Quick Controls module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** 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 Digia Plc and its Subsidiary(-ies) 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.1 +import QtQuick.Controls 1.1 +import QtQuick.Layouts 1.1 + + +ApplicationWindow { + id: window + title: "Window constraints" + + property var g_content: canvas_Component.createObject(contentItem) + + menuBar: MenuBar { + Menu { + title: "Options" + MenuItem { + id: ckToolBarVisible + text: "Show ToolBar" + checkable: true + checked: true + } + MenuItem { + id: ckStatusBarVisible + text: "Show StatusBar" + checkable: true + checked: true + } + MenuItem { + id: ckUseLayout + text: "Use layout" + checkable: true + checked: false + onCheckedChanged: { + if (g_content) { + g_content.destroy() + } + if (checked) { + g_content = layout_Component.createObject(contentItem) + } else { + g_content = canvas_Component.createObject(contentItem) + } + } + } + } + } + + + toolBar: ToolBar { + visible: ckToolBarVisible.checked + Row { + ToolButton { + text: "One" + } + ToolButton { + text: "Two" + } + } + } + + statusBar: StatusBar { + visible: ckStatusBarVisible.checked + Row { + Label { + text: "Window size:(" + window.width + "x" + window.height + ")" + } + } + } + + Component { + id: layout_Component + GridLayout { + id: layout + anchors.fill: parent + rowSpacing: 2 + columnSpacing: 2 + columns: 5 + Repeater { + model: 10 + Rectangle { + Layout.fillWidth: true + Layout.fillHeight: true + color: 'red' + Layout.minimumWidth: 30 + Layout.minimumHeight: 30 + implicitWidth: 42 + implicitHeight: 42 + Layout.maximumWidth: 200 + Layout.maximumHeight: 200 + Text { + anchors.centerIn: parent + text: parent.width + "x" + parent.height + } + } + } + } + } + + + Component { + id: canvas_Component + Canvas { + id: canvas + width: 200 + height: 200 + antialiasing: false + + onPaint: { + var ctx = getContext('2d') + if (ctx) { + ctx.save() + ctx.fillStyle = "#e0e0e0" + ctx.strokeStyle = "#000000" + ctx.lineWidth = 1 + + + ctx.fillRect(0, 0, canvas.width, canvas.height) + + ctx.fillStyle = "#000000" + ctx.strokeStyle = "#000000" + ctx.antiAliasing= false + + ctx.beginPath(); + for (var x = 5; x < Math.max(canvas.width, canvas.height); x+=5) { + var extent = 2 + if (x % 100 == 0) + extent = 10 + else if (x % 10 == 0) + extent = 5 + else extent = 2 + ctx.moveTo(x, 0) + ctx.lineTo(x, 0 + extent) + ctx.moveTo(0, x) + ctx.lineTo(0 + extent, x) + } + ctx.closePath() + ctx.stroke() + + ctx.restore() + } + } + } + } +} |