diff options
19 files changed, 502 insertions, 235 deletions
diff --git a/examples/quickcontrols2/contactlist/ContactDelegate.ui.qml b/examples/quickcontrols2/contactlist/ContactDelegate.ui.qml index cab26e63..383bb4ec 100644 --- a/examples/quickcontrols2/contactlist/ContactDelegate.ui.qml +++ b/examples/quickcontrols2/contactlist/ContactDelegate.ui.qml @@ -49,111 +49,68 @@ ****************************************************************************/ import QtQuick 2.7 +import QtQuick.Layouts 1.0 import QtQuick.Controls 2.1 -AbstractButton { +ItemDelegate { id: delegate - property alias remove: remove - property alias edit: edit - - width: 300 - height: 50 - clip: true checkable: true - autoExclusive: true - - Column { - id: column1 - height: 400 - width: parent.width - 20 - spacing: 4 - Row { - id: row1 - spacing: 10 + contentItem: ColumnLayout { + spacing: 10 - Label { - text: fullName - font.pointSize: 16 - anchors.verticalCenter: parent.verticalCenter - font.bold: true - } + Label { + text: fullName + font.bold: true + elide: Text.ElideRight + Layout.fillWidth: true } - Grid { + GridLayout { id: grid - opacity: 0 + visible: false - x: 60 - spacing: 10 columns: 2 + rowSpacing: 10 + columnSpacing: 10 + Label { text: qsTr("Address:") - font.bold: true - font.pixelSize: 16 + Layout.leftMargin: 60 } Label { text: address - font.pixelSize: 16 font.bold: true + elide: Text.ElideRight + Layout.fillWidth: true } Label { text: qsTr("City:") - font.pixelSize: 16 - font.bold: true + Layout.leftMargin: 60 } Label { text: city - font.pixelSize: 16 font.bold: true + elide: Text.ElideRight + Layout.fillWidth: true } Label { text: qsTr("Number:") - font.pixelSize: 16 - font.bold: true + Layout.leftMargin: 60 } Label { text: number - font.pixelSize: 16 font.bold: true + elide: Text.ElideRight + Layout.fillWidth: true } } - - Row { - id: row - spacing: 12 - anchors.right: parent.right - - Button { - id: remove - width: 60 - height: 20 - text: "Remove" - } - - Button { - id: edit - width: 60 - height: 20 - text: "Edit" - } - } - - MenuSeparator { - id: separator - opacity: 0 - padding: 0 - anchors.right: parent.right - anchors.rightMargin: 4 - anchors.left: parent.left - anchors.leftMargin: 4 - } } states: [ @@ -162,18 +119,8 @@ AbstractButton { when: delegate.checked PropertyChanges { - target: delegate - height: 160 - } - - PropertyChanges { - target: separator - opacity: 1 - } - - PropertyChanges { target: grid - opacity: 1 + visible: true } } ] diff --git a/examples/quickcontrols2/contactlist/ContactDialog.qml b/examples/quickcontrols2/contactlist/ContactDialog.qml index 1836ea28..54256e47 100644 --- a/examples/quickcontrols2/contactlist/ContactDialog.qml +++ b/examples/quickcontrols2/contactlist/ContactDialog.qml @@ -54,7 +54,6 @@ import QtQuick.Controls 2.1 Dialog { id: dialog - property int index: -1 signal finished(string fullName, string address, string city, string number) function createContact() { @@ -64,18 +63,16 @@ Dialog { form.number.clear(); dialog.title = qsTr("Add Contact"); - dialog.index = -1; dialog.open(); } - function editContact(index, contact) { + function editContact(contact) { form.fullName.text = contact.fullName; form.address.text = contact.address; form.city.text = contact.city; form.number.text = contact.number; dialog.title = qsTr("Edit Contact"); - dialog.index = index; dialog.open(); } diff --git a/examples/quickcontrols2/contactlist/ContactView.ui.qml b/examples/quickcontrols2/contactlist/ContactView.ui.qml index 30a72b65..2aaaa31d 100644 --- a/examples/quickcontrols2/contactlist/ContactView.ui.qml +++ b/examples/quickcontrols2/contactlist/ContactView.ui.qml @@ -52,65 +52,36 @@ import QtQuick 2.7 import QtQuick.Controls 2.1 import Backend 1.0 -Page { - id: page +ListView { + id: listView - signal addContact() - signal editContact(int index) - signal removeContact(int index) - - property alias model: contactModel + signal pressAndHold(int index) width: 320 height: 480 - ListView { - id: listView - anchors.fill: parent - - focus: true - boundsBehavior: Flickable.StopAtBounds - - section.property: "fullName" - section.criteria: ViewSection.FirstCharacter - section.delegate: SectionDelegate { - width: listView.width - } - - delegate: ContactDelegate { - id: delegate - width: listView.width + focus: true + boundsBehavior: Flickable.StopAtBounds - Connections { - target: delegate.edit - onClicked: page.editContact(index) - } + section.property: "fullName" + section.criteria: ViewSection.FirstCharacter + section.delegate: SectionDelegate { + width: listView.width + } - Connections { - target: delegate.remove - onClicked: page.removeContact(index) - } - } + delegate: ContactDelegate { + id: delegate + width: listView.width - model: ContactModel { - id: contactModel + Connections { + target: delegate + onPressAndHold: listView.pressAndHold(index) } - - ScrollBar.vertical: ScrollBar { } } - footer: ToolBar { - id: footer - - ToolButton { - id: addButton - text: qsTr("Add Contact") - anchors.right: parent.right - - Connections { - target: addButton - onClicked: page.addContact() - } - } + model: ContactModel { + id: contactModel } + + ScrollBar.vertical: ScrollBar { } } diff --git a/examples/quickcontrols2/contactlist/contactlist.qml b/examples/quickcontrols2/contactlist/contactlist.qml index 04382407..13406fbe 100644 --- a/examples/quickcontrols2/contactlist/contactlist.qml +++ b/examples/quickcontrols2/contactlist/contactlist.qml @@ -54,6 +54,8 @@ import QtQuick.Controls 2.1 ApplicationWindow { id: window + property int currentContact: -1 + width: 320 height: 480 visible: true @@ -62,19 +64,54 @@ ApplicationWindow { ContactDialog { id: contactDialog onFinished: { - if (index === -1) + if (currentContact === -1) contactView.model.append(fullName, address, city, number) else - contactView.model.set(index, fullName, address, city, number) + contactView.model.set(currentContact, fullName, address, city, number) + } + } + + Menu { + id: contactMenu + x: parent.width / 2 - width / 2 + y: parent.height / 2 - height / 2 + modal: true + + Label { + padding: 10 + font.bold: true + width: parent.width + horizontalAlignment: Qt.AlignHCenter + text: currentContact >= 0 ? contactView.model.get(currentContact).fullName : "" + } + MenuItem { + text: qsTr("Edit...") + onTriggered: contactDialog.editContact(contactView.model.get(currentContact)) + } + MenuItem { + text: qsTr("Remove") + onTriggered: contactView.model.remove(currentContact) } } ContactView { id: contactView anchors.fill: parent + onPressAndHold: { + currentContact = index + contactMenu.open() + } + } - onAddContact: contactDialog.createContact() - onEditContact: contactDialog.editContact(index, model.get(index)) - onRemoveContact: model.remove(index) + RoundButton { + text: qsTr("+") + highlighted: true + anchors.margins: 10 + anchors.right: parent.right + anchors.bottom: parent.bottom + onClicked: { + currentContact = -1 + contactDialog.createContact() + } } } diff --git a/examples/quickcontrols2/contactlist/doc/images/qtquickcontrols2-contactlist.png b/examples/quickcontrols2/contactlist/doc/images/qtquickcontrols2-contactlist.png Binary files differindex 642cf2dc..d7424ed3 100644 --- a/examples/quickcontrols2/contactlist/doc/images/qtquickcontrols2-contactlist.png +++ b/examples/quickcontrols2/contactlist/doc/images/qtquickcontrols2-contactlist.png diff --git a/examples/quickcontrols2/contactlist/doc/src/qtquickcontrols2-contactlist.qdoc b/examples/quickcontrols2/contactlist/doc/src/qtquickcontrols2-contactlist.qdoc index 2b4de68b..17e1aec2 100644 --- a/examples/quickcontrols2/contactlist/doc/src/qtquickcontrols2-contactlist.qdoc +++ b/examples/quickcontrols2/contactlist/doc/src/qtquickcontrols2-contactlist.qdoc @@ -36,9 +36,9 @@ For the declarative parts of the UI, .ui.qml files are used that can be edited visually in the Qt Quick Designer. - \section1 C++ Backend + \image qtquickcontrols2-contactlist.png - \borderedimage qtquickcontrols2-contactlist.png + \section1 C++ Backend The contact list application allows the user to add, edit, and remove contacts. The actual implementation is done in C++ and exposed as a QAbstractListModel. diff --git a/src/imports/controls/material/Drawer.qml b/src/imports/controls/material/Drawer.qml index 855b5d88..55cabc9a 100644 --- a/src/imports/controls/material/Drawer.qml +++ b/src/imports/controls/material/Drawer.qml @@ -50,15 +50,32 @@ T.Drawer { contentWidth: contentItem.implicitWidth || (contentChildren.length === 1 ? contentChildren[0].implicitWidth : 0) contentHeight: contentItem.implicitHeight || (contentChildren.length === 1 ? contentChildren[0].implicitHeight : 0) + topPadding: !dim && edge === Qt.BottomEdge && Material.elevation === 0 + leftPadding: !dim && edge === Qt.RightEdge && Material.elevation === 0 + rightPadding: !dim && edge === Qt.LeftEdge && Material.elevation === 0 + bottomPadding: !dim && edge === Qt.TopEdge && Material.elevation === 0 + enter: Transition { SmoothedAnimation { velocity: 5 } } exit: Transition { SmoothedAnimation { velocity: 5 } } + Material.elevation: 16 + background: Rectangle { color: control.Material.dialogColor + Rectangle { + readonly property bool horizontal: control.edge === Qt.LeftEdge || control.edge === Qt.RightEdge + width: horizontal ? 1 : parent.width + height: horizontal ? parent.height : 1 + color: control.Material.dividerColor + x: control.edge === Qt.LeftEdge ? parent.width - 1 : 0 + y: control.edge === Qt.TopEdge ? parent.height - 1 : 0 + visible: !control.dim && control.Material.elevation === 0 + } + layer.enabled: control.position > 0 layer.effect: ElevationEffect { - elevation: 16 + elevation: control.Material.elevation fullHeight: true } } diff --git a/src/imports/controls/material/qquickmaterialripple_p.h b/src/imports/controls/material/qquickmaterialripple_p.h index 5b86fb2a..6fdcd28d 100644 --- a/src/imports/controls/material/qquickmaterialripple_p.h +++ b/src/imports/controls/material/qquickmaterialripple_p.h @@ -49,6 +49,7 @@ // #include <QtQuick/qquickitem.h> +#include <QtGui/qcolor.h> QT_BEGIN_NAMESPACE diff --git a/src/imports/templates/qtquicktemplates2plugin.cpp b/src/imports/templates/qtquicktemplates2plugin.cpp index 83bbb94a..57e8f88e 100644 --- a/src/imports/templates/qtquicktemplates2plugin.cpp +++ b/src/imports/templates/qtquicktemplates2plugin.cpp @@ -73,6 +73,7 @@ #include <QtQuickTemplates2/private/qquickslider_p.h> #include <QtQuickTemplates2/private/qquickspinbox_p.h> #include <QtQuickTemplates2/private/qquickstackview_p.h> +#include <QtQuickTemplates2/private/qquickswipe_p.h> #include <QtQuickTemplates2/private/qquickswipedelegate_p.h> #include <QtQuickTemplates2/private/qquickswipeview_p.h> #include <QtQuickTemplates2/private/qquickswitch_p.h> diff --git a/src/quicktemplates2/qquickabstractbutton.cpp b/src/quicktemplates2/qquickabstractbutton.cpp index 350af84a..ffd8efa2 100644 --- a/src/quicktemplates2/qquickabstractbutton.cpp +++ b/src/quicktemplates2/qquickabstractbutton.cpp @@ -555,7 +555,7 @@ void QQuickAbstractButton::mouseReleaseEvent(QMouseEvent *event) bool wasPressed = d->pressed; setPressed(false); - if (d->keepPressed || contains(event->pos())) + if (!d->wasHeld && (d->keepPressed || contains(event->pos()))) nextCheckState(); if (wasPressed) { diff --git a/src/quicktemplates2/qquickswipe_p.h b/src/quicktemplates2/qquickswipe_p.h new file mode 100644 index 00000000..c1a28819 --- /dev/null +++ b/src/quicktemplates2/qquickswipe_p.h @@ -0,0 +1,120 @@ +/**************************************************************************** +** +** 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 QQUICKSWIPE_P_H +#define QQUICKSWIPE_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 <QtCore/qobject.h> +#include <QtQuickTemplates2/private/qtquicktemplates2global_p.h> + +QT_BEGIN_NAMESPACE + +class QQmlComponent; +class QQuickItem; +class QQuickSwipeDelegate; +class QQuickSwipePrivate; + +class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickSwipe : public QObject +{ + Q_OBJECT + Q_PROPERTY(qreal position READ position NOTIFY positionChanged FINAL) + Q_PROPERTY(bool complete READ isComplete NOTIFY completeChanged FINAL) + Q_PROPERTY(QQmlComponent *left READ left WRITE setLeft NOTIFY leftChanged FINAL) + Q_PROPERTY(QQmlComponent *behind READ behind WRITE setBehind NOTIFY behindChanged FINAL) + Q_PROPERTY(QQmlComponent *right READ right WRITE setRight NOTIFY rightChanged FINAL) + Q_PROPERTY(QQuickItem *leftItem READ leftItem NOTIFY leftItemChanged FINAL) + Q_PROPERTY(QQuickItem *behindItem READ behindItem NOTIFY behindItemChanged FINAL) + Q_PROPERTY(QQuickItem *rightItem READ rightItem NOTIFY rightItemChanged FINAL) + +public: + explicit QQuickSwipe(QQuickSwipeDelegate *control); + + qreal position() const; + void setPosition(qreal position); + + bool isComplete() const; + void setComplete(bool complete); + + QQmlComponent *left() const; + void setLeft(QQmlComponent *left); + + QQmlComponent *behind() const; + void setBehind(QQmlComponent *behind); + + QQmlComponent *right() const; + void setRight(QQmlComponent *right); + + QQuickItem *leftItem() const; + void setLeftItem(QQuickItem *item); + + QQuickItem *behindItem() const; + void setBehindItem(QQuickItem *item); + + QQuickItem *rightItem() const; + void setRightItem(QQuickItem *item); + + Q_REVISION(1) Q_INVOKABLE void close(); + +Q_SIGNALS: + void positionChanged(); + void completeChanged(); + /*Q_REVISION(1)*/ void completed(); + void leftChanged(); + void behindChanged(); + void rightChanged(); + void leftItemChanged(); + void behindItemChanged(); + void rightItemChanged(); + +private: + Q_DISABLE_COPY(QQuickSwipe) + Q_DECLARE_PRIVATE(QQuickSwipe) +}; + +QT_END_NAMESPACE + +#endif // QQUICKSWIPE_P_H diff --git a/src/quicktemplates2/qquickswipedelegate.cpp b/src/quicktemplates2/qquickswipedelegate.cpp index fe678b80..5430a4de 100644 --- a/src/quicktemplates2/qquickswipedelegate.cpp +++ b/src/quicktemplates2/qquickswipedelegate.cpp @@ -35,6 +35,7 @@ ****************************************************************************/ #include "qquickswipedelegate_p.h" +#include "qquickswipedelegate_p_p.h" #include "qquickcontrol_p_p.h" #include "qquickitemdelegate_p_p.h" #include "qquickvelocitycalculator_p_p.h" @@ -148,6 +149,8 @@ public: void warnAboutMixingDelegates(); void warnAboutSettingDelegatesWhileVisible(); + bool hasDelegates() const; + QQuickSwipeDelegate *control; // Same range as position, but is set before press events so that we can // keep track of which direction the user must swipe when using left and right delegates. @@ -348,6 +351,11 @@ void QQuickSwipePrivate::warnAboutSettingDelegatesWhileVisible() qmlInfo(control) << "left/right/behind properties may only be set when swipe.position is 0"; } +bool QQuickSwipePrivate::hasDelegates() const +{ + return left || right || behind; +} + QQuickSwipe::QQuickSwipe(QQuickSwipeDelegate *control) : QObject(*(new QQuickSwipePrivate(control))) { @@ -382,6 +390,8 @@ void QQuickSwipe::setLeft(QQmlComponent *left) d->leftItem = nullptr; } + d->control->setFiltersChildMouseEvents(d->hasDelegates()); + emit leftChanged(); } @@ -414,6 +424,8 @@ void QQuickSwipe::setBehind(QQmlComponent *behind) d->behindItem = nullptr; } + d->control->setFiltersChildMouseEvents(d->hasDelegates()); + emit behindChanged(); } @@ -446,6 +458,8 @@ void QQuickSwipe::setRight(QQmlComponent *right) d->rightItem = nullptr; } + d->control->setFiltersChildMouseEvents(d->hasDelegates()); + emit rightChanged(); } @@ -562,28 +576,18 @@ void QQuickSwipe::setComplete(bool complete) void QQuickSwipe::close() { + Q_D(QQuickSwipe); setPosition(0); setComplete(false); + d->wasComplete = false; + d->positionBeforePress = 0.0; + d->velocityCalculator.reset(); } -class QQuickSwipeDelegatePrivate : public QQuickItemDelegatePrivate +QQuickSwipeDelegatePrivate::QQuickSwipeDelegatePrivate(QQuickSwipeDelegate *control) : + swipe(control) { - Q_DECLARE_PUBLIC(QQuickSwipeDelegate) - -public: - QQuickSwipeDelegatePrivate(QQuickSwipeDelegate *control) : - swipe(control) - { - } - - bool handleMousePressEvent(QQuickItem *item, QMouseEvent *event); - bool handleMouseMoveEvent(QQuickItem *item, QMouseEvent *event); - bool handleMouseReleaseEvent(QQuickItem *item, QMouseEvent *event); - - void resizeContent() override; - - QQuickSwipe swipe; -}; +} bool QQuickSwipeDelegatePrivate::handleMousePressEvent(QQuickItem *item, QMouseEvent *event) { @@ -594,6 +598,10 @@ bool QQuickSwipeDelegatePrivate::handleMousePressEvent(QQuickItem *item, QMouseE // events will go through the regular channels (mousePressEvent()) until then. if (qFuzzyIsNull(swipePrivate->position)) { q->mousePressEvent(event); + // The press point could be incorrect if the press happened over a child item, + // so we correct it after calling the base class' mousePressEvent(), rather + // than having to duplicate its code just so we can set the pressPoint. + pressPoint = item->mapToItem(q, event->pos()); return true; } @@ -704,6 +712,13 @@ bool QQuickSwipeDelegatePrivate::handleMouseMoveEvent(QQuickItem *item, QMouseEv swipe.setPosition(position); } + } else { + // The swipe wasn't initiated. + if (event->pos().y() < 0 || event->pos().y() > height) { + // The mouse went outside the vertical bounds of the control, so + // we should no longer consider it pressed. + q->setPressed(false); + } } event->accept(); @@ -787,7 +802,6 @@ void QQuickSwipeDelegatePrivate::resizeContent() QQuickSwipeDelegate::QQuickSwipeDelegate(QQuickItem *parent) : QQuickItemDelegate(*(new QQuickSwipeDelegatePrivate(this)), parent) { - setFiltersChildMouseEvents(true); } /*! @@ -957,14 +971,17 @@ void QQuickSwipeDelegate::mousePressEvent(QMouseEvent *event) void QQuickSwipeDelegate::mouseMoveEvent(QMouseEvent *event) { Q_D(QQuickSwipeDelegate); - d->handleMouseMoveEvent(this, event); + if (filtersChildMouseEvents()) + d->handleMouseMoveEvent(this, event); + else + QQuickItemDelegate::mouseMoveEvent(event); } void QQuickSwipeDelegate::mouseReleaseEvent(QMouseEvent *event) { Q_D(QQuickSwipeDelegate); - QQuickItemDelegate::mouseReleaseEvent(event); - d->handleMouseReleaseEvent(this, event); + if (!filtersChildMouseEvents() || !d->handleMouseReleaseEvent(this, event)) + QQuickItemDelegate::mouseReleaseEvent(event); } void QQuickSwipeDelegate::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) diff --git a/src/quicktemplates2/qquickswipedelegate_p.h b/src/quicktemplates2/qquickswipedelegate_p.h index ae23672b..16aa9837 100644 --- a/src/quicktemplates2/qquickswipedelegate_p.h +++ b/src/quicktemplates2/qquickswipedelegate_p.h @@ -52,8 +52,8 @@ QT_BEGIN_NAMESPACE -class QQuickSwipeDelegatePrivate; class QQuickSwipe; +class QQuickSwipeDelegatePrivate; class QQuickSwipeDelegateAttached; class QQuickSwipeDelegateAttachedPrivate; @@ -88,65 +88,6 @@ private: Q_DECLARE_PRIVATE(QQuickSwipeDelegate) }; -class QQuickSwipePrivate; - -class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickSwipe : public QObject -{ - Q_OBJECT - Q_PROPERTY(qreal position READ position NOTIFY positionChanged FINAL) - Q_PROPERTY(bool complete READ isComplete NOTIFY completeChanged FINAL) - Q_PROPERTY(QQmlComponent *left READ left WRITE setLeft NOTIFY leftChanged FINAL) - Q_PROPERTY(QQmlComponent *behind READ behind WRITE setBehind NOTIFY behindChanged FINAL) - Q_PROPERTY(QQmlComponent *right READ right WRITE setRight NOTIFY rightChanged FINAL) - Q_PROPERTY(QQuickItem *leftItem READ leftItem NOTIFY leftItemChanged FINAL) - Q_PROPERTY(QQuickItem *behindItem READ behindItem NOTIFY behindItemChanged FINAL) - Q_PROPERTY(QQuickItem *rightItem READ rightItem NOTIFY rightItemChanged FINAL) - -public: - explicit QQuickSwipe(QQuickSwipeDelegate *control); - - qreal position() const; - void setPosition(qreal position); - - bool isComplete() const; - void setComplete(bool complete); - - QQmlComponent *left() const; - void setLeft(QQmlComponent *left); - - QQmlComponent *behind() const; - void setBehind(QQmlComponent *behind); - - QQmlComponent *right() const; - void setRight(QQmlComponent *right); - - QQuickItem *leftItem() const; - void setLeftItem(QQuickItem *item); - - QQuickItem *behindItem() const; - void setBehindItem(QQuickItem *item); - - QQuickItem *rightItem() const; - void setRightItem(QQuickItem *item); - - Q_REVISION(1) Q_INVOKABLE void close(); - -Q_SIGNALS: - void positionChanged(); - void completeChanged(); - /*Q_REVISION(1)*/ void completed(); - void leftChanged(); - void behindChanged(); - void rightChanged(); - void leftItemChanged(); - void behindItemChanged(); - void rightItemChanged(); - -private: - Q_DISABLE_COPY(QQuickSwipe) - Q_DECLARE_PRIVATE(QQuickSwipe) -}; - class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickSwipeDelegateAttached : public QObject { Q_OBJECT diff --git a/src/quicktemplates2/qquickswipedelegate_p_p.h b/src/quicktemplates2/qquickswipedelegate_p_p.h new file mode 100644 index 00000000..0387ad70 --- /dev/null +++ b/src/quicktemplates2/qquickswipedelegate_p_p.h @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** 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 QQUICKSWIPEDELEGATE_P_P_H +#define QQUICKSWIPEDELEGATE_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 <QtQuickTemplates2/private/qquickitemdelegate_p_p.h> +#include <QtQuickTemplates2/private/qquickswipe_p.h> + +QT_BEGIN_NAMESPACE + +class QQuickSwipeDelegate; + +class QQuickSwipeDelegatePrivate : public QQuickItemDelegatePrivate +{ + Q_DECLARE_PUBLIC(QQuickSwipeDelegate) + +public: + QQuickSwipeDelegatePrivate(QQuickSwipeDelegate *control); + + bool handleMousePressEvent(QQuickItem *item, QMouseEvent *event); + bool handleMouseMoveEvent(QQuickItem *item, QMouseEvent *event); + bool handleMouseReleaseEvent(QQuickItem *item, QMouseEvent *event); + + void resizeContent() override; + + QQuickSwipe swipe; +}; + +QT_END_NAMESPACE + +#endif // QQUICKSWIPEDELEGATE_P_P_H diff --git a/src/quicktemplates2/quicktemplates2.pri b/src/quicktemplates2/quicktemplates2.pri index 2c387aa4..fd92e9d1 100644 --- a/src/quicktemplates2/quicktemplates2.pri +++ b/src/quicktemplates2/quicktemplates2.pri @@ -59,7 +59,9 @@ HEADERS += \ $$PWD/qquickstacktransition_p_p.h \ $$PWD/qquickstackview_p.h \ $$PWD/qquickstackview_p_p.h \ + $$PWD/qquickswipe_p.h \ $$PWD/qquickswipedelegate_p.h \ + $$PWD/qquickswipedelegate_p_p.h \ $$PWD/qquickswipeview_p.h \ $$PWD/qquickswitch_p.h \ $$PWD/qquickswitchdelegate_p.h \ diff --git a/tests/auto/controls/data/tst_abstractbutton.qml b/tests/auto/controls/data/tst_abstractbutton.qml index 27fc4525..83ca7980 100644 --- a/tests/auto/controls/data/tst_abstractbutton.qml +++ b/tests/auto/controls/data/tst_abstractbutton.qml @@ -60,6 +60,11 @@ TestCase { Item { } } + Component { + id: signalSpy + SignalSpy { } + } + function test_text() { var control = button.createObject(testCase); verify(control); @@ -103,4 +108,21 @@ TestCase { control.destroy() } + + function test_pressAndHold() { + var control = button.createObject(testCase, {checkable: true}) + verify(control) + + var pressAndHoldSpy = signalSpy.createObject(control, {target: control, signalName: "pressAndHold"}) + verify(pressAndHoldSpy.valid) + + mousePress(control) + pressAndHoldSpy.wait() + compare(control.checked, false) + + mouseRelease(control) + compare(control.checked, false) + + control.destroy() + } } diff --git a/tests/auto/controls/data/tst_swipedelegate.qml b/tests/auto/controls/data/tst_swipedelegate.qml index fa2d218f..92f25e2a 100644 --- a/tests/auto/controls/data/tst_swipedelegate.qml +++ b/tests/auto/controls/data/tst_swipedelegate.qml @@ -377,7 +377,7 @@ TestCase { verify(control.swipe.rightItem); verify(!control.swipe.rightItem.visible); - mouseSignalSequenceSpy.expectedSequence = [["pressedChanged", { "pressed": false }], "released", "clicked"]; + mouseSignalSequenceSpy.expectedSequence = [["pressedChanged", { "pressed": false }], "canceled"]; mouseRelease(control, control.width / 2, control.height / 2); verify(!control.pressed); compare(control.swipe.position, 1.0); @@ -407,7 +407,8 @@ TestCase { compare(completedSpy.count, 1); compare(control.swipe.position, 1.0 - overDragDistance / control.width); - mouseSignalSequenceSpy.expectedSequence = [["pressedChanged", { "pressed": false }], "released", "clicked"]; + // Since we went over the drag distance, we should expect canceled() to be emitted. + mouseSignalSequenceSpy.expectedSequence = [["pressedChanged", { "pressed": false }], "canceled"]; mouseRelease(control, control.width * 0.4, control.height / 2); verify(!control.pressed); compare(control.swipe.position, 1.0); @@ -431,7 +432,7 @@ TestCase { compare(completedSpy.count, 2); compare(control.swipe.position, 0.4); - mouseSignalSequenceSpy.expectedSequence = [["pressedChanged", { "pressed": false }], "released", "clicked"]; + mouseSignalSequenceSpy.expectedSequence = [["pressedChanged", { "pressed": false }], "canceled"]; mouseRelease(control, control.width * -0.1, control.height / 2); verify(!control.pressed); compare(control.swipe.position, 0.0); @@ -1054,17 +1055,17 @@ TestCase { text: "SwipeDelegate" width: 150 - onClicked: close() - swipe.right: Item { width: parent.width height: parent.height + + SwipeDelegate.onClicked: swipe.close() } } } function test_close() { - var control = swipeDelegateComponent.createObject(testCase); + var control = closeSwipeDelegateComponent.createObject(testCase); verify(control); swipe(control, 0.0, -1.0); @@ -1073,6 +1074,16 @@ TestCase { compare(control.swipe.rightItem.x, 0); tryCompare(control.swipe.rightItem, "x", control.background.x + control.background.width); + mousePress(control); + verify(control.swipe.rightItem.SwipeDelegate.pressed); + + mouseRelease(control); + verify(!control.swipe.rightItem.SwipeDelegate.pressed); + tryCompare(control.swipe, "position", 0); + + // Swiping after closing should work as normal. + swipe(control, 0.0, -1.0); + control.destroy(); } @@ -1242,4 +1253,118 @@ TestCase { control.destroy(); } + + function test_releaseOutside_data() { + return [ + { tag: "no delegates", component: emptySwipeDelegateComponent }, + { tag: "delegates", component: swipeDelegateComponent }, + ]; + } + + function test_releaseOutside(data) { + var control = data.component.createObject(testCase); + verify(control); + + // Press and then release below the control. + mouseSignalSequenceSpy.target = control; + mouseSignalSequenceSpy.expectedSequence = [["pressedChanged", { "pressed": true }], "pressed", ["pressedChanged", { "pressed": false }]]; + mousePress(control, control.width / 2, control.height / 2, Qt.LeftButton); + mouseMove(control, control.width / 2, control.height + 10, Qt.LeftButton); + verify(mouseSignalSequenceSpy.success); + + mouseSignalSequenceSpy.expectedSequence = ["canceled"]; + mouseRelease(control, control.width / 2, control.height + 10, Qt.LeftButton); + verify(mouseSignalSequenceSpy.success); + + // Press and then release to the right of the control. + var hasDelegates = control.swipe.left || control.swipe.right || control.swipe.behind; + mouseSignalSequenceSpy.target = control; + mouseSignalSequenceSpy.expectedSequence = hasDelegates + ? [["pressedChanged", { "pressed": true }], "pressed"] + : [["pressedChanged", { "pressed": true }], "pressed", ["pressedChanged", { "pressed": false }]]; + mousePress(control, control.width / 2, control.height / 2, Qt.LeftButton); + mouseMove(control, control.width + 10, control.height / 2, Qt.LeftButton); + if (hasDelegates) + verify(control.swipe.position > 0); + verify(mouseSignalSequenceSpy.success); + + mouseSignalSequenceSpy.expectedSequence = hasDelegates ? [["pressedChanged", { "pressed": false }], "canceled"] : ["canceled"]; + mouseRelease(control, control.width + 10, control.height / 2, Qt.LeftButton); + verify(mouseSignalSequenceSpy.success); + } + + Component { + id: leftRightWithLabelsComponent + + SwipeDelegate { + id: delegate + text: "SwipeDelegate" + width: 150 + + background.opacity: 0.5 + + swipe.left: Rectangle { + width: parent.width + height: parent.height + color: SwipeDelegate.pressed ? Qt.darker("green") : "green" + + property alias label: label + + Label { + id: label + text: "Left" + color: "white" + anchors.margins: 10 + anchors.left: parent.left + anchors.verticalCenter: parent.verticalCenter + } + + SwipeDelegate.onClicked: delegate.swipe.close() + } + + swipe.right: Rectangle { + width: parent.width + height: parent.height + anchors.right: parent.right + color: SwipeDelegate.pressed ? Qt.darker("green") : "red" + + property alias label: label + + Label { + id: label + text: "Right" + color: "white" + anchors.margins: 10 + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + } + + SwipeDelegate.onClicked: delegate.swipe.close() + } + } + } + + function test_beginSwipeOverRightItem() { + var control = leftRightWithLabelsComponent.createObject(testCase); + verify(control); + + // Swipe to the left, exposing the right item. + swipe(control, 0.0, -1.0); + + // Click to close it and go back to a position of 0. + mouseClick(control); + + // TODO: Swipe to the left, with the mouse over the Label in the right item. + // The left item should not become visible at any point. + var rightLabel = control.swipe.rightItem.label; + var overDragDistance = Math.round(dragDistance * 1.1); + mousePress(rightLabel, rightLabel.width / 2, rightLabel.height / 2, Qt.rightButton); + mouseMove(rightLabel, rightLabel.width / 2 - overDragDistance, rightLabel.height / 2, Qt.LeftButton); + verify(!control.swipe.leftItem); + + mouseRelease(rightLabel, rightLabel.width / 2 - overDragDistance, control.height / 2, Qt.LeftButton); + verify(!control.swipe.leftItem); + + control.destroy(); + } } diff --git a/tests/auto/controls/data/tst_tooltip.qml b/tests/auto/controls/data/tst_tooltip.qml index d9c95dbf..51601d66 100644 --- a/tests/auto/controls/data/tst_tooltip.qml +++ b/tests/auto/controls/data/tst_tooltip.qml @@ -240,8 +240,7 @@ TestCase { else control.visible = false verify(control.exit.running) - wait(100) // TODO: replace with tryVerify() in 5.8 - verify(control.opacity < 1) + tryVerify(function() { return control.opacity < 1; }) if (data.imperative) control.open() diff --git a/tests/auto/controls/data/tst_tumbler.qml b/tests/auto/controls/data/tst_tumbler.qml index 8fde5e8c..cde319ea 100644 --- a/tests/auto/controls/data/tst_tumbler.qml +++ b/tests/auto/controls/data/tst_tumbler.qml @@ -83,16 +83,10 @@ TestCase { } function cleanup() { - var destroyed = false; - cleanupItem.Component.destruction.connect(function() { destroyed = true; }); - cleanupItem.destroy(); - // Waiting until it's deleted before continuing makes debugging // test failures much easier, because there aren't unrelated items hanging around. - // TODO: Replace with tryVerify(!tumbler) in 5.8. - while (!destroyed) - wait(0) + tryVerify(function() { return !tumbler; }); } function createTumbler(args) { |