diff options
-rw-r--r-- | src/imports/controls/SwipeDelegate.qml | 18 | ||||
-rw-r--r-- | src/imports/controls/material/SwipeDelegate.qml | 18 | ||||
-rw-r--r-- | src/imports/controls/universal/SwipeDelegate.qml | 18 | ||||
-rw-r--r-- | src/quicktemplates2/qquickswipe_p.h | 8 | ||||
-rw-r--r-- | src/quicktemplates2/qquickswipedelegate.cpp | 109 | ||||
-rw-r--r-- | tests/auto/controls/data/tst_swipedelegate.qml | 31 |
6 files changed, 126 insertions, 76 deletions
diff --git a/src/imports/controls/SwipeDelegate.qml b/src/imports/controls/SwipeDelegate.qml index 099ee117..1c900b52 100644 --- a/src/imports/controls/SwipeDelegate.qml +++ b/src/imports/controls/SwipeDelegate.qml @@ -52,6 +52,8 @@ T.SwipeDelegate { padding: 12 spacing: 12 + swipe.rebound: Transition { SmoothedAnimation { velocity: 3; easing.type: Easing.InOutCubic } } + contentItem: Text { leftPadding: control.mirrored ? (control.indicator ? control.indicator.width : 0) + control.spacing : 0 rightPadding: !control.mirrored ? (control.indicator ? control.indicator.width : 0) + control.spacing : 0 @@ -63,27 +65,11 @@ T.SwipeDelegate { visible: control.text horizontalAlignment: Text.AlignLeft verticalAlignment: Text.AlignVCenter - - Behavior on x { - enabled: !control.down - NumberAnimation { - easing.type: Easing.InOutCubic - duration: 400 - } - } } background: Rectangle { color: control.visualFocus ? (control.down ? Default.focusPressedColor : Default.delegateFocusColor) : (control.down ? Default.delegatePressedColor : Default.backgroundColor) - - Behavior on x { - enabled: !control.down - NumberAnimation { - easing.type: Easing.InOutCubic - duration: 400 - } - } } } diff --git a/src/imports/controls/material/SwipeDelegate.qml b/src/imports/controls/material/SwipeDelegate.qml index c6240910..4247ddf1 100644 --- a/src/imports/controls/material/SwipeDelegate.qml +++ b/src/imports/controls/material/SwipeDelegate.qml @@ -54,6 +54,8 @@ T.SwipeDelegate { bottomPadding: 8 spacing: 16 + swipe.rebound: Transition { SmoothedAnimation { velocity: 3; easing.type: Easing.InOutCubic } } + contentItem: Text { leftPadding: !control.mirrored ? (control.indicator ? control.indicator.width + control.spacing : 0) : 0 rightPadding: control.mirrored ? (control.indicator ? control.indicator.width + control.spacing : 0) : 0 @@ -65,14 +67,6 @@ T.SwipeDelegate { visible: control.text horizontalAlignment: Text.AlignLeft verticalAlignment: Text.AlignVCenter - - Behavior on x { - enabled: !control.down - NumberAnimation { - easing.type: Easing.InOutCubic - duration: 400 - } - } } background: Rectangle { @@ -98,13 +92,5 @@ T.SwipeDelegate { color: control.Material.rippleColor enabled: control.swipe.position === 0 } - - Behavior on x { - enabled: !control.down - NumberAnimation { - easing.type: Easing.InOutCubic - duration: 400 - } - } } } diff --git a/src/imports/controls/universal/SwipeDelegate.qml b/src/imports/controls/universal/SwipeDelegate.qml index 0b888e70..193d1ab1 100644 --- a/src/imports/controls/universal/SwipeDelegate.qml +++ b/src/imports/controls/universal/SwipeDelegate.qml @@ -54,6 +54,8 @@ T.SwipeDelegate { topPadding: padding - 1 bottomPadding: padding + 1 + swipe.rebound: Transition { SmoothedAnimation { velocity: 3; easing.type: Easing.InOutCubic } } + contentItem: Text { leftPadding: !control.mirrored ? (control.indicator ? control.indicator.width : 0) + control.spacing : 0 rightPadding: control.mirrored ? (control.indicator ? control.indicator.width : 0) + control.spacing : 0 @@ -68,14 +70,6 @@ T.SwipeDelegate { opacity: enabled ? 1.0 : 0.2 color: control.Universal.foreground - - Behavior on x { - enabled: !control.down - NumberAnimation { - easing.type: Easing.InOutCubic - duration: 400 - } - } } background: Rectangle { @@ -94,13 +88,5 @@ T.SwipeDelegate { opacity: control.Universal.theme === Universal.Light ? 0.4 : 0.6 } } - - Behavior on x { - enabled: !control.down - NumberAnimation { - easing.type: Easing.InOutCubic - duration: 400 - } - } } } diff --git a/src/quicktemplates2/qquickswipe_p.h b/src/quicktemplates2/qquickswipe_p.h index bedf5b1f..2201bb06 100644 --- a/src/quicktemplates2/qquickswipe_p.h +++ b/src/quicktemplates2/qquickswipe_p.h @@ -56,12 +56,13 @@ QT_BEGIN_NAMESPACE class QQmlComponent; class QQuickItem; +class QQuickTransition; class QQuickSwipePrivate; class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickSwipe : public QObject { Q_OBJECT - Q_PROPERTY(qreal position READ position NOTIFY positionChanged FINAL) + Q_PROPERTY(qreal position READ position WRITE setPosition NOTIFY positionChanged FINAL) Q_PROPERTY(bool complete READ isComplete NOTIFY completeChanged FINAL) Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY enabledChanged FINAL) // REVISION 2 Q_PROPERTY(QQmlComponent *left READ left WRITE setLeft NOTIFY leftChanged FINAL) @@ -70,6 +71,7 @@ class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickSwipe : public QObject 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) + Q_PROPERTY(QQuickTransition *rebound READ rebound WRITE setRebound NOTIFY reboundChanged FINAL) // REVISION 2 public: explicit QQuickSwipe(QQuickSwipeDelegate *control); @@ -101,6 +103,9 @@ public: QQuickItem *rightItem() const; void setRightItem(QQuickItem *item); + QQuickTransition *rebound() const; + void setRebound(QQuickTransition *rebound); + Q_REVISION(2) Q_INVOKABLE void open(QQuickSwipeDelegate::Side side); Q_REVISION(1) Q_INVOKABLE void close(); @@ -115,6 +120,7 @@ Q_SIGNALS: void leftItemChanged(); void behindItemChanged(); void rightItemChanged(); + /*Q_REVISION(2)*/ void reboundChanged(); private: Q_DISABLE_COPY(QQuickSwipe) diff --git a/src/quicktemplates2/qquickswipedelegate.cpp b/src/quicktemplates2/qquickswipedelegate.cpp index 2f7e7382..5504dfc8 100644 --- a/src/quicktemplates2/qquickswipedelegate.cpp +++ b/src/quicktemplates2/qquickswipedelegate.cpp @@ -44,6 +44,9 @@ #include <QtGui/private/qguiapplication_p.h> #include <QtGui/qpa/qplatformtheme.h> #include <QtQml/qqmlinfo.h> +#include <QtQuick/private/qquickanimation_p.h> +#include <QtQuick/private/qquicktransition_p.h> +#include <QtQuick/private/qquicktransitionmanager_p_p.h> QT_BEGIN_NAMESPACE @@ -113,6 +116,48 @@ namespace { }; } +class QQuickSwipeTransitionManager : public QQuickTransitionManager +{ +public: + QQuickSwipeTransitionManager(QQuickSwipe *swipe); + + void transition(QQuickTransition *rebound, qreal position); + +protected: + void finished() override; + +private: + QQuickSwipe *m_swipe; +}; + +QQuickSwipeTransitionManager::QQuickSwipeTransitionManager(QQuickSwipe *swipe) + : m_swipe(swipe) +{ +} + +void QQuickSwipeTransitionManager::transition(QQuickTransition *rebound, qreal position) +{ + qmlExecuteDeferred(rebound); + + QQmlProperty defaultTarget(m_swipe, QLatin1String("position")); + QQmlListProperty<QQuickAbstractAnimation> animations = rebound->animations(); + const int count = animations.count(&animations); + for (int i = 0; i < count; ++i) { + QQuickAbstractAnimation *anim = animations.at(&animations, i); + anim->setDefaultTarget(defaultTarget); + } + + QList<QQuickStateAction> actions; + actions << QQuickStateAction(m_swipe, QLatin1String("position"), position); + QQuickTransitionManager::transition(actions, rebound, m_swipe); +} + +void QQuickSwipeTransitionManager::finished() +{ + const qreal pos = m_swipe->position(); + m_swipe->setComplete(qFuzzyCompare(qAbs(pos), 1.0)); +} + class QQuickSwipePrivate : public QObjectPrivate { Q_DECLARE_PUBLIC(QQuickSwipe) @@ -130,7 +175,9 @@ public: right(nullptr), leftItem(nullptr), behindItem(nullptr), - rightItem(nullptr) + rightItem(nullptr), + rebound(nullptr), + transitionManager(nullptr) { } @@ -152,6 +199,9 @@ public: bool hasDelegates() const; + bool isTransitioning() const; + void transition(qreal position); + 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. @@ -169,6 +219,8 @@ public: QQuickItem *leftItem; QQuickItem *behindItem; QQuickItem *rightItem; + QQuickTransition *rebound; + QScopedPointer<QQuickSwipeTransitionManager> transitionManager; }; QQuickSwipePrivate *QQuickSwipePrivate::get(QQuickSwipe *swipe) @@ -358,6 +410,26 @@ bool QQuickSwipePrivate::hasDelegates() const return left || right || behind; } +bool QQuickSwipePrivate::isTransitioning() const +{ + return transitionManager && transitionManager->isRunning(); +} + +void QQuickSwipePrivate::transition(qreal position) +{ + Q_Q(QQuickSwipe); + if (!rebound) { + q->setPosition(position); + q->setComplete(qFuzzyCompare(qAbs(position), 1.0)); + return; + } + + if (!transitionManager) + transitionManager.reset(new QQuickSwipeTransitionManager(q)); + + transitionManager->transition(rebound, position); +} + QQuickSwipe::QQuickSwipe(QQuickSwipeDelegate *control) : QObject(*(new QQuickSwipePrivate(control))) { @@ -592,6 +664,22 @@ void QQuickSwipe::setEnabled(bool enabled) emit enabledChanged(); } +QQuickTransition *QQuickSwipe::rebound() const +{ + Q_D(const QQuickSwipe); + return d->rebound; +} + +void QQuickSwipe::setRebound(QQuickTransition *rebound) +{ + Q_D(QQuickSwipe); + if (rebound == d->rebound) + return; + + d->rebound = rebound; + emit reboundChanged(); +} + void QQuickSwipe::open(QQuickSwipeDelegate::Side side) { Q_D(QQuickSwipe); @@ -600,8 +688,7 @@ void QQuickSwipe::open(QQuickSwipeDelegate::Side side) || (!d->right && !d->behind && side == QQuickSwipeDelegate::Right)) return; - setPosition(side); - setComplete(true); + d->transition(side); d->wasComplete = true; d->velocityCalculator.reset(); d->positionBeforePress = d->position; @@ -610,8 +697,7 @@ void QQuickSwipe::open(QQuickSwipeDelegate::Side side) void QQuickSwipe::close() { Q_D(QQuickSwipe); - setPosition(0); - setComplete(false); + d->transition(0.0); d->wasComplete = false; d->positionBeforePress = 0.0; d->velocityCalculator.reset(); @@ -748,6 +834,8 @@ bool QQuickSwipeDelegatePrivate::handleMouseMoveEvent(QQuickItem *item, QMouseEv position = distance > 0 ? normalizedDistance - 1.0 : normalizedDistance + 1.0; } + if (swipePrivate->isTransitioning()) + swipePrivate->transitionManager->cancel(); swipe.setPosition(position); } } else { @@ -794,17 +882,14 @@ bool QQuickSwipeDelegatePrivate::handleMouseReleaseEvent(QQuickItem *item, QMous const qreal swipeVelocity = swipePrivate->velocityCalculator.velocity().x(); if (swipePrivate->position > 0.5 || (swipePrivate->position > 0.0 && swipeVelocity > exposeVelocityThreshold)) { - swipe.setPosition(1.0); - swipe.setComplete(true); + swipePrivate->transition(1.0); swipePrivate->wasComplete = true; } else if (swipePrivate->position < -0.5 || (swipePrivate->position < 0.0 && swipeVelocity < -exposeVelocityThreshold)) { - swipe.setPosition(-1.0); - swipe.setComplete(true); + swipePrivate->transition(-1.0); swipePrivate->wasComplete = true; - } else { - swipe.setPosition(0.0); - swipe.setComplete(false); + } else if (!swipePrivate->isTransitioning()) { + swipePrivate->transition(0.0); swipePrivate->wasComplete = false; } diff --git a/tests/auto/controls/data/tst_swipedelegate.qml b/tests/auto/controls/data/tst_swipedelegate.qml index a6e11246..27a1028b 100644 --- a/tests/auto/controls/data/tst_swipedelegate.qml +++ b/tests/auto/controls/data/tst_swipedelegate.qml @@ -40,7 +40,7 @@ import QtQuick 2.6 import QtTest 1.0 -import QtQuick.Controls 2.1 +import QtQuick.Controls 2.2 TestCase { @@ -380,8 +380,8 @@ TestCase { mouseSignalSequenceSpy.expectedSequence = [["pressedChanged", { "pressed": false }], "canceled"]; mouseRelease(control, control.width / 2, control.height / 2); verify(!control.pressed); - compare(control.swipe.position, 1.0); - verify(control.swipe.complete); + tryCompare(control.swipe, "position", 1.0); + tryCompare(control.swipe, "complete", true); compare(completedSpy.count, 1); verify(mouseSignalSequenceSpy.success); verify(control.swipe.leftItem); @@ -411,8 +411,8 @@ TestCase { mouseSignalSequenceSpy.expectedSequence = [["pressedChanged", { "pressed": false }], "canceled"]; mouseRelease(control, control.width * 0.4, control.height / 2); verify(!control.pressed); - compare(control.swipe.position, 1.0); - verify(control.swipe.complete); + tryCompare(control.swipe, "position", 1.0); + tryCompare(control.swipe, "complete", true); compare(completedSpy.count, 2); verify(mouseSignalSequenceSpy.success); tryCompare(control.contentItem, "x", control.width + control.leftPadding); @@ -435,7 +435,7 @@ TestCase { mouseSignalSequenceSpy.expectedSequence = [["pressedChanged", { "pressed": false }], "canceled"]; mouseRelease(control, control.width * -0.1, control.height / 2); verify(!control.pressed); - compare(control.swipe.position, 0.0); + tryCompare(control.swipe, "position", 0.0); verify(!control.swipe.complete); compare(completedSpy.count, 2); verify(mouseSignalSequenceSpy.success); @@ -572,7 +572,7 @@ TestCase { // Returning back to a position of 0 and pressing on the control should // result in the control being pressed. mouseDrag(control, control.width / 2, control.height / 2, control.width * 0.6, 0); - compare(control.swipe.position, 0); + tryCompare(control.swipe, "position", 0); mousePress(control, control.width / 2, control.height / 2); verify(control.pressed); verify(!button.pressed); @@ -730,8 +730,8 @@ TestCase { mouseRelease(listView, firstItem.width / 2, firstItem.height / 2); verify(!firstItem.pressed); - compare(firstItem.swipe.position, 1.0); - verify(firstItem.swipe.complete); + tryCompare(firstItem.swipe, "position", 1.0); + tryCompare(firstItem.swipe, "complete", true); compare(listView.count, 3); // Wait for it to settle down. @@ -1032,7 +1032,7 @@ TestCase { mouseMove(control, control.width / 2 + control.swipe.behindItem.width * 0.8, control.height / 2, Qt.LeftButton); compare(control.swipe.position, -0.2); mouseRelease(control, control.width / 2 + control.swipe.behindItem.width * 0.8, control.height / 2, Qt.LeftButton); - compare(control.swipe.position, 0.0); + tryCompare(control.swipe, "position", 0.0); // Try wrapping the other way. swipe(control, 0.0, -1.0); @@ -1043,7 +1043,7 @@ TestCase { mouseMove(control, control.width / 2 - control.swipe.behindItem.width * 0.8, control.height / 2, Qt.LeftButton); compare(control.swipe.position, 0.2); mouseRelease(control, control.width / 2 - control.swipe.behindItem.width * 0.8, control.height / 2, Qt.LeftButton); - compare(control.swipe.position, 0.0); + tryCompare(control.swipe, "position", 0.0); control.destroy(); } @@ -1475,8 +1475,8 @@ TestCase { verify(control); control.swipe.open(data.side); - compare(control.swipe.position, data.position); - compare(control.swipe.complete, data.complete); + tryCompare(control.swipe, "position", data.position); + tryCompare(control.swipe, "complete", data.complete); control.destroy(); } @@ -1502,12 +1502,12 @@ TestCase { verify(control); mouseClick(control); - compare(control.swipe.position, SwipeDelegate.Right); + tryCompare(control.swipe, "position", SwipeDelegate.Right); tryCompare(control.background, "x", -control.background.width); // Swiping after opening should work as normal. swipe(control, SwipeDelegate.Right, 0.0); - compare(control.swipe.position, 0.0); + tryCompare(control.swipe, "position", 0.0); tryCompare(control.background, "x", 0); control.destroy(); @@ -1522,6 +1522,7 @@ TestCase { width: 150 swipe.left: greenLeftComponent swipe.right: redRightComponent + swipe.rebound: null property alias behavior: xBehavior property alias animation: numberAnimation |