From 8d093a47f52ffcebc4e61f9918985e62424658c0 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Tue, 30 Aug 2016 11:47:49 +0200 Subject: ScrollIndicator: respect the paddings when overshooting Task-number: QTBUG-55620 Change-Id: I4c06a9e7fefbdbaff7f14a972ed47242c51ca8c6 Reviewed-by: Mitch Curtis --- src/quicktemplates2/qquickscrollindicator.cpp | 13 ++++++--- tests/auto/controls/data/tst_scrollindicator.qml | 34 ++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 4 deletions(-) diff --git a/src/quicktemplates2/qquickscrollindicator.cpp b/src/quicktemplates2/qquickscrollindicator.cpp index 55e86d87..1c2700bc 100644 --- a/src/quicktemplates2/qquickscrollindicator.cpp +++ b/src/quicktemplates2/qquickscrollindicator.cpp @@ -109,12 +109,17 @@ void QQuickScrollIndicatorPrivate::resizeContent() if (!contentItem) return; + // - negative overshoot (pos < 0): clamp the pos to 0, and deduct the overshoot from the size + // - positive overshoot (pos + size > 1): clamp the size to 1-pos + const qreal clampedSize = qBound(0, size + qMin(0, position), 1.0 - position); + const qreal clampedPos = qBound(0, position, 1.0 - clampedSize); + if (orientation == Qt::Horizontal) { - contentItem->setPosition(QPointF(q->leftPadding() + position * q->availableWidth(), q->topPadding())); - contentItem->setSize(QSizeF(q->availableWidth() * size, q->availableHeight())); + contentItem->setPosition(QPointF(q->leftPadding() + clampedPos * q->availableWidth(), q->topPadding())); + contentItem->setSize(QSizeF(q->availableWidth() * clampedSize, q->availableHeight())); } else { - contentItem->setPosition(QPointF(q->leftPadding(), q->topPadding() + position * q->availableHeight())); - contentItem->setSize(QSizeF(q->availableWidth(), q->availableHeight() * size)); + contentItem->setPosition(QPointF(q->leftPadding(), q->topPadding() + clampedPos * q->availableHeight())); + contentItem->setSize(QSizeF(q->availableWidth(), q->availableHeight() * clampedSize)); } } diff --git a/tests/auto/controls/data/tst_scrollindicator.qml b/tests/auto/controls/data/tst_scrollindicator.qml index 39b40852..90d9287a 100644 --- a/tests/auto/controls/data/tst_scrollindicator.qml +++ b/tests/auto/controls/data/tst_scrollindicator.qml @@ -143,4 +143,38 @@ TestCase { ignoreWarning(Qt.resolvedUrl("tst_scrollindicator.qml") + ":45:1: QML TestCase: ScrollIndicator must be attached to a Flickable") testCase.ScrollIndicator.vertical = null } + + function test_overshoot() { + var container = flickable.createObject(testCase) + verify(container) + waitForRendering(container) + + var vertical = scrollIndicator.createObject(container, {size: 0.5}) + container.ScrollIndicator.vertical = vertical + + var horizontal = scrollIndicator.createObject(container, {size: 0.5}) + container.ScrollIndicator.horizontal = horizontal + + // negative vertical overshoot (pos < 0) + vertical.position = -0.1 + compare(vertical.contentItem.y, vertical.topPadding) + compare(vertical.contentItem.height, 0.4 * vertical.availableHeight) + + // positive vertical overshoot (pos + size > 1) + vertical.position = 0.8 + compare(vertical.contentItem.y, vertical.topPadding + 0.8 * vertical.availableHeight) + compare(vertical.contentItem.height, 0.2 * vertical.availableHeight) + + // negative horizontal overshoot (pos < 0) + horizontal.position = -0.1 + compare(horizontal.contentItem.x, horizontal.leftPadding) + compare(horizontal.contentItem.width, 0.4 * horizontal.availableWidth) + + // positive horizontal overshoot (pos + size > 1) + horizontal.position = 0.8 + compare(horizontal.contentItem.x, horizontal.leftPadding + 0.8 * horizontal.availableWidth) + compare(horizontal.contentItem.width, 0.2 * horizontal.availableWidth) + + container.destroy() + } } -- cgit v1.2.3 From 87b21a5702be5f91e18ca8af5ac169fa111c31d5 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Tue, 30 Aug 2016 17:16:43 +0200 Subject: Make a plain Control calculate suitable implicit size [ChangeLog][Controls][Control] A plain Control now calculates its implicit size based on the implicit size of the content item plus paddings, and the implicit size of the background item. Change-Id: I086ecf8e3f564ee49df2f9d30015e127dc88db6e Reviewed-by: Mitch Curtis --- src/imports/controls/Control.qml | 47 +++++++++++++++++++++++++ src/imports/controls/controls.pri | 1 + src/imports/controls/qtquickcontrols2plugin.cpp | 2 +- tests/auto/controls/data/tst_control.qml | 29 ++++++++++++++- 4 files changed, 77 insertions(+), 2 deletions(-) create mode 100644 src/imports/controls/Control.qml diff --git a/src/imports/controls/Control.qml b/src/imports/controls/Control.qml new file mode 100644 index 00000000..a4bb95fe --- /dev/null +++ b/src/imports/controls/Control.qml @@ -0,0 +1,47 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.6 +import QtQuick.Templates 2.0 as T + +T.Control { + id: control + + implicitWidth: Math.max(background ? background.implicitWidth : 0, + (contentItem ? contentItem.implicitWidth : 0) + leftPadding + rightPadding) + implicitHeight: Math.max(background ? background.implicitHeight : 0, + (contentItem ? contentItem.implicitHeight : 0) + topPadding + bottomPadding) +} diff --git a/src/imports/controls/controls.pri b/src/imports/controls/controls.pri index 523356a1..dc4f7d4e 100644 --- a/src/imports/controls/controls.pri +++ b/src/imports/controls/controls.pri @@ -16,6 +16,7 @@ QML_CONTROLS = \ CheckDelegate.qml \ CheckIndicator.qml \ ComboBox.qml \ + Control.qml \ Dial.qml \ Drawer.qml \ Frame.qml \ diff --git a/src/imports/controls/qtquickcontrols2plugin.cpp b/src/imports/controls/qtquickcontrols2plugin.cpp index 1982b392..c2e27ba3 100644 --- a/src/imports/controls/qtquickcontrols2plugin.cpp +++ b/src/imports/controls/qtquickcontrols2plugin.cpp @@ -86,7 +86,6 @@ void QtQuickControls2Plugin::registerTypes(const char *uri) qmlRegisterType(uri, 2, 0, "ButtonGroup"); qmlRegisterType(); qmlRegisterType(uri, 2, 0, "Container"); - qmlRegisterType(uri, 2, 0, "Control"); QQuickStyleSelector selector; selector.setBaseUrl(typeUrl()); @@ -101,6 +100,7 @@ void QtQuickControls2Plugin::registerTypes(const char *uri) qmlRegisterType(selector.select(QStringLiteral("CheckBox.qml")), uri, 2, 0, "CheckBox"); qmlRegisterType(selector.select(QStringLiteral("CheckDelegate.qml")), uri, 2, 0, "CheckDelegate"); qmlRegisterType(selector.select(QStringLiteral("ComboBox.qml")), uri, 2, 0, "ComboBox"); + qmlRegisterType(selector.select(QStringLiteral("Control.qml")), uri, 2, 0, "Control"); qmlRegisterType(selector.select(QStringLiteral("Dial.qml")), uri, 2, 0, "Dial"); qmlRegisterType(selector.select(QStringLiteral("Drawer.qml")), uri, 2, 0, "Drawer"); qmlRegisterType(selector.select(QStringLiteral("Frame.qml")), uri, 2, 0, "Frame"); diff --git a/tests/auto/controls/data/tst_control.qml b/tests/auto/controls/data/tst_control.qml index 89266d16..601b7f8f 100644 --- a/tests/auto/controls/data/tst_control.qml +++ b/tests/auto/controls/data/tst_control.qml @@ -53,7 +53,12 @@ TestCase { Component { id: component - T.Control { } + Control { } + } + + Component { + id: rectangle + Rectangle { } } Component { @@ -877,4 +882,26 @@ TestCase { control.destroy() } + + function test_implicitSize() { + var control = component.createObject(testCase) + verify(control) + + compare(control.implicitWidth, 0) + compare(control.implicitHeight, 0) + + control.contentItem = rectangle.createObject(control, {implicitWidth: 10, implicitHeight: 20}) + compare(control.implicitWidth, 10) + compare(control.implicitHeight, 20) + + control.background = rectangle.createObject(control, {implicitWidth: 20, implicitHeight: 30}) + compare(control.implicitWidth, 20) + compare(control.implicitHeight, 30) + + control.padding = 100 + compare(control.implicitWidth, 210) + compare(control.implicitHeight, 220) + + control.destroy() + } } -- cgit v1.2.3 From 0e01d1d979fd747671512b2c4e987d1f8cb3c019 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Tue, 30 Aug 2016 17:26:50 +0200 Subject: Make a plain Container calculate suitable implicit size [ChangeLog][Controls][Container] A plain Container now calculates its implicit size based on the implicit size of the content item plus paddings, and the implicit size of the background item. Change-Id: I0481aef0ce713d92bee8b119bf5158dea612d598 Reviewed-by: Mitch Curtis --- src/imports/controls/Container.qml | 47 ++++++++++++++ src/imports/controls/controls.pri | 1 + src/imports/controls/qtquickcontrols2plugin.cpp | 2 +- tests/auto/controls/data/tst_container.qml | 85 +++++++++++++++++++++++++ 4 files changed, 134 insertions(+), 1 deletion(-) create mode 100644 src/imports/controls/Container.qml create mode 100644 tests/auto/controls/data/tst_container.qml diff --git a/src/imports/controls/Container.qml b/src/imports/controls/Container.qml new file mode 100644 index 00000000..9e9215f8 --- /dev/null +++ b/src/imports/controls/Container.qml @@ -0,0 +1,47 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.6 +import QtQuick.Templates 2.0 as T + +T.Container { + id: control + + implicitWidth: Math.max(background ? background.implicitWidth : 0, + (contentItem ? contentItem.implicitWidth : 0) + leftPadding + rightPadding) + implicitHeight: Math.max(background ? background.implicitHeight : 0, + (contentItem ? contentItem.implicitHeight : 0) + topPadding + bottomPadding) +} diff --git a/src/imports/controls/controls.pri b/src/imports/controls/controls.pri index dc4f7d4e..788bfe27 100644 --- a/src/imports/controls/controls.pri +++ b/src/imports/controls/controls.pri @@ -16,6 +16,7 @@ QML_CONTROLS = \ CheckDelegate.qml \ CheckIndicator.qml \ ComboBox.qml \ + Container.qml \ Control.qml \ Dial.qml \ Drawer.qml \ diff --git a/src/imports/controls/qtquickcontrols2plugin.cpp b/src/imports/controls/qtquickcontrols2plugin.cpp index c2e27ba3..541d18d6 100644 --- a/src/imports/controls/qtquickcontrols2plugin.cpp +++ b/src/imports/controls/qtquickcontrols2plugin.cpp @@ -85,7 +85,6 @@ void QtQuickControls2Plugin::registerTypes(const char *uri) qmlRegisterType(uri, 2, 0, "AbstractButton"); qmlRegisterType(uri, 2, 0, "ButtonGroup"); qmlRegisterType(); - qmlRegisterType(uri, 2, 0, "Container"); QQuickStyleSelector selector; selector.setBaseUrl(typeUrl()); @@ -100,6 +99,7 @@ void QtQuickControls2Plugin::registerTypes(const char *uri) qmlRegisterType(selector.select(QStringLiteral("CheckBox.qml")), uri, 2, 0, "CheckBox"); qmlRegisterType(selector.select(QStringLiteral("CheckDelegate.qml")), uri, 2, 0, "CheckDelegate"); qmlRegisterType(selector.select(QStringLiteral("ComboBox.qml")), uri, 2, 0, "ComboBox"); + qmlRegisterType(selector.select(QStringLiteral("Container.qml")), uri, 2, 0, "Container"); qmlRegisterType(selector.select(QStringLiteral("Control.qml")), uri, 2, 0, "Control"); qmlRegisterType(selector.select(QStringLiteral("Dial.qml")), uri, 2, 0, "Dial"); qmlRegisterType(selector.select(QStringLiteral("Drawer.qml")), uri, 2, 0, "Drawer"); diff --git a/tests/auto/controls/data/tst_container.qml b/tests/auto/controls/data/tst_container.qml new file mode 100644 index 00000000..d1ff54e0 --- /dev/null +++ b/tests/auto/controls/data/tst_container.qml @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite 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 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.Controls 2.0 +import QtQuick.Templates 2.0 as T + +TestCase { + id: testCase + width: 400 + height: 400 + visible: true + when: windowShown + name: "Container" + + Component { + id: container + Container { } + } + + Component { + id: rectangle + Rectangle { } + } + + function test_implicitSize() { + var control = container.createObject(testCase) + verify(control) + + compare(control.implicitWidth, 0) + compare(control.implicitHeight, 0) + + control.contentItem = rectangle.createObject(control, {implicitWidth: 10, implicitHeight: 20}) + compare(control.implicitWidth, 10) + compare(control.implicitHeight, 20) + + control.background = rectangle.createObject(control, {implicitWidth: 20, implicitHeight: 30}) + compare(control.implicitWidth, 20) + compare(control.implicitHeight, 30) + + control.padding = 100 + compare(control.implicitWidth, 210) + compare(control.implicitHeight, 220) + + control.destroy() + } +} -- cgit v1.2.3 From f59e5d7bbd17c79ca2f06d79897212a5fc9b6ee7 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Wed, 31 Aug 2016 17:32:28 +0200 Subject: Popup: respect dynamic dim & modal changes What comes to the visual background dimming, popups did not respect dynamic 'dim' or 'modal' property changes. This was half-intentional, because it was thought an unrealistic use-case to toggle these while the popup is visible. As a result, the background dimming was missing if a popup was made visible in a declarative way, and either 'dim' or 'modal' was evaluated after the popup was already visible. Task-number: QTBUG-54797 Change-Id: Icfb171e619540fef2d91908867b702790cde6c32 Reviewed-by: Mitch Curtis --- src/quicktemplates2/qquickoverlay.cpp | 19 ++++++++++++++++++- tests/auto/controls/data/tst_popup.qml | 10 ++++++++-- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/src/quicktemplates2/qquickoverlay.cpp b/src/quicktemplates2/qquickoverlay.cpp index 850de875..5dd92a26 100644 --- a/src/quicktemplates2/qquickoverlay.cpp +++ b/src/quicktemplates2/qquickoverlay.cpp @@ -57,6 +57,7 @@ public: void createOverlay(QQuickPopup *popup); void destroyOverlay(QQuickPopup *popup); void resizeOverlay(QQuickPopup *popup); + void toggleOverlay(); QVector stackingOrderPopups() const; @@ -106,7 +107,7 @@ static QQuickItem *createDimmer(QQmlComponent *component, QQuickPopup *popup, QQ context->setContextObject(popup); QQuickItem *item = qobject_cast(component->beginCreate(context)); if (item) { - item->setOpacity(0.0); + item->setOpacity(popup->isVisible() ? 1.0 : 0.0); item->setParentItem(parent); item->stackBefore(popup->popupItem()); item->setZ(popup->z()); @@ -150,6 +151,18 @@ void QQuickOverlayPrivate::resizeOverlay(QQuickPopup *popup) } } +void QQuickOverlayPrivate::toggleOverlay() +{ + Q_Q(QQuickOverlay); + QQuickPopup *popup = qobject_cast(q->sender()); + if (!popup) + return; + + destroyOverlay(popup); + if (popup->dim()) + createOverlay(popup); +} + QVector QQuickOverlayPrivate::stackingOrderPopups() const { const QList children = paintOrderChildItems(); @@ -233,6 +246,8 @@ void QQuickOverlay::itemChange(ItemChange change, const ItemChangeData &data) d->popups.append(popup); if (popup->dim()) d->createOverlay(popup); + QObjectPrivate::connect(popup, &QQuickPopup::dimChanged, d, &QQuickOverlayPrivate::toggleOverlay); + QObjectPrivate::connect(popup, &QQuickPopup::modalChanged, d, &QQuickOverlayPrivate::toggleOverlay); QQuickDrawer *drawer = qobject_cast(popup); if (drawer) { @@ -247,6 +262,8 @@ void QQuickOverlay::itemChange(ItemChange change, const ItemChangeData &data) } else if (change == ItemChildRemovedChange) { d->popups.removeOne(popup); d->destroyOverlay(popup); + QObjectPrivate::disconnect(popup, &QQuickPopup::dimChanged, d, &QQuickOverlayPrivate::toggleOverlay); + QObjectPrivate::disconnect(popup, &QQuickPopup::modalChanged, d, &QQuickOverlayPrivate::toggleOverlay); QQuickDrawer *drawer = qobject_cast(popup); if (drawer) { diff --git a/tests/auto/controls/data/tst_popup.qml b/tests/auto/controls/data/tst_popup.qml index 72cd6999..2c6d60da 100644 --- a/tests/auto/controls/data/tst_popup.qml +++ b/tests/auto/controls/data/tst_popup.qml @@ -1124,17 +1124,23 @@ TestCase { tryCompare(window.plainPopup, "visible", true) compare(window.overlay.children.length, countBefore + 1) // only popup added, no overlays involved + window.plainPopup.modal = true + compare(window.overlay.children.length, countBefore + 2) // overlay added + window.plainPopup.close() tryCompare(window.plainPopup, "visible", false) - compare(window.overlay.children.length, countBefore) // only popup removed, no overlays involved + compare(window.overlay.children.length, countBefore) // popup + overlay removed window.modalPopupWithoutDim.open() tryCompare(window.modalPopupWithoutDim, "visible", true) compare(window.overlay.children.length, countBefore + 1) // only popup added, no overlays involved + window.modalPopupWithoutDim.dim = true + compare(window.overlay.children.length, countBefore + 2) // overlay added + window.modalPopupWithoutDim.close() tryCompare(window.modalPopupWithoutDim, "visible", false) - compare(window.overlay.children.length, countBefore) // only popup added, no overlays involved + compare(window.overlay.children.length, countBefore) // popup + overlay removed window.destroy() } -- cgit v1.2.3 From 79636b847d9ee04475cf1a0415996d483ad32593 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Thu, 1 Sep 2016 13:20:09 +0200 Subject: Fix QQuickDrawerPrivate::handleMouseReleaseEvent() QQuickDrawer operates on scene/window coordinates, se it must use QMouseEvent::windowPos() instead of QMouseEvent::x() or y() which return local coordinates. QMouseEvent::windowPos() is already used in handleMousePressEvent() and handleMouseMoveEvent(). The delta between the press and the release point is used to calculate the velocity. The two points must be specified in the same coordinate space to get correct velocity calculation. Change-Id: Ic9ee904e0b2b022a58b674ee663d8963eb2417a6 Reviewed-by: Mitch Curtis --- src/quicktemplates2/qquickdrawer.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/quicktemplates2/qquickdrawer.cpp b/src/quicktemplates2/qquickdrawer.cpp index 056a636f..b5bebd9b 100644 --- a/src/quicktemplates2/qquickdrawer.cpp +++ b/src/quicktemplates2/qquickdrawer.cpp @@ -283,7 +283,8 @@ bool QQuickDrawerPrivate::handleMouseReleaseEvent(QQuickItem *item, QMouseEvent bool wasGrabbed = popupItem->keepMouseGrab(); if (wasGrabbed) { - velocityCalculator.stopMeasuring(event->pos(), event->timestamp()); + const QPointF releasePoint = event->windowPos(); + velocityCalculator.stopMeasuring(releasePoint, event->timestamp()); const qreal velocity = velocityCalculator.velocity().x(); if (position > 0.7 || velocity > openCloseVelocityThreshold) { @@ -293,25 +294,25 @@ bool QQuickDrawerPrivate::handleMouseReleaseEvent(QQuickItem *item, QMouseEvent } else { switch (edge) { case Qt::LeftEdge: - if (event->x() - pressPoint.x() > 0) + if (releasePoint.x() - pressPoint.x() > 0) transitionManager.transitionEnter(); else transitionManager.transitionExit(); break; case Qt::RightEdge: - if (event->x() - pressPoint.x() < 0) + if (releasePoint.x() - pressPoint.x() < 0) transitionManager.transitionEnter(); else transitionManager.transitionExit(); break; case Qt::TopEdge: - if (event->y() - pressPoint.y() > 0) + if (releasePoint.y() - pressPoint.y() > 0) transitionManager.transitionEnter(); else transitionManager.transitionExit(); break; case Qt::BottomEdge: - if (event->y() - pressPoint.y() < 0) + if (releasePoint.y() - pressPoint.y() < 0) transitionManager.transitionEnter(); else transitionManager.transitionExit(); -- cgit v1.2.3 From d00c6d93ce1974e27bb49c57ae87156260501577 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Thu, 1 Sep 2016 20:31:50 +0200 Subject: Switch: fix Qt::ClickFocus on the indicator Task-number: QTBUG-55647 Change-Id: Ic89beaa1e6674d3f94c9a713fd9bd8e8fdfafbb6 Reviewed-by: Mitch Curtis --- src/quicktemplates2/qquickswitch.cpp | 8 ++++++++ tests/auto/controls/data/tst_switch.qml | 11 +++++++++++ 2 files changed, 19 insertions(+) diff --git a/src/quicktemplates2/qquickswitch.cpp b/src/quicktemplates2/qquickswitch.cpp index 439950d8..cb966568 100644 --- a/src/quicktemplates2/qquickswitch.cpp +++ b/src/quicktemplates2/qquickswitch.cpp @@ -37,6 +37,8 @@ #include "qquickswitch_p.h" #include "qquickabstractbutton_p_p.h" +#include +#include #include #include @@ -119,6 +121,9 @@ bool QQuickSwitchPrivate::handleMousePressEvent(QQuickItem *child, QMouseEvent * { Q_Q(QQuickSwitch); Q_UNUSED(child); + if ((focusPolicy & Qt::ClickFocus) == Qt::ClickFocus && !QGuiApplication::styleHints()->setFocusOnTouchRelease()) + q->forceActiveFocus(Qt::MouseFocusReason); + pressPoint = event->pos(); q->setPressed(true); event->accept(); @@ -140,6 +145,9 @@ bool QQuickSwitchPrivate::handleMouseMoveEvent(QQuickItem *child, QMouseEvent *e bool QQuickSwitchPrivate::handleMouseReleaseEvent(QQuickItem *child, QMouseEvent *event) { Q_Q(QQuickSwitch); + if ((focusPolicy & Qt::ClickFocus) == Qt::ClickFocus && QGuiApplication::styleHints()->setFocusOnTouchRelease()) + q->forceActiveFocus(Qt::MouseFocusReason); + pressPoint = QPoint(); q->setPressed(false); if (child->keepMouseGrab()) { diff --git a/tests/auto/controls/data/tst_switch.qml b/tests/auto/controls/data/tst_switch.qml index f12e7612..ff81be16 100644 --- a/tests/auto/controls/data/tst_switch.qml +++ b/tests/auto/controls/data/tst_switch.qml @@ -263,4 +263,15 @@ TestCase { compare(control.baselineOffset, control.contentItem.y + control.contentItem.baselineOffset) control.destroy() } + + function test_focus() { + var control = swtch.createObject(testCase) + verify(control) + + verify(!control.activeFocus) + mouseClick(control.indicator) + verify(control.activeFocus) + + control.destroy() + } } -- cgit v1.2.3 From 58326f2bc3bceafc0054e790832e0a77db340606 Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Fri, 26 Aug 2016 12:46:42 +0200 Subject: StackView: add removed() attached signal This provides an opportunity for users to destroy items that StackView doesn't, like objects that are pushed as Items. [ChangeLog][Controls][StackView] Added StackView.removed() attached signal to provide a way to delete items that StackView won't. Task-number: QTBUG-55405 Change-Id: I59096efaf1a95d36451fbf1f46b8f68ee96c20de Reviewed-by: J-P Nurmi --- src/quicktemplates2/qquickstackview.cpp | 17 ++++++++++ src/quicktemplates2/qquickstackview_p.cpp | 5 ++- src/quicktemplates2/qquickstackview_p.h | 1 + tests/auto/controls/data/tst_stackview.qml | 54 ++++++++++++++++++++++++++++++ 4 files changed, 76 insertions(+), 1 deletion(-) diff --git a/src/quicktemplates2/qquickstackview.cpp b/src/quicktemplates2/qquickstackview.cpp index df163089..040eff1b 100644 --- a/src/quicktemplates2/qquickstackview.cpp +++ b/src/quicktemplates2/qquickstackview.cpp @@ -1092,4 +1092,21 @@ QQuickStackView::Status QQuickStackAttached::status() const \sa status */ +/*! + \qmlattachedsignal QtQuick.Controls::StackView::removed() + \since QtQuick.Controls 2.1 + + This attached signal is emitted when the item it's attached to has been + removed from the stack. It can be used to safely destroy an Item that was + pushed onto the stack, for example: + + \code + Item { + StackView.onRemoved: destroy() // Will be destroyed sometime after this call. + } + \endcode + + \sa status +*/ + QT_END_NAMESPACE diff --git a/src/quicktemplates2/qquickstackview_p.cpp b/src/quicktemplates2/qquickstackview_p.cpp index 0f5674c2..438b4269 100644 --- a/src/quicktemplates2/qquickstackview_p.cpp +++ b/src/quicktemplates2/qquickstackview_p.cpp @@ -85,6 +85,7 @@ QQuickStackElement::~QQuickStackElement() if (ownComponent) delete component; + QQuickStackAttached *attached = attachedStackObject(this); if (item) { if (ownItem) { item->setParentItem(nullptr); @@ -99,13 +100,15 @@ QQuickStackElement::~QQuickStackElement() if (item->parentItem() != originalParent) { item->setParentItem(originalParent); } else { - QQuickStackAttached *attached = attachedStackObject(this); if (attached) QQuickStackAttachedPrivate::get(attached)->itemParentChanged(item, nullptr); } } } + if (attached) + emit attached->removed(); + delete context; } diff --git a/src/quicktemplates2/qquickstackview_p.h b/src/quicktemplates2/qquickstackview_p.h index d8b6ce7c..9bf60183 100644 --- a/src/quicktemplates2/qquickstackview_p.h +++ b/src/quicktemplates2/qquickstackview_p.h @@ -182,6 +182,7 @@ Q_SIGNALS: /*Q_REVISION(1)*/ void activating(); /*Q_REVISION(1)*/ void deactivated(); /*Q_REVISION(1)*/ void deactivating(); + /*Q_REVISION(1)*/ void removed(); private: Q_DISABLE_COPY(QQuickStackAttached) diff --git a/tests/auto/controls/data/tst_stackview.qml b/tests/auto/controls/data/tst_stackview.qml index 2de0fb98..4de8bed0 100644 --- a/tests/auto/controls/data/tst_stackview.qml +++ b/tests/auto/controls/data/tst_stackview.qml @@ -679,6 +679,60 @@ TestCase { control.destroy() } + Component { + id: removeComponent + + Item { + objectName: "removeItem" + StackView.onRemoved: destroy() + } + } + + function test_destroyOnRemoved() { + var control = stackView.createObject(testCase, { initialItem: component }) + verify(control) + + var item = removeComponent.createObject(control) + verify(item) + + var removedSpy = signalSpy.createObject(control, { target: item.StackView, signalName: "removed" }) + verify(removedSpy) + verify(removedSpy.valid) + + var destructionSpy = signalSpy.createObject(control, { target: item.Component, signalName: "destruction" }) + verify(destructionSpy) + verify(destructionSpy.valid) + + // push-pop + control.push(item, StackView.Immediate) + compare(control.currentItem, item) + control.pop(StackView.Transition) + item = null + tryCompare(removedSpy, "count", 1) + tryCompare(destructionSpy, "count", 1) + compare(control.busy, false) + + item = removeComponent.createObject(control) + verify(item) + + removedSpy.target = item.StackView + verify(removedSpy.valid) + + destructionSpy.target = item.Component + verify(destructionSpy.valid) + + // push-replace + control.push(item, StackView.Immediate) + compare(control.currentItem, item) + control.replace(component, StackView.Transition) + item = null + tryCompare(removedSpy, "count", 2) + tryCompare(destructionSpy, "count", 2) + compare(control.busy, false) + + control.destroy() + } + Component { id: attachedItem Item { -- cgit v1.2.3 From dac19e5054c354752f4da8e1ec33cccde16a699b Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Thu, 1 Sep 2016 13:23:47 +0200 Subject: QQuickDrawer: fix velocity calculation Use the vertical velocity for top and bottom edges, and invert the speed for right and bottom edges. Change-Id: I362dda23f0a2cda60ad7cd52e7373d0707feea83 Reviewed-by: Mitch Curtis --- src/quicktemplates2/qquickdrawer.cpp | 18 +++++++++++++++++- tests/auto/drawer/tst_drawer.cpp | 3 +++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/quicktemplates2/qquickdrawer.cpp b/src/quicktemplates2/qquickdrawer.cpp index b5bebd9b..d11a8bdf 100644 --- a/src/quicktemplates2/qquickdrawer.cpp +++ b/src/quicktemplates2/qquickdrawer.cpp @@ -285,7 +285,23 @@ bool QQuickDrawerPrivate::handleMouseReleaseEvent(QQuickItem *item, QMouseEvent if (wasGrabbed) { const QPointF releasePoint = event->windowPos(); velocityCalculator.stopMeasuring(releasePoint, event->timestamp()); - const qreal velocity = velocityCalculator.velocity().x(); + + qreal velocity = 0; + if (edge == Qt::LeftEdge || edge == Qt::RightEdge) + velocity = velocityCalculator.velocity().x(); + else + velocity = velocityCalculator.velocity().y(); + + // the velocity is calculated so that swipes from left to right + // and top to bottom have positive velocity, and swipes from right + // to left and bottom to top have negative velocity. + // + // - top/left edge: positive velocity opens, negative velocity closes + // - bottom/right edge: negative velocity opens, positive velocity closes + // + // => invert the velocity for bottom and right edges, for the threshold comparison below + if (edge == Qt::RightEdge || edge == Qt::BottomEdge) + velocity = -velocity; if (position > 0.7 || velocity > openCloseVelocityThreshold) { transitionManager.transitionEnter(); diff --git a/tests/auto/drawer/tst_drawer.cpp b/tests/auto/drawer/tst_drawer.cpp index 0507d01e..0b334387 100644 --- a/tests/auto/drawer/tst_drawer.cpp +++ b/tests/auto/drawer/tst_drawer.cpp @@ -98,7 +98,10 @@ void tst_Drawer::position() QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, from); QTest::mouseMove(window, to); QCOMPARE(drawer->position(), position); + + // moved half-way open at almost infinite speed => snap to open QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, to); + QTRY_COMPARE(drawer->position(), 1.0); } void tst_Drawer::dragMargin_data() -- cgit v1.2.3 From 470c222196d4d1d21d1d80b550f632c030e9b651 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Fri, 2 Sep 2016 11:51:58 +0200 Subject: Fix style name casing When QQuickStyle looks up the appropriate folder where the specified style exists, it also fixes up the casing of the style name to match what is on the file system. For example, "material" becomes "Material". Since 54480f3, QtQuickControls2Plugin initializes the default style path so QQuickStyle no longer has to create a temporary QQmlEngine to be able to lookup styles in one of the import paths. It still needs to fixup the casing of the style name to ensure that "-style material" and QT_QUICK_CONTROLS_STYLE=material work. Change-Id: If35b870bb335e024b94fb328a927a5550b51cba1 Reviewed-by: Mitch Curtis --- src/quickcontrols2/qquickstyle.cpp | 50 ++++++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 21 deletions(-) diff --git a/src/quickcontrols2/qquickstyle.cpp b/src/quickcontrols2/qquickstyle.cpp index bee837e9..ca5beafe 100644 --- a/src/quickcontrols2/qquickstyle.cpp +++ b/src/quickcontrols2/qquickstyle.cpp @@ -109,6 +109,24 @@ struct QQuickStyleSpec resolve(); } + static QString findStyle(const QString &path, const QString &name) + { + QDir dir(path); + if (!dir.exists()) + return QString(); + + if (name.isEmpty()) + return dir.absolutePath() + QLatin1Char('/'); + + const QStringList entries = dir.entryList(QStringList(), QDir::Dirs | QDir::NoDotAndDotDot); + for (const QString &entry : entries) { + if (entry.compare(name, Qt::CaseInsensitive) == 0) + return dir.absoluteFilePath(entry); + } + + return QString(); + } + void resolve(const QUrl &baseUrl = QUrl()) { if (style.isEmpty()) @@ -122,10 +140,12 @@ struct QQuickStyleSpec } if (baseUrl.isValid()) { - if (style.isEmpty()) - style = baseUrl.toString(QUrl::StripTrailingSlash) + QLatin1Char('/'); - else if (!style.contains(QLatin1Char('/'))) - style = baseUrl.toString(QUrl::StripTrailingSlash) + QLatin1Char('/') + style; + QString path = QQmlFile::urlToLocalFileOrQrc(baseUrl); + QString stylePath = findStyle(path, style); + if (!stylePath.isEmpty()) { + style = stylePath; + resolved = true; + } } if (QGuiApplication::instance()) { @@ -134,24 +154,12 @@ struct QQuickStyleSpec const QStringList importPaths = QQmlEngine().importPathList(); for (const QString &importPath : importPaths) { - QDir importDir(importPath); - if (importDir.cd(targetPath)) { - if (style.isEmpty()) { - style = importDir.absolutePath() + QLatin1Char('/'); - resolved = true; - break; - } - const QStringList entries = importDir.entryList(QStringList(), QDir::Dirs | QDir::NoDotAndDotDot); - for (const QString &entry : entries) { - if (entry.compare(style, Qt::CaseInsensitive) == 0) { - style = importDir.absoluteFilePath(entry); - resolved = true; - break; - } - } - } - if (resolved) + QString stylePath = findStyle(importPath + QLatin1Char('/') + targetPath, style); + if (!stylePath.isEmpty()) { + style = stylePath; + resolved = true; break; + } } } resolved = true; -- cgit v1.2.3 From c8372be0b96b1aaa9f8cb8737f8d4a662252d446 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Thu, 1 Sep 2016 21:21:44 +0200 Subject: Cleanup unused QQuickMaterialStyle::drawerBackgroundColor Drawer uses Material.dialogColor Change-Id: I4af7c5920a3603685fdca9d39b23f7db9edd09df Reviewed-by: Mitch Curtis --- src/imports/controls/material/qquickmaterialstyle.cpp | 5 ----- src/imports/controls/material/qquickmaterialstyle_p.h | 2 -- 2 files changed, 7 deletions(-) diff --git a/src/imports/controls/material/qquickmaterialstyle.cpp b/src/imports/controls/material/qquickmaterialstyle.cpp index 9361e535..bc53695a 100644 --- a/src/imports/controls/material/qquickmaterialstyle.cpp +++ b/src/imports/controls/material/qquickmaterialstyle.cpp @@ -1017,11 +1017,6 @@ QColor QQuickMaterialStyle::scrollBarPressedColor() const return QColor::fromRgba(m_theme == Light ? 0x80000000 : 0x80FFFFFF); } -QColor QQuickMaterialStyle::drawerBackgroundColor() const -{ - return QColor::fromRgba(dividerColorLight); -} - QColor QQuickMaterialStyle::dialogColor() const { return QColor::fromRgba(m_theme == Light ? dialogColorLight : dialogColorDark); diff --git a/src/imports/controls/material/qquickmaterialstyle_p.h b/src/imports/controls/material/qquickmaterialstyle_p.h index 044d30d9..ff8fcce5 100644 --- a/src/imports/controls/material/qquickmaterialstyle_p.h +++ b/src/imports/controls/material/qquickmaterialstyle_p.h @@ -98,7 +98,6 @@ class QQuickMaterialStyle : public QQuickStyleAttached Q_PROPERTY(QColor switchDisabledHandleColor READ switchDisabledHandleColor NOTIFY paletteChanged FINAL) Q_PROPERTY(QColor scrollBarColor READ scrollBarColor NOTIFY paletteChanged FINAL) Q_PROPERTY(QColor scrollBarPressedColor READ scrollBarPressedColor NOTIFY paletteChanged FINAL) - Q_PROPERTY(QColor drawerBackgroundColor READ drawerBackgroundColor NOTIFY paletteChanged FINAL) Q_PROPERTY(QColor dialogColor READ dialogColor NOTIFY paletteChanged FINAL) Q_PROPERTY(QColor backgroundDimColor READ backgroundDimColor NOTIFY paletteChanged FINAL) Q_PROPERTY(QColor listHighlightColor READ listHighlightColor NOTIFY paletteChanged FINAL) @@ -226,7 +225,6 @@ public: QColor switchDisabledHandleColor() const; QColor scrollBarColor() const; QColor scrollBarPressedColor() const; - QColor drawerBackgroundColor() const; QColor dialogColor() const; QColor backgroundDimColor() const; QColor listHighlightColor() const; -- cgit v1.2.3 From f6c3ecdb0646a4d83be5c07dd5369d0b0350260c Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Wed, 27 Jul 2016 11:12:41 +0200 Subject: Add RoundButton [ChangeLog][Controls] Added RoundButton. Change-Id: I30a8b9e942a61089e87fb1aa248432e42caf0d20 Task-number: QTBUG-54967 Reviewed-by: J-P Nurmi --- src/imports/controls/RoundButton.qml | 77 +++++++++++ src/imports/controls/controls.pri | 1 + .../doc/images/qtquickcontrols2-roundbutton.png | Bin 0 -> 1001 bytes .../doc/snippets/qtquickcontrols2-roundbutton.qml | 36 ++++++ .../doc/src/qtquickcontrols2-customize.qdoc | 6 + src/imports/controls/material/RoundButton.qml | 115 +++++++++++++++++ src/imports/controls/material/material.pri | 1 + src/imports/controls/qtquickcontrols2plugin.cpp | 1 + src/imports/controls/universal/RoundButton.qml | 87 +++++++++++++ src/imports/controls/universal/universal.pri | 1 + src/imports/templates/qtquicktemplates2plugin.cpp | 2 + src/quicktemplates2/qquickbutton.cpp | 18 +-- src/quicktemplates2/qquickbutton_p.h | 2 + src/quicktemplates2/qquickbutton_p_p.h | 68 ++++++++++ src/quicktemplates2/qquickroundbutton.cpp | 143 +++++++++++++++++++++ src/quicktemplates2/qquickroundbutton_p.h | 84 ++++++++++++ src/quicktemplates2/quicktemplates2.pri | 3 + tests/auto/controls/data/tst_roundbutton.qml | 79 ++++++++++++ tests/manual/buttons/ButtonLoader.qml | 91 +++++++++++++ tests/manual/buttons/buttons.pro | 2 +- tests/manual/buttons/buttons.qml | 43 ++++--- tests/manual/testbench/main.qml | 102 +++++++++++++++ 22 files changed, 930 insertions(+), 32 deletions(-) create mode 100644 src/imports/controls/RoundButton.qml create mode 100644 src/imports/controls/doc/images/qtquickcontrols2-roundbutton.png create mode 100644 src/imports/controls/doc/snippets/qtquickcontrols2-roundbutton.qml create mode 100644 src/imports/controls/material/RoundButton.qml create mode 100644 src/imports/controls/universal/RoundButton.qml create mode 100644 src/quicktemplates2/qquickbutton_p_p.h create mode 100644 src/quicktemplates2/qquickroundbutton.cpp create mode 100644 src/quicktemplates2/qquickroundbutton_p.h create mode 100644 tests/auto/controls/data/tst_roundbutton.qml create mode 100644 tests/manual/buttons/ButtonLoader.qml diff --git a/src/imports/controls/RoundButton.qml b/src/imports/controls/RoundButton.qml new file mode 100644 index 00000000..102774e0 --- /dev/null +++ b/src/imports/controls/RoundButton.qml @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.6 +import QtQuick.Templates 2.1 as T + +T.RoundButton { + id: control + + implicitWidth: Math.max(background ? background.implicitWidth : 0, + contentItem.implicitWidth + leftPadding + rightPadding) + implicitHeight: Math.max(background ? background.implicitHeight : 0, + contentItem.implicitHeight + topPadding + bottomPadding) + baselineOffset: contentItem.y + contentItem.baselineOffset + + padding: 6 + + //! [contentItem] + contentItem: Text { + text: control.text + font: control.font + opacity: enabled || control.highlighted || control.checked ? 1 : 0.3 + color: control.checked || control.highlighted ? "#ffffff" : (control.visualFocus ? "#0066ff" : (control.down ? "#26282a" : "#353637")) + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + elide: Text.ElideRight + } + //! [contentItem] + + //! [background] + background: Rectangle { + implicitWidth: 40 + implicitHeight: 40 + radius: control.radius + opacity: enabled ? 1 : 0.3 + visible: !control.flat || control.down || control.checked || control.highlighted + color: control.checked || control.highlighted ? + (control.visualFocus ? (control.down ? "#599bff" : "#0066ff") : (control.down ? "#585a5c" : "#353637")) : + (control.visualFocus ? (control.down ? "#cce0ff" : "#f0f6ff") : (control.down ? "#d0d0d0" : "#e0e0e0")) + border.color: "#0066ff" + border.width: control.visualFocus ? 2 : 0 + } + //! [background] +} diff --git a/src/imports/controls/controls.pri b/src/imports/controls/controls.pri index 9eeb2c1f..eecaccd4 100644 --- a/src/imports/controls/controls.pri +++ b/src/imports/controls/controls.pri @@ -36,6 +36,7 @@ QML_CONTROLS = \ RadioDelegate.qml \ RadioIndicator.qml \ RangeSlider.qml \ + RoundButton.qml \ ScrollBar.qml \ ScrollIndicator.qml \ Slider.qml \ diff --git a/src/imports/controls/doc/images/qtquickcontrols2-roundbutton.png b/src/imports/controls/doc/images/qtquickcontrols2-roundbutton.png new file mode 100644 index 00000000..9f1d44fc Binary files /dev/null and b/src/imports/controls/doc/images/qtquickcontrols2-roundbutton.png differ diff --git a/src/imports/controls/doc/snippets/qtquickcontrols2-roundbutton.qml b/src/imports/controls/doc/snippets/qtquickcontrols2-roundbutton.qml new file mode 100644 index 00000000..fa926302 --- /dev/null +++ b/src/imports/controls/doc/snippets/qtquickcontrols2-roundbutton.qml @@ -0,0 +1,36 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: http://www.gnu.org/copyleft/fdl.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 +import QtQuick.Controls 2.1 + +//! [1] +RoundButton { + text: "\u2713" // Unicode Character 'CHECK MARK' + onClicked: textArea.readOnly = true +} +//! [1] diff --git a/src/imports/controls/doc/src/qtquickcontrols2-customize.qdoc b/src/imports/controls/doc/src/qtquickcontrols2-customize.qdoc index d98b70d1..3e804bd4 100644 --- a/src/imports/controls/doc/src/qtquickcontrols2-customize.qdoc +++ b/src/imports/controls/doc/src/qtquickcontrols2-customize.qdoc @@ -548,6 +548,12 @@ \snippet qtquickcontrols2-rangeslider-custom.qml file + \section2 Customizing RoundButton + + RoundButton can be customized in the same manner as + \l {Customizing Button}{Button}. + + \section2 Customizing ScrollBar ScrollBar consists of two visual items: \l {Control::background}{background} diff --git a/src/imports/controls/material/RoundButton.qml b/src/imports/controls/material/RoundButton.qml new file mode 100644 index 00000000..57f30e30 --- /dev/null +++ b/src/imports/controls/material/RoundButton.qml @@ -0,0 +1,115 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.6 +import QtQuick.Templates 2.1 as T +import QtQuick.Controls.Material 2.1 +import QtQuick.Controls.Material.impl 2.1 + +T.RoundButton { + id: control + + implicitWidth: Math.max(background ? background.implicitWidth : 0, + contentItem.implicitWidth + leftPadding + rightPadding) + implicitHeight: Math.max(background ? background.implicitHeight : 0, + contentItem.implicitHeight + topPadding + bottomPadding) + baselineOffset: contentItem.y + contentItem.baselineOffset + + // external vertical padding is 6 (to increase touch area) + padding: 12 + + hoverEnabled: Qt.styleHints.useHoverEffects + + Material.elevation: flat ? control.down || control.hovered ? 2 : 0 + : control.down ? 8 : 2 + Material.background: flat ? "transparent" : undefined + + contentItem: Text { + text: control.text + font: control.font + color: !control.enabled ? control.Material.hintTextColor : + control.flat && control.highlighted ? control.Material.accentColor : + control.highlighted ? control.Material.primaryHighlightedTextColor : control.Material.primaryTextColor + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + elide: Text.ElideRight + } + + // TODO: Add a proper ripple/ink effect for mouse/touch input and focus state + background: Rectangle { + implicitWidth: 48 + implicitHeight: 48 + + // external vertical padding is 6 (to increase touch area) + x: 6 + y: 6 + width: parent.width - 12 + height: parent.height - 12 + radius: control.radius + color: !control.enabled ? control.Material.buttonDisabledColor + : control.checked || control.highlighted ? control.Material.highlightedButtonColor : control.Material.buttonColor + + Rectangle { + width: parent.width + height: parent.height + radius: control.radius + visible: control.hovered || control.visualFocus + color: control.Material.rippleColor + } + + Rectangle { + width: parent.width + height: parent.height + radius: control.radius + visible: control.down + color: control.Material.rippleColor + } + + Behavior on color { + ColorAnimation { + duration: 400 + } + } + + // The layer is disabled when the button color is transparent so that you can do + // Material.background: "transparent" and get a proper flat button without needing + // to set Material.elevation as well + layer.enabled: control.enabled && control.Material.buttonColor.a > 0 + layer.effect: ElevationEffect { + elevation: control.Material.elevation + } + } +} diff --git a/src/imports/controls/material/material.pri b/src/imports/controls/material/material.pri index 437edeee..3170a695 100644 --- a/src/imports/controls/material/material.pri +++ b/src/imports/controls/material/material.pri @@ -42,6 +42,7 @@ QML_FILES += \ $$PWD/RadioDelegate.qml \ $$PWD/RadioIndicator.qml \ $$PWD/RangeSlider.qml \ + $$PWD/RoundButton.qml \ $$PWD/RectangularGlow.qml \ $$PWD/ScrollBar.qml \ $$PWD/ScrollIndicator.qml \ diff --git a/src/imports/controls/qtquickcontrols2plugin.cpp b/src/imports/controls/qtquickcontrols2plugin.cpp index 3cd3b8b2..8804fff2 100644 --- a/src/imports/controls/qtquickcontrols2plugin.cpp +++ b/src/imports/controls/qtquickcontrols2plugin.cpp @@ -144,6 +144,7 @@ void QtQuickControls2Plugin::registerTypes(const char *uri) qmlRegisterType(selector.select(QStringLiteral("Dialog.qml")), uri, 2, 1, "Dialog"); qmlRegisterType(selector.select(QStringLiteral("DialogButtonBox.qml")), uri, 2, 1, "DialogButtonBox"); qmlRegisterType(selector.select(QStringLiteral("MenuSeparator.qml")), uri, 2, 1, "MenuSeparator"); + qmlRegisterType(selector.select(QStringLiteral("RoundButton.qml")), uri, 2, 1, "RoundButton"); qmlRegisterType(selector.select(QStringLiteral("ToolSeparator.qml")), uri, 2, 1, "ToolSeparator"); } diff --git a/src/imports/controls/universal/RoundButton.qml b/src/imports/controls/universal/RoundButton.qml new file mode 100644 index 00000000..61701099 --- /dev/null +++ b/src/imports/controls/universal/RoundButton.qml @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.6 +import QtQuick.Templates 2.1 as T +import QtQuick.Controls.Universal 2.1 + +T.RoundButton { + id: control + + implicitWidth: Math.max(background ? background.implicitWidth : 0, + contentItem.implicitWidth + leftPadding + rightPadding) + implicitHeight: Math.max(background ? background.implicitHeight : 0, + contentItem.implicitHeight + topPadding + bottomPadding) + baselineOffset: contentItem.y + contentItem.baselineOffset + + hoverEnabled: Qt.styleHints.useHoverEffects + + padding: 8 + + property bool useSystemFocusVisuals: true + + contentItem: Text { + text: control.text + font: control.font + elide: Text.ElideRight + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + + opacity: enabled ? 1.0 : 0.2 + color: control.Universal.foreground + } + + background: Rectangle { + implicitWidth: 32 + implicitHeight: 32 + + radius: control.radius + visible: !control.flat || control.down || control.checked || control.highlighted + color: control.down ? control.Universal.baseMediumLowColor : + control.enabled && (control.highlighted || control.checked) ? control.Universal.accent : + control.Universal.baseLowColor + + Rectangle { + width: parent.width + height: parent.height + radius: control.radius + color: "transparent" + visible: control.hovered + border.width: 2 // ButtonBorderThemeThickness + border.color: control.Universal.baseMediumLowColor + } + } +} diff --git a/src/imports/controls/universal/universal.pri b/src/imports/controls/universal/universal.pri index 72edbc32..3697a2a6 100644 --- a/src/imports/controls/universal/universal.pri +++ b/src/imports/controls/universal/universal.pri @@ -26,6 +26,7 @@ QML_FILES += \ $$PWD/RadioDelegate.qml \ $$PWD/RadioIndicator.qml \ $$PWD/RangeSlider.qml \ + $$PWD/RoundButton.qml \ $$PWD/ScrollBar.qml \ $$PWD/ScrollIndicator.qml \ $$PWD/Slider.qml \ diff --git a/src/imports/templates/qtquicktemplates2plugin.cpp b/src/imports/templates/qtquicktemplates2plugin.cpp index 67a52d14..6624b019 100644 --- a/src/imports/templates/qtquicktemplates2plugin.cpp +++ b/src/imports/templates/qtquicktemplates2plugin.cpp @@ -66,6 +66,7 @@ #include #include #include +#include #include #include #include @@ -186,6 +187,7 @@ void QtQuickTemplates2Plugin::registerTypes(const char *uri) qmlRegisterType(uri, 2, 1, "MenuSeparator"); qmlRegisterType(uri, 2, 1, "Popup"); qmlRegisterType(uri, 2, 1, "RangeSlider"); + qmlRegisterType(uri, 2, 1, "RoundButton"); qmlRegisterType(uri, 2, 1, "Slider"); qmlRegisterType(uri, 2, 1, "SpinBox"); qmlRegisterType(uri, 2, 1, "StackView"); diff --git a/src/quicktemplates2/qquickbutton.cpp b/src/quicktemplates2/qquickbutton.cpp index a51e2210..19310713 100644 --- a/src/quicktemplates2/qquickbutton.cpp +++ b/src/quicktemplates2/qquickbutton.cpp @@ -35,7 +35,7 @@ ****************************************************************************/ #include "qquickbutton_p.h" -#include "qquickabstractbutton_p_p.h" +#include "qquickbutton_p_p.h" #include @@ -91,17 +91,6 @@ QT_BEGIN_NAMESPACE \sa {Customizing Button}, {Button Controls} */ -class QQuickButtonPrivate : public QQuickAbstractButtonPrivate -{ - Q_DECLARE_PUBLIC(QQuickButton) - -public: - QQuickButtonPrivate(); - - bool flat; - bool highlighted; -}; - QQuickButtonPrivate::QQuickButtonPrivate() : flat(false), highlighted(false) { @@ -112,6 +101,11 @@ QQuickButton::QQuickButton(QQuickItem *parent) : { } +QQuickButton::QQuickButton(QQuickButtonPrivate &dd, QQuickItem *parent) : + QQuickAbstractButton(dd, parent) +{ +} + /*! \qmlproperty bool QtQuick.Controls::Button::checkable diff --git a/src/quicktemplates2/qquickbutton_p.h b/src/quicktemplates2/qquickbutton_p.h index fafce150..95f94f10 100644 --- a/src/quicktemplates2/qquickbutton_p.h +++ b/src/quicktemplates2/qquickbutton_p.h @@ -78,6 +78,8 @@ Q_SIGNALS: void flatChanged(); protected: + QQuickButton(QQuickButtonPrivate &dd, QQuickItem *parent); + void checkableChange() override; void autoRepeatChange() override; diff --git a/src/quicktemplates2/qquickbutton_p_p.h b/src/quicktemplates2/qquickbutton_p_p.h new file mode 100644 index 00000000..86663e9e --- /dev/null +++ b/src/quicktemplates2/qquickbutton_p_p.h @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKBUTTON_P_P_H +#define QQUICKBUTTON_P_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +QT_BEGIN_NAMESPACE + +class QQuickButtonPrivate : public QQuickAbstractButtonPrivate +{ + Q_DECLARE_PUBLIC(QQuickButton) + +public: + QQuickButtonPrivate(); + + bool flat; + bool highlighted; +}; + +QT_END_NAMESPACE + +#endif // QQUICKBUTTON_P_P_H diff --git a/src/quicktemplates2/qquickroundbutton.cpp b/src/quicktemplates2/qquickroundbutton.cpp new file mode 100644 index 00000000..4169b269 --- /dev/null +++ b/src/quicktemplates2/qquickroundbutton.cpp @@ -0,0 +1,143 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquickroundbutton_p.h" + +#include + +QT_BEGIN_NAMESPACE + +/*! + \qmltype RoundButton + \inherits Button + \instantiates QQuickRoundButton + \inqmlmodule QtQuick.Controls + \since 5.8 + \ingroup qtquickcontrols2-buttons + \brief A push-button control with rounded corners that can be clicked by the user. + + \image qtquickcontrols2-roundbutton.png + + RoundButton is identical to \l Button, except that it has a \l radius property + which allows the corners to be rounded without having to customize the + \l background. + + \snippet qtquickcontrols2-roundbutton.qml 1 + + \sa {Customizing RoundButton}, {Button Controls} +*/ + +class QQuickRoundButtonPrivate : public QQuickButtonPrivate +{ + Q_DECLARE_PUBLIC(QQuickRoundButton) + +public: + QQuickRoundButtonPrivate(); + + qreal radius; + bool explicitRadius; + + void setRadius(qreal newRadius = -1.0); +}; + +QQuickRoundButtonPrivate::QQuickRoundButtonPrivate() : + radius(0), + explicitRadius(false) +{ +} + +void QQuickRoundButtonPrivate::setRadius(qreal newRadius) +{ + Q_Q(QQuickRoundButton); + const qreal oldRadius = radius; + if (newRadius < 0) + radius = qMax(0, qMin(width, height) / 2); + else + radius = newRadius; + + if (!qFuzzyCompare(radius, oldRadius)) + emit q->radiusChanged(); +} + +QQuickRoundButton::QQuickRoundButton(QQuickItem *parent) : + QQuickButton(*(new QQuickRoundButtonPrivate), parent) +{ +} + +/*! + \qmlproperty real QtQuick.Controls::RoundButton::radius + + This property holds the radius of the button. + + To create a relatively square button that has slightly rounded corners, + use a small value, such as \c 3. + + To create a completely circular button (the default), use a value that is + equal to half of the width or height of the button, and make the button's + width and height identical. + + To reset this property back to the default value, set its value to + \c undefined. +*/ +qreal QQuickRoundButton::radius() const +{ + Q_D(const QQuickRoundButton); + return d->radius; +} + +void QQuickRoundButton::setRadius(qreal radius) +{ + Q_D(QQuickRoundButton); + d->explicitRadius = true; + d->setRadius(radius); +} + +void QQuickRoundButton::resetRadius() +{ + Q_D(QQuickRoundButton); + d->explicitRadius = false; + d->setRadius(); +} + +void QQuickRoundButton::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) +{ + Q_D(QQuickRoundButton); + QQuickControl::geometryChanged(newGeometry, oldGeometry); + if (!d->explicitRadius) + d->setRadius(); +} + +QT_END_NAMESPACE diff --git a/src/quicktemplates2/qquickroundbutton_p.h b/src/quicktemplates2/qquickroundbutton_p.h new file mode 100644 index 00000000..f308ddd3 --- /dev/null +++ b/src/quicktemplates2/qquickroundbutton_p.h @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKROUNDBUTTON_P_H +#define QQUICKROUNDBUTTON_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +QT_BEGIN_NAMESPACE + +class QQuickRoundButtonPrivate; + +class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickRoundButton : public QQuickButton +{ + Q_OBJECT + Q_PROPERTY(qreal radius READ radius WRITE setRadius RESET resetRadius NOTIFY radiusChanged FINAL) + +public: + explicit QQuickRoundButton(QQuickItem *parent = nullptr); + + qreal radius() const; + void setRadius(qreal radius); + void resetRadius(); + +Q_SIGNALS: + void radiusChanged(); + +protected: + void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) override; + +private: + Q_DISABLE_COPY(QQuickRoundButton) + Q_DECLARE_PRIVATE(QQuickRoundButton) +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QQuickRoundButton) + +#endif // QQUICKROUNDBUTTON_P_H diff --git a/src/quicktemplates2/quicktemplates2.pri b/src/quicktemplates2/quicktemplates2.pri index f5e95aea..686cbd52 100644 --- a/src/quicktemplates2/quicktemplates2.pri +++ b/src/quicktemplates2/quicktemplates2.pri @@ -6,6 +6,7 @@ HEADERS += \ $$PWD/qquickapplicationwindow_p.h \ $$PWD/qquickbusyindicator_p.h \ $$PWD/qquickbutton_p.h \ + $$PWD/qquickbutton_p_p.h \ $$PWD/qquickbuttongroup_p.h \ $$PWD/qquickcheckbox_p.h \ $$PWD/qquickcheckdelegate_p.h \ @@ -44,6 +45,7 @@ HEADERS += \ $$PWD/qquickradiobutton_p.h \ $$PWD/qquickradiodelegate_p.h \ $$PWD/qquickrangeslider_p.h \ + $$PWD/qquickroundbutton_p.h \ $$PWD/qquickscrollbar_p.h \ $$PWD/qquickscrollindicator_p.h \ $$PWD/qquickslider_p.h \ @@ -101,6 +103,7 @@ SOURCES += \ $$PWD/qquickradiobutton.cpp \ $$PWD/qquickradiodelegate.cpp \ $$PWD/qquickrangeslider.cpp \ + $$PWD/qquickroundbutton.cpp \ $$PWD/qquickscrollbar.cpp \ $$PWD/qquickscrollindicator.cpp \ $$PWD/qquickslider.cpp \ diff --git a/tests/auto/controls/data/tst_roundbutton.qml b/tests/auto/controls/data/tst_roundbutton.qml new file mode 100644 index 00000000..aa956776 --- /dev/null +++ b/tests/auto/controls/data/tst_roundbutton.qml @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite 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 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.Controls 2.1 + +TestCase { + id: testCase + width: 200 + height: 200 + visible: true + when: windowShown + name: "RoundButton" + + Component { + id: roundButton + RoundButton { } + } + + function test_radius() { + var control = roundButton.createObject(testCase); + verify(control); + + var implicitRadius = control.radius; + compare(implicitRadius, Math.min(control.width, control.height) / 2); + + control.radius = 10; + compare(control.radius, 10); + + control.radius = undefined; + compare(control.radius, implicitRadius); + + control.width = -1; + compare(control.radius, 0); + + control.width = 10; + compare(control.radius, 5); + + control.destroy(); + } +} diff --git a/tests/manual/buttons/ButtonLoader.qml b/tests/manual/buttons/ButtonLoader.qml new file mode 100644 index 00000000..8793d98f --- /dev/null +++ b/tests/manual/buttons/ButtonLoader.qml @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite 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 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.8 +import QtQuick.Controls 2.1 + +Item { + id: root + implicitWidth: activeButton.implicitWidth + implicitHeight: activeButton.implicitHeight + + property bool round: false + + property string text + property bool flat + property bool hoverEnabled + property bool highlighted + property bool checked + property var down: undefined + + property AbstractButton activeButton: round ? roundButton : button + + Button { + id: button + visible: !round + text: root.text + flat: root.flat + hoverEnabled: root.hoverEnabled + highlighted: root.highlighted + checked: root.checked + down: root.down + enabled: root.enabled + } + + RoundButton { + id: roundButton + visible: round + text: "\u2713" + flat: root.flat + hoverEnabled: root.hoverEnabled + highlighted: root.highlighted + checked: root.checked + down: root.down + enabled: root.enabled + + Label { + text: root.text + font.pixelSize: roundButton.contentItem.font.pixelSize * 0.5 + anchors.top: parent.bottom + anchors.topMargin: 2 + anchors.horizontalCenter: parent.horizontalCenter + } + } +} diff --git a/tests/manual/buttons/buttons.pro b/tests/manual/buttons/buttons.pro index d0a6eb28..2cb1c14c 100644 --- a/tests/manual/buttons/buttons.pro +++ b/tests/manual/buttons/buttons.pro @@ -3,4 +3,4 @@ TARGET = buttons QT += qml quickcontrols2 SOURCES += buttons.cpp -RESOURCES += buttons.qml +RESOURCES += $$files(*.qml) diff --git a/tests/manual/buttons/buttons.qml b/tests/manual/buttons/buttons.qml index e1a393fd..b3aba775 100644 --- a/tests/manual/buttons/buttons.qml +++ b/tests/manual/buttons/buttons.qml @@ -62,6 +62,11 @@ ApplicationWindow { text: "Hover" checked: true } + CheckBox { + id: roundBox + text: "Round" + checked: false + } } } @@ -105,25 +110,25 @@ ApplicationWindow { spacing: 20 padding: 20 - Button { text: "Normal"; flat: modelData.flat; hoverEnabled: hoverBox.checked } - Button { text: "Disabled"; flat: modelData.flat; hoverEnabled: hoverBox.checked; enabled: false } - Button { text: "Down"; flat: modelData.flat; hoverEnabled: hoverBox.checked; down: true } - Button { text: "Disabled"; flat: modelData.flat; hoverEnabled: hoverBox.checked; down: true; enabled: false } - - Button { text: "Checked"; flat: modelData.flat; hoverEnabled: hoverBox.checked; checked: true } - Button { text: "Disabled"; flat: modelData.flat; hoverEnabled: hoverBox.checked; checked: true; enabled: false } - Button { text: "Down"; flat: modelData.flat; hoverEnabled: hoverBox.checked; checked: true; down: true } - Button { text: "Disabled"; flat: modelData.flat; hoverEnabled: hoverBox.checked; checked: true; down: true; enabled: false } - - Button { text: "Highlighted"; flat: modelData.flat; hoverEnabled: hoverBox.checked; highlighted: true } - Button { text: "Disabled"; flat: modelData.flat; hoverEnabled: hoverBox.checked; highlighted: true; enabled: false } - Button { text: "Down"; flat: modelData.flat; hoverEnabled: hoverBox.checked; highlighted: true; down: true } - Button { text: "Disabled"; flat: modelData.flat; hoverEnabled: hoverBox.checked; highlighted: true; down: true; enabled: false } - - Button { text: "Hi-checked"; flat: modelData.flat; hoverEnabled: hoverBox.checked; highlighted: true; checked: true } - Button { text: "Disabled"; flat: modelData.flat; hoverEnabled: hoverBox.checked; highlighted: true; checked: true; enabled: false } - Button { text: "Down"; flat: modelData.flat; hoverEnabled: hoverBox.checked; highlighted: true; checked: true; down: true } - Button { text: "Disabled"; flat: modelData.flat; hoverEnabled: hoverBox.checked; highlighted: true; checked: true; down: true; enabled: false } + ButtonLoader { text: "Normal"; flat: modelData.flat; hoverEnabled: hoverBox.checked; round: roundBox.checked } + ButtonLoader { text: "Disabled"; flat: modelData.flat; hoverEnabled: hoverBox.checked; enabled: false; round: roundBox.checked } + ButtonLoader { text: "Down"; flat: modelData.flat; hoverEnabled: hoverBox.checked; down: true; round: roundBox.checked } + ButtonLoader { text: "Disabled"; flat: modelData.flat; hoverEnabled: hoverBox.checked; down: true; enabled: false; round: roundBox.checked } + + ButtonLoader { text: "Checked"; flat: modelData.flat; hoverEnabled: hoverBox.checked; checked: true; round: roundBox.checked } + ButtonLoader { text: "Disabled"; flat: modelData.flat; hoverEnabled: hoverBox.checked; checked: true; enabled: false; round: roundBox.checked } + ButtonLoader { text: "Down"; flat: modelData.flat; hoverEnabled: hoverBox.checked; checked: true; down: true; round: roundBox.checked } + ButtonLoader { text: "Disabled"; flat: modelData.flat; hoverEnabled: hoverBox.checked; checked: true; down: true; enabled: false; round: roundBox.checked } + + ButtonLoader { text: "Highlighted"; flat: modelData.flat; hoverEnabled: hoverBox.checked; highlighted: true; round: roundBox.checked } + ButtonLoader { text: "Disabled"; flat: modelData.flat; hoverEnabled: hoverBox.checked; highlighted: true; enabled: false; round: roundBox.checked } + ButtonLoader { text: "Down"; flat: modelData.flat; hoverEnabled: hoverBox.checked; highlighted: true; down: true; round: roundBox.checked } + ButtonLoader { text: "Disabled"; flat: modelData.flat; hoverEnabled: hoverBox.checked; highlighted: true; down: true; enabled: false; round: roundBox.checked } + + ButtonLoader { text: "Hi-checked"; flat: modelData.flat; hoverEnabled: hoverBox.checked; highlighted: true; checked: true; round: roundBox.checked } + ButtonLoader { text: "Disabled"; flat: modelData.flat; hoverEnabled: hoverBox.checked; highlighted: true; checked: true; enabled: false; round: roundBox.checked } + ButtonLoader { text: "Down"; flat: modelData.flat; hoverEnabled: hoverBox.checked; highlighted: true; checked: true; down: true; round: roundBox.checked } + ButtonLoader { text: "Disabled"; flat: modelData.flat; hoverEnabled: hoverBox.checked; highlighted: true; checked: true; down: true; enabled: false; round: roundBox.checked } } } } diff --git a/tests/manual/testbench/main.qml b/tests/manual/testbench/main.qml index dd1a1de8..ea59d5b5 100644 --- a/tests/manual/testbench/main.qml +++ b/tests/manual/testbench/main.qml @@ -250,6 +250,108 @@ ApplicationWindow { } } + RowLayout { + spacing: window.controlSpacing * 2 + + Button { + text: "Normal" + } + Button { + text: "Pressed" + down: true + } + Button { + text: "Checked" + checked: true + } + Button { + text: "CH + PR" + checked: true + down: true + } + Button { + text: "Disabled" + enabled: false + } + Button { + text: "CH + DIS" + enabled: false + checked: true + } + } + + RowLayout { + spacing: window.controlSpacing * 2 + + ColumnLayout { + RoundButton { + highlighted: true + Layout.alignment: Qt.AlignHCenter + } + Label { + text: "HI" + Layout.alignment: Qt.AlignHCenter + } + } + ColumnLayout { + RoundButton { + highlighted: true + down: true + Layout.alignment: Qt.AlignHCenter + } + Label { + text: "HI + PR" + Layout.alignment: Qt.AlignHCenter + } + } + ColumnLayout { + RoundButton { + highlighted: true + checked: true + Layout.alignment: Qt.AlignHCenter + } + Label { + text: "HI + CH" + Layout.alignment: Qt.AlignHCenter + } + } + ColumnLayout { + RoundButton { + highlighted: true + down: true + checked: true + Layout.alignment: Qt.AlignHCenter + } + Label { + text: "HI+CH+PR" + Layout.alignment: Qt.AlignHCenter + } + } + ColumnLayout { + RoundButton { + highlighted: true + enabled: false + Layout.alignment: Qt.AlignHCenter + } + Label { + text: "HI + DIS" + Layout.alignment: Qt.AlignHCenter + } + } + ColumnLayout { + RoundButton { + highlighted: true + enabled: false + checked: true + Layout.alignment: Qt.AlignHCenter + } + Label { + text: "HI+CH+DIS" + Layout.alignment: Qt.AlignHCenter + } + } + } + RowLayout { CheckBox { text: "Normal" -- cgit v1.2.3 From 33904b63ce9971efc3763a0048a084ec3324dfc4 Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Tue, 23 Aug 2016 16:33:21 +0200 Subject: Material: ignore Material.background unless explicitly set Doing Material.background: "red" in an ApplicationWindow shouldn't affect the background color of e.g. a Button. The background property should still propagate though, so we change buttonColor() to ignore the value of background if it wasn't explicitly set. Change-Id: I09b4df142935b19de35a77bd68c6c062417b74fc Reviewed-by: J-P Nurmi --- .../controls/material/qquickmaterialstyle.cpp | 3 ++- .../auto/qquickmaterialstyle/data/tst_material.qml | 29 ++++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/imports/controls/material/qquickmaterialstyle.cpp b/src/imports/controls/material/qquickmaterialstyle.cpp index bc53695a..8562cdbb 100644 --- a/src/imports/controls/material/qquickmaterialstyle.cpp +++ b/src/imports/controls/material/qquickmaterialstyle.cpp @@ -716,6 +716,7 @@ void QQuickMaterialStyle::setBackground(const QVariant &var) m_background = background; propagateBackground(); emit backgroundChanged(); + emit paletteChanged(); } void QQuickMaterialStyle::inheritBackground(uint background, bool custom, bool has) @@ -865,7 +866,7 @@ QColor QQuickMaterialStyle::buttonColor(bool highlighted, bool pressed, bool hov QColor color = Qt::transparent; - if (m_hasBackground) { + if (m_explicitBackground) { color = backgroundColor(shade); } else if (highlighted) { color = accentColor(shade); diff --git a/tests/auto/qquickmaterialstyle/data/tst_material.qml b/tests/auto/qquickmaterialstyle/data/tst_material.qml index 7305b732..1cd1d16d 100644 --- a/tests/auto/qquickmaterialstyle/data/tst_material.qml +++ b/tests/auto/qquickmaterialstyle/data/tst_material.qml @@ -73,6 +73,11 @@ TestCase { Window { } } + Component { + id: applicationWindow + ApplicationWindow { } + } + Component { id: styledWindow Window { @@ -600,4 +605,28 @@ TestCase { window.destroy() } + + function test_buttonBackground() { + var appWindow = applicationWindow.createObject(testCase) + verify(appWindow) + appWindow.visible = true + + var childButton = button.createObject(appWindow) + verify(childButton) + + var buttonBackgroundColor = childButton.background.color + appWindow.Material.background = "red" + // We wait the length of the color animation to be sure that it hasn't actually changed. + wait(400) + // We want childButton.Material.background to be equal to appWindow.Material.background, + // because we want the color to propagate to items that might actually use it... + // but Button doesn't use the background color unless explicitly set, + // so we compare the actual background rect color instead. + compare(childButton.background.color, buttonBackgroundColor) + + childButton.Material.background = "#0000ff" + tryCompare(childButton.background, "color", "#0000ff") + + appWindow.destroy() + } } -- cgit v1.2.3 From 73baf55b107350211e53bdf839a6ba2d273865bd Mon Sep 17 00:00:00 2001 From: Anton Kudryavtsev Date: Tue, 23 Aug 2016 11:33:30 +0300 Subject: Replace 'foreach' with 'range for' And add QT_NO_FOREACH define to .qmake.conf. Now QuickControls2 is 'foreach' free. Change-Id: I98695258859decadae6fd2f23f5f6f5ef2b0550f Reviewed-by: J-P Nurmi --- .qmake.conf | 1 + tests/auto/focus/tst_focus.cpp | 2 +- tests/auto/sanity/tst_sanity.cpp | 12 +++++++----- tests/auto/snippets/tst_snippets.cpp | 2 +- tests/benchmarks/creationtime/tst_creationtime.cpp | 7 ++++--- tests/benchmarks/objectcount/tst_objectcount.cpp | 11 ++++++----- tests/manual/gifs/eventcapturer.cpp | 3 ++- tests/manual/gifs/tst_gifs.cpp | 3 ++- 8 files changed, 24 insertions(+), 17 deletions(-) diff --git a/.qmake.conf b/.qmake.conf index bef29089..98def4f4 100644 --- a/.qmake.conf +++ b/.qmake.conf @@ -1,5 +1,6 @@ load(qt_build_config) CONFIG += warning_clean +DEFINES += QT_NO_FOREACH QQC2_SOURCE_TREE = $$PWD diff --git a/tests/auto/focus/tst_focus.cpp b/tests/auto/focus/tst_focus.cpp index 2c9573c6..36bc2d32 100644 --- a/tests/auto/focus/tst_focus.cpp +++ b/tests/auto/focus/tst_focus.cpp @@ -107,7 +107,7 @@ void tst_focus::navigation() QVERIFY(QTest::qWaitForWindowActive(&view)); QVERIFY(QGuiApplication::focusWindow() == &view); - foreach (const QString &name, order) { + for (const QString &name : qAsConst(order)) { QKeyEvent event(QEvent::KeyPress, key, Qt::NoModifier); QGuiApplication::sendEvent(&view, &event); QVERIFY(event.isAccepted()); diff --git a/tests/auto/sanity/tst_sanity.cpp b/tests/auto/sanity/tst_sanity.cpp index 6b9e05ba..10348ba4 100644 --- a/tests/auto/sanity/tst_sanity.cpp +++ b/tests/auto/sanity/tst_sanity.cpp @@ -114,7 +114,8 @@ public: QQmlJS::Parser parser(&engine); if (!parser.parse()) { - foreach (const QQmlJS::DiagnosticMessage &msg, parser.diagnosticMessages()) + const auto diagnosticMessages = parser.diagnosticMessages(); + for (const QQmlJS::DiagnosticMessage &msg : diagnosticMessages) m_errors += QString("%s:%d : %s").arg(m_fileName).arg(msg.loc.startLine).arg(msg.message); return false; } @@ -267,11 +268,12 @@ static void addTestRows(QQmlEngine *engine, const QString &sourcePath, const QSt // the engine's import path. This way we can use QQmlComponent to load each QML file // for benchmarking. - QFileInfoList entries = QDir(QQC2_IMPORT_PATH "/" + sourcePath).entryInfoList(QStringList("*.qml"), QDir::Files); - foreach (const QFileInfo &entry, entries) { + const QFileInfoList entries = QDir(QQC2_IMPORT_PATH "/" + sourcePath).entryInfoList(QStringList("*.qml"), QDir::Files); + for (const QFileInfo &entry : entries) { QString name = entry.baseName(); if (!skiplist.contains(name)) { - foreach (const QString &importPath, engine->importPathList()) { + const auto importPathList = engine->importPathList(); + for (const QString &importPath : importPathList) { QString name = entry.dir().dirName() + "/" + entry.fileName(); QString filePath = importPath + "/" + targetPath + "/" + entry.fileName(); if (QFile::exists(filePath)) { @@ -296,7 +298,7 @@ void tst_Sanity::attachedObjects() QSet classNames; QScopedPointer object(component.create()); QVERIFY2(object.data(), qPrintable(component.errorString())); - foreach (QObject *object, *qt_qobjects) { + for (QObject *object : qAsConst(*qt_qobjects)) { if (object->parent() == &engine) continue; // allow "global" instances QString className = object->metaObject()->className(); diff --git a/tests/auto/snippets/tst_snippets.cpp b/tests/auto/snippets/tst_snippets.cpp index fb581b90..6ca9e72c 100644 --- a/tests/auto/snippets/tst_snippets.cpp +++ b/tests/auto/snippets/tst_snippets.cpp @@ -101,7 +101,7 @@ void tst_Snippets::screenshots() QVERIFY(QTest::qWaitForWindowActive(&view)); bool generateScreenshot = true; - foreach (const QString &baseName, nonVisualSnippets) { + for (const QString &baseName : qAsConst(nonVisualSnippets)) { if (input.contains(baseName)) { generateScreenshot = false; break; diff --git a/tests/benchmarks/creationtime/tst_creationtime.cpp b/tests/benchmarks/creationtime/tst_creationtime.cpp index 877cf273..3eec3825 100644 --- a/tests/benchmarks/creationtime/tst_creationtime.cpp +++ b/tests/benchmarks/creationtime/tst_creationtime.cpp @@ -78,11 +78,12 @@ static void addTestRows(QQmlEngine *engine, const QString &sourcePath, const QSt // the engine's import path. This way we can use QQmlComponent to load each QML file // for benchmarking. - QFileInfoList entries = QDir(QQC2_IMPORT_PATH "/" + sourcePath).entryInfoList(QStringList("*.qml"), QDir::Files); - foreach (const QFileInfo &entry, entries) { + const QFileInfoList entries = QDir(QQC2_IMPORT_PATH "/" + sourcePath).entryInfoList(QStringList("*.qml"), QDir::Files); + for (const QFileInfo &entry : entries) { QString name = entry.baseName(); if (!skiplist.contains(name)) { - foreach (const QString &importPath, engine->importPathList()) { + const auto importPathList = engine->importPathList(); + for (const QString &importPath : importPathList) { QString name = entry.dir().dirName() + "/" + entry.fileName(); QString filePath = importPath + "/" + targetPath + "/" + entry.fileName(); if (QFile::exists(filePath)) { diff --git a/tests/benchmarks/objectcount/tst_objectcount.cpp b/tests/benchmarks/objectcount/tst_objectcount.cpp index 554b8af1..549d7eef 100644 --- a/tests/benchmarks/objectcount/tst_objectcount.cpp +++ b/tests/benchmarks/objectcount/tst_objectcount.cpp @@ -100,7 +100,7 @@ static void printItems(const QList &items) std::cout << " QQuickItems: " << items.count() << " (total of QObjects: " << qt_qobjects->count() << ")" << std::endl; if (qt_verbose) { - foreach (QObject *object, *qt_qobjects) + for (QObject *object : qAsConst(*qt_qobjects)) qInfo() << "\t" << object; } } @@ -118,11 +118,12 @@ static void addTestRows(QQmlEngine *engine, const QString &sourcePath, const QSt // the engine's import path. This way we can use QQmlComponent to load each QML file // for benchmarking. - QFileInfoList entries = QDir(QQC2_IMPORT_PATH "/" + sourcePath).entryInfoList(QStringList("*.qml"), QDir::Files); - foreach (const QFileInfo &entry, entries) { + const QFileInfoList entries = QDir(QQC2_IMPORT_PATH "/" + sourcePath).entryInfoList(QStringList("*.qml"), QDir::Files); + for (const QFileInfo &entry : entries) { QString name = entry.baseName(); if (!skiplist.contains(name)) { - foreach (const QString &importPath, engine->importPathList()) { + const auto importPathList = engine->importPathList(); + for (const QString &importPath : importPathList) { QString name = entry.dir().dirName() + "/" + entry.fileName(); QString filePath = importPath + "/" + targetPath + "/" + entry.fileName(); if (QFile::exists(filePath)) { @@ -148,7 +149,7 @@ static void doBenchmark(QQmlEngine *engine, const QUrl &url) QVERIFY2(object.data(), qPrintable(component.errorString())); QList items; - foreach (QObject *object, *qt_qobjects()) { + for (QObject *object : qAsConst(*qt_qobjects)) { QQuickItem *item = qobject_cast(object); if (item) items += item; diff --git a/tests/manual/gifs/eventcapturer.cpp b/tests/manual/gifs/eventcapturer.cpp index 83e1c76b..3c355f59 100644 --- a/tests/manual/gifs/eventcapturer.cpp +++ b/tests/manual/gifs/eventcapturer.cpp @@ -57,7 +57,8 @@ // interact with the view here, in order for the events to be captured qDebug() << "\n"; - foreach (CapturedEvent event, eventCapturer.capturedEvents()) + const auto capturedEvents = eventCapturer.capturedEvents(); + for (CapturedEvent event : capturedEvents) qDebug().noquote() << event.cppCommand(); \endcode diff --git a/tests/manual/gifs/tst_gifs.cpp b/tests/manual/gifs/tst_gifs.cpp index 078813e1..24472036 100644 --- a/tests/manual/gifs/tst_gifs.cpp +++ b/tests/manual/gifs/tst_gifs.cpp @@ -188,7 +188,8 @@ void tst_Gifs::tumblerWrap() gifRecorder.waitForFinish(); - foreach (CapturedEvent event, eventCapturer.capturedEvents()) + const auto capturedEvents = eventCapturer.capturedEvents(); + for (CapturedEvent event : capturedEvents) qDebug().noquote() << event.cppCommand(); } -- cgit v1.2.3 From 61ed2a96c7e87193d37b8b6f1ab03469e294ba41 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Fri, 2 Sep 2016 21:04:25 +0200 Subject: Update .gitignore Change-Id: Ie23caad334346a87703655fd83c447447bbfbce0 Reviewed-by: J-P Nurmi --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 5597a2f7..6a83e3c0 100644 --- a/.gitignore +++ b/.gitignore @@ -24,9 +24,11 @@ /tests/auto/popup/tst_popup /tests/auto/pressandhold/tst_pressandhold /tests/auto/qquickmaterialstyle/tst_qquickmaterialstyle +/tests/auto/qquickmaterialstyleconf/tst_qquickmaterialstyleconf /tests/auto/qquickstyle/tst_qquickstyle /tests/auto/qquickstyleselector/tst_qquickstyleselector /tests/auto/qquickuniversalstyle/tst_qquickuniversalstyle +/tests/auto/qquickuniversalstyleconf/tst_qquickuniversalstyleconf /tests/auto/sanity/tst_sanity /tests/auto/snippets/tst_snippets /tests/auto/styles/tst_styles -- cgit v1.2.3 From 82a17dc90144459982be0ea28145ea8b5e1057a0 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Sat, 3 Sep 2016 12:48:46 +0200 Subject: Update plugins.qmltypes Change-Id: I0a2996deb02d873dc970f15ce6f6416b64baeab7 Reviewed-by: J-P Nurmi --- src/imports/controls/plugins.qmltypes | 81 ++++++++++++++++++++++++++++------ src/imports/templates/plugins.qmltypes | 17 +++++++ 2 files changed, 84 insertions(+), 14 deletions(-) diff --git a/src/imports/controls/plugins.qmltypes b/src/imports/controls/plugins.qmltypes index 0700e7bf..a1ca509b 100644 --- a/src/imports/controls/plugins.qmltypes +++ b/src/imports/controls/plugins.qmltypes @@ -16,14 +16,14 @@ Module { name: "QQuickBusyIndicatorRing" defaultProperty: "data" prototype: "QQuickItem" - exports: ["QtQuick.Controls.impl/BusyRing 2.1"] + exports: ["QtQuick.Controls.impl/BusyRing 2.0"] exportMetaObjectRevisions: [0] } Component { name: "QQuickDialRing" defaultProperty: "data" prototype: "QQuickPaintedItem" - exports: ["QtQuick.Controls.impl/DialRing 2.1"] + exports: ["QtQuick.Controls.impl/DialRing 2.0"] exportMetaObjectRevisions: [0] Property { name: "progress"; type: "double" } Property { name: "color"; type: "QColor" } @@ -32,7 +32,7 @@ Module { name: "QQuickProgressStrip" defaultProperty: "data" prototype: "QQuickItem" - exports: ["QtQuick.Controls.impl/ProgressStrip 2.1"] + exports: ["QtQuick.Controls.impl/ProgressStrip 2.0"] exportMetaObjectRevisions: [0] Property { name: "indeterminate"; type: "bool" } Property { name: "progress"; type: "double" } @@ -89,9 +89,9 @@ Module { } Component { prototype: "QQuickRectangle" - name: "QtQuick.Controls.impl/CheckIndicator 2.1" - exports: ["QtQuick.Controls.impl/CheckIndicator 2.1"] - exportMetaObjectRevisions: [1] + name: "QtQuick.Controls.impl/CheckIndicator 2.0" + exports: ["QtQuick.Controls.impl/CheckIndicator 2.0"] + exportMetaObjectRevisions: [0] isComposite: true defaultProperty: "data" Property { name: "control"; type: "QQuickItem"; isPointer: true } @@ -104,6 +104,22 @@ Module { isComposite: true defaultProperty: "data" } + Component { + prototype: "QQuickContainer" + name: "QtQuick.Controls/Container 2.0" + exports: ["QtQuick.Controls/Container 2.0"] + exportMetaObjectRevisions: [0] + isComposite: true + defaultProperty: "contentData" + } + Component { + prototype: "QQuickControl" + name: "QtQuick.Controls/Control 2.0" + exports: ["QtQuick.Controls/Control 2.0"] + exportMetaObjectRevisions: [0] + isComposite: true + defaultProperty: "data" + } Component { prototype: "QQuickDial" name: "QtQuick.Controls/Dial 2.0" @@ -184,6 +200,14 @@ Module { isComposite: true defaultProperty: "data" } + Component { + prototype: "QQuickMenuSeparator" + name: "QtQuick.Controls/MenuSeparator 2.1" + exports: ["QtQuick.Controls/MenuSeparator 2.1"] + exportMetaObjectRevisions: [1] + isComposite: true + defaultProperty: "data" + } Component { prototype: "QQuickPage" name: "QtQuick.Controls/Page 2.0" @@ -242,9 +266,9 @@ Module { } Component { prototype: "QQuickRectangle" - name: "QtQuick.Controls.impl/RadioIndicator 2.1" - exports: ["QtQuick.Controls.impl/RadioIndicator 2.1"] - exportMetaObjectRevisions: [1] + name: "QtQuick.Controls.impl/RadioIndicator 2.0" + exports: ["QtQuick.Controls.impl/RadioIndicator 2.0"] + exportMetaObjectRevisions: [0] isComposite: true defaultProperty: "data" Property { name: "control"; type: "QQuickItem"; isPointer: true } @@ -257,6 +281,14 @@ Module { isComposite: true defaultProperty: "data" } + Component { + prototype: "QQuickRoundButton" + name: "QtQuick.Controls/RoundButton 2.1" + exports: ["QtQuick.Controls/RoundButton 2.1"] + exportMetaObjectRevisions: [1] + isComposite: true + defaultProperty: "data" + } Component { prototype: "QQuickScrollBar" name: "QtQuick.Controls/ScrollBar 2.0" @@ -331,9 +363,9 @@ Module { } Component { prototype: "QQuickItem" - name: "QtQuick.Controls.impl/SwitchIndicator 2.1" - exports: ["QtQuick.Controls.impl/SwitchIndicator 2.1"] - exportMetaObjectRevisions: [1] + name: "QtQuick.Controls.impl/SwitchIndicator 2.0" + exports: ["QtQuick.Controls.impl/SwitchIndicator 2.0"] + exportMetaObjectRevisions: [0] isComposite: true defaultProperty: "data" Property { name: "control"; type: "QQuickItem"; isPointer: true } @@ -529,11 +561,15 @@ Module { name: "QQuickComboBox" defaultProperty: "data" prototype: "QQuickControl" - exports: ["QtQuick.Templates/ComboBox 2.0"] - exportMetaObjectRevisions: [0] + exports: [ + "QtQuick.Templates/ComboBox 2.0", + "QtQuick.Templates/ComboBox 2.1" + ] + exportMetaObjectRevisions: [0, 1] Property { name: "count"; type: "int"; isReadonly: true } Property { name: "model"; type: "QVariant" } Property { name: "delegateModel"; type: "QQmlInstanceModel"; isReadonly: true; isPointer: true } + Property { name: "flat"; revision: 1; type: "bool" } Property { name: "pressed"; type: "bool" } Property { name: "highlightedIndex"; type: "int"; isReadonly: true } Property { name: "currentIndex"; type: "int" } @@ -543,6 +579,7 @@ Module { Property { name: "delegate"; type: "QQmlComponent"; isPointer: true } Property { name: "indicator"; type: "QQuickItem"; isPointer: true } Property { name: "popup"; type: "QQuickPopup"; isPointer: true } + Signal { name: "flatChanged"; revision: 1 } Signal { name: "activated" Parameter { name: "index"; type: "int" } @@ -981,6 +1018,13 @@ Module { Property { name: "highlighted"; type: "bool" } Signal { name: "triggered" } } + Component { + name: "QQuickMenuSeparator" + defaultProperty: "data" + prototype: "QQuickControl" + exports: ["QtQuick.Templates/MenuSeparator 2.1"] + exportMetaObjectRevisions: [0] + } Component { name: "QQuickOverlay" defaultProperty: "data" @@ -1201,6 +1245,14 @@ Module { Parameter { name: "h"; type: "int" } } } + Component { + name: "QQuickRoundButton" + defaultProperty: "data" + prototype: "QQuickButton" + exports: ["QtQuick.Templates/RoundButton 2.1"] + exportMetaObjectRevisions: [1] + Property { name: "radius"; type: "double" } + } Component { name: "QQuickScrollBar" defaultProperty: "data" @@ -1333,6 +1385,7 @@ Module { Signal { name: "activating" } Signal { name: "deactivated" } Signal { name: "deactivating" } + Signal { name: "removed" } } Component { name: "QQuickStackView" diff --git a/src/imports/templates/plugins.qmltypes b/src/imports/templates/plugins.qmltypes index cbcc1fc7..dd991cfe 100644 --- a/src/imports/templates/plugins.qmltypes +++ b/src/imports/templates/plugins.qmltypes @@ -144,6 +144,7 @@ Module { Property { name: "delegate"; type: "QQmlComponent"; isPointer: true } Property { name: "indicator"; type: "QQuickItem"; isPointer: true } Property { name: "popup"; type: "QQuickPopup"; isPointer: true } + Signal { name: "flatChanged"; revision: 1 } Signal { name: "activated" Parameter { name: "index"; type: "int" } @@ -582,6 +583,13 @@ Module { Property { name: "highlighted"; type: "bool" } Signal { name: "triggered" } } + Component { + name: "QQuickMenuSeparator" + defaultProperty: "data" + prototype: "QQuickControl" + exports: ["QtQuick.Templates/MenuSeparator 2.1"] + exportMetaObjectRevisions: [0] + } Component { name: "QQuickOverlay" defaultProperty: "data" @@ -802,6 +810,14 @@ Module { Parameter { name: "h"; type: "int" } } } + Component { + name: "QQuickRoundButton" + defaultProperty: "data" + prototype: "QQuickButton" + exports: ["QtQuick.Templates/RoundButton 2.1"] + exportMetaObjectRevisions: [1] + Property { name: "radius"; type: "double" } + } Component { name: "QQuickScrollBar" defaultProperty: "data" @@ -934,6 +950,7 @@ Module { Signal { name: "activating" } Signal { name: "deactivated" } Signal { name: "deactivating" } + Signal { name: "removed" } } Component { name: "QQuickStackView" -- cgit v1.2.3 From 850f6e2f2f096541e3c02cc1030d3a7f7b9ae190 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Sat, 3 Sep 2016 12:42:17 +0200 Subject: texteditor: allow passing -touch as a command line argument It was already possible to specify QT_FILE_SELECTORS=touch, but in Qt Creator, it's more convenient to specify a command line argument than an environment variable. Change-Id: I83a86aa88fb0c229d9bcedb6646351f0675db199 Reviewed-by: Mitch Curtis --- examples/quickcontrols2/texteditor/texteditor.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/examples/quickcontrols2/texteditor/texteditor.cpp b/examples/quickcontrols2/texteditor/texteditor.cpp index 7fda4fa9..10ba675c 100644 --- a/examples/quickcontrols2/texteditor/texteditor.cpp +++ b/examples/quickcontrols2/texteditor/texteditor.cpp @@ -70,10 +70,17 @@ int main(int argc, char *argv[]) qmlRegisterType("io.qt.examples.texteditor", 1, 0, "DocumentHandler"); - QQmlApplicationEngine engine; + QStringList selectors; #ifdef QT_EXTRA_FILE_SELECTOR - QQmlFileSelector::get(&engine)->setExtraSelectors(QStringList() << QT_EXTRA_FILE_SELECTOR); + selectors += QT_EXTRA_FILE_SELECTOR; +#else + if (app.arguments().contains("-touch")) + selectors += "touch"; #endif + + QQmlApplicationEngine engine; + QQmlFileSelector::get(&engine)->setExtraSelectors(selectors); + engine.load(QUrl("qrc:/qml/texteditor.qml")); if (engine.rootObjects().isEmpty()) return -1; -- cgit v1.2.3 From 9a55b34e292c725a4fa394a71e0a3d851e4e488f Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Sat, 3 Sep 2016 12:46:10 +0200 Subject: texteditor: use RoundButton Change-Id: I4cb9b2151698e30deec969868ffdb0100b7d98a3 Reviewed-by: Mitch Curtis --- .../quickcontrols2/texteditor/qml/+touch/texteditor.qml | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/examples/quickcontrols2/texteditor/qml/+touch/texteditor.qml b/examples/quickcontrols2/texteditor/qml/+touch/texteditor.qml index a7f176a9..11d153f5 100644 --- a/examples/quickcontrols2/texteditor/qml/+touch/texteditor.qml +++ b/examples/quickcontrols2/texteditor/qml/+touch/texteditor.qml @@ -38,7 +38,6 @@ ** ****************************************************************************/ -import QtGraphicalEffects 1.0 import QtQuick 2.8 import QtQuick.Controls 2.1 import QtQuick.Controls.Material 2.1 @@ -226,7 +225,7 @@ ApplicationWindow { } } - Button { + RoundButton { id: editButton font.family: "fontello" text: "\uE809" // icon-pencil @@ -245,20 +244,6 @@ ApplicationWindow { // Force focus on the text area so the cursor and footer show up. textArea.forceActiveFocus() } - - background: Rectangle { - implicitWidth: parent.width - implicitHeight: parent.height - radius: width / 2 - color: parent.down ? Qt.darker(Material.accent) : Material.accent - - layer.enabled: editButton.enabled - layer.effect: DropShadow { - color: "#44000000" - verticalOffset: 2 - samples: 16 - } - } } Dialog { -- cgit v1.2.3 From 0947ce01d0a82e1f4dbc7eee53b0e1f91a573b0b Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Sat, 3 Sep 2016 23:41:28 +0200 Subject: Fix tst_Drawer::dragMargin() The width of the window in the test is 400px, and the width of the drawer is 200px. The default drag margin equals to QStyleHints::startDragDistance(), which reports 19px on Linux installed on a Chromebook Pixel 2. The test attempts to drag from (double drag margin): 2 x startDragDistance = 38px to: 0.25 x width of the drawer = 50px 12px does not exceed the start drag distance of 19px, so the drawer is not dragged even though the test expects it to be dragged to the logical position of 0.25. Increase the dragged distance a bit to exceed the threshold. Change-Id: Id469533b08c4221430446a2d995e36b4ebdc0258 Reviewed-by: Mitch Curtis --- tests/auto/drawer/tst_drawer.cpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/tests/auto/drawer/tst_drawer.cpp b/tests/auto/drawer/tst_drawer.cpp index 0b334387..3c128fbc 100644 --- a/tests/auto/drawer/tst_drawer.cpp +++ b/tests/auto/drawer/tst_drawer.cpp @@ -113,8 +113,8 @@ void tst_Drawer::dragMargin_data() QTest::newRow("left:0") << Qt::LeftEdge << qreal(0) << qreal(0) << qreal(0); QTest::newRow("left:-1") << Qt::LeftEdge << qreal(-1) << qreal(0) << qreal(0); - QTest::newRow("left:startDragDistance") << Qt::LeftEdge << qreal(QGuiApplication::styleHints()->startDragDistance()) << qreal(0.25) << qreal(0); - QTest::newRow("left:startDragDistance*2") << Qt::LeftEdge << qreal(QGuiApplication::styleHints()->startDragDistance() * 2) << qreal(0.25) << qreal(0); + QTest::newRow("left:startDragDistance") << Qt::LeftEdge << qreal(QGuiApplication::styleHints()->startDragDistance()) << qreal(0.45) << qreal(0); + QTest::newRow("left:startDragDistance*2") << Qt::LeftEdge << qreal(QGuiApplication::styleHints()->startDragDistance() * 2) << qreal(0.45) << qreal(0); QTest::newRow("right:0") << Qt::RightEdge << qreal(0) << qreal(0) << qreal(0); QTest::newRow("right:-1") << Qt::RightEdge << qreal(-1) << qreal(0) << qreal(0); @@ -143,20 +143,24 @@ void tst_Drawer::dragMargin() // drag from the left int leftX = qMax(0, dragMargin); + int leftDistance = drawer->width() * 0.45; + QVERIFY(leftDistance > QGuiApplication::styleHints()->startDragDistance()); QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, QPoint(leftX, drawer->height() / 2)); - QTest::mouseMove(window, QPoint(drawer->width() * 0.25, drawer->height() / 2)); + QTest::mouseMove(window, QPoint(leftDistance, drawer->height() / 2)); QCOMPARE(drawer->position(), dragFromLeft); - QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, QPoint(drawer->width() * 0.25, drawer->height() / 2)); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, QPoint(leftDistance, drawer->height() / 2)); drawer->close(); QTRY_COMPARE(drawer->position(), qreal(0.0)); // drag from the right int rightX = qMin(window->width() - 1, window->width() - dragMargin); + int rightDistance = drawer->width() * 0.75; + QVERIFY(rightDistance > QGuiApplication::styleHints()->startDragDistance()); QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, QPoint(rightX, drawer->height() / 2)); - QTest::mouseMove(window, QPoint(window->width() - drawer->width() * 0.75, drawer->height() / 2)); + QTest::mouseMove(window, QPoint(window->width() - rightDistance, drawer->height() / 2)); QCOMPARE(drawer->position(), dragFromRight); - QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, QPoint(window->width() - drawer->width() * 0.75, drawer->height() / 2)); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, QPoint(window->width() - rightDistance, drawer->height() / 2)); } void tst_Drawer::reposition() -- cgit v1.2.3 From 28daf8cc73c6ba51bcdda3079d73c2db7919fc2a Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Sun, 4 Sep 2016 11:38:40 +0200 Subject: tst_Drawer: cleanup applicationwindow.qml The MouseArea workaround was not removed when QTBUG-54629 was fixed. Change-Id: I725ca9a0b05811246e9a6a378f2c5e25c1cdca0f Reviewed-by: Mitch Curtis --- tests/auto/drawer/data/applicationwindow.qml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/tests/auto/drawer/data/applicationwindow.qml b/tests/auto/drawer/data/applicationwindow.qml index a8ae69ed..9032ea0d 100644 --- a/tests/auto/drawer/data/applicationwindow.qml +++ b/tests/auto/drawer/data/applicationwindow.qml @@ -51,12 +51,5 @@ ApplicationWindow { id: drawer width: 200 height: 200 - - MouseArea { - // QTBUG-54629 - anchors.fill: parent - anchors.margins: -Qt.styleHints.startDragDistance - Rectangle { color: "red"; opacity: 0.25; anchors.fill: parent } - } } } -- cgit v1.2.3 From a0d77ff082b6a5aa02a36f5a82649c45c0dcd265 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Sat, 3 Sep 2016 15:15:53 +0200 Subject: auto tests: allow using QQuickWindow with QQuickApplicationHelper This allows us to run the relevant popup tests for both QQuickWindow and QQuickApplicationWindow. Change-Id: I14b6435afeeb8a6cf640d8c52ad1d9e1fae070b0 Reviewed-by: Mitch Curtis --- tests/auto/drawer/tst_drawer.cpp | 20 +++++----- tests/auto/menu/tst_menu.cpp | 10 ++--- tests/auto/popup/tst_popup.cpp | 44 +++++++++++----------- .../tst_qquickmaterialstyleconf.cpp | 2 +- .../tst_qquickuniversalstyleconf.cpp | 2 +- tests/auto/shared/visualtestutil.h | 8 ++-- 6 files changed, 44 insertions(+), 42 deletions(-) diff --git a/tests/auto/drawer/tst_drawer.cpp b/tests/auto/drawer/tst_drawer.cpp index 3c128fbc..ffa1f896 100644 --- a/tests/auto/drawer/tst_drawer.cpp +++ b/tests/auto/drawer/tst_drawer.cpp @@ -86,12 +86,12 @@ void tst_Drawer::position() QQuickApplicationHelper helper(this, QStringLiteral("applicationwindow.qml")); - QQuickApplicationWindow *window = helper.window; + QQuickApplicationWindow *window = helper.appWindow; window->show(); window->requestActivate(); QVERIFY(QTest::qWaitForWindowActive(window)); - QQuickDrawer *drawer = helper.window->property("drawer").value(); + QQuickDrawer *drawer = helper.appWindow->property("drawer").value(); QVERIFY(drawer); drawer->setEdge(edge); @@ -131,12 +131,12 @@ void tst_Drawer::dragMargin() QQuickApplicationHelper helper(this, QStringLiteral("applicationwindow.qml")); - QQuickApplicationWindow *window = helper.window; + QQuickApplicationWindow *window = helper.appWindow; window->show(); window->requestActivate(); QVERIFY(QTest::qWaitForWindowActive(window)); - QQuickDrawer *drawer = helper.window->property("drawer").value(); + QQuickDrawer *drawer = helper.appWindow->property("drawer").value(); QVERIFY(drawer); drawer->setEdge(edge); drawer->setDragMargin(dragMargin); @@ -167,12 +167,12 @@ void tst_Drawer::reposition() { QQuickApplicationHelper helper(this, QStringLiteral("applicationwindow.qml")); - QQuickApplicationWindow *window = helper.window; + QQuickApplicationWindow *window = helper.appWindow; window->show(); window->requestActivate(); QVERIFY(QTest::qWaitForWindowActive(window)); - QQuickDrawer *drawer = helper.window->property("drawer").value(); + QQuickDrawer *drawer = helper.appWindow->property("drawer").value(); QVERIFY(drawer); drawer->setEdge(Qt::RightEdge); @@ -199,20 +199,20 @@ void tst_Drawer::hover() QFETCH(bool, modal); QQuickApplicationHelper helper(this, QStringLiteral("hover.qml")); - QQuickApplicationWindow *window = helper.window; + QQuickApplicationWindow *window = helper.appWindow; window->show(); window->requestActivate(); QVERIFY(QTest::qWaitForWindowActive(window)); - QQuickDrawer *drawer = helper.window->property("drawer").value(); + QQuickDrawer *drawer = helper.appWindow->property("drawer").value(); QVERIFY(drawer); drawer->setModal(modal); - QQuickButton *backgroundButton = helper.window->property("backgroundButton").value(); + QQuickButton *backgroundButton = helper.appWindow->property("backgroundButton").value(); QVERIFY(backgroundButton); backgroundButton->setHoverEnabled(true); - QQuickButton *drawerButton = helper.window->property("drawerButton").value(); + QQuickButton *drawerButton = helper.appWindow->property("drawerButton").value(); QVERIFY(drawerButton); drawerButton->setHoverEnabled(true); diff --git a/tests/auto/menu/tst_menu.cpp b/tests/auto/menu/tst_menu.cpp index dc9c296a..7617cfcc 100644 --- a/tests/auto/menu/tst_menu.cpp +++ b/tests/auto/menu/tst_menu.cpp @@ -71,7 +71,7 @@ void tst_menu::defaults() { QQuickApplicationHelper helper(this, QLatin1String("applicationwindow.qml")); - QQuickMenu *emptyMenu = helper.window->property("emptyMenu").value(); + QQuickMenu *emptyMenu = helper.appWindow->property("emptyMenu").value(); QCOMPARE(emptyMenu->isVisible(), false); QCOMPARE(emptyMenu->contentItem()->property("currentIndex"), QVariant(-1)); } @@ -80,7 +80,7 @@ void tst_menu::mouse() { QQuickApplicationHelper helper(this, QLatin1String("applicationwindow.qml")); - QQuickApplicationWindow *window = helper.window; + QQuickApplicationWindow *window = helper.appWindow; window->show(); QVERIFY(QTest::qWaitForWindowActive(window)); @@ -152,7 +152,7 @@ void tst_menu::contextMenuKeyboard() QQuickApplicationHelper helper(this, QLatin1String("applicationwindow.qml")); - QQuickApplicationWindow *window = helper.window; + QQuickApplicationWindow *window = helper.appWindow; window->show(); window->requestActivate(); QVERIFY(QTest::qWaitForWindowActive(window)); @@ -230,7 +230,7 @@ void tst_menu::menuButton() QQuickApplicationHelper helper(this, QLatin1String("applicationwindow.qml")); - QQuickApplicationWindow *window = helper.window; + QQuickApplicationWindow *window = helper.appWindow; window->show(); window->requestActivate(); QVERIFY(QTest::qWaitForWindowActive(window)); @@ -254,7 +254,7 @@ void tst_menu::menuButton() void tst_menu::addItem() { QQuickApplicationHelper helper(this, QLatin1String("addItem.qml")); - QQuickApplicationWindow *window = helper.window; + QQuickApplicationWindow *window = helper.appWindow; window->show(); QVERIFY(QTest::qWaitForWindowActive(window)); diff --git a/tests/auto/popup/tst_popup.cpp b/tests/auto/popup/tst_popup.cpp index 1166b517..abd20df0 100644 --- a/tests/auto/popup/tst_popup.cpp +++ b/tests/auto/popup/tst_popup.cpp @@ -68,12 +68,12 @@ void tst_popup::visible() { QQuickApplicationHelper helper(this, QStringLiteral("applicationwindow.qml")); - QQuickApplicationWindow *window = helper.window; + QQuickApplicationWindow *window = helper.appWindow; window->show(); window->requestActivate(); QVERIFY(QTest::qWaitForWindowActive(window)); - QQuickPopup *popup = helper.window->property("popup").value(); + QQuickPopup *popup = helper.appWindow->property("popup").value(); QVERIFY(popup); QQuickItem *popupItem = popup->popupItem(); @@ -98,7 +98,7 @@ void tst_popup::overlay() { QQuickApplicationHelper helper(this, QStringLiteral("applicationwindow.qml")); - QQuickApplicationWindow *window = helper.window; + QQuickApplicationWindow *window = helper.appWindow; window->show(); window->requestActivate(); QVERIFY(QTest::qWaitForWindowActive(window)); @@ -115,10 +115,10 @@ void tst_popup::overlay() QCOMPARE(overlayPressedSignal.count(), 0); QCOMPARE(overlayReleasedSignal.count(), 0); - QQuickPopup *popup = helper.window->property("popup").value(); + QQuickPopup *popup = helper.appWindow->property("popup").value(); QVERIFY(popup); - QQuickButton *button = helper.window->property("button").value(); + QQuickButton *button = helper.appWindow->property("button").value(); QVERIFY(button); popup->open(); @@ -160,16 +160,16 @@ void tst_popup::zOrder() { QQuickApplicationHelper helper(this, QStringLiteral("applicationwindow.qml")); - QQuickApplicationWindow *window = helper.window; + QQuickApplicationWindow *window = helper.appWindow; window->show(); window->requestActivate(); QVERIFY(QTest::qWaitForWindowActive(window)); - QQuickPopup *popup = helper.window->property("popup").value(); + QQuickPopup *popup = helper.appWindow->property("popup").value(); QVERIFY(popup); popup->setModal(true); - QQuickPopup *popup2 = helper.window->property("popup2").value(); + QQuickPopup *popup2 = helper.appWindow->property("popup2").value(); QVERIFY(popup2); popup2->setModal(true); @@ -237,15 +237,15 @@ void tst_popup::closePolicy() QQuickApplicationHelper helper(this, QStringLiteral("applicationwindow.qml")); - QQuickApplicationWindow *window = helper.window; + QQuickApplicationWindow *window = helper.appWindow; window->show(); window->requestActivate(); QVERIFY(QTest::qWaitForWindowActive(window)); - QQuickPopup *popup = helper.window->property("popup").value(); + QQuickPopup *popup = helper.appWindow->property("popup").value(); QVERIFY(popup); - QQuickButton *button = helper.window->property("button").value(); + QQuickButton *button = helper.appWindow->property("button").value(); QVERIFY(button); popup->setModal(true); @@ -308,15 +308,15 @@ void tst_popup::activeFocusOnClose1() // Test that a popup that never sets focus: true (e.g. ToolTip) doesn't affect // the active focus item when it closes. QQuickApplicationHelper helper(this, QStringLiteral("activeFocusOnClose1.qml")); - QQuickApplicationWindow *window = helper.window; + QQuickApplicationWindow *window = helper.appWindow; window->show(); window->requestActivate(); QVERIFY(QTest::qWaitForWindowActive(window)); - QQuickPopup *focusedPopup = helper.window->property("focusedPopup").value(); + QQuickPopup *focusedPopup = helper.appWindow->property("focusedPopup").value(); QVERIFY(focusedPopup); - QQuickPopup *nonFocusedPopup = helper.window->property("nonFocusedPopup").value(); + QQuickPopup *nonFocusedPopup = helper.appWindow->property("nonFocusedPopup").value(); QVERIFY(nonFocusedPopup); focusedPopup->open(); @@ -338,18 +338,18 @@ void tst_popup::activeFocusOnClose2() // calling forceActiveFocus() on another item) before it closes doesn't // affect the active focus item when it closes. QQuickApplicationHelper helper(this, QStringLiteral("activeFocusOnClose2.qml")); - QQuickApplicationWindow *window = helper.window; + QQuickApplicationWindow *window = helper.appWindow; window->show(); window->requestActivate(); QVERIFY(QTest::qWaitForWindowActive(window)); - QQuickPopup *popup1 = helper.window->property("popup1").value(); + QQuickPopup *popup1 = helper.appWindow->property("popup1").value(); QVERIFY(popup1); - QQuickPopup *popup2 = helper.window->property("popup2").value(); + QQuickPopup *popup2 = helper.appWindow->property("popup2").value(); QVERIFY(popup2); - QQuickButton *closePopup2Button = helper.window->property("closePopup2Button").value(); + QQuickButton *closePopup2Button = helper.appWindow->property("closePopup2Button").value(); QVERIFY(closePopup2Button); popup1->open(); @@ -380,20 +380,20 @@ void tst_popup::hover() QFETCH(bool, modal); QQuickApplicationHelper helper(this, QStringLiteral("hover.qml")); - QQuickApplicationWindow *window = helper.window; + QQuickApplicationWindow *window = helper.appWindow; window->show(); window->requestActivate(); QVERIFY(QTest::qWaitForWindowActive(window)); - QQuickPopup *popup = helper.window->property("popup").value(); + QQuickPopup *popup = helper.appWindow->property("popup").value(); QVERIFY(popup); popup->setModal(modal); - QQuickButton *parentButton = helper.window->property("parentButton").value(); + QQuickButton *parentButton = helper.appWindow->property("parentButton").value(); QVERIFY(parentButton); parentButton->setHoverEnabled(true); - QQuickButton *childButton = helper.window->property("childButton").value(); + QQuickButton *childButton = helper.appWindow->property("childButton").value(); QVERIFY(childButton); childButton->setHoverEnabled(true); diff --git a/tests/auto/qquickmaterialstyleconf/tst_qquickmaterialstyleconf.cpp b/tests/auto/qquickmaterialstyleconf/tst_qquickmaterialstyleconf.cpp index c7670c21..c0db7c49 100644 --- a/tests/auto/qquickmaterialstyleconf/tst_qquickmaterialstyleconf.cpp +++ b/tests/auto/qquickmaterialstyleconf/tst_qquickmaterialstyleconf.cpp @@ -55,7 +55,7 @@ void tst_qquickmaterialstyleconf::conf() { QQuickApplicationHelper helper(this, QLatin1String("applicationwindow.qml")); - QQuickApplicationWindow *window = helper.window; + QQuickApplicationWindow *window = helper.appWindow; window->show(); QVERIFY(QTest::qWaitForWindowExposed(window)); // We specified a custom background color, so the window should have it. diff --git a/tests/auto/qquickuniversalstyleconf/tst_qquickuniversalstyleconf.cpp b/tests/auto/qquickuniversalstyleconf/tst_qquickuniversalstyleconf.cpp index c676ae6d..ce018a05 100644 --- a/tests/auto/qquickuniversalstyleconf/tst_qquickuniversalstyleconf.cpp +++ b/tests/auto/qquickuniversalstyleconf/tst_qquickuniversalstyleconf.cpp @@ -55,7 +55,7 @@ void tst_qquickuniversalstyleconf::conf() { QQuickApplicationHelper helper(this, QLatin1String("applicationwindow.qml")); - QQuickApplicationWindow *window = helper.window; + QQuickApplicationWindow *window = helper.appWindow; window->show(); QVERIFY(QTest::qWaitForWindowExposed(window)); // We specified a custom background color, so the window should have it. diff --git a/tests/auto/shared/visualtestutil.h b/tests/auto/shared/visualtestutil.h index c1cc9c7d..c67e5bdc 100644 --- a/tests/auto/shared/visualtestutil.h +++ b/tests/auto/shared/visualtestutil.h @@ -118,9 +118,10 @@ namespace QQuickVisualTestUtil component.loadUrl(testCase->testFileUrl(testFilePath)); QObject *rootObject = component.create(); cleanup.reset(rootObject); - QVERIFY2(rootObject, qPrintable(QString::fromLatin1("Failed to create ApplicationWindow: %1").arg(component.errorString()))); + QVERIFY2(rootObject, qPrintable(QString::fromLatin1("Failed to create window: %1").arg(component.errorString()))); - window = qobject_cast(rootObject); + window = qobject_cast(rootObject); + appWindow = qobject_cast(rootObject); QVERIFY(window); QVERIFY(!window->isVisible()); } @@ -128,7 +129,8 @@ namespace QQuickVisualTestUtil QQmlEngine engine; QQmlComponent component; QScopedPointer cleanup; - QQuickApplicationWindow *window; + QQuickApplicationWindow *appWindow; + QQuickWindow *window; }; } -- cgit v1.2.3 From ef45aff14c61983b3659094e0cf5d9db706d9cbd Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Fri, 2 Sep 2016 17:26:57 +0200 Subject: Doc: mention Material.elevation in the docs Change-Id: I514a784df656d2690c8c2cb285cec8d48102b3be Reviewed-by: Mitch Curtis --- src/imports/controls/doc/src/qtquickcontrols2-material.qdoc | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/imports/controls/doc/src/qtquickcontrols2-material.qdoc b/src/imports/controls/doc/src/qtquickcontrols2-material.qdoc index 9416a505..a5ac25d2 100644 --- a/src/imports/controls/doc/src/qtquickcontrols2-material.qdoc +++ b/src/imports/controls/doc/src/qtquickcontrols2-material.qdoc @@ -39,6 +39,7 @@ \list \li \l {material-accent-attached-prop}{\b accent} : color \li \l {material-background-attached-prop}{\b background} : color + \li \l {material-elevation-attached-prop}{\b elevation} : int \li \l {material-foreground-attached-prop}{\b foreground} : color \li \l {material-primary-attached-prop}{\b primary} : color \li \l {material-theme-attached-prop}{\b theme} : enumeration @@ -280,6 +281,16 @@ \endstyleproperty + \styleproperty {Material.elevation} {int} {material-elevation-attached-prop} + \target material-elevation-attached-prop + This attached property holds the elevation of the control. The higher the + elevation, the deeper the shadow. The property can be attached to any control, + but not all controls visualize elevation. + + The default value is control-specific. + + \endstyleproperty + \styleproperty {Material.foreground} {color} {material-foreground-attached-prop} \target material-foreground-attached-prop This attached property holds the foreground color of the theme. The property -- cgit v1.2.3 From 588dc30b44c42b63239085ea5f2817eb3a48995a Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Fri, 2 Sep 2016 22:35:16 +0200 Subject: Switch: fix missing pressed() and released() signals Change-Id: I4bf81c06a77980ed3201b43f9d106017f236a8bd Reviewed-by: Mitch Curtis --- src/quicktemplates2/qquickswitch.cpp | 6 +- tests/auto/controls/data/tst_switch.qml | 138 +++++++++++++++----------------- 2 files changed, 68 insertions(+), 76 deletions(-) diff --git a/src/quicktemplates2/qquickswitch.cpp b/src/quicktemplates2/qquickswitch.cpp index cb966568..37ae53f0 100644 --- a/src/quicktemplates2/qquickswitch.cpp +++ b/src/quicktemplates2/qquickswitch.cpp @@ -126,6 +126,7 @@ bool QQuickSwitchPrivate::handleMousePressEvent(QQuickItem *child, QMouseEvent * pressPoint = event->pos(); q->setPressed(true); + emit q->pressed(); event->accept(); return true; } @@ -155,11 +156,14 @@ bool QQuickSwitchPrivate::handleMouseReleaseEvent(QQuickItem *child, QMouseEvent q->setChecked(position > 0.5); q->setPosition(checked ? 1.0 : 0.0); child->setKeepMouseGrab(false); - if (wasChecked != checked) + if (wasChecked != checked) { + emit q->released(); emit q->clicked(); + } event->accept(); } else { q->toggle(); + emit q->released(); emit q->clicked(); event->accept(); } diff --git a/tests/auto/controls/data/tst_switch.qml b/tests/auto/controls/data/tst_switch.qml index ff81be16..ba41015f 100644 --- a/tests/auto/controls/data/tst_switch.qml +++ b/tests/auto/controls/data/tst_switch.qml @@ -50,42 +50,16 @@ TestCase { when: windowShown name: "Switch" - SignalSpy { - id: checkedSpy - signalName: "checkedChanged" - } - - SignalSpy { - id: pressedSpy - signalName: "pressedChanged" - } - - SignalSpy { - id: clickedSpy - signalName: "clicked" - } - Component { id: swtch Switch { } } - function init() { - verify(!checkedSpy.target) - verify(!pressedSpy.target) - verify(!clickedSpy.target) - compare(checkedSpy.count, 0) - compare(pressedSpy.count, 0) - compare(clickedSpy.count, 0) - } - - function cleanup() { - checkedSpy.target = null - pressedSpy.target = null - clickedSpy.target = null - checkedSpy.clear() - pressedSpy.clear() - clickedSpy.clear() + Component { + id: signalSequenceSpy + SignalSequenceSpy { + signals: ["pressed", "released", "canceled", "clicked", "pressedChanged", "checkedChanged"] + } } function test_text() { @@ -105,19 +79,18 @@ TestCase { var control = swtch.createObject(testCase) verify(control) - checkedSpy.target = control - verify(checkedSpy.valid) - compare(control.checked, false) - compare(checkedSpy.count, 0) + var spy = signalSequenceSpy.createObject(control, {target: control}) + spy.expectedSequence = [["checkedChanged", { "checked": true }]] control.checked = true compare(control.checked, true) - compare(checkedSpy.count, 1) + verify(spy.success) + spy.expectedSequence = [["checkedChanged", { "checked": false }]] control.checked = false compare(control.checked, false) - compare(checkedSpy.count, 2) + verify(spy.success) control.destroy() } @@ -126,71 +99,80 @@ TestCase { var control = swtch.createObject(testCase) verify(control) - checkedSpy.target = control - pressedSpy.target = control - clickedSpy.target = control - verify(checkedSpy.valid) - verify(pressedSpy.valid) - verify(clickedSpy.valid) - // check + var spy = signalSequenceSpy.createObject(control, {target: control}) + spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": false }], + "pressed"] mousePress(control, control.width / 2, control.height / 2, Qt.LeftButton) - compare(pressedSpy.count, 1) compare(control.pressed, true) + verify(spy.success) + spy.expectedSequence = [["pressedChanged", { "pressed": false, "checked": false }], + ["checkedChanged", { "pressed": false, "checked": true }], + "released", + "clicked"] mouseRelease(control, control.width / 2, control.height / 2, Qt.LeftButton) - compare(clickedSpy.count, 1) - compare(checkedSpy.count, 1) - compare(pressedSpy.count, 2) compare(control.checked, true) compare(control.pressed, false) + verify(spy.success) // uncheck + spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": true }], + "pressed"] mousePress(control, control.width / 2, control.height / 2, Qt.LeftButton) - compare(pressedSpy.count, 3) compare(control.pressed, true) + verify(spy.success) + spy.expectedSequence = [["pressedChanged", { "pressed": false, "checked": true }], + ["checkedChanged", { "pressed": false, "checked": false }], + "released", + "clicked"] mouseRelease(control, control.width / 2, control.height / 2, Qt.LeftButton) - compare(clickedSpy.count, 2) - compare(checkedSpy.count, 2) - compare(pressedSpy.count, 4) compare(control.checked, false) compare(control.pressed, false) + verify(spy.success) // release on the right + spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": false }], + "pressed"] mousePress(control, control.width / 2, control.height / 2, Qt.LeftButton) - compare(pressedSpy.count, 5) compare(control.pressed, true) + verify(spy.success) mouseMove(control, control.width * 2, control.height / 2, 0, Qt.LeftButton) compare(control.pressed, true) + spy.expectedSequence = [["pressedChanged", { "pressed": false, "checked": false }], + ["checkedChanged", { "pressed": false, "checked": true }], + "released", + "clicked"] mouseRelease(control, control.width * 2, control.height / 2, Qt.LeftButton) - compare(clickedSpy.count, 3) - compare(checkedSpy.count, 3) - compare(pressedSpy.count, 6) compare(control.checked, true) compare(control.pressed, false) + verify(spy.success) // release on the left + spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": true }], + "pressed"] mousePress(control, control.width / 2, control.height / 2, Qt.LeftButton) - compare(pressedSpy.count, 7) compare(control.pressed, true) + verify(spy.success) mouseMove(control, -control.width, control.height / 2, 0, Qt.LeftButton) compare(control.pressed, true) + spy.expectedSequence = [["pressedChanged", { "pressed": false, "checked": true }], + ["checkedChanged", { "pressed": false, "checked": false }], + "released", + "clicked"] mouseRelease(control, -control.width, control.height / 2, Qt.LeftButton) - compare(clickedSpy.count, 4) - compare(checkedSpy.count, 4) - compare(pressedSpy.count, 8) compare(control.checked, false) compare(control.pressed, false) + verify(spy.success) // right button + spy.expectedSequence = [] mousePress(control, control.width / 2, control.height / 2, Qt.RightButton) - compare(pressedSpy.count, 8) compare(control.pressed, false) + verify(spy.success) mouseRelease(control, control.width / 2, control.height / 2, Qt.RightButton) - compare(clickedSpy.count, 4) - compare(checkedSpy.count, 4) - compare(pressedSpy.count, 8) compare(control.checked, false) compare(control.pressed, false) + verify(spy.success) control.destroy() } @@ -199,33 +181,39 @@ TestCase { var control = swtch.createObject(testCase) verify(control) - checkedSpy.target = control - clickedSpy.target = control - verify(checkedSpy.valid) - verify(clickedSpy.valid) - control.forceActiveFocus() verify(control.activeFocus) // check + var spy = signalSequenceSpy.createObject(control, {target: control}) + spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": false }], + "pressed", + ["pressedChanged", { "pressed": false, "checked": false }], + ["checkedChanged", { "pressed": false, "checked": true }], + "released", + "clicked"] keyClick(Qt.Key_Space) - compare(clickedSpy.count, 1) - compare(checkedSpy.count, 1) compare(control.checked, true) + verify(spy.success) // uncheck + spy.expectedSequence = [["pressedChanged", { "pressed": true, "checked": true }], + "pressed", + ["pressedChanged", { "pressed": false, "checked": true }], + ["checkedChanged", { "pressed": false, "checked": false }], + "released", + "clicked"] keyClick(Qt.Key_Space) - compare(clickedSpy.count, 2) - compare(checkedSpy.count, 2) compare(control.checked, false) + verify(spy.success) // no change + spy.expectedSequence = [] var keys = [Qt.Key_Enter, Qt.Key_Return, Qt.Key_Escape, Qt.Key_Tab] for (var i = 0; i < keys.length; ++i) { keyClick(keys[i]) - compare(clickedSpy.count, 2) - compare(checkedSpy.count, 2) compare(control.checked, false) + verify(spy.success) } control.destroy() -- cgit v1.2.3 From c7b8289a706f982c1cf5091a4d86606ec758b05d Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Thu, 1 Sep 2016 19:43:20 +0200 Subject: TextField: improve the implicit size calculation In general, we don't want TextField to grow while typing, but if there is no background nor placeholder, use content width as a fallback. Also take content height into account while calculating the implicit height. Task-number: QTBUG-55684 Change-Id: Iee0eff6861c3573045036a06d7e53f7fc313fbe8 Reviewed-by: Mitch Curtis --- src/imports/controls/TextField.qml | 6 ++++-- src/imports/controls/material/TextField.qml | 8 +++++--- src/imports/controls/universal/TextField.qml | 6 +++--- tests/auto/controls/data/tst_textfield.qml | 19 +++++++++++++++++++ 4 files changed, 31 insertions(+), 8 deletions(-) diff --git a/src/imports/controls/TextField.qml b/src/imports/controls/TextField.qml index 2234646f..35703940 100644 --- a/src/imports/controls/TextField.qml +++ b/src/imports/controls/TextField.qml @@ -41,8 +41,10 @@ T.TextField { id: control implicitWidth: Math.max(background ? background.implicitWidth : 0, - placeholder.implicitWidth + leftPadding + rightPadding) - implicitHeight: Math.max(background ? background.implicitHeight : 0, + placeholderText ? placeholder.implicitWidth + leftPadding + rightPadding : 0) + || contentWidth + leftPadding + rightPadding + implicitHeight: Math.max(contentHeight + topPadding + bottomPadding, + background ? background.implicitHeight : 0, placeholder.implicitHeight + topPadding + bottomPadding) padding: 6 diff --git a/src/imports/controls/material/TextField.qml b/src/imports/controls/material/TextField.qml index 9c576ca6..580b43bd 100644 --- a/src/imports/controls/material/TextField.qml +++ b/src/imports/controls/material/TextField.qml @@ -42,9 +42,11 @@ T.TextField { id: control implicitWidth: Math.max(background ? background.implicitWidth : 0, - placeholder.implicitWidth + leftPadding + rightPadding) - implicitHeight: Math.max(background ? background.implicitHeight : 0, - placeholder.implicitHeight + 1 + topPadding + bottomPadding) + placeholderText ? placeholder.implicitWidth + leftPadding + rightPadding : 0) + || contentWidth + leftPadding + rightPadding + implicitHeight: Math.max(contentHeight + topPadding + bottomPadding, + background ? background.implicitHeight : 0, + placeholder.implicitHeight + topPadding + bottomPadding) topPadding: 8 bottomPadding: 16 diff --git a/src/imports/controls/universal/TextField.qml b/src/imports/controls/universal/TextField.qml index a245ba39..bd496ecc 100644 --- a/src/imports/controls/universal/TextField.qml +++ b/src/imports/controls/universal/TextField.qml @@ -41,9 +41,9 @@ import QtQuick.Controls.Universal 2.0 T.TextField { id: control - implicitWidth: Math.max(contentWidth + leftPadding + rightPadding, - background ? background.implicitWidth : 0, - placeholder.implicitWidth + leftPadding + rightPadding) + implicitWidth: Math.max(background ? background.implicitWidth : 0, + placeholderText ? placeholder.implicitWidth + leftPadding + rightPadding : 0) + || contentWidth + leftPadding + rightPadding implicitHeight: Math.max(contentHeight + topPadding + bottomPadding, background ? background.implicitHeight : 0, placeholder.implicitHeight + topPadding + bottomPadding) diff --git a/tests/auto/controls/data/tst_textfield.qml b/tests/auto/controls/data/tst_textfield.qml index f2907b36..959662ee 100644 --- a/tests/auto/controls/data/tst_textfield.qml +++ b/tests/auto/controls/data/tst_textfield.qml @@ -72,6 +72,7 @@ TestCase { var implicitWidthSpy = signalSpy.createObject(control, { target: control, signalName: "implicitWidthChanged"} ) var implicitHeightSpy = signalSpy.createObject(control, { target: control, signalName: "implicitHeightChanged"} ) + control.background.implicitWidth = 400 control.background.implicitHeight = 200 compare(control.implicitWidth, 400) @@ -79,6 +80,24 @@ TestCase { compare(implicitWidthSpy.count, 1) compare(implicitHeightSpy.count, 1) + control.background = null + compare(control.implicitWidth, control.leftPadding + control.rightPadding) + compare(control.implicitHeight, control.contentHeight + control.topPadding + control.bottomPadding) + compare(implicitWidthSpy.count, 2) + compare(implicitHeightSpy.count, 2) + + control.text = "TextField" + compare(control.implicitWidth, control.contentWidth + control.leftPadding + control.rightPadding) + compare(control.implicitHeight, control.contentHeight + control.topPadding + control.bottomPadding) + compare(implicitWidthSpy.count, 3) + compare(implicitHeightSpy.count, 2) + + control.placeholderText = "..." + verify(control.implicitWidth < control.contentWidth + control.leftPadding + control.rightPadding) + compare(control.implicitHeight, control.contentHeight + control.topPadding + control.bottomPadding) + compare(implicitWidthSpy.count, 4) + compare(implicitHeightSpy.count, 2) + control.destroy() } -- cgit v1.2.3 From 6f3f262574d2bb0cf7ccd5148f29e078aef8d16a Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Sat, 3 Sep 2016 14:49:49 +0200 Subject: Make QQuickOverlay resize itself This prepares QQuickOverlay to be usable with a plain QQuickWindow, for which we cannot override resizeEvent(). Change-Id: Ib021c510539b134477bb8d532787721a5ac7fca4 Reviewed-by: Mitch Curtis --- src/quicktemplates2/qquickapplicationwindow.cpp | 8 +------- src/quicktemplates2/qquickoverlay.cpp | 22 +++++++++++++++++++++- src/quicktemplates2/qquickoverlay_p.h | 1 + 3 files changed, 23 insertions(+), 8 deletions(-) diff --git a/src/quicktemplates2/qquickapplicationwindow.cpp b/src/quicktemplates2/qquickapplicationwindow.cpp index 2706d9b6..bf903b8a 100644 --- a/src/quicktemplates2/qquickapplicationwindow.cpp +++ b/src/quicktemplates2/qquickapplicationwindow.cpp @@ -157,12 +157,6 @@ void QQuickApplicationWindowPrivate::relayout() content->setWidth(q->width()); content->setHeight(q->height() - hh - fh); - if (overlay) { - overlay->setWidth(q->width()); - overlay->setHeight(q->height()); - overlay->stackAfter(content); - } - if (header) { header->setY(-hh); QQuickItemPrivate *p = QQuickItemPrivate::get(header); @@ -484,7 +478,7 @@ QQuickOverlay *QQuickApplicationWindow::overlay() const QQuickApplicationWindowPrivate *d = const_cast(d_func()); if (!d->overlay) { d->overlay = new QQuickOverlay(QQuickWindow::contentItem()); - d->relayout(); + d->overlay->stackAfter(QQuickApplicationWindow::contentItem()); } return d->overlay; } diff --git a/src/quicktemplates2/qquickoverlay.cpp b/src/quicktemplates2/qquickoverlay.cpp index 5dd92a26..c5818b90 100644 --- a/src/quicktemplates2/qquickoverlay.cpp +++ b/src/quicktemplates2/qquickoverlay.cpp @@ -41,10 +41,11 @@ #include #include #include +#include QT_BEGIN_NAMESPACE -class QQuickOverlayPrivate : public QQuickItemPrivate +class QQuickOverlayPrivate : public QQuickItemPrivate, public QQuickItemChangeListener { Q_DECLARE_PUBLIC(QQuickOverlay) @@ -61,6 +62,8 @@ public: QVector stackingOrderPopups() const; + void itemGeometryChanged(QQuickItem *item, const QRectF &newGeometry, const QRectF &oldGeometry) override; + QQmlComponent *modal; QQmlComponent *modeless; QVector drawers; @@ -179,6 +182,12 @@ QVector QQuickOverlayPrivate::stackingOrderPopups() const return popups; } +void QQuickOverlayPrivate::itemGeometryChanged(QQuickItem *, const QRectF &newGeometry, const QRectF &) +{ + Q_Q(QQuickOverlay); + q->setSize(newGeometry.size()); +} + QQuickOverlayPrivate::QQuickOverlayPrivate() : modal(nullptr), modeless(nullptr), @@ -189,10 +198,21 @@ QQuickOverlayPrivate::QQuickOverlayPrivate() : QQuickOverlay::QQuickOverlay(QQuickItem *parent) : QQuickItem(*(new QQuickOverlayPrivate), parent) { + Q_D(QQuickOverlay); setZ(1000001); // DefaultWindowDecoration+1 setAcceptedMouseButtons(Qt::AllButtons); setFiltersChildMouseEvents(true); setVisible(false); + + if (parent) + QQuickItemPrivate::get(parent)->addItemChangeListener(d, QQuickItemPrivate::Geometry); +} + +QQuickOverlay::~QQuickOverlay() +{ + Q_D(QQuickOverlay); + if (QQuickItem *parent = parentItem()) + QQuickItemPrivate::get(parent)->removeItemChangeListener(d, QQuickItemPrivate::Geometry); } QQmlComponent *QQuickOverlay::modal() const diff --git a/src/quicktemplates2/qquickoverlay_p.h b/src/quicktemplates2/qquickoverlay_p.h index 99d7ba75..480a5a6a 100644 --- a/src/quicktemplates2/qquickoverlay_p.h +++ b/src/quicktemplates2/qquickoverlay_p.h @@ -64,6 +64,7 @@ class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickOverlay : public QQuickItem public: explicit QQuickOverlay(QQuickItem *parent = nullptr); + ~QQuickOverlay(); QQmlComponent *modal() const; void setModal(QQmlComponent *modal); -- cgit v1.2.3 From 14dd934c3203b614e43be9fa5b17761d43092351 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Sat, 3 Sep 2016 15:39:04 +0200 Subject: Use QQuickOverlay with plain QQuickWindow Get rid of the ugly and broken event filter approach that was used with QQuickWindow. Create an instance of QQuickOverlay so that the same overlay code path is used for both QQuickApplicationWindow and plain QQuickWindow. Task-number: QTBUG-55729 Change-Id: I6e26b19cd94a9580418912803f50c30b9dcaeedb Reviewed-by: Mitch Curtis --- src/quicktemplates2/qquickapplicationwindow.cpp | 3 + src/quicktemplates2/qquickoverlay.cpp | 28 +++++++- src/quicktemplates2/qquickoverlay_p.h | 2 + src/quicktemplates2/qquickpopup.cpp | 19 +---- src/quicktemplates2/qquickpopup_p.h | 1 - tests/auto/popup/data/window.qml | 84 ++++++++++++++++++++++ tests/auto/popup/tst_popup.cpp | 96 ++++++++++++++++++------- 7 files changed, 186 insertions(+), 47 deletions(-) create mode 100644 tests/auto/popup/data/window.qml diff --git a/src/quicktemplates2/qquickapplicationwindow.cpp b/src/quicktemplates2/qquickapplicationwindow.cpp index bf903b8a..28095aa6 100644 --- a/src/quicktemplates2/qquickapplicationwindow.cpp +++ b/src/quicktemplates2/qquickapplicationwindow.cpp @@ -476,6 +476,9 @@ QQuickItem *QQuickApplicationWindow::activeFocusControl() const QQuickOverlay *QQuickApplicationWindow::overlay() const { QQuickApplicationWindowPrivate *d = const_cast(d_func()); + if (!d) // being deleted + return nullptr; + if (!d->overlay) { d->overlay = new QQuickOverlay(QQuickWindow::contentItem()); d->overlay->stackAfter(QQuickApplicationWindow::contentItem()); diff --git a/src/quicktemplates2/qquickoverlay.cpp b/src/quicktemplates2/qquickoverlay.cpp index c5818b90..0395ed41 100644 --- a/src/quicktemplates2/qquickoverlay.cpp +++ b/src/quicktemplates2/qquickoverlay.cpp @@ -37,6 +37,7 @@ #include "qquickoverlay_p.h" #include "qquickpopup_p_p.h" #include "qquickdrawer_p.h" +#include "qquickapplicationwindow_p.h" #include #include #include @@ -204,8 +205,10 @@ QQuickOverlay::QQuickOverlay(QQuickItem *parent) setFiltersChildMouseEvents(true); setVisible(false); - if (parent) + if (parent) { + setSize(QSizeF(parent->width(), parent->height())); QQuickItemPrivate::get(parent)->addItemChangeListener(d, QQuickItemPrivate::Geometry); + } } QQuickOverlay::~QQuickOverlay() @@ -249,6 +252,29 @@ void QQuickOverlay::setModeless(QQmlComponent *modeless) emit modelessChanged(); } +QQuickOverlay *QQuickOverlay::overlay(QQuickWindow *window) +{ + if (!window) + return nullptr; + + QQuickApplicationWindow *applicationWindow = qobject_cast(window); + if (applicationWindow) + return applicationWindow->overlay(); + + const char *name = "_q_QQuickOverlay"; + QQuickOverlay *overlay = window->property(name).value(); + if (!overlay) { + QQuickItem *content = window->contentItem(); + // Do not re-create the overlay if the window is being destroyed + // and thus, its content item no longer has a window associated. + if (content->window()) { + overlay = new QQuickOverlay(window->contentItem()); + window->setProperty(name, QVariant::fromValue(overlay)); + } + } + return overlay; +} + void QQuickOverlay::itemChange(ItemChange change, const ItemChangeData &data) { Q_D(QQuickOverlay); diff --git a/src/quicktemplates2/qquickoverlay_p.h b/src/quicktemplates2/qquickoverlay_p.h index 480a5a6a..ecb0e20a 100644 --- a/src/quicktemplates2/qquickoverlay_p.h +++ b/src/quicktemplates2/qquickoverlay_p.h @@ -72,6 +72,8 @@ public: QQmlComponent *modeless() const; void setModeless(QQmlComponent *modeless); + static QQuickOverlay *overlay(QQuickWindow *window); + Q_SIGNALS: void modalChanged(); void modelessChanged(); diff --git a/src/quicktemplates2/qquickpopup.cpp b/src/quicktemplates2/qquickpopup.cpp index b4022247..fa5864df 100644 --- a/src/quicktemplates2/qquickpopup.cpp +++ b/src/quicktemplates2/qquickpopup.cpp @@ -188,15 +188,7 @@ void QQuickPopupPrivate::prepareEnterTransition(bool notify) return; } - QQuickApplicationWindow *applicationWindow = qobject_cast(window); - if (!applicationWindow) { - window->installEventFilter(q); - popupItem->setZ(1000001); // DefaultWindowDecoration+1 - popupItem->setParentItem(window->contentItem()); - } else { - popupItem->setParentItem(applicationWindow->overlay()); - } - + popupItem->setParentItem(QQuickOverlay::overlay(window)); if (notify) emit q->aboutToShow(); visible = notify; @@ -208,8 +200,6 @@ void QQuickPopupPrivate::prepareEnterTransition(bool notify) void QQuickPopupPrivate::prepareExitTransition() { Q_Q(QQuickPopup); - if (window && !qobject_cast(window)) - window->removeEventFilter(q); if (focus) { // The setFocus(false) call below removes any active focus before we're // able to check it in finalizeExitTransition. @@ -1837,13 +1827,6 @@ bool QQuickPopup::isComponentComplete() const return d->complete; } -bool QQuickPopup::eventFilter(QObject *object, QEvent *event) -{ - if (QQuickWindow *window = qobject_cast(object)) - return overlayEvent(window->contentItem(), event); - return false; -} - bool QQuickPopup::childMouseEventFilter(QQuickItem *child, QEvent *event) { Q_UNUSED(child); diff --git a/src/quicktemplates2/qquickpopup_p.h b/src/quicktemplates2/qquickpopup_p.h index be6a8e22..9ef5c64b 100644 --- a/src/quicktemplates2/qquickpopup_p.h +++ b/src/quicktemplates2/qquickpopup_p.h @@ -334,7 +334,6 @@ protected: void componentComplete() override; bool isComponentComplete() const; - bool eventFilter(QObject *object, QEvent *event) override; virtual bool childMouseEventFilter(QQuickItem *child, QEvent *event); virtual void focusInEvent(QFocusEvent *event); virtual void focusOutEvent(QFocusEvent *event); diff --git a/tests/auto/popup/data/window.qml b/tests/auto/popup/data/window.qml new file mode 100644 index 00000000..92bfbd70 --- /dev/null +++ b/tests/auto/popup/data/window.qml @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite 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 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.6 +import QtQuick.Window 2.2 +import QtQuick.Controls 2.0 + +Window { + width: 400 + height: 400 + + property alias popup: popup + property alias popup2: popup2 + property alias button: button + + Button { + id: button + text: "Open" + anchors.centerIn: parent + anchors.verticalCenterOffset: -height + + Popup { + id: popup + y: parent.height + + Text { + color: "white" + text: "Hello, world!" + + MouseArea { + anchors.fill: parent + onClicked: popup.close() + } + } + } + } + + Popup { + id: popup2 + y: popup.y + z: 1 + contentItem: Text { + text: "Popup2" + font.pixelSize: 36 + } + } +} diff --git a/tests/auto/popup/tst_popup.cpp b/tests/auto/popup/tst_popup.cpp index abd20df0..ef649187 100644 --- a/tests/auto/popup/tst_popup.cpp +++ b/tests/auto/popup/tst_popup.cpp @@ -51,8 +51,11 @@ class tst_popup : public QQmlDataTest Q_OBJECT private slots: + void visible_data(); void visible(); + void overlay_data(); void overlay(); + void zOrder_data(); void zOrder(); void windowChange(); void closePolicy_data(); @@ -64,46 +67,67 @@ private slots: void parentDestroyed(); }; +void tst_popup::visible_data() +{ + QTest::addColumn("source"); + QTest::newRow("Window") << "window.qml"; + QTest::newRow("ApplicationWindow") << "applicationwindow.qml"; +} + void tst_popup::visible() { - QQuickApplicationHelper helper(this, QStringLiteral("applicationwindow.qml")); + QFETCH(QString, source); + QQuickApplicationHelper helper(this, source); - QQuickApplicationWindow *window = helper.appWindow; + QQuickWindow *window = helper.window; window->show(); window->requestActivate(); QVERIFY(QTest::qWaitForWindowActive(window)); - QQuickPopup *popup = helper.appWindow->property("popup").value(); + QQuickPopup *popup = window->property("popup").value(); QVERIFY(popup); QQuickItem *popupItem = popup->popupItem(); popup->open(); QVERIFY(popup->isVisible()); - QVERIFY(window->overlay()->childItems().contains(popupItem)); + + QQuickOverlay *overlay = QQuickOverlay::overlay(window); + QVERIFY(overlay); + QVERIFY(overlay->childItems().contains(popupItem)); popup->close(); QVERIFY(!popup->isVisible()); - QVERIFY(!window->overlay()->childItems().contains(popupItem)); + QVERIFY(!overlay->childItems().contains(popupItem)); popup->setVisible(true); QVERIFY(popup->isVisible()); - QVERIFY(window->overlay()->childItems().contains(popupItem)); + QVERIFY(overlay->childItems().contains(popupItem)); popup->setVisible(false); QVERIFY(!popup->isVisible()); - QVERIFY(!window->overlay()->childItems().contains(popupItem)); + QVERIFY(!overlay->childItems().contains(popupItem)); +} + +void tst_popup::overlay_data() +{ + QTest::addColumn("source"); + QTest::newRow("Window") << "window.qml"; + QTest::newRow("ApplicationWindow") << "applicationwindow.qml"; } void tst_popup::overlay() { - QQuickApplicationHelper helper(this, QStringLiteral("applicationwindow.qml")); + QFETCH(QString, source); + QQuickApplicationHelper helper(this, source); - QQuickApplicationWindow *window = helper.appWindow; + QQuickWindow *window = helper.window; window->show(); window->requestActivate(); QVERIFY(QTest::qWaitForWindowActive(window)); - QQuickItem *overlay = window->overlay(); + QQuickOverlay *overlay = QQuickOverlay::overlay(window); + QVERIFY(overlay); + QSignalSpy overlayPressedSignal(overlay, SIGNAL(pressed())); QSignalSpy overlayReleasedSignal(overlay, SIGNAL(released())); QVERIFY(overlayPressedSignal.isValid()); @@ -115,10 +139,10 @@ void tst_popup::overlay() QCOMPARE(overlayPressedSignal.count(), 0); QCOMPARE(overlayReleasedSignal.count(), 0); - QQuickPopup *popup = helper.appWindow->property("popup").value(); + QQuickPopup *popup = window->property("popup").value(); QVERIFY(popup); - QQuickButton *button = helper.appWindow->property("button").value(); + QQuickButton *button = window->property("button").value(); QVERIFY(button); popup->open(); @@ -156,20 +180,28 @@ void tst_popup::overlay() QVERIFY(!overlay->isVisible()); } +void tst_popup::zOrder_data() +{ + QTest::addColumn("source"); + QTest::newRow("Window") << "window.qml"; + QTest::newRow("ApplicationWindow") << "applicationwindow.qml"; +} + void tst_popup::zOrder() { - QQuickApplicationHelper helper(this, QStringLiteral("applicationwindow.qml")); + QFETCH(QString, source); + QQuickApplicationHelper helper(this, source); - QQuickApplicationWindow *window = helper.appWindow; + QQuickWindow *window = helper.window; window->show(); window->requestActivate(); QVERIFY(QTest::qWaitForWindowActive(window)); - QQuickPopup *popup = helper.appWindow->property("popup").value(); + QQuickPopup *popup = window->property("popup").value(); QVERIFY(popup); popup->setModal(true); - QQuickPopup *popup2 = helper.appWindow->property("popup2").value(); + QQuickPopup *popup2 = window->property("popup2").value(); QVERIFY(popup2); popup2->setModal(true); @@ -220,32 +252,42 @@ void tst_popup::closePolicy_data() { qRegisterMetaType(); + QTest::addColumn("source"); QTest::addColumn("closePolicy"); - QTest::newRow("NoAutoClose") << static_cast(QQuickPopup::NoAutoClose); - QTest::newRow("CloseOnPressOutside") << static_cast(QQuickPopup::CloseOnPressOutside); - QTest::newRow("CloseOnPressOutsideParent") << static_cast(QQuickPopup::CloseOnPressOutsideParent); - QTest::newRow("CloseOnPressOutside|Parent") << static_cast(QQuickPopup::CloseOnPressOutside | QQuickPopup::CloseOnPressOutsideParent); - QTest::newRow("CloseOnReleaseOutside") << static_cast(QQuickPopup::CloseOnReleaseOutside); - QTest::newRow("CloseOnReleaseOutside|Parent") << static_cast(QQuickPopup::CloseOnReleaseOutside | QQuickPopup::CloseOnReleaseOutsideParent); - QTest::newRow("CloseOnEscape") << static_cast(QQuickPopup::CloseOnEscape); + QTest::newRow("Window:NoAutoClose") << "window.qml"<< static_cast(QQuickPopup::NoAutoClose); + QTest::newRow("Window:CloseOnPressOutside") << "window.qml"<< static_cast(QQuickPopup::CloseOnPressOutside); + QTest::newRow("Window:CloseOnPressOutsideParent") << "window.qml"<< static_cast(QQuickPopup::CloseOnPressOutsideParent); + QTest::newRow("Window:CloseOnPressOutside|Parent") << "window.qml"<< static_cast(QQuickPopup::CloseOnPressOutside | QQuickPopup::CloseOnPressOutsideParent); + QTest::newRow("Window:CloseOnReleaseOutside") << "window.qml"<< static_cast(QQuickPopup::CloseOnReleaseOutside); + QTest::newRow("Window:CloseOnReleaseOutside|Parent") << "window.qml"<< static_cast(QQuickPopup::CloseOnReleaseOutside | QQuickPopup::CloseOnReleaseOutsideParent); + QTest::newRow("Window:CloseOnEscape") << "window.qml"<< static_cast(QQuickPopup::CloseOnEscape); + + QTest::newRow("ApplicationWindow:NoAutoClose") << "applicationwindow.qml"<< static_cast(QQuickPopup::NoAutoClose); + QTest::newRow("ApplicationWindow:CloseOnPressOutside") << "applicationwindow.qml"<< static_cast(QQuickPopup::CloseOnPressOutside); + QTest::newRow("ApplicationWindow:CloseOnPressOutsideParent") << "applicationwindow.qml"<< static_cast(QQuickPopup::CloseOnPressOutsideParent); + QTest::newRow("ApplicationWindow:CloseOnPressOutside|Parent") << "applicationwindow.qml"<< static_cast(QQuickPopup::CloseOnPressOutside | QQuickPopup::CloseOnPressOutsideParent); + QTest::newRow("ApplicationWindow:CloseOnReleaseOutside") << "applicationwindow.qml"<< static_cast(QQuickPopup::CloseOnReleaseOutside); + QTest::newRow("ApplicationWindow:CloseOnReleaseOutside|Parent") << "applicationwindow.qml"<< static_cast(QQuickPopup::CloseOnReleaseOutside | QQuickPopup::CloseOnReleaseOutsideParent); + QTest::newRow("ApplicationWindow:CloseOnEscape") << "applicationwindow.qml"<< static_cast(QQuickPopup::CloseOnEscape); } void tst_popup::closePolicy() { + QFETCH(QString, source); QFETCH(QQuickPopup::ClosePolicy, closePolicy); - QQuickApplicationHelper helper(this, QStringLiteral("applicationwindow.qml")); + QQuickApplicationHelper helper(this, source); - QQuickApplicationWindow *window = helper.appWindow; + QQuickWindow *window = helper.window; window->show(); window->requestActivate(); QVERIFY(QTest::qWaitForWindowActive(window)); - QQuickPopup *popup = helper.appWindow->property("popup").value(); + QQuickPopup *popup = window->property("popup").value(); QVERIFY(popup); - QQuickButton *button = helper.appWindow->property("button").value(); + QQuickButton *button = window->property("button").value(); QVERIFY(button); popup->setModal(true); -- cgit v1.2.3 From df12dbe976876bbb4e36b16eb4836c4109bb80d0 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Sat, 3 Sep 2016 15:46:37 +0200 Subject: Fix hover event delivery with plain QQuickWindow A plain QQuickWindow cannot provide a modal background dimming visual, but we can create a QQuickItem as a fallback to take care of blocking the hover events for modal popups. Change-Id: I3ead985c4e2e030aaf28f1ec6c8a1ae285637819 Task-number: QTBUG-54913 Reviewed-by: Mitch Curtis --- src/quicktemplates2/qquickoverlay.cpp | 25 +++++--- tests/auto/drawer/data/applicationwindow-hover.qml | 72 +++++++++++++++++++++ tests/auto/drawer/data/hover.qml | 72 --------------------- tests/auto/drawer/data/window-hover.qml | 73 ++++++++++++++++++++++ tests/auto/drawer/tst_drawer.cpp | 18 +++--- tests/auto/popup/data/applicationwindow-hover.qml | 69 ++++++++++++++++++++ tests/auto/popup/data/hover.qml | 69 -------------------- tests/auto/popup/data/window-hover.qml | 70 +++++++++++++++++++++ tests/auto/popup/tst_popup.cpp | 18 +++--- 9 files changed, 322 insertions(+), 164 deletions(-) create mode 100644 tests/auto/drawer/data/applicationwindow-hover.qml delete mode 100644 tests/auto/drawer/data/hover.qml create mode 100644 tests/auto/drawer/data/window-hover.qml create mode 100644 tests/auto/popup/data/applicationwindow-hover.qml delete mode 100644 tests/auto/popup/data/hover.qml create mode 100644 tests/auto/popup/data/window-hover.qml diff --git a/src/quicktemplates2/qquickoverlay.cpp b/src/quicktemplates2/qquickoverlay.cpp index 0395ed41..7e9e57f4 100644 --- a/src/quicktemplates2/qquickoverlay.cpp +++ b/src/quicktemplates2/qquickoverlay.cpp @@ -101,15 +101,21 @@ void QQuickOverlayPrivate::popupAboutToHide() static QQuickItem *createDimmer(QQmlComponent *component, QQuickPopup *popup, QQuickItem *parent) { - if (!component) - return nullptr; + QQuickItem *item = nullptr; + if (component) { + QQmlContext *creationContext = component->creationContext(); + if (!creationContext) + creationContext = qmlContext(parent); + QQmlContext *context = new QQmlContext(creationContext); + context->setContextObject(popup); + item = qobject_cast(component->beginCreate(context)); + } + + // when there is no overlay component available (with plain QQuickWindow), + // use a plain QQuickItem as a fallback to block hover events + if (!item && popup->isModal()) + item = new QQuickItem; - QQmlContext *creationContext = component->creationContext(); - if (!creationContext) - creationContext = qmlContext(parent); - QQmlContext *context = new QQmlContext(creationContext); - context->setContextObject(popup); - QQuickItem *item = qobject_cast(component->beginCreate(context)); if (item) { item->setOpacity(popup->isVisible() ? 1.0 : 0.0); item->setParentItem(parent); @@ -121,7 +127,8 @@ static QQuickItem *createDimmer(QQmlComponent *component, QQuickPopup *popup, QQ // item->setAcceptHoverEvents(QGuiApplication::styleHints()->useHoverEffects()); // connect(QGuiApplication::styleHints(), &QStyleHints::useHoverEffectsChanged, item, &QQuickItem::setAcceptHoverEvents); } - component->completeCreate(); + if (component) + component->completeCreate(); } return item; } diff --git a/tests/auto/drawer/data/applicationwindow-hover.qml b/tests/auto/drawer/data/applicationwindow-hover.qml new file mode 100644 index 00000000..5ac41457 --- /dev/null +++ b/tests/auto/drawer/data/applicationwindow-hover.qml @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite 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 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.6 +import QtQuick.Controls 2.0 + +ApplicationWindow { + width: 400 + height: 400 + + property alias drawer: drawer + property alias backgroundButton: backgroundButton + property alias drawerButton: drawerButton + + Button { + id: backgroundButton + text: "Background" + anchors.fill: parent + } + + Drawer { + id: drawer + width: 100 + height: 400 + topPadding: 2 + leftPadding: 2 + rightPadding: 2 + bottomPadding: 2 + + contentItem: Button { + id: drawerButton + text: "Drawer" + } + } +} diff --git a/tests/auto/drawer/data/hover.qml b/tests/auto/drawer/data/hover.qml deleted file mode 100644 index 5ac41457..00000000 --- a/tests/auto/drawer/data/hover.qml +++ /dev/null @@ -1,72 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the test suite 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 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.6 -import QtQuick.Controls 2.0 - -ApplicationWindow { - width: 400 - height: 400 - - property alias drawer: drawer - property alias backgroundButton: backgroundButton - property alias drawerButton: drawerButton - - Button { - id: backgroundButton - text: "Background" - anchors.fill: parent - } - - Drawer { - id: drawer - width: 100 - height: 400 - topPadding: 2 - leftPadding: 2 - rightPadding: 2 - bottomPadding: 2 - - contentItem: Button { - id: drawerButton - text: "Drawer" - } - } -} diff --git a/tests/auto/drawer/data/window-hover.qml b/tests/auto/drawer/data/window-hover.qml new file mode 100644 index 00000000..872b934e --- /dev/null +++ b/tests/auto/drawer/data/window-hover.qml @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite 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 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.6 +import QtQuick.Window 2.2 +import QtQuick.Controls 2.0 + +Window { + width: 400 + height: 400 + + property alias drawer: drawer + property alias backgroundButton: backgroundButton + property alias drawerButton: drawerButton + + Button { + id: backgroundButton + text: "Background" + anchors.fill: parent + } + + Drawer { + id: drawer + width: 100 + height: 400 + topPadding: 2 + leftPadding: 2 + rightPadding: 2 + bottomPadding: 2 + + contentItem: Button { + id: drawerButton + text: "Drawer" + } + } +} diff --git a/tests/auto/drawer/tst_drawer.cpp b/tests/auto/drawer/tst_drawer.cpp index ffa1f896..43236817 100644 --- a/tests/auto/drawer/tst_drawer.cpp +++ b/tests/auto/drawer/tst_drawer.cpp @@ -188,31 +188,35 @@ void tst_Drawer::reposition() void tst_Drawer::hover_data() { + QTest::addColumn("source"); QTest::addColumn("modal"); - QTest::newRow("modal") << true; - QTest::newRow("modeless") << false; + QTest::newRow("Window:modal") << "window-hover.qml" << true; + QTest::newRow("Window:modeless") << "window-hover.qml" << false; + QTest::newRow("ApplicationWindow:modal") << "applicationwindow-hover.qml" << true; + QTest::newRow("ApplicationWindow:modeless") << "applicationwindow-hover.qml" << false; } void tst_Drawer::hover() { + QFETCH(QString, source); QFETCH(bool, modal); - QQuickApplicationHelper helper(this, QStringLiteral("hover.qml")); - QQuickApplicationWindow *window = helper.appWindow; + QQuickApplicationHelper helper(this, source); + QQuickWindow *window = helper.window; window->show(); window->requestActivate(); QVERIFY(QTest::qWaitForWindowActive(window)); - QQuickDrawer *drawer = helper.appWindow->property("drawer").value(); + QQuickDrawer *drawer = window->property("drawer").value(); QVERIFY(drawer); drawer->setModal(modal); - QQuickButton *backgroundButton = helper.appWindow->property("backgroundButton").value(); + QQuickButton *backgroundButton = window->property("backgroundButton").value(); QVERIFY(backgroundButton); backgroundButton->setHoverEnabled(true); - QQuickButton *drawerButton = helper.appWindow->property("drawerButton").value(); + QQuickButton *drawerButton = window->property("drawerButton").value(); QVERIFY(drawerButton); drawerButton->setHoverEnabled(true); diff --git a/tests/auto/popup/data/applicationwindow-hover.qml b/tests/auto/popup/data/applicationwindow-hover.qml new file mode 100644 index 00000000..044d983c --- /dev/null +++ b/tests/auto/popup/data/applicationwindow-hover.qml @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite 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 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.6 +import QtQuick.Controls 2.0 + +ApplicationWindow { + width: 400 + height: 400 + + property alias popup: popup + property alias parentButton: parentButton + property alias childButton: childButton + + Button { + id: parentButton + text: "Parent" + anchors.fill: parent + + Popup { + id: popup + x: 1 + y: 1 + padding: 1 + + Button { + id: childButton + text: "Child" + } + } + } +} diff --git a/tests/auto/popup/data/hover.qml b/tests/auto/popup/data/hover.qml deleted file mode 100644 index 044d983c..00000000 --- a/tests/auto/popup/data/hover.qml +++ /dev/null @@ -1,69 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the test suite 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 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.6 -import QtQuick.Controls 2.0 - -ApplicationWindow { - width: 400 - height: 400 - - property alias popup: popup - property alias parentButton: parentButton - property alias childButton: childButton - - Button { - id: parentButton - text: "Parent" - anchors.fill: parent - - Popup { - id: popup - x: 1 - y: 1 - padding: 1 - - Button { - id: childButton - text: "Child" - } - } - } -} diff --git a/tests/auto/popup/data/window-hover.qml b/tests/auto/popup/data/window-hover.qml new file mode 100644 index 00000000..78d650fa --- /dev/null +++ b/tests/auto/popup/data/window-hover.qml @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite 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 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.6 +import QtQuick.Window 2.2 +import QtQuick.Controls 2.0 + +Window { + width: 400 + height: 400 + + property alias popup: popup + property alias parentButton: parentButton + property alias childButton: childButton + + Button { + id: parentButton + text: "Parent" + anchors.fill: parent + + Popup { + id: popup + x: 1 + y: 1 + padding: 1 + + Button { + id: childButton + text: "Child" + } + } + } +} diff --git a/tests/auto/popup/tst_popup.cpp b/tests/auto/popup/tst_popup.cpp index ef649187..990140db 100644 --- a/tests/auto/popup/tst_popup.cpp +++ b/tests/auto/popup/tst_popup.cpp @@ -411,31 +411,35 @@ void tst_popup::activeFocusOnClose2() void tst_popup::hover_data() { + QTest::addColumn("source"); QTest::addColumn("modal"); - QTest::newRow("modal") << true; - QTest::newRow("modeless") << false; + QTest::newRow("Window:modal") << "window-hover.qml" << true; + QTest::newRow("Window:modeless") << "window-hover.qml" << false; + QTest::newRow("ApplicationWindow:modal") << "applicationwindow-hover.qml" << true; + QTest::newRow("ApplicationWindow:modeless") << "applicationwindow-hover.qml" << false; } void tst_popup::hover() { + QFETCH(QString, source); QFETCH(bool, modal); - QQuickApplicationHelper helper(this, QStringLiteral("hover.qml")); - QQuickApplicationWindow *window = helper.appWindow; + QQuickApplicationHelper helper(this, source); + QQuickWindow *window = helper.window; window->show(); window->requestActivate(); QVERIFY(QTest::qWaitForWindowActive(window)); - QQuickPopup *popup = helper.appWindow->property("popup").value(); + QQuickPopup *popup = window->property("popup").value(); QVERIFY(popup); popup->setModal(modal); - QQuickButton *parentButton = helper.appWindow->property("parentButton").value(); + QQuickButton *parentButton = window->property("parentButton").value(); QVERIFY(parentButton); parentButton->setHoverEnabled(true); - QQuickButton *childButton = helper.appWindow->property("childButton").value(); + QQuickButton *childButton = window->property("childButton").value(); QVERIFY(childButton); childButton->setHoverEnabled(true); -- cgit v1.2.3 From aa4964843f2faca2d52469edc2ba899f9b11e15c Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Sat, 3 Sep 2016 19:33:35 +0200 Subject: Make QQuickOverlayPrivate accessible via qquickoverlay_p_p.h Required by the subsequent patches. Done separately keep the other patches smaller and easier to review. Change-Id: I90ae08ea196354b3db74e2203983ca95733ef0c8 Reviewed-by: Mitch Curtis --- src/quicktemplates2/qquickoverlay.cpp | 30 +---------- src/quicktemplates2/qquickoverlay_p_p.h | 95 +++++++++++++++++++++++++++++++++ src/quicktemplates2/quicktemplates2.pri | 1 + 3 files changed, 97 insertions(+), 29 deletions(-) create mode 100644 src/quicktemplates2/qquickoverlay_p_p.h diff --git a/src/quicktemplates2/qquickoverlay.cpp b/src/quicktemplates2/qquickoverlay.cpp index 7e9e57f4..e98544cd 100644 --- a/src/quicktemplates2/qquickoverlay.cpp +++ b/src/quicktemplates2/qquickoverlay.cpp @@ -35,44 +35,16 @@ ****************************************************************************/ #include "qquickoverlay_p.h" +#include "qquickoverlay_p_p.h" #include "qquickpopup_p_p.h" #include "qquickdrawer_p.h" #include "qquickapplicationwindow_p.h" #include #include #include -#include -#include QT_BEGIN_NAMESPACE -class QQuickOverlayPrivate : public QQuickItemPrivate, public QQuickItemChangeListener -{ - Q_DECLARE_PUBLIC(QQuickOverlay) - -public: - QQuickOverlayPrivate(); - - void popupAboutToShow(); - void popupAboutToHide(); - - void createOverlay(QQuickPopup *popup); - void destroyOverlay(QQuickPopup *popup); - void resizeOverlay(QQuickPopup *popup); - void toggleOverlay(); - - QVector stackingOrderPopups() const; - - void itemGeometryChanged(QQuickItem *item, const QRectF &newGeometry, const QRectF &oldGeometry) override; - - QQmlComponent *modal; - QQmlComponent *modeless; - QVector drawers; - QVector popups; - QPointer mouseGrabberPopup; - int modalPopups; -}; - void QQuickOverlayPrivate::popupAboutToShow() { Q_Q(QQuickOverlay); diff --git a/src/quicktemplates2/qquickoverlay_p_p.h b/src/quicktemplates2/qquickoverlay_p_p.h new file mode 100644 index 00000000..0b6ba21c --- /dev/null +++ b/src/quicktemplates2/qquickoverlay_p_p.h @@ -0,0 +1,95 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKOVERLAY_P_P_H +#define QQUICKOVERLAY_P_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qquickoverlay_p.h" + +#include +#include + +QT_BEGIN_NAMESPACE + +class QQuickPopup; +class QQuickDrawer; + +class QQuickOverlayPrivate : public QQuickItemPrivate, public QQuickItemChangeListener +{ + Q_DECLARE_PUBLIC(QQuickOverlay) + +public: + QQuickOverlayPrivate(); + + static QQuickOverlayPrivate *get(QQuickOverlay *overlay) + { + return overlay->d_func(); + } + + void popupAboutToShow(); + void popupAboutToHide(); + + void createOverlay(QQuickPopup *popup); + void destroyOverlay(QQuickPopup *popup); + void resizeOverlay(QQuickPopup *popup); + void toggleOverlay(); + + QVector stackingOrderPopups() const; + + void itemGeometryChanged(QQuickItem *item, const QRectF &newGeometry, const QRectF &oldGeometry) override; + + QQmlComponent *modal; + QQmlComponent *modeless; + QVector drawers; + QVector popups; + QPointer mouseGrabberPopup; + int modalPopups; +}; + +QT_END_NAMESPACE + +#endif // QQUICKOVERLAY_P_P_H diff --git a/src/quicktemplates2/quicktemplates2.pri b/src/quicktemplates2/quicktemplates2.pri index 173112d3..0d693b1b 100644 --- a/src/quicktemplates2/quicktemplates2.pri +++ b/src/quicktemplates2/quicktemplates2.pri @@ -27,6 +27,7 @@ HEADERS += \ $$PWD/qquickmenu_p_p.h \ $$PWD/qquickmenuitem_p.h \ $$PWD/qquickoverlay_p.h \ + $$PWD/qquickoverlay_p_p.h \ $$PWD/qquickpage_p.h \ $$PWD/qquickpageindicator_p.h \ $$PWD/qquickpane_p.h \ -- cgit v1.2.3 From 5f9f81a1d43fd840d37982aadbe49f7343c3cbaa Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Sat, 3 Sep 2016 19:47:35 +0200 Subject: QQuickOverlay: keep track of all popups Required by the subsequent patches. Done separately keep the other patches smaller and easier to review. Change-Id: I60212451cf53443ae7abd58b8eaad94b66984e03 Reviewed-by: Mitch Curtis --- src/quicktemplates2/qquickoverlay.cpp | 10 ++++++++++ src/quicktemplates2/qquickoverlay_p_p.h | 4 ++++ src/quicktemplates2/qquickpopup.cpp | 14 +++++++++++++- 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/quicktemplates2/qquickoverlay.cpp b/src/quicktemplates2/qquickoverlay.cpp index e98544cd..ae90a5f8 100644 --- a/src/quicktemplates2/qquickoverlay.cpp +++ b/src/quicktemplates2/qquickoverlay.cpp @@ -175,6 +175,16 @@ QQuickOverlayPrivate::QQuickOverlayPrivate() : { } +void QQuickOverlayPrivate::addPopup(QQuickPopup *popup) +{ + allPopups += popup; +} + +void QQuickOverlayPrivate::removePopup(QQuickPopup *popup) +{ + allPopups.removeOne(popup); +} + QQuickOverlay::QQuickOverlay(QQuickItem *parent) : QQuickItem(*(new QQuickOverlayPrivate), parent) { diff --git a/src/quicktemplates2/qquickoverlay_p_p.h b/src/quicktemplates2/qquickoverlay_p_p.h index 0b6ba21c..a3d2cda7 100644 --- a/src/quicktemplates2/qquickoverlay_p_p.h +++ b/src/quicktemplates2/qquickoverlay_p_p.h @@ -70,6 +70,9 @@ public: return overlay->d_func(); } + void addPopup(QQuickPopup *popup); + void removePopup(QQuickPopup *popup); + void popupAboutToShow(); void popupAboutToHide(); @@ -86,6 +89,7 @@ public: QQmlComponent *modeless; QVector drawers; QVector popups; + QVector allPopups; QPointer mouseGrabberPopup; int modalPopups; }; diff --git a/src/quicktemplates2/qquickpopup.cpp b/src/quicktemplates2/qquickpopup.cpp index fa5864df..6c184243 100644 --- a/src/quicktemplates2/qquickpopup.cpp +++ b/src/quicktemplates2/qquickpopup.cpp @@ -37,7 +37,7 @@ #include "qquickpopup_p.h" #include "qquickpopup_p_p.h" #include "qquickapplicationwindow_p.h" -#include "qquickoverlay_p.h" +#include "qquickoverlay_p_p.h" #include "qquickcontrol_p_p.h" #include @@ -304,6 +304,18 @@ void QQuickPopupPrivate::setWindow(QQuickWindow *newWindow) if (window == newWindow) return; + if (window) { + QQuickOverlay *overlay = QQuickOverlay::overlay(window); + if (overlay) + QQuickOverlayPrivate::get(overlay)->removePopup(q); + } + + if (newWindow) { + QQuickOverlay *overlay = QQuickOverlay::overlay(newWindow); + if (overlay) + QQuickOverlayPrivate::get(overlay)->addPopup(q); + } + window = newWindow; emit q->windowChanged(newWindow); } -- cgit v1.2.3 From c1563a67b7cce03c27367fab4d470b9ee129bd1f Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Sat, 3 Sep 2016 19:50:40 +0200 Subject: QQuickOverlay: keep track of all drawers Required by the subsequent patches. Done separately keep the other patches smaller and easier to review. Change-Id: Id5d13e19f98155cfd3d0474c7d3839808133bab1 Reviewed-by: Mitch Curtis --- src/quicktemplates2/qquickoverlay.cpp | 17 +++++------------ src/quicktemplates2/qquickoverlay_p_p.h | 2 +- 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/src/quicktemplates2/qquickoverlay.cpp b/src/quicktemplates2/qquickoverlay.cpp index ae90a5f8..f45b1049 100644 --- a/src/quicktemplates2/qquickoverlay.cpp +++ b/src/quicktemplates2/qquickoverlay.cpp @@ -178,11 +178,14 @@ QQuickOverlayPrivate::QQuickOverlayPrivate() : void QQuickOverlayPrivate::addPopup(QQuickPopup *popup) { allPopups += popup; + if (QQuickDrawer *drawer = qobject_cast(popup)) + allDrawers += drawer; } void QQuickOverlayPrivate::removePopup(QQuickPopup *popup) { allPopups.removeOne(popup); + allDrawers.removeOne(static_cast(popup)); } QQuickOverlay::QQuickOverlay(QQuickItem *parent) @@ -283,14 +286,9 @@ void QQuickOverlay::itemChange(ItemChange change, const ItemChangeData &data) d->createOverlay(popup); QObjectPrivate::connect(popup, &QQuickPopup::dimChanged, d, &QQuickOverlayPrivate::toggleOverlay); QObjectPrivate::connect(popup, &QQuickPopup::modalChanged, d, &QQuickOverlayPrivate::toggleOverlay); - - QQuickDrawer *drawer = qobject_cast(popup); - if (drawer) { - d->drawers.append(drawer); - } else { + if (!qobject_cast(popup)) { if (popup->isModal()) ++d->modalPopups; - QObjectPrivate::connect(popup, &QQuickPopup::aboutToShow, d, &QQuickOverlayPrivate::popupAboutToShow); QObjectPrivate::connect(popup, &QQuickPopup::aboutToHide, d, &QQuickOverlayPrivate::popupAboutToHide); } @@ -299,14 +297,9 @@ void QQuickOverlay::itemChange(ItemChange change, const ItemChangeData &data) d->destroyOverlay(popup); QObjectPrivate::disconnect(popup, &QQuickPopup::dimChanged, d, &QQuickOverlayPrivate::toggleOverlay); QObjectPrivate::disconnect(popup, &QQuickPopup::modalChanged, d, &QQuickOverlayPrivate::toggleOverlay); - - QQuickDrawer *drawer = qobject_cast(popup); - if (drawer) { - d->drawers.removeOne(drawer); - } else { + if (!qobject_cast(popup)) { if (popup->isModal()) --d->modalPopups; - QObjectPrivate::disconnect(popup, &QQuickPopup::aboutToShow, d, &QQuickOverlayPrivate::popupAboutToShow); QObjectPrivate::disconnect(popup, &QQuickPopup::aboutToHide, d, &QQuickOverlayPrivate::popupAboutToHide); } diff --git a/src/quicktemplates2/qquickoverlay_p_p.h b/src/quicktemplates2/qquickoverlay_p_p.h index a3d2cda7..7e63a99b 100644 --- a/src/quicktemplates2/qquickoverlay_p_p.h +++ b/src/quicktemplates2/qquickoverlay_p_p.h @@ -87,9 +87,9 @@ public: QQmlComponent *modal; QQmlComponent *modeless; - QVector drawers; QVector popups; QVector allPopups; + QVector allDrawers; QPointer mouseGrabberPopup; int modalPopups; }; -- cgit v1.2.3 From f6d74e89bbe9e4cf42eeb17cb4bdd0e415aa946f Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Sun, 4 Sep 2016 10:01:50 +0200 Subject: Remove superfluous QQuickOverlayPrivate::popups First of all, the name was a bit misleading. It was a list of _visible_ popups. Anyway, it is unnecessary to maintain such list anymore. The only use case for it was to resize the background dimming items of visible popups when the window was resized. For that infrequent desktop -only event, we can fetch the background dimming items from the list of all popups. Change-Id: Ie17db042719d4614189a78a2e5314136ca95df42 Reviewed-by: Mitch Curtis --- src/quicktemplates2/qquickoverlay.cpp | 4 +--- src/quicktemplates2/qquickoverlay_p_p.h | 1 - 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/quicktemplates2/qquickoverlay.cpp b/src/quicktemplates2/qquickoverlay.cpp index f45b1049..d34fd7fc 100644 --- a/src/quicktemplates2/qquickoverlay.cpp +++ b/src/quicktemplates2/qquickoverlay.cpp @@ -281,7 +281,6 @@ void QQuickOverlay::itemChange(ItemChange change, const ItemChangeData &data) return; if (change == ItemChildAddedChange) { - d->popups.append(popup); if (popup->dim()) d->createOverlay(popup); QObjectPrivate::connect(popup, &QQuickPopup::dimChanged, d, &QQuickOverlayPrivate::toggleOverlay); @@ -293,7 +292,6 @@ void QQuickOverlay::itemChange(ItemChange change, const ItemChangeData &data) QObjectPrivate::connect(popup, &QQuickPopup::aboutToHide, d, &QQuickOverlayPrivate::popupAboutToHide); } } else if (change == ItemChildRemovedChange) { - d->popups.removeOne(popup); d->destroyOverlay(popup); QObjectPrivate::disconnect(popup, &QQuickPopup::dimChanged, d, &QQuickOverlayPrivate::toggleOverlay); QObjectPrivate::disconnect(popup, &QQuickPopup::modalChanged, d, &QQuickOverlayPrivate::toggleOverlay); @@ -310,7 +308,7 @@ void QQuickOverlay::geometryChanged(const QRectF &newGeometry, const QRectF &old { Q_D(QQuickOverlay); QQuickItem::geometryChanged(newGeometry, oldGeometry); - for (QQuickPopup *popup : d->popups) + for (QQuickPopup *popup : qAsConst(d->allPopups)) d->resizeOverlay(popup); } diff --git a/src/quicktemplates2/qquickoverlay_p_p.h b/src/quicktemplates2/qquickoverlay_p_p.h index 7e63a99b..f9e962ee 100644 --- a/src/quicktemplates2/qquickoverlay_p_p.h +++ b/src/quicktemplates2/qquickoverlay_p_p.h @@ -87,7 +87,6 @@ public: QQmlComponent *modal; QQmlComponent *modeless; - QVector popups; QVector allPopups; QVector allDrawers; QPointer mouseGrabberPopup; -- cgit v1.2.3 From c4a7bcfa0bd92fdbfca362cd84487433507561c5 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Sun, 4 Sep 2016 09:24:26 +0200 Subject: Make QQuickDrawerPrivate accessible via qquickdrawer_p_p.h Required by the subsequent patches. Done separately keep the other patches smaller and easier to review. Change-Id: Ibce7f131684ef48a60c7023e7566d8b6907ac6af Reviewed-by: Mitch Curtis --- src/quicktemplates2/qquickdrawer.cpp | 33 ++---------- src/quicktemplates2/qquickdrawer_p_p.h | 91 +++++++++++++++++++++++++++++++++ src/quicktemplates2/quicktemplates2.pri | 1 + 3 files changed, 97 insertions(+), 28 deletions(-) create mode 100644 src/quicktemplates2/qquickdrawer_p_p.h diff --git a/src/quicktemplates2/qquickdrawer.cpp b/src/quicktemplates2/qquickdrawer.cpp index d11a8bdf..6b0d9849 100644 --- a/src/quicktemplates2/qquickdrawer.cpp +++ b/src/quicktemplates2/qquickdrawer.cpp @@ -35,8 +35,7 @@ ****************************************************************************/ #include "qquickdrawer_p.h" -#include "qquickpopup_p_p.h" -#include "qquickvelocitycalculator_p_p.h" +#include "qquickdrawer_p_p.h" #include #include @@ -114,33 +113,11 @@ QT_BEGIN_NAMESPACE \sa SwipeView, {Customizing Drawer}, {Navigation Controls}, {Popup Controls} */ -class QQuickDrawerPrivate : public QQuickPopupPrivate +QQuickDrawerPrivate::QQuickDrawerPrivate() + : edge(Qt::LeftEdge), offset(0), position(0), + dragMargin(QGuiApplication::styleHints()->startDragDistance()) { - Q_DECLARE_PUBLIC(QQuickDrawer) - -public: - QQuickDrawerPrivate() : edge(Qt::LeftEdge), offset(0), position(0), - dragMargin(QGuiApplication::styleHints()->startDragDistance()) { } - - qreal positionAt(const QPointF &point) const; - void reposition() override; - - bool handleMousePressEvent(QQuickItem *item, QMouseEvent *event); - bool handleMouseMoveEvent(QQuickItem *item, QMouseEvent *event); - bool handleMouseReleaseEvent(QQuickItem *item, QMouseEvent *event); - - void prepareEnterTransition(bool notify = true) override; - void prepareExitTransition() override; - void finalizeEnterTransition() override; - void finalizeExitTransition(bool hide = true) override; - - Qt::Edge edge; - qreal offset; - qreal position; - qreal dragMargin; - QPointF pressPoint; - QQuickVelocityCalculator velocityCalculator; -}; +} qreal QQuickDrawerPrivate::positionAt(const QPointF &point) const { diff --git a/src/quicktemplates2/qquickdrawer_p_p.h b/src/quicktemplates2/qquickdrawer_p_p.h new file mode 100644 index 00000000..232b0b08 --- /dev/null +++ b/src/quicktemplates2/qquickdrawer_p_p.h @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKDRAWER_P_P_H +#define QQUICKDRAWER_P_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qquickdrawer_p.h" +#include "qquickpopup_p_p.h" +#include "qquickvelocitycalculator_p_p.h" + +QT_BEGIN_NAMESPACE + +class QQuickDrawerPrivate : public QQuickPopupPrivate +{ + Q_DECLARE_PUBLIC(QQuickDrawer) + +public: + QQuickDrawerPrivate(); + + static QQuickDrawerPrivate *get(QQuickDrawer *drawer) + { + return drawer->d_func(); + } + + qreal positionAt(const QPointF &point) const; + void reposition() override; + + bool handleMousePressEvent(QQuickItem *item, QMouseEvent *event); + bool handleMouseMoveEvent(QQuickItem *item, QMouseEvent *event); + bool handleMouseReleaseEvent(QQuickItem *item, QMouseEvent *event); + + void prepareEnterTransition(bool notify = true) override; + void prepareExitTransition() override; + void finalizeEnterTransition() override; + void finalizeExitTransition(bool hide = true) override; + + Qt::Edge edge; + qreal offset; + qreal position; + qreal dragMargin; + QPointF pressPoint; + QQuickVelocityCalculator velocityCalculator; +}; + +QT_END_NAMESPACE + +#endif // QQUICKDRAWER_P_P_H diff --git a/src/quicktemplates2/quicktemplates2.pri b/src/quicktemplates2/quicktemplates2.pri index 0d693b1b..0a9d2fd5 100644 --- a/src/quicktemplates2/quicktemplates2.pri +++ b/src/quicktemplates2/quicktemplates2.pri @@ -16,6 +16,7 @@ HEADERS += \ $$PWD/qquickcontrol_p_p.h \ $$PWD/qquickdial_p.h \ $$PWD/qquickdrawer_p.h \ + $$PWD/qquickdrawer_p_p.h \ $$PWD/qquickframe_p.h \ $$PWD/qquickframe_p_p.h \ $$PWD/qquickgroupbox_p.h \ -- cgit v1.2.3 From 7e109cdd105d3d152d4a5c9dba16926e78602a04 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Thu, 1 Sep 2016 21:42:55 +0200 Subject: Material: fix popups to respect Material.background Task-number: QTBUG-55687 Change-Id: I217ad905cc06228a6a1608c0721dc20a31db6d9b Reviewed-by: Mitch Curtis --- .../controls/material/qquickmaterialstyle.cpp | 4 +++ .../auto/qquickmaterialstyle/data/tst_material.qml | 40 ++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/src/imports/controls/material/qquickmaterialstyle.cpp b/src/imports/controls/material/qquickmaterialstyle.cpp index 8562cdbb..3676bdbb 100644 --- a/src/imports/controls/material/qquickmaterialstyle.cpp +++ b/src/imports/controls/material/qquickmaterialstyle.cpp @@ -1020,6 +1020,8 @@ QColor QQuickMaterialStyle::scrollBarPressedColor() const QColor QQuickMaterialStyle::dialogColor() const { + if (m_hasBackground) + return backgroundColor(); return QColor::fromRgba(m_theme == Light ? dialogColorLight : dialogColorDark); } @@ -1035,6 +1037,8 @@ QColor QQuickMaterialStyle::listHighlightColor() const QColor QQuickMaterialStyle::tooltipColor() const { + if (m_explicitBackground) + return backgroundColor(); return color(Grey, Shade700); } diff --git a/tests/auto/qquickmaterialstyle/data/tst_material.qml b/tests/auto/qquickmaterialstyle/data/tst_material.qml index 1cd1d16d..727de2e4 100644 --- a/tests/auto/qquickmaterialstyle/data/tst_material.qml +++ b/tests/auto/qquickmaterialstyle/data/tst_material.qml @@ -629,4 +629,44 @@ TestCase { appWindow.destroy() } + + Component { + id: popups + ApplicationWindow { + id: window + property Drawer drawer: Drawer { parent: window.contentItem } + property Menu menu: Menu { parent: window.contentItem; visible: true } + property Popup popup: Popup { parent: window.contentItem; visible: true } + property ToolTip tooltip: ToolTip { parent: window.contentItem; visible: true } + } + } + + function test_popupBackground_data() { + return [ + { tag: "drawer", inherit: true }, + { tag: "menu", inherit: true }, + { tag: "popup", inherit: true }, + { tag: "tooltip", inherit: false } + ] + } + + function test_popupBackground(data) { + var window = popups.createObject(testCase) + verify(window) + + var control = window[data.tag] + verify(control) + + window.Material.background = "#ff0000" + compare(window.color, "#ff0000") + if (data.inherit) + compare(control.background.color, "#ff0000") + else + verify(control.background !== "#ff0000") + + control.Material.background = "#0000ff" + compare(control.background.color, "#0000ff") + + window.destroy() + } } -- cgit v1.2.3 From 058f2dcc6070a9a36f269dd3fff6017c546d0b53 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Fri, 2 Sep 2016 01:15:33 +0200 Subject: Material: fix ToolBar to respect Material.background Task-number: QTBUG-55687 Change-Id: I815291847bad72ae58b66dc70b510ce11cd88b8d Reviewed-by: Mitch Curtis --- src/imports/controls/material/ToolBar.qml | 2 +- src/imports/controls/material/qquickmaterialstyle.cpp | 7 +++++++ src/imports/controls/material/qquickmaterialstyle_p.h | 2 ++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/imports/controls/material/ToolBar.qml b/src/imports/controls/material/ToolBar.qml index 1bcffd82..f0b50f73 100644 --- a/src/imports/controls/material/ToolBar.qml +++ b/src/imports/controls/material/ToolBar.qml @@ -56,7 +56,7 @@ T.ToolBar { background: Rectangle { implicitHeight: 48 - color: control.Material.primaryColor + color: control.Material.toolBarColor layer.enabled: control.Material.elevation > 0 layer.effect: ElevationEffect { diff --git a/src/imports/controls/material/qquickmaterialstyle.cpp b/src/imports/controls/material/qquickmaterialstyle.cpp index 3676bdbb..ae8c3a11 100644 --- a/src/imports/controls/material/qquickmaterialstyle.cpp +++ b/src/imports/controls/material/qquickmaterialstyle.cpp @@ -1042,6 +1042,13 @@ QColor QQuickMaterialStyle::tooltipColor() const return color(Grey, Shade700); } +QColor QQuickMaterialStyle::toolBarColor() const +{ + if (m_explicitBackground) + return backgroundColor(); + return primaryColor(); +} + QColor QQuickMaterialStyle::toolTextColor() const { if (m_hasForeground || m_customPrimary) diff --git a/src/imports/controls/material/qquickmaterialstyle_p.h b/src/imports/controls/material/qquickmaterialstyle_p.h index ff8fcce5..e0ac29cf 100644 --- a/src/imports/controls/material/qquickmaterialstyle_p.h +++ b/src/imports/controls/material/qquickmaterialstyle_p.h @@ -102,6 +102,7 @@ class QQuickMaterialStyle : public QQuickStyleAttached Q_PROPERTY(QColor backgroundDimColor READ backgroundDimColor NOTIFY paletteChanged FINAL) Q_PROPERTY(QColor listHighlightColor READ listHighlightColor NOTIFY paletteChanged FINAL) Q_PROPERTY(QColor tooltipColor READ tooltipColor NOTIFY paletteChanged FINAL) + Q_PROPERTY(QColor toolBarColor READ toolBarColor NOTIFY paletteChanged FINAL) Q_PROPERTY(QColor toolTextColor READ toolTextColor NOTIFY paletteChanged FINAL) Q_PROPERTY(QColor spinBoxDisabledIconColor READ spinBoxDisabledIconColor NOTIFY paletteChanged FINAL) @@ -229,6 +230,7 @@ public: QColor backgroundDimColor() const; QColor listHighlightColor() const; QColor tooltipColor() const; + QColor toolBarColor() const; QColor toolTextColor() const; QColor spinBoxDisabledIconColor() const; -- cgit v1.2.3 From b9600bb83536ad3072072a374883ce835302dc56 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Sun, 4 Sep 2016 10:11:20 +0200 Subject: QQuickDrawerPrivate::startDrag() Split startDrag() out of handleMousePressEvent(). This makes the mouse press handling code a bit easier to read. The new method will be later utilized by QQuickOverlay. Change-Id: I1118d86657a77d72353faac928b0a8deba4ff501 Reviewed-by: Mitch Curtis --- src/quicktemplates2/qquickdrawer.cpp | 45 ++++++++++++++++++++-------------- src/quicktemplates2/qquickdrawer_p_p.h | 2 ++ 2 files changed, 29 insertions(+), 18 deletions(-) diff --git a/src/quicktemplates2/qquickdrawer.cpp b/src/quicktemplates2/qquickdrawer.cpp index 6b0d9849..ae9442f8 100644 --- a/src/quicktemplates2/qquickdrawer.cpp +++ b/src/quicktemplates2/qquickdrawer.cpp @@ -168,31 +168,40 @@ static bool dragOverThreshold(qreal d, Qt::Axis axis, QMouseEvent *event, int th return QQuickWindowPrivate::dragOverThreshold(d, axis, event, threshold); } +bool QQuickDrawerPrivate::startDrag(QQuickWindow *window, QMouseEvent *event) +{ + if (!window || dragMargin < 0.0 || qFuzzyIsNull(dragMargin)) + return false; + + bool drag = false; + switch (edge) { + case Qt::LeftEdge: + drag = !dragOverThreshold(event->windowPos().x(), Qt::XAxis, event, dragMargin); + break; + case Qt::RightEdge: + drag = !dragOverThreshold(window->width() - event->windowPos().x(), Qt::XAxis, event, dragMargin); + break; + case Qt::TopEdge: + drag = !dragOverThreshold(event->windowPos().y(), Qt::YAxis, event, dragMargin); + break; + case Qt::BottomEdge: + drag = !dragOverThreshold(window->height() - event->windowPos().y(), Qt::YAxis, event, dragMargin); + break; + default: + break; + } + + return drag; +} + bool QQuickDrawerPrivate::handleMousePressEvent(QQuickItem *item, QMouseEvent *event) { pressPoint = event->windowPos(); offset = 0; - QQuickWindow *window = item->window(); - if (!window) - return false; - if (qFuzzyIsNull(position)) { // only accept pressing at drag margins when fully closed - switch (edge) { - case Qt::LeftEdge: - event->setAccepted(dragMargin > 0 && !dragOverThreshold(event->windowPos().x(), Qt::XAxis, event, dragMargin)); - break; - case Qt::RightEdge: - event->setAccepted(dragMargin > 0 && !dragOverThreshold(window->width() - event->windowPos().x(), Qt::XAxis, event, dragMargin)); - break; - case Qt::TopEdge: - event->setAccepted(dragMargin > 0 && !dragOverThreshold(event->windowPos().y(), Qt::YAxis, event, dragMargin)); - break; - case Qt::BottomEdge: - event->setAccepted(dragMargin > 0 && !dragOverThreshold(window->height() - event->windowPos().y(), Qt::YAxis, event, dragMargin)); - break; - } + event->setAccepted(startDrag(item->window(), event)); } else { if (modal) event->setAccepted(item->isAncestorOf(popupItem)); diff --git a/src/quicktemplates2/qquickdrawer_p_p.h b/src/quicktemplates2/qquickdrawer_p_p.h index 232b0b08..2cf752d5 100644 --- a/src/quicktemplates2/qquickdrawer_p_p.h +++ b/src/quicktemplates2/qquickdrawer_p_p.h @@ -69,6 +69,8 @@ public: qreal positionAt(const QPointF &point) const; void reposition() override; + bool startDrag(QQuickWindow *window, QMouseEvent *event); + bool handleMousePressEvent(QQuickItem *item, QMouseEvent *event); bool handleMouseMoveEvent(QQuickItem *item, QMouseEvent *event); bool handleMouseReleaseEvent(QQuickItem *item, QMouseEvent *event); -- cgit v1.2.3 From 1d3233e9737b494787941ceefad361fb39488f05 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Sun, 4 Sep 2016 14:31:58 +0200 Subject: QQuickDrawerPrivate::grabMouse() Split grabMouse() out of handleMouseMoveEvent(). This makes the mouse move handling code a bit easier to read. Change-Id: I39971e995d8d202e702bddeec0d1f9554c298c0e Reviewed-by: Mitch Curtis --- src/quicktemplates2/qquickdrawer.cpp | 71 +++++++++++++++++++--------------- src/quicktemplates2/qquickdrawer_p_p.h | 1 + 2 files changed, 40 insertions(+), 32 deletions(-) diff --git a/src/quicktemplates2/qquickdrawer.cpp b/src/quicktemplates2/qquickdrawer.cpp index ae9442f8..b2f9f519 100644 --- a/src/quicktemplates2/qquickdrawer.cpp +++ b/src/quicktemplates2/qquickdrawer.cpp @@ -194,6 +194,37 @@ bool QQuickDrawerPrivate::startDrag(QQuickWindow *window, QMouseEvent *event) return drag; } +bool QQuickDrawerPrivate::grabMouse(QMouseEvent *event) +{ + Q_Q(QQuickDrawer); + if (!window || popupItem->keepMouseGrab()) + return false; + + const QPointF movePoint = event->windowPos(); + + // Flickable uses a hard-coded threshold of 15 for flicking, and + // QStyleHints::startDragDistance for dragging. Drawer uses a bit + // larger threshold to avoid being too eager to steal touch (QTBUG-50045) + const int threshold = qMax(20, QGuiApplication::styleHints()->startDragDistance() + 5); + bool overThreshold = false; + if (position > 0 || dragMargin > 0) { + if (edge == Qt::LeftEdge || edge == Qt::RightEdge) + overThreshold = dragOverThreshold(movePoint.x() - pressPoint.x(), Qt::XAxis, event, threshold); + else + overThreshold = dragOverThreshold(movePoint.y() - pressPoint.y(), Qt::YAxis, event, threshold); + } + + // Don't be too eager to steal presses outside the drawer (QTBUG-53929) + if (overThreshold && qFuzzyCompare(position, qreal(1.0)) && !popupItem->contains(popupItem->mapFromScene(movePoint))) { + if (edge == Qt::LeftEdge || edge == Qt::RightEdge) + overThreshold = qAbs(movePoint.x() - q->width()) < dragMargin; + else + overThreshold = qAbs(movePoint.y() - q->height()) < dragMargin; + } + + return overThreshold; +} + bool QQuickDrawerPrivate::handleMousePressEvent(QQuickItem *item, QMouseEvent *event) { pressPoint = event->windowPos(); @@ -217,40 +248,16 @@ bool QQuickDrawerPrivate::handleMousePressEvent(QQuickItem *item, QMouseEvent *e bool QQuickDrawerPrivate::handleMouseMoveEvent(QQuickItem *item, QMouseEvent *event) { Q_Q(QQuickDrawer); - QQuickWindow *window = item->window(); - if (!window) - return false; + Q_UNUSED(item); - QPointF movePoint = event->windowPos(); - - if (!popupItem->keepMouseGrab()) { - // Flickable uses a hard-coded threshold of 15 for flicking, and - // QStyleHints::startDragDistance for dragging. Drawer uses a bit - // larger threshold to avoid being too eager to steal touch (QTBUG-50045) - int threshold = qMax(20, QGuiApplication::styleHints()->startDragDistance() + 5); - bool overThreshold = false; - if (position > 0 || dragMargin > 0) { - if (edge == Qt::LeftEdge || edge == Qt::RightEdge) - overThreshold = dragOverThreshold(movePoint.x() - pressPoint.x(), Qt::XAxis, event, threshold); - else - overThreshold = dragOverThreshold(movePoint.y() - pressPoint.y(), Qt::YAxis, event, threshold); - } + const QPointF movePoint = event->windowPos(); - // Don't be too eager to steal presses outside the drawer (QTBUG-53929) - if (overThreshold && qFuzzyCompare(position, qreal(1.0)) && !popupItem->contains(popupItem->mapFromScene(movePoint))) { - if (edge == Qt::LeftEdge || edge == Qt::RightEdge) - overThreshold = qAbs(movePoint.x() - q->width()) < dragMargin; - else - overThreshold = qAbs(movePoint.y() - q->height()) < dragMargin; - } - - if (overThreshold) { - QQuickItem *grabber = window->mouseGrabberItem(); - if (!grabber || !grabber->keepMouseGrab()) { - popupItem->grabMouse(); - popupItem->setKeepMouseGrab(overThreshold); - offset = qMin(0.0, positionAt(movePoint) - position); - } + if (grabMouse(event)) { + QQuickItem *grabber = window->mouseGrabberItem(); + if (!grabber || !grabber->keepMouseGrab()) { + popupItem->grabMouse(); + popupItem->setKeepMouseGrab(true); + offset = qMin(0.0, positionAt(movePoint) - position); } } diff --git a/src/quicktemplates2/qquickdrawer_p_p.h b/src/quicktemplates2/qquickdrawer_p_p.h index 2cf752d5..323ba319 100644 --- a/src/quicktemplates2/qquickdrawer_p_p.h +++ b/src/quicktemplates2/qquickdrawer_p_p.h @@ -70,6 +70,7 @@ public: void reposition() override; bool startDrag(QQuickWindow *window, QMouseEvent *event); + bool grabMouse(QMouseEvent *event); bool handleMousePressEvent(QQuickItem *item, QMouseEvent *event); bool handleMouseMoveEvent(QQuickItem *item, QMouseEvent *event); -- cgit v1.2.3 From 61c85fdf580742ba174960400e806c057d0a6bd1 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Sun, 4 Sep 2016 14:38:20 +0200 Subject: QQuickDrawerPrivate::ungrabMouse() Split ungrabMouse() out of handleMouseReleaseEvent(). This makes the mouse release handling code a bit easier to read. Change-Id: Ibc1286083edb4f832b6e5ee761ee5c16a0e68ba1 Reviewed-by: Mitch Curtis --- src/quicktemplates2/qquickdrawer.cpp | 102 ++++++++++++++++++--------------- src/quicktemplates2/qquickdrawer_p_p.h | 1 + 2 files changed, 56 insertions(+), 47 deletions(-) diff --git a/src/quicktemplates2/qquickdrawer.cpp b/src/quicktemplates2/qquickdrawer.cpp index b2f9f519..551352de 100644 --- a/src/quicktemplates2/qquickdrawer.cpp +++ b/src/quicktemplates2/qquickdrawer.cpp @@ -225,55 +225,10 @@ bool QQuickDrawerPrivate::grabMouse(QMouseEvent *event) return overThreshold; } -bool QQuickDrawerPrivate::handleMousePressEvent(QQuickItem *item, QMouseEvent *event) -{ - pressPoint = event->windowPos(); - offset = 0; - - if (qFuzzyIsNull(position)) { - // only accept pressing at drag margins when fully closed - event->setAccepted(startDrag(item->window(), event)); - } else { - if (modal) - event->setAccepted(item->isAncestorOf(popupItem)); - else - event->setAccepted(false); - } - - velocityCalculator.startMeasuring(pressPoint, event->timestamp()); - - return event->isAccepted(); -} - -bool QQuickDrawerPrivate::handleMouseMoveEvent(QQuickItem *item, QMouseEvent *event) -{ - Q_Q(QQuickDrawer); - Q_UNUSED(item); - - const QPointF movePoint = event->windowPos(); - - if (grabMouse(event)) { - QQuickItem *grabber = window->mouseGrabberItem(); - if (!grabber || !grabber->keepMouseGrab()) { - popupItem->grabMouse(); - popupItem->setKeepMouseGrab(true); - offset = qMin(0.0, positionAt(movePoint) - position); - } - } - - if (popupItem->keepMouseGrab()) - q->setPosition(positionAt(movePoint) - offset); - event->accept(); - - return popupItem->keepMouseGrab(); -} - static const qreal openCloseVelocityThreshold = 300; -bool QQuickDrawerPrivate::handleMouseReleaseEvent(QQuickItem *item, QMouseEvent *event) +bool QQuickDrawerPrivate::ungrabMouse(QMouseEvent *event) { - Q_UNUSED(item); - bool wasGrabbed = popupItem->keepMouseGrab(); if (wasGrabbed) { const QPointF releasePoint = event->windowPos(); @@ -328,10 +283,63 @@ bool QQuickDrawerPrivate::handleMouseReleaseEvent(QQuickItem *item, QMouseEvent break; } } - popupItem->setKeepMouseGrab(false); } + return wasGrabbed; +} + +bool QQuickDrawerPrivate::handleMousePressEvent(QQuickItem *item, QMouseEvent *event) +{ + pressPoint = event->windowPos(); + offset = 0; + + if (qFuzzyIsNull(position)) { + // only accept pressing at drag margins when fully closed + event->setAccepted(startDrag(item->window(), event)); + } else { + if (modal) + event->setAccepted(item->isAncestorOf(popupItem)); + else + event->setAccepted(false); + } + + velocityCalculator.startMeasuring(pressPoint, event->timestamp()); + + return event->isAccepted(); +} + +bool QQuickDrawerPrivate::handleMouseMoveEvent(QQuickItem *item, QMouseEvent *event) +{ + Q_Q(QQuickDrawer); + Q_UNUSED(item); + + const QPointF movePoint = event->windowPos(); + + if (grabMouse(event)) { + QQuickItem *grabber = window->mouseGrabberItem(); + if (!grabber || !grabber->keepMouseGrab()) { + popupItem->grabMouse(); + popupItem->setKeepMouseGrab(true); + offset = qMin(0.0, positionAt(movePoint) - position); + } + } + + if (popupItem->keepMouseGrab()) + q->setPosition(positionAt(movePoint) - offset); + event->accept(); + + return popupItem->keepMouseGrab(); +} + +bool QQuickDrawerPrivate::handleMouseReleaseEvent(QQuickItem *item, QMouseEvent *event) +{ + Q_UNUSED(item); + + const bool wasGrabbed = ungrabMouse(event); + + popupItem->setKeepMouseGrab(false); pressPoint = QPoint(); event->accept(); + return wasGrabbed; } diff --git a/src/quicktemplates2/qquickdrawer_p_p.h b/src/quicktemplates2/qquickdrawer_p_p.h index 323ba319..e8add86c 100644 --- a/src/quicktemplates2/qquickdrawer_p_p.h +++ b/src/quicktemplates2/qquickdrawer_p_p.h @@ -71,6 +71,7 @@ public: bool startDrag(QQuickWindow *window, QMouseEvent *event); bool grabMouse(QMouseEvent *event); + bool ungrabMouse(QMouseEvent *event); bool handleMousePressEvent(QQuickItem *item, QMouseEvent *event); bool handleMouseMoveEvent(QQuickItem *item, QMouseEvent *event); -- cgit v1.2.3 From 671a4a83bc709e5f871ed5d5b76ad078140283bf Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Fri, 2 Sep 2016 01:27:07 +0200 Subject: tst_material: test the background of some more controls Task-number: QTBUG-55687 Change-Id: I515bcbbed76e08da6d300434cf92b3539a79afec Reviewed-by: J-P Nurmi --- .../auto/qquickmaterialstyle/data/tst_material.qml | 76 ++++++++++++---------- 1 file changed, 42 insertions(+), 34 deletions(-) diff --git a/tests/auto/qquickmaterialstyle/data/tst_material.qml b/tests/auto/qquickmaterialstyle/data/tst_material.qml index 727de2e4..63edb556 100644 --- a/tests/auto/qquickmaterialstyle/data/tst_material.qml +++ b/tests/auto/qquickmaterialstyle/data/tst_material.qml @@ -606,66 +606,74 @@ TestCase { window.destroy() } - function test_buttonBackground() { - var appWindow = applicationWindow.createObject(testCase) - verify(appWindow) - appWindow.visible = true - - var childButton = button.createObject(appWindow) - verify(childButton) - - var buttonBackgroundColor = childButton.background.color - appWindow.Material.background = "red" - // We wait the length of the color animation to be sure that it hasn't actually changed. - wait(400) - // We want childButton.Material.background to be equal to appWindow.Material.background, - // because we want the color to propagate to items that might actually use it... - // but Button doesn't use the background color unless explicitly set, - // so we compare the actual background rect color instead. - compare(childButton.background.color, buttonBackgroundColor) - - childButton.Material.background = "#0000ff" - tryCompare(childButton.background, "color", "#0000ff") - - appWindow.destroy() - } - Component { - id: popups + id: backgroundControls ApplicationWindow { id: window - property Drawer drawer: Drawer { parent: window.contentItem } - property Menu menu: Menu { parent: window.contentItem; visible: true } - property Popup popup: Popup { parent: window.contentItem; visible: true } - property ToolTip tooltip: ToolTip { parent: window.contentItem; visible: true } + property Button button: Button { } + property ComboBox combobox: ComboBox { } + property Drawer drawer: Drawer { } + property GroupBox groupbox: GroupBox { Material.elevation: 10 } + property Frame frame: Frame { Material.elevation: 10 } + property Menu menu: Menu { } + property Page page: Page { } + property Pane pane: Pane { } + property Popup popup: Popup { } + property TabBar tabbar: TabBar { } + property ToolBar toolbar: ToolBar { } + property ToolTip tooltip: ToolTip { } } } - function test_popupBackground_data() { + function test_background_data() { return [ + { tag: "button", inherit: false, wait: 400 }, + { tag: "combobox", inherit: false, wait: 400 }, { tag: "drawer", inherit: true }, + { tag: "groupbox", inherit: true }, + { tag: "frame", inherit: true }, { tag: "menu", inherit: true }, + { tag: "page", inherit: true }, + { tag: "pane", inherit: true }, { tag: "popup", inherit: true }, + { tag: "tabbar", inherit: true }, + { tag: "toolbar", inherit: false }, { tag: "tooltip", inherit: false } ] } - function test_popupBackground(data) { - var window = popups.createObject(testCase) + function test_background(data) { + var window = backgroundControls.createObject(testCase) verify(window) var control = window[data.tag] verify(control) + control.parent = window.contentItem + control.visible = true + + var defaultBackground = control.background.color + window.Material.background = "#ff0000" compare(window.color, "#ff0000") + + // For controls that have an animated background color, we wait the length + // of the color animation to be sure that the color hasn't actually changed. + if (data.wait) + wait(data.wait) + + // We want the control's background color to be equal to the window's background + // color, because we want the color to propagate to items that might actually use + // it... Button, ComboBox, ToolBar and ToolTip have a special background color, + // so they don't use the generic background color unless explicitly set, so we + // compare the actual background rect color instead. if (data.inherit) compare(control.background.color, "#ff0000") else - verify(control.background !== "#ff0000") + compare(control.background.color, defaultBackground) control.Material.background = "#0000ff" - compare(control.background.color, "#0000ff") + tryCompare(control.background, "color", "#0000ff") window.destroy() } -- cgit v1.2.3 From bc0fdae8fad4e199792b3f00ebcb74bd80473227 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Sat, 3 Sep 2016 21:16:03 +0200 Subject: Fix drawer visibility and overlay event handling Drawers were visible all the time, lurking at the window edges to be able to catch presses and drag themselves visible when appropriate. This change moves the handling of window edge presses from QQuickDrawer to QQuickOverlay, making it possible to show and hide drawers like any other popups. Instead of having all drawers visible all the time, we just keep QQuickOverlay visible when there are any registered drawers, even hidden ones. Furthermore, this change makes modal popup/drawer background dimming items accept mouse press events just like they accept hover events to ensure that a modal overlay does not leak input events through. When the background dimming of a modal drawer has been dragged over the drag-threshold, the drawer simply steals/grabs mouse to start dragging of the drawer. Task-number: QTBUG-54794 Task-number: QTBUG-54800 Task-number: QTBUG-55022 Task-number: QTBUG-55703 Task-number: QTBUG-55713 Change-Id: I65fb38fcf1466d4e41192c4321d80fb90b49da9a Reviewed-by: Mitch Curtis --- src/quicktemplates2/qquickdrawer.cpp | 40 ++----- src/quicktemplates2/qquickdrawer_p.h | 2 - src/quicktemplates2/qquickoverlay.cpp | 144 ++++++++++++++----------- src/quicktemplates2/qquickoverlay_p.h | 4 +- src/quicktemplates2/qquickoverlay_p_p.h | 2 +- src/quicktemplates2/qquickpopup.cpp | 6 ++ tests/auto/controls/data/tst_popup.qml | 72 +++++-------- tests/auto/drawer/data/multiple.qml | 85 +++++++++++++++ tests/auto/drawer/data/window.qml | 56 ++++++++++ tests/auto/drawer/tst_drawer.cpp | 181 +++++++++++++++++++++++++++++++- 10 files changed, 449 insertions(+), 143 deletions(-) create mode 100644 tests/auto/drawer/data/multiple.qml create mode 100644 tests/auto/drawer/data/window.qml diff --git a/src/quicktemplates2/qquickdrawer.cpp b/src/quicktemplates2/qquickdrawer.cpp index 551352de..44fc8f50 100644 --- a/src/quicktemplates2/qquickdrawer.cpp +++ b/src/quicktemplates2/qquickdrawer.cpp @@ -191,6 +191,12 @@ bool QQuickDrawerPrivate::startDrag(QQuickWindow *window, QMouseEvent *event) break; } + if (drag) { + prepareEnterTransition(); + reposition(); + handleMousePressEvent(window->contentItem(), event); + } + return drag; } @@ -289,21 +295,12 @@ bool QQuickDrawerPrivate::ungrabMouse(QMouseEvent *event) bool QQuickDrawerPrivate::handleMousePressEvent(QQuickItem *item, QMouseEvent *event) { - pressPoint = event->windowPos(); offset = 0; - - if (qFuzzyIsNull(position)) { - // only accept pressing at drag margins when fully closed - event->setAccepted(startDrag(item->window(), event)); - } else { - if (modal) - event->setAccepted(item->isAncestorOf(popupItem)); - else - event->setAccepted(false); - } - + pressPoint = event->windowPos(); velocityCalculator.startMeasuring(pressPoint, event->timestamp()); + // don't block press events a) outside a non-modal drawer, or b) to drawer children + event->setAccepted(modal && !popupItem->isAncestorOf(item)); return event->isAccepted(); } @@ -384,7 +381,7 @@ void QQuickDrawerPrivate::finalizeEnterTransition() void QQuickDrawerPrivate::finalizeExitTransition(bool hide) { - QQuickPopupPrivate::finalizeExitTransition(hide = false); + QQuickPopupPrivate::finalizeExitTransition(hide); } QQuickDrawer::QQuickDrawer(QObject *parent) : @@ -448,12 +445,8 @@ void QQuickDrawer::setPosition(qreal position) d->position = position; if (isComponentComplete()) d->reposition(); - if (d->dimmer) { + if (d->dimmer) d->dimmer->setOpacity(position); - // TODO: check QStyleHints::useHoverEffects in Qt 5.8 - d->dimmer->setAcceptHoverEvents(d->modal && position > 0.0); - // d->dimmer->setAcceptHoverEvents(d->modal && position > 0.0 && QGuiApplication::styleHints()->useHoverEffects()); - } emit positionChanged(); } @@ -548,15 +541,4 @@ bool QQuickDrawer::overlayEvent(QQuickItem *item, QEvent *event) } } -void QQuickDrawer::componentComplete() -{ - Q_D(QQuickDrawer); - QQuickPopup::componentComplete(); - if (d->window) { - bool notify = false; - d->prepareEnterTransition(notify); - d->reposition(); - } -} - QT_END_NAMESPACE diff --git a/src/quicktemplates2/qquickdrawer_p.h b/src/quicktemplates2/qquickdrawer_p.h index 23c5c2ab..e694e27b 100644 --- a/src/quicktemplates2/qquickdrawer_p.h +++ b/src/quicktemplates2/qquickdrawer_p.h @@ -87,8 +87,6 @@ protected: void mouseUngrabEvent() override; bool overlayEvent(QQuickItem *item, QEvent *event) override; - void componentComplete() override; - private: Q_DISABLE_COPY(QQuickDrawer) Q_DECLARE_PRIVATE(QQuickDrawer) diff --git a/src/quicktemplates2/qquickoverlay.cpp b/src/quicktemplates2/qquickoverlay.cpp index d34fd7fc..19677cb7 100644 --- a/src/quicktemplates2/qquickoverlay.cpp +++ b/src/quicktemplates2/qquickoverlay.cpp @@ -37,11 +37,12 @@ #include "qquickoverlay_p.h" #include "qquickoverlay_p_p.h" #include "qquickpopup_p_p.h" -#include "qquickdrawer_p.h" +#include "qquickdrawer_p_p.h" #include "qquickapplicationwindow_p.h" #include #include #include +#include QT_BEGIN_NAMESPACE @@ -93,7 +94,8 @@ static QQuickItem *createDimmer(QQmlComponent *component, QQuickPopup *popup, QQ item->setParentItem(parent); item->stackBefore(popup->popupItem()); item->setZ(popup->z()); - if (popup->isModal() && !qobject_cast(popup)) { + if (popup->isModal()) { + item->setAcceptedMouseButtons(Qt::AllButtons); // TODO: switch to QStyleHints::useHoverEffects in Qt 5.8 item->setAcceptHoverEvents(true); // item->setAcceptHoverEvents(QGuiApplication::styleHints()->useHoverEffects()); @@ -162,6 +164,15 @@ QVector QQuickOverlayPrivate::stackingOrderPopups() const return popups; } +QVector QQuickOverlayPrivate::stackingOrderDrawers() const +{ + QVector sorted(allDrawers); + std::sort(sorted.begin(), sorted.end(), [](const QQuickDrawer *one, const QQuickDrawer *another) { + return one->z() > another->z(); + }); + return sorted; +} + void QQuickOverlayPrivate::itemGeometryChanged(QQuickItem *, const QRectF &newGeometry, const QRectF &) { Q_Q(QQuickOverlay); @@ -170,22 +181,26 @@ void QQuickOverlayPrivate::itemGeometryChanged(QQuickItem *, const QRectF &newGe QQuickOverlayPrivate::QQuickOverlayPrivate() : modal(nullptr), - modeless(nullptr), - modalPopups(0) + modeless(nullptr) { } void QQuickOverlayPrivate::addPopup(QQuickPopup *popup) { + Q_Q(QQuickOverlay); allPopups += popup; - if (QQuickDrawer *drawer = qobject_cast(popup)) + if (QQuickDrawer *drawer = qobject_cast(popup)) { allDrawers += drawer; + q->setVisible(!allDrawers.isEmpty() || !q->childItems().isEmpty()); + } } void QQuickOverlayPrivate::removePopup(QQuickPopup *popup) { + Q_Q(QQuickOverlay); allPopups.removeOne(popup); - allDrawers.removeOne(static_cast(popup)); + if (allDrawers.removeOne(static_cast(popup))) + q->setVisible(!allDrawers.isEmpty() || !q->childItems().isEmpty()); } QQuickOverlay::QQuickOverlay(QQuickItem *parent) @@ -275,7 +290,7 @@ void QQuickOverlay::itemChange(ItemChange change, const ItemChangeData &data) QQuickPopup *popup = nullptr; if (change == ItemChildAddedChange || change == ItemChildRemovedChange) { popup = qobject_cast(data.item->parent()); - setVisible(!childItems().isEmpty()); + setVisible(!d->allDrawers.isEmpty() || !childItems().isEmpty()); } if (!popup) return; @@ -286,8 +301,6 @@ void QQuickOverlay::itemChange(ItemChange change, const ItemChangeData &data) QObjectPrivate::connect(popup, &QQuickPopup::dimChanged, d, &QQuickOverlayPrivate::toggleOverlay); QObjectPrivate::connect(popup, &QQuickPopup::modalChanged, d, &QQuickOverlayPrivate::toggleOverlay); if (!qobject_cast(popup)) { - if (popup->isModal()) - ++d->modalPopups; QObjectPrivate::connect(popup, &QQuickPopup::aboutToShow, d, &QQuickOverlayPrivate::popupAboutToShow); QObjectPrivate::connect(popup, &QQuickPopup::aboutToHide, d, &QQuickOverlayPrivate::popupAboutToHide); } @@ -296,8 +309,6 @@ void QQuickOverlay::itemChange(ItemChange change, const ItemChangeData &data) QObjectPrivate::disconnect(popup, &QQuickPopup::dimChanged, d, &QQuickOverlayPrivate::toggleOverlay); QObjectPrivate::disconnect(popup, &QQuickPopup::modalChanged, d, &QQuickOverlayPrivate::toggleOverlay); if (!qobject_cast(popup)) { - if (popup->isModal()) - --d->modalPopups; QObjectPrivate::disconnect(popup, &QQuickPopup::aboutToShow, d, &QQuickOverlayPrivate::popupAboutToShow); QObjectPrivate::disconnect(popup, &QQuickPopup::aboutToHide, d, &QQuickOverlayPrivate::popupAboutToHide); } @@ -312,75 +323,82 @@ void QQuickOverlay::geometryChanged(const QRectF &newGeometry, const QRectF &old d->resizeOverlay(popup); } -bool QQuickOverlay::event(QEvent *event) +void QQuickOverlay::mousePressEvent(QMouseEvent *event) { Q_D(QQuickOverlay); - switch (event->type()) { - case QEvent::MouseButtonPress: { - emit pressed(); + emit pressed(); + + if (!d->allDrawers.isEmpty()) { + // the overlay background was pressed, so there are no modal popups open. + // test if the press point lands on any drawer's drag margin + + const QVector drawers = d->stackingOrderDrawers(); + for (QQuickDrawer *drawer : drawers) { + QQuickDrawerPrivate *p = QQuickDrawerPrivate::get(drawer); + if (p->startDrag(window(), event)) { + d->mouseGrabberPopup = drawer; + return; + } + } + } + + if (!d->mouseGrabberPopup) { const auto popups = d->stackingOrderPopups(); for (QQuickPopup *popup : popups) { if (popup->overlayEvent(this, event)) { d->mouseGrabberPopup = popup; - return true; + return; } } - break; } - case QEvent::MouseMove: - if (d->mouseGrabberPopup) { - if (d->mouseGrabberPopup->overlayEvent(this, event)) - return true; - } else { - const auto popups = d->stackingOrderPopups(); - for (QQuickPopup *popup : popups) { - if (popup->overlayEvent(this, event)) - return true; - } - } - break; - case QEvent::MouseButtonRelease: - emit released(); - if (d->mouseGrabberPopup) { - QQuickPopup *grabber = d->mouseGrabberPopup; - d->mouseGrabberPopup = nullptr; - if (grabber->overlayEvent(this, event)) - return true; - } else { - const auto popups = d->stackingOrderPopups(); - for (QQuickPopup *popup : popups) { - if (popup->overlayEvent(this, event)) - return true; - } + + event->ignore(); +} + +void QQuickOverlay::mouseMoveEvent(QMouseEvent *event) +{ + Q_D(QQuickOverlay); + if (d->mouseGrabberPopup) + d->mouseGrabberPopup->overlayEvent(this, event); +} + +void QQuickOverlay::mouseReleaseEvent(QMouseEvent *event) +{ + Q_D(QQuickOverlay); + emit released(); + + if (d->mouseGrabberPopup) { + d->mouseGrabberPopup->overlayEvent(this, event); + d->mouseGrabberPopup = nullptr; + } else { + const auto popups = d->stackingOrderPopups(); + for (QQuickPopup *popup : popups) { + if (popup->overlayEvent(this, event)) + break; } - break; - default: - break; } - - return QQuickItem::event(event); } bool QQuickOverlay::childMouseEventFilter(QQuickItem *item, QEvent *event) { Q_D(QQuickOverlay); - if (d->modalPopups == 0) - return false; - // TODO Filter touch events - if (event->type() != QEvent::MouseButtonPress) - return false; - while (item->parentItem() != this) - item = item->parentItem(); - - const auto popups = d->stackingOrderPopups(); - for (QQuickPopup *popup : popups) { - if (popup->popupItem() == item) - break; - - if (popup->overlayEvent(item, event)) - return true; + for (QQuickPopup *popup : qAsConst(d->allPopups)) { + QQuickItem *dimmer = QQuickPopupPrivate::get(popup)->dimmer; + if (item == dimmer) { + switch (event->type()) { + case QEvent::MouseButtonPress: + emit pressed(); + return popup->overlayEvent(item, event); + case QEvent::MouseMove: + return popup->overlayEvent(item, event); + case QEvent::MouseButtonRelease: + emit released(); + return popup->overlayEvent(item, event); + default: + break; + } + } } - return false; } diff --git a/src/quicktemplates2/qquickoverlay_p.h b/src/quicktemplates2/qquickoverlay_p.h index ecb0e20a..07f7daec 100644 --- a/src/quicktemplates2/qquickoverlay_p.h +++ b/src/quicktemplates2/qquickoverlay_p.h @@ -84,7 +84,9 @@ protected: void itemChange(ItemChange change, const ItemChangeData &data) override; void geometryChanged(const QRectF &oldGeometry, const QRectF &newGeometry) override; - bool event(QEvent *event) override; + void mousePressEvent(QMouseEvent *event) override; + void mouseMoveEvent(QMouseEvent *event) override; + void mouseReleaseEvent(QMouseEvent *event) override; bool childMouseEventFilter(QQuickItem *item, QEvent *event) override; private: diff --git a/src/quicktemplates2/qquickoverlay_p_p.h b/src/quicktemplates2/qquickoverlay_p_p.h index f9e962ee..6dc2853c 100644 --- a/src/quicktemplates2/qquickoverlay_p_p.h +++ b/src/quicktemplates2/qquickoverlay_p_p.h @@ -82,6 +82,7 @@ public: void toggleOverlay(); QVector stackingOrderPopups() const; + QVector stackingOrderDrawers() const; void itemGeometryChanged(QQuickItem *item, const QRectF &newGeometry, const QRectF &oldGeometry) override; @@ -90,7 +91,6 @@ public: QVector allPopups; QVector allDrawers; QPointer mouseGrabberPopup; - int modalPopups; }; QT_END_NAMESPACE diff --git a/src/quicktemplates2/qquickpopup.cpp b/src/quicktemplates2/qquickpopup.cpp index 6c184243..6d06708b 100644 --- a/src/quicktemplates2/qquickpopup.cpp +++ b/src/quicktemplates2/qquickpopup.cpp @@ -1898,6 +1898,12 @@ void QQuickPopup::mouseDoubleClickEvent(QMouseEvent *event) void QQuickPopup::mouseUngrabEvent() { + QQuickOverlay *overlay = QQuickOverlay::overlay(window()); + if (overlay) { + QQuickOverlayPrivate *p = QQuickOverlayPrivate::get(overlay); + if (p->mouseGrabberPopup == this) + p->mouseGrabberPopup = nullptr; + } } bool QQuickPopup::overlayEvent(QQuickItem *item, QEvent *event) diff --git a/tests/auto/controls/data/tst_popup.qml b/tests/auto/controls/data/tst_popup.qml index 2c6d60da..e714a7d0 100644 --- a/tests/auto/controls/data/tst_popup.qml +++ b/tests/auto/controls/data/tst_popup.qml @@ -971,18 +971,13 @@ TestCase { ApplicationWindow { property alias firstDrawer: firstDrawer property alias secondDrawer: secondDrawer - property alias upperDrawer: upperDrawer property alias modalPopup: modalPopup property alias modelessPopup: modelessPopup property alias plainPopup: plainPopup property alias modalPopupWithoutDim: modalPopupWithoutDim visible: true Drawer { - z: 5 - id: upperDrawer - } - Drawer { - z: 1 + z: 0 id: firstDrawer } Drawer { @@ -1038,52 +1033,41 @@ TestCase { window.requestActivate() tryCompare(window, "active", true) - var countBefore = window.overlay.children.length - compare(countBefore, 6) // 3 drawers + 3 overlays + compare(window.overlay.children.length, 0) var firstOverlay = findOverlay(window, window.firstDrawer) + verify(!firstOverlay) + window.firstDrawer.open() + compare(window.overlay.children.length, 2) // 1 drawer + 1 overlay + firstOverlay = findOverlay(window, window.firstDrawer) verify(firstOverlay) - compare(firstOverlay.opacity, 0.0) compare(firstOverlay.z, window.firstDrawer.z) compare(indexOf(window.overlay.children, firstOverlay), indexOf(window.overlay.children, window.firstDrawer.contentItem.parent) - 1) + tryCompare(firstOverlay, "opacity", 1.0) var secondOverlay = findOverlay(window, window.secondDrawer) + verify(!secondOverlay) + window.secondDrawer.open() + compare(window.overlay.children.length, 4) // 2 drawers + 2 overlays + secondOverlay = findOverlay(window, window.secondDrawer) verify(secondOverlay) - compare(secondOverlay.opacity, 0.0) compare(secondOverlay.z, window.secondDrawer.z) compare(indexOf(window.overlay.children, secondOverlay), indexOf(window.overlay.children, window.secondDrawer.contentItem.parent) - 1) + tryCompare(secondOverlay, "opacity", 1.0) - var upperOverlay = findOverlay(window, window.upperDrawer) - verify(upperOverlay) - compare(upperOverlay.opacity, 0.0) - compare(upperOverlay.z, window.upperDrawer.z) - compare(indexOf(window.overlay.children, upperOverlay), - indexOf(window.overlay.children, window.upperDrawer.contentItem.parent) - 1) - - window.firstDrawer.open() - compare(firstOverlay.z, 1.0) - tryCompare(firstOverlay, "opacity", 1.0) window.firstDrawer.close() - tryCompare(firstOverlay, "opacity", 0.0) tryCompare(window.firstDrawer, "visible", false) + firstOverlay = findOverlay(window, window.firstDrawer) + verify(!firstOverlay) + compare(window.overlay.children.length, 2) // 1 drawer + 1 overlay - window.secondDrawer.open() - compare(secondOverlay.z, 1.0) - tryCompare(secondOverlay, "opacity", 1.0) window.secondDrawer.close() - tryCompare(secondOverlay, "opacity", 0.0) tryCompare(window.secondDrawer, "visible", false) - - window.firstDrawer.open() - window.secondDrawer.open() - tryCompare(firstOverlay, "opacity", 1.0) - tryCompare(secondOverlay, "opacity", 1.0) - window.firstDrawer.close() - window.secondDrawer.close() - tryCompare(firstOverlay, "opacity", 0.0) - tryCompare(secondOverlay, "opacity", 0.0) + secondOverlay = findOverlay(window, window.secondDrawer) + verify(!secondOverlay) + compare(window.overlay.children.length, 0) var modalOverlay = findOverlay(window, window.modalPopup) verify(!modalOverlay) @@ -1093,7 +1077,7 @@ TestCase { compare(modalOverlay.z, window.modalPopup.z) compare(window.modalPopup.visible, true) tryCompare(modalOverlay, "opacity", 1.0) - compare(window.overlay.children.length, countBefore + 2) // 1 popup + 1 overlay + compare(window.overlay.children.length, 2) // 1 popup + 1 overlay var modelessOverlay = findOverlay(window, window.modelessPopup) verify(!modelessOverlay) @@ -1103,13 +1087,13 @@ TestCase { compare(modelessOverlay.z, window.modelessPopup.z) compare(window.modelessPopup.visible, true) tryCompare(modelessOverlay, "opacity", 1.0) - compare(window.overlay.children.length, countBefore + 4) // 2 popups + 2 overlays + compare(window.overlay.children.length, 4) // 2 popups + 2 overlays window.modelessPopup.close() tryCompare(window.modelessPopup, "visible", false) modelessOverlay = findOverlay(window, window.modelessPopup) verify(!modelessOverlay) - compare(window.overlay.children.length, countBefore + 2) // 1 popup + 1 overlay + compare(window.overlay.children.length, 2) // 1 popup + 1 overlay compare(window.modalPopup.visible, true) compare(modalOverlay.opacity, 1.0) @@ -1118,29 +1102,29 @@ TestCase { tryCompare(window.modalPopup, "visible", false) modalOverlay = findOverlay(window, window.modalPopup) verify(!modalOverlay) - compare(window.overlay.children.length, countBefore) + compare(window.overlay.children.length, 0) window.plainPopup.open() tryCompare(window.plainPopup, "visible", true) - compare(window.overlay.children.length, countBefore + 1) // only popup added, no overlays involved + compare(window.overlay.children.length, 1) // only popup added, no overlays involved window.plainPopup.modal = true - compare(window.overlay.children.length, countBefore + 2) // overlay added + compare(window.overlay.children.length, 2) // overlay added window.plainPopup.close() tryCompare(window.plainPopup, "visible", false) - compare(window.overlay.children.length, countBefore) // popup + overlay removed + compare(window.overlay.children.length, 0) // popup + overlay removed window.modalPopupWithoutDim.open() tryCompare(window.modalPopupWithoutDim, "visible", true) - compare(window.overlay.children.length, countBefore + 1) // only popup added, no overlays involved + compare(window.overlay.children.length, 1) // only popup added, no overlays involved window.modalPopupWithoutDim.dim = true - compare(window.overlay.children.length, countBefore + 2) // overlay added + compare(window.overlay.children.length, 2) // overlay added window.modalPopupWithoutDim.close() tryCompare(window.modalPopupWithoutDim, "visible", false) - compare(window.overlay.children.length, countBefore) // popup + overlay removed + compare(window.overlay.children.length, 0) // popup + overlay removed window.destroy() } diff --git a/tests/auto/drawer/data/multiple.qml b/tests/auto/drawer/data/multiple.qml new file mode 100644 index 00000000..b2ef9781 --- /dev/null +++ b/tests/auto/drawer/data/multiple.qml @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite 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 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.6 +import QtQuick.Controls 2.0 + +ApplicationWindow { + width: 400 + height: 400 + + property alias leftDrawer: leftDrawer + property alias leftButton: leftButton + + property alias rightDrawer: rightDrawer + property alias rightButton: rightButton + + property alias contentButton: contentButton + + Drawer { + id: leftDrawer + width: 300 + height: 400 + z: 1 + + contentItem: Button { + id: leftButton + text: "Left" + } + } + + Button { + id: contentButton + text: "Content" + anchors.fill: parent + } + + Drawer { + id: rightDrawer + width: 300 + height: 400 + edge: Qt.RightEdge + + contentItem: Button { + id: rightButton + text: "Right" + } + } +} diff --git a/tests/auto/drawer/data/window.qml b/tests/auto/drawer/data/window.qml new file mode 100644 index 00000000..47ef5cb0 --- /dev/null +++ b/tests/auto/drawer/data/window.qml @@ -0,0 +1,56 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the test suite 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 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.6 +import QtQuick.Window 2.2 +import QtQuick.Controls 2.0 + +Window { + width: 400 + height: 400 + + property alias drawer: drawer + + Drawer { + id: drawer + width: 200 + height: 200 + } +} diff --git a/tests/auto/drawer/tst_drawer.cpp b/tests/auto/drawer/tst_drawer.cpp index 43236817..02a4f91f 100644 --- a/tests/auto/drawer/tst_drawer.cpp +++ b/tests/auto/drawer/tst_drawer.cpp @@ -42,6 +42,7 @@ #include #include #include +#include #include #include @@ -52,6 +53,9 @@ class tst_Drawer : public QQmlDataTest Q_OBJECT private slots: + void visible_data(); + void visible(); + void position_data(); void position(); @@ -62,8 +66,58 @@ private slots: void hover_data(); void hover(); + + void multiple(); }; +void tst_Drawer::visible_data() +{ + QTest::addColumn("source"); + QTest::newRow("Window") << "window.qml"; + QTest::newRow("ApplicationWindow") << "applicationwindow.qml"; +} + +void tst_Drawer::visible() +{ + QFETCH(QString, source); + QQuickApplicationHelper helper(this, source); + + QQuickWindow *window = helper.window; + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window)); + + QQuickDrawer *drawer = window->property("drawer").value(); + QVERIFY(drawer); + QQuickItem *popupItem = drawer->popupItem(); + + QCOMPARE(drawer->isVisible(), false); + QCOMPARE(drawer->position(), qreal(0.0)); + + QQuickOverlay *overlay = QQuickOverlay::overlay(window); + QVERIFY(overlay); + QVERIFY(!overlay->childItems().contains(popupItem)); + + drawer->open(); + QVERIFY(drawer->isVisible()); + QVERIFY(overlay->childItems().contains(popupItem)); + QTRY_COMPARE(drawer->position(), qreal(1.0)); + + drawer->close(); + QTRY_VERIFY(!drawer->isVisible()); + QTRY_COMPARE(drawer->position(), qreal(0.0)); + QVERIFY(!overlay->childItems().contains(popupItem)); + + drawer->setVisible(true); + QVERIFY(drawer->isVisible()); + QVERIFY(overlay->childItems().contains(popupItem)); + QTRY_COMPARE(drawer->position(), qreal(1.0)); + + drawer->setVisible(false); + QTRY_VERIFY(!drawer->isVisible()); + QTRY_COMPARE(drawer->position(), qreal(0.0)); + QTRY_VERIFY(!overlay->childItems().contains(popupItem)); +} + void tst_Drawer::position_data() { QTest::addColumn("edge"); @@ -179,10 +233,10 @@ void tst_Drawer::reposition() drawer->open(); QTRY_COMPARE(drawer->popupItem()->x(), window->width() - drawer->width()); - drawer->close(); - QTRY_COMPARE(drawer->popupItem()->x(), static_cast(window->width())); - window->setWidth(window->width() + 100); + QTRY_COMPARE(drawer->popupItem()->x(), window->width() - drawer->width()); + + drawer->close(); QTRY_COMPARE(drawer->popupItem()->x(), static_cast(window->width())); } @@ -250,6 +304,127 @@ void tst_Drawer::hover() QVERIFY(backgroundButton->isHovered()); } +void tst_Drawer::multiple() +{ + QQuickApplicationHelper helper(this, QStringLiteral("multiple.qml")); + QQuickWindow *window = helper.window; + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window)); + + QQuickDrawer *leftDrawer = window->property("leftDrawer").value(); + QVERIFY(leftDrawer); + QQuickButton *leftButton = window->property("leftButton").value(); + QVERIFY(leftButton); + QSignalSpy leftClickSpy(leftButton, SIGNAL(clicked())); + QVERIFY(leftClickSpy.isValid()); + + QQuickDrawer *rightDrawer = window->property("rightDrawer").value(); + QVERIFY(rightDrawer); + QQuickButton *rightButton = window->property("rightButton").value(); + QVERIFY(rightButton); + QSignalSpy rightClickSpy(rightButton, SIGNAL(clicked())); + QVERIFY(rightClickSpy.isValid()); + + QQuickButton *contentButton = window->property("contentButton").value(); + QVERIFY(contentButton); + QSignalSpy contentClickSpy(contentButton, SIGNAL(clicked())); + QVERIFY(contentClickSpy.isValid()); + + // no drawers open, click the content + QTest::mouseClick(window, Qt::LeftButton); + QCOMPARE(contentClickSpy.count(), 1); + QCOMPARE(leftClickSpy.count(), 0); + QCOMPARE(rightClickSpy.count(), 0); + + // drag the left drawer open + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, QPoint(0, window->height() / 2)); + QTest::mouseMove(window, QPoint(leftDrawer->width() / 2, window->height() / 2)); + QCOMPARE(leftDrawer->position(), 0.5); + QCOMPARE(rightDrawer->position(), 0.0); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, QPoint(leftDrawer->width() / 2, window->height() / 2)); + QTRY_COMPARE(leftDrawer->position(), 1.0); + QCOMPARE(rightDrawer->position(), 0.0); + + // cannot drag the right drawer while the left drawer is open + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, QPoint(window->width() - 1, window->height() / 2)); + QTest::mouseMove(window, QPoint(window->width() - leftDrawer->width() / 2, window->height() / 2)); + QCOMPARE(leftDrawer->position(), 1.0); + QCOMPARE(rightDrawer->position(), 0.0); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, QPoint(window->width() - leftDrawer->width() / 2, window->height() / 2)); + QCOMPARE(rightDrawer->position(), 0.0); + QCOMPARE(leftDrawer->position(), 1.0); + + // open the right drawer below the left drawer + rightDrawer->open(); + QTRY_COMPARE(rightDrawer->position(), 1.0); + + // click the left drawer's button + QTest::mouseClick(window, Qt::LeftButton); + QCOMPARE(contentClickSpy.count(), 1); + QCOMPARE(leftClickSpy.count(), 1); + QCOMPARE(rightClickSpy.count(), 0); + + // click the left drawer's background (button disabled, don't leak through to the right drawer below) + leftButton->setEnabled(false); + QTest::mouseClick(window, Qt::LeftButton); + QCOMPARE(contentClickSpy.count(), 1); + QCOMPARE(leftClickSpy.count(), 1); + QCOMPARE(rightClickSpy.count(), 0); + leftButton->setEnabled(true); + + // click the overlay of the left drawer (don't leak through to right drawer below) + QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, QPoint(window->width() - (window->width() - leftDrawer->width()) / 2, window->height() / 2)); + QCOMPARE(contentClickSpy.count(), 1); + QCOMPARE(leftClickSpy.count(), 1); + QCOMPARE(rightClickSpy.count(), 0); + QTRY_VERIFY(!leftDrawer->isVisible()); + + // click the right drawer's button + QTest::mouseClick(window, Qt::LeftButton); + QCOMPARE(contentClickSpy.count(), 1); + QCOMPARE(leftClickSpy.count(), 1); + QCOMPARE(rightClickSpy.count(), 1); + + // cannot drag the left drawer while the right drawer is open + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, QPoint(0, window->height() / 2)); + QTest::mouseMove(window, QPoint(leftDrawer->width() / 2, window->height() / 2)); + QCOMPARE(leftDrawer->position(), 0.0); + QCOMPARE(rightDrawer->position(), 1.0); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, QPoint(leftDrawer->width() / 2, window->height() / 2)); + QCOMPARE(leftDrawer->position(), 0.0); + QCOMPARE(rightDrawer->position(), 1.0); + + // click the right drawer's background (button disabled, don't leak through to the content below) + rightButton->setEnabled(false); + QTest::mouseClick(window, Qt::LeftButton); + QCOMPARE(contentClickSpy.count(), 1); + QCOMPARE(leftClickSpy.count(), 1); + QCOMPARE(rightClickSpy.count(), 1); + rightButton->setEnabled(true); + + // click the overlay of the right drawer (don't leak through to the content below) + QTest::mouseClick(window, Qt::LeftButton, Qt::NoModifier, QPoint((window->width() - rightDrawer->width()) / 2, window->height() / 2)); + QCOMPARE(contentClickSpy.count(), 1); + QCOMPARE(leftClickSpy.count(), 1); + QCOMPARE(rightClickSpy.count(), 1); + QTRY_VERIFY(!rightDrawer->isVisible()); + + // no drawers open, click the content + QTest::mouseClick(window, Qt::LeftButton); + QCOMPARE(contentClickSpy.count(), 2); + QCOMPARE(leftClickSpy.count(), 1); + QCOMPARE(rightClickSpy.count(), 1); + + // drag the right drawer open + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, QPoint(window->width() - 1, window->height() / 2)); + QTest::mouseMove(window, QPoint(window->width() - rightDrawer->width() / 2, window->height() / 2)); + QCOMPARE(rightDrawer->position(), 0.5); + QCOMPARE(leftDrawer->position(), 0.0); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, QPoint(window->width() - rightDrawer->width() / 2, window->height() / 2)); + QTRY_COMPARE(rightDrawer->position(), 1.0); + QCOMPARE(leftDrawer->position(), 0.0); +} + QTEST_MAIN(tst_Drawer) #include "tst_drawer.moc" -- cgit v1.2.3 From 9ae57848671419b2622e254af8642fef7b1b7c33 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Tue, 6 Sep 2016 09:21:15 +0200 Subject: QQuickDrawer: fix the internal transition state When QQuickDrawer was visible all the time, it did not emit the visibility related signals at all. Now the signals are emitted, but aboutToShow() and visibleChanged() were emitted twice when a drawer was manually dragged open. First time when the dragging begins (the drawer becomes effectively visible), and second time when the open transition begins after mouse/touch release. This change ensures that the signals won't be emitted again when the transition begins, in case they were already emitted. Change-Id: I2a175c9e86a480d5cd23e306f41f0d85e2416f75 Reviewed-by: Mitch Curtis --- src/quicktemplates2/qquickdrawer.cpp | 18 ++---- src/quicktemplates2/qquickdrawer_p_p.h | 6 +- src/quicktemplates2/qquickpopup.cpp | 74 +++++++++++++----------- src/quicktemplates2/qquickpopup_p_p.h | 16 +++--- tests/auto/drawer/tst_drawer.cpp | 102 +++++++++++++++++++++++++++++++++ tests/auto/popup/tst_popup.cpp | 41 +++++++++++++ 6 files changed, 197 insertions(+), 60 deletions(-) diff --git a/src/quicktemplates2/qquickdrawer.cpp b/src/quicktemplates2/qquickdrawer.cpp index 44fc8f50..15b53914 100644 --- a/src/quicktemplates2/qquickdrawer.cpp +++ b/src/quicktemplates2/qquickdrawer.cpp @@ -360,28 +360,18 @@ static QList prepareTransition(QQuickDrawer *drawer, QQuickTr return actions; } -void QQuickDrawerPrivate::prepareEnterTransition(bool notify) +bool QQuickDrawerPrivate::prepareEnterTransition() { Q_Q(QQuickDrawer); enterActions = prepareTransition(q, enter, 1.0); - QQuickPopupPrivate::prepareEnterTransition(notify); + return QQuickPopupPrivate::prepareEnterTransition(); } -void QQuickDrawerPrivate::prepareExitTransition() +bool QQuickDrawerPrivate::prepareExitTransition() { Q_Q(QQuickDrawer); exitActions = prepareTransition(q, exit, 0.0); - QQuickPopupPrivate::prepareExitTransition(); -} - -void QQuickDrawerPrivate::finalizeEnterTransition() -{ - QQuickPopupPrivate::finalizeEnterTransition(); -} - -void QQuickDrawerPrivate::finalizeExitTransition(bool hide) -{ - QQuickPopupPrivate::finalizeExitTransition(hide); + return QQuickPopupPrivate::prepareExitTransition(); } QQuickDrawer::QQuickDrawer(QObject *parent) : diff --git a/src/quicktemplates2/qquickdrawer_p_p.h b/src/quicktemplates2/qquickdrawer_p_p.h index e8add86c..f14c36dd 100644 --- a/src/quicktemplates2/qquickdrawer_p_p.h +++ b/src/quicktemplates2/qquickdrawer_p_p.h @@ -77,10 +77,8 @@ public: bool handleMouseMoveEvent(QQuickItem *item, QMouseEvent *event); bool handleMouseReleaseEvent(QQuickItem *item, QMouseEvent *event); - void prepareEnterTransition(bool notify = true) override; - void prepareExitTransition() override; - void finalizeEnterTransition() override; - void finalizeExitTransition(bool hide = true) override; + bool prepareEnterTransition() override; + bool prepareExitTransition() override; Qt::Edge edge; qreal offset; diff --git a/src/quicktemplates2/qquickpopup.cpp b/src/quicktemplates2/qquickpopup.cpp index 6d06708b..0eab6ad5 100644 --- a/src/quicktemplates2/qquickpopup.cpp +++ b/src/quicktemplates2/qquickpopup.cpp @@ -143,6 +143,7 @@ QQuickPopupPrivate::QQuickPopupPrivate() , bottomMargin(0) , contentWidth(0) , contentHeight(0) + , transitionState(QQuickPopupPrivate::NoTransition) , closePolicy(QQuickPopup::CloseOnEscape | QQuickPopup::CloseOnPressOutside) , parentItem(nullptr) , dimmer(nullptr) @@ -180,33 +181,46 @@ bool QQuickPopupPrivate::tryClose(QQuickItem *item, QMouseEvent *event) return false; } -void QQuickPopupPrivate::prepareEnterTransition(bool notify) +bool QQuickPopupPrivate::prepareEnterTransition() { Q_Q(QQuickPopup); if (!window) { qmlInfo(q) << "cannot find any window to open popup in."; - return; + return false; } - popupItem->setParentItem(QQuickOverlay::overlay(window)); - if (notify) + if (transitionState == EnterTransition && transitionManager.isRunning()) + return false; + + if (transitionState != EnterTransition) { + popupItem->setParentItem(QQuickOverlay::overlay(window)); emit q->aboutToShow(); - visible = notify; - popupItem->setVisible(true); - positioner.setParentItem(parentItem); - emit q->visibleChanged(); + visible = true; + transitionState = EnterTransition; + popupItem->setVisible(true); + positioner.setParentItem(parentItem); + emit q->visibleChanged(); + } + return true; } -void QQuickPopupPrivate::prepareExitTransition() +bool QQuickPopupPrivate::prepareExitTransition() { Q_Q(QQuickPopup); - if (focus) { - // The setFocus(false) call below removes any active focus before we're - // able to check it in finalizeExitTransition. - hadActiveFocusBeforeExitTransition = popupItem->hasActiveFocus(); - popupItem->setFocus(false); + if (transitionState == ExitTransition && transitionManager.isRunning()) + return false; + + if (transitionState != ExitTransition) { + if (focus) { + // The setFocus(false) call below removes any active focus before we're + // able to check it in finalizeExitTransition. + hadActiveFocusBeforeExitTransition = popupItem->hasActiveFocus(); + popupItem->setFocus(false); + } + transitionState = ExitTransition; + emit q->aboutToHide(); } - emit q->aboutToHide(); + return true; } void QQuickPopupPrivate::finalizeEnterTransition() @@ -214,17 +228,16 @@ void QQuickPopupPrivate::finalizeEnterTransition() Q_Q(QQuickPopup); if (focus) popupItem->setFocus(true); + transitionState = NoTransition; emit q->opened(); } -void QQuickPopupPrivate::finalizeExitTransition(bool hide) +void QQuickPopupPrivate::finalizeExitTransition() { Q_Q(QQuickPopup); - if (hide) { - positioner.setParentItem(nullptr); - popupItem->setParentItem(nullptr); - popupItem->setVisible(false); - } + positioner.setParentItem(nullptr); + popupItem->setParentItem(nullptr); + popupItem->setVisible(false); if (hadActiveFocusBeforeExitTransition) { QQuickApplicationWindow *applicationWindow = qobject_cast(window); @@ -235,6 +248,7 @@ void QQuickPopupPrivate::finalizeExitTransition(bool hide) } visible = false; + transitionState = NoTransition; hadActiveFocusBeforeExitTransition = false; emit q->visibleChanged(); emit q->closed(); @@ -713,19 +727,15 @@ bool QQuickPopupPositioner::isAncestor(QQuickItem *item) const } QQuickPopupTransitionManager::QQuickPopupTransitionManager(QQuickPopupPrivate *popup) - : QQuickTransitionManager() - , state(Off) - , popup(popup) + : QQuickTransitionManager(), popup(popup) { } void QQuickPopupTransitionManager::transitionEnter() { - if (state == Enter && isRunning()) + if (!popup->prepareEnterTransition()) return; - state = Enter; - popup->prepareEnterTransition(); if (popup->window) transition(popup->enterActions, popup->enter, popup->q_func()); else @@ -734,11 +744,9 @@ void QQuickPopupTransitionManager::transitionEnter() void QQuickPopupTransitionManager::transitionExit() { - if (state == Exit && isRunning()) + if (!popup->prepareExitTransition()) return; - state = Exit; - popup->prepareExitTransition(); if (popup->window) transition(popup->exitActions, popup->exit, popup->q_func()); else @@ -747,12 +755,10 @@ void QQuickPopupTransitionManager::transitionExit() void QQuickPopupTransitionManager::finished() { - if (state == Enter) + if (popup->transitionState == QQuickPopupPrivate::EnterTransition) popup->finalizeEnterTransition(); - else if (state == Exit) + else if (popup->transitionState == QQuickPopupPrivate::ExitTransition) popup->finalizeExitTransition(); - - state = Off; } QQuickPopup::QQuickPopup(QObject *parent) diff --git a/src/quicktemplates2/qquickpopup_p_p.h b/src/quicktemplates2/qquickpopup_p_p.h index 80cb8522..b828edc1 100644 --- a/src/quicktemplates2/qquickpopup_p_p.h +++ b/src/quicktemplates2/qquickpopup_p_p.h @@ -76,11 +76,6 @@ protected: void finished() override; private: - enum TransitionState { - Off, Enter, Exit - }; - - TransitionState state; QQuickPopupPrivate *popup; }; @@ -163,10 +158,10 @@ public: bool tryClose(QQuickItem *item, QMouseEvent *event); virtual void reposition(); - virtual void prepareEnterTransition(bool notify = true); - virtual void prepareExitTransition(); + virtual bool prepareEnterTransition(); + virtual bool prepareExitTransition(); virtual void finalizeEnterTransition(); - virtual void finalizeExitTransition(bool hide = true); + virtual void finalizeExitTransition(); QMarginsF getMargins() const; @@ -178,6 +173,10 @@ public: void setWindow(QQuickWindow *window); void itemDestroyed(QQuickItem *item) override; + enum TransitionState { + NoTransition, EnterTransition, ExitTransition + }; + bool focus; bool modal; bool dim; @@ -202,6 +201,7 @@ public: qreal bottomMargin; qreal contentWidth; qreal contentHeight; + TransitionState transitionState; QQuickPopup::ClosePolicy closePolicy; QQuickItem *parentItem; QQuickItem *dimmer; diff --git a/tests/auto/drawer/tst_drawer.cpp b/tests/auto/drawer/tst_drawer.cpp index 02a4f91f..8f023c29 100644 --- a/tests/auto/drawer/tst_drawer.cpp +++ b/tests/auto/drawer/tst_drawer.cpp @@ -56,6 +56,8 @@ private slots: void visible_data(); void visible(); + void state(); + void position_data(); void position(); @@ -118,6 +120,106 @@ void tst_Drawer::visible() QTRY_VERIFY(!overlay->childItems().contains(popupItem)); } +void tst_Drawer::state() +{ + QQuickApplicationHelper helper(this, "applicationwindow.qml"); + + QQuickWindow *window = helper.window; + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window)); + + QQuickDrawer *drawer = window->property("drawer").value(); + QVERIFY(drawer); + + QCOMPARE(drawer->isVisible(), false); + + QSignalSpy visibleChangedSpy(drawer, SIGNAL(visibleChanged())); + QSignalSpy aboutToShowSpy(drawer, SIGNAL(aboutToShow())); + QSignalSpy aboutToHideSpy(drawer, SIGNAL(aboutToHide())); + QSignalSpy openedSpy(drawer, SIGNAL(opened())); + QSignalSpy closedSpy(drawer, SIGNAL(closed())); + + QVERIFY(visibleChangedSpy.isValid()); + QVERIFY(aboutToShowSpy.isValid()); + QVERIFY(aboutToHideSpy.isValid()); + QVERIFY(openedSpy.isValid()); + QVERIFY(closedSpy.isValid()); + + int visibleChangedCount = 0; + int aboutToShowCount = 0; + int aboutToHideCount = 0; + int openedCount = 0; + int closedCount = 0; + + // open programmatically... + drawer->open(); + QCOMPARE(visibleChangedSpy.count(), ++visibleChangedCount); + QCOMPARE(aboutToShowSpy.count(), ++aboutToShowCount); + QCOMPARE(aboutToHideSpy.count(), aboutToHideCount); + QCOMPARE(openedSpy.count(), openedCount); + QCOMPARE(closedSpy.count(), closedCount); + + // ...and wait until fully open + QVERIFY(openedSpy.wait()); + QCOMPARE(visibleChangedSpy.count(), visibleChangedCount); + QCOMPARE(aboutToShowSpy.count(), aboutToShowCount); + QCOMPARE(aboutToHideSpy.count(), aboutToHideCount); + QCOMPARE(openedSpy.count(), ++openedCount); + QCOMPARE(closedSpy.count(), closedCount); + + // close programmatically... + drawer->close(); + QCOMPARE(visibleChangedSpy.count(), visibleChangedCount); + QCOMPARE(aboutToShowSpy.count(), aboutToShowCount); + QCOMPARE(aboutToHideSpy.count(), ++aboutToHideCount); + QCOMPARE(openedSpy.count(), openedCount); + QCOMPARE(closedSpy.count(), closedCount); + + // ...and wait until fully closed + QVERIFY(closedSpy.wait()); + QCOMPARE(visibleChangedSpy.count(), ++visibleChangedCount); + QCOMPARE(aboutToShowSpy.count(), aboutToShowCount); + QCOMPARE(aboutToHideSpy.count(), aboutToHideCount); + QCOMPARE(openedSpy.count(), openedCount); + QCOMPARE(closedSpy.count(), ++closedCount); + + // open interactively... + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, QPoint(0, drawer->height() / 2)); + QTest::mouseMove(window, QPoint(drawer->width() * 0.2, drawer->height() / 2), 16); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, QPoint(drawer->width() * 0.8, drawer->height() / 2), 16); + QCOMPARE(visibleChangedSpy.count(), ++visibleChangedCount); + QCOMPARE(aboutToShowSpy.count(), ++aboutToShowCount); + QCOMPARE(aboutToHideSpy.count(), aboutToHideCount); + QCOMPARE(openedSpy.count(), openedCount); + QCOMPARE(closedSpy.count(), closedCount); + + // ...and wait until fully open + QVERIFY(openedSpy.wait()); + QCOMPARE(visibleChangedSpy.count(), visibleChangedCount); + QCOMPARE(aboutToShowSpy.count(), aboutToShowCount); + QCOMPARE(aboutToHideSpy.count(), aboutToHideCount); + QCOMPARE(openedSpy.count(), ++openedCount); + QCOMPARE(closedSpy.count(), closedCount); + + // close interactively... + QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, QPoint(drawer->width(), drawer->height() / 2)); + QTest::mouseMove(window, QPoint(drawer->width() * 0.8, drawer->height() / 2), 16); + QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, QPoint(drawer->width() * 0.2, drawer->height() / 2), 16); + QCOMPARE(visibleChangedSpy.count(), visibleChangedCount); + QCOMPARE(aboutToShowSpy.count(), aboutToShowCount); + QCOMPARE(aboutToHideSpy.count(), ++aboutToHideCount); + QCOMPARE(openedSpy.count(), openedCount); + QCOMPARE(closedSpy.count(), closedCount); + + // ...and wait until fully closed + QVERIFY(closedSpy.wait()); + QCOMPARE(visibleChangedSpy.count(), ++visibleChangedCount); + QCOMPARE(aboutToShowSpy.count(), aboutToShowCount); + QCOMPARE(aboutToHideSpy.count(), aboutToHideCount); + QCOMPARE(openedSpy.count(), openedCount); + QCOMPARE(closedSpy.count(), ++closedCount); +} + void tst_Drawer::position_data() { QTest::addColumn("edge"); diff --git a/tests/auto/popup/tst_popup.cpp b/tests/auto/popup/tst_popup.cpp index 990140db..a6848fc8 100644 --- a/tests/auto/popup/tst_popup.cpp +++ b/tests/auto/popup/tst_popup.cpp @@ -53,6 +53,7 @@ class tst_popup : public QQmlDataTest private slots: void visible_data(); void visible(); + void state(); void overlay_data(); void overlay(); void zOrder_data(); @@ -108,6 +109,46 @@ void tst_popup::visible() QVERIFY(!overlay->childItems().contains(popupItem)); } +void tst_popup::state() +{ + QQuickApplicationHelper helper(this, "applicationwindow.qml"); + + QQuickWindow *window = helper.window; + window->show(); + QVERIFY(QTest::qWaitForWindowExposed(window)); + + QQuickPopup *popup = window->property("popup").value(); + QVERIFY(popup); + + QCOMPARE(popup->isVisible(), false); + + QSignalSpy visibleChangedSpy(popup, SIGNAL(visibleChanged())); + QSignalSpy aboutToShowSpy(popup, SIGNAL(aboutToShow())); + QSignalSpy aboutToHideSpy(popup, SIGNAL(aboutToHide())); + QSignalSpy openedSpy(popup, SIGNAL(opened())); + QSignalSpy closedSpy(popup, SIGNAL(closed())); + + QVERIFY(visibleChangedSpy.isValid()); + QVERIFY(aboutToShowSpy.isValid()); + QVERIFY(aboutToHideSpy.isValid()); + QVERIFY(openedSpy.isValid()); + QVERIFY(closedSpy.isValid()); + + popup->open(); + QCOMPARE(visibleChangedSpy.count(), 1); + QCOMPARE(aboutToShowSpy.count(), 1); + QCOMPARE(aboutToHideSpy.count(), 0); + QTRY_COMPARE(openedSpy.count(), 1); + QCOMPARE(closedSpy.count(), 0); + + popup->close(); + QCOMPARE(visibleChangedSpy.count(), 2); + QCOMPARE(aboutToShowSpy.count(), 1); + QCOMPARE(aboutToHideSpy.count(), 1); + QCOMPARE(openedSpy.count(), 1); + QTRY_COMPARE(closedSpy.count(), 1); +} + void tst_popup::overlay_data() { QTest::addColumn("source"); -- cgit v1.2.3