aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--examples/quickcontrols2/gallery/pages/DelegatePage.qml6
-rw-r--r--src/imports/controls/doc/snippets/qtquickcontrols2-swipedelegate-custom.qml2
-rw-r--r--src/quicktemplates2/qquickswipedelegate.cpp203
-rw-r--r--src/quicktemplates2/qquickswipedelegate_p.h25
-rw-r--r--tests/auto/controls/data/tst_swipedelegate.qml168
5 files changed, 385 insertions, 19 deletions
diff --git a/examples/quickcontrols2/gallery/pages/DelegatePage.qml b/examples/quickcontrols2/gallery/pages/DelegatePage.qml
index ed817938..525487d1 100644
--- a/examples/quickcontrols2/gallery/pages/DelegatePage.qml
+++ b/examples/quickcontrols2/gallery/pages/DelegatePage.qml
@@ -70,17 +70,17 @@ Pane {
text: labelText
width: parent.width
- onClicked: if (swipe.complete) view.model.remove(ourIndex)
-
Component {
id: removeComponent
Rectangle {
- color: swipeDelegate.swipe.complete && swipeDelegate.pressed ? "#333" : "#444"
+ color: SwipeDelegate.pressed ? "#333" : "#444"
width: parent.width
height: parent.height
clip: true
+ SwipeDelegate.onClicked: view.model.remove(ourIndex)
+
Label {
font.pixelSize: swipeDelegate.font.pixelSize
text: "Remove"
diff --git a/src/imports/controls/doc/snippets/qtquickcontrols2-swipedelegate-custom.qml b/src/imports/controls/doc/snippets/qtquickcontrols2-swipedelegate-custom.qml
index c30dd76f..087e17fe 100644
--- a/src/imports/controls/doc/snippets/qtquickcontrols2-swipedelegate-custom.qml
+++ b/src/imports/controls/doc/snippets/qtquickcontrols2-swipedelegate-custom.qml
@@ -37,7 +37,7 @@ SwipeDelegate {
id: component
Rectangle {
- color: control.swipe.complete && control.down ? "#333" : "#444"
+ color: SwipeDelegate.pressed ? "#333" : "#444"
width: parent.width
height: parent.height
clip: true
diff --git a/src/quicktemplates2/qquickswipedelegate.cpp b/src/quicktemplates2/qquickswipedelegate.cpp
index a8ba2e80..04f3f7cf 100644
--- a/src/quicktemplates2/qquickswipedelegate.cpp
+++ b/src/quicktemplates2/qquickswipedelegate.cpp
@@ -92,6 +92,14 @@ QT_BEGIN_NAMESPACE
\sa {Customizing SwipeDelegate}, {Delegate Controls}
*/
+namespace {
+ typedef QQuickSwipeDelegateAttached Attached;
+
+ Attached *attachedObject(QQuickItem *item) {
+ return qobject_cast<Attached*>(qmlAttachedPropertiesObject<QQuickSwipeDelegate>(item, false));
+ }
+}
+
class QQuickSwipePrivate : public QObjectPrivate
{
Q_DECLARE_PUBLIC(QQuickSwipe)
@@ -561,9 +569,22 @@ bool QQuickSwipeDelegatePrivate::handleMousePressEvent(QQuickItem *item, QMouseE
return true;
}
+ // The position is non-zero, this press could be either for a delegate or the control itself
+ // (the control can be clicked to e.g. close the swipe). Either way, we must begin measuring
+ // mouse movement in case it turns into a swipe, in which case we grab the mouse.
swipePrivate->positionBeforePress = swipePrivate->position;
swipePrivate->velocityCalculator.startMeasuring(event->pos(), event->timestamp());
pressPoint = item->mapToItem(q, event->pos());
+
+ // When a delegate uses the attached properties and signals, it declares that it wants mouse events.
+ Attached *attached = attachedObject(item);
+ if (attached) {
+ attached->setPressed(true);
+ // Stop the event from propagating, as QQuickItem explicitly ignores events.
+ event->accept();
+ return true;
+ }
+
return false;
}
@@ -589,7 +610,8 @@ bool QQuickSwipeDelegatePrivate::handleMouseMoveEvent(QQuickItem *item, QMouseEv
if (item == q && !pressed)
return false;
- const qreal distance = (event->pos() - pressPoint).x();
+ const QPointF mappedEventPos = item->mapToItem(q, event->pos());
+ const qreal distance = (mappedEventPos - pressPoint).x();
if (!q->keepMouseGrab()) {
// Taken from QQuickDrawer::handleMouseMoveEvent; see comments there.
int threshold = qMax(20, QGuiApplication::styleHints()->startDragDistance() + 5);
@@ -598,9 +620,12 @@ bool QQuickSwipeDelegatePrivate::handleMouseMoveEvent(QQuickItem *item, QMouseEv
QQuickItem *grabber = q->window()->mouseGrabberItem();
if (!grabber || !grabber->keepMouseGrab()) {
q->grabMouse();
- q->setKeepMouseGrab(overThreshold);
+ q->setKeepMouseGrab(true);
q->setPressed(true);
swipe.setComplete(false);
+
+ if (Attached *attached = attachedObject(item))
+ attached->setPressed(false);
}
}
}
@@ -660,7 +685,7 @@ bool QQuickSwipeDelegatePrivate::handleMouseMoveEvent(QQuickItem *item, QMouseEv
static const qreal exposeVelocityThreshold = 300.0;
-bool QQuickSwipeDelegatePrivate::handleMouseReleaseEvent(QQuickItem *, QMouseEvent *event)
+bool QQuickSwipeDelegatePrivate::handleMouseReleaseEvent(QQuickItem *item, QMouseEvent *event)
{
Q_Q(QQuickSwipeDelegate);
QQuickSwipePrivate *swipePrivate = QQuickSwipePrivate::get(&swipe);
@@ -687,6 +712,14 @@ bool QQuickSwipeDelegatePrivate::handleMouseReleaseEvent(QQuickItem *, QMouseEve
swipePrivate->wasComplete = false;
}
+ if (Attached *attached = attachedObject(item)) {
+ const bool wasPressed = attached->isPressed();
+ if (wasPressed) {
+ attached->setPressed(false);
+ emit attached->clicked();
+ }
+ }
+
// Only consume child events if we had grabbed the mouse.
return hadGrabbedMouse;
}
@@ -805,6 +838,11 @@ QQuickSwipe *QQuickSwipeDelegate::swipe() const
return const_cast<QQuickSwipe*>(&d->swipe);
}
+QQuickSwipeDelegateAttached *QQuickSwipeDelegate::qmlAttachedProperties(QObject *object)
+{
+ return new QQuickSwipeDelegateAttached(object);
+}
+
static bool isChildOrGrandchildOf(QQuickItem *child, QQuickItem *item)
{
return item && (child == item || item->isAncestorOf(child));
@@ -835,6 +873,14 @@ bool QQuickSwipeDelegate::childMouseEventFilter(QQuickItem *child, QEvent *event
QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
QQuickItemDelegate::mouseReleaseEvent(mouseEvent);
return d->handleMouseReleaseEvent(child, mouseEvent);
+ } case QEvent::UngrabMouse: {
+ // If the mouse was pressed over e.g. rightItem and then dragged down,
+ // the ListView would eventually grab the mouse, at which point we must
+ // clear the pressed flag so that it doesn't stay pressed after the release.
+ Attached *attached = attachedObject(child);
+ if (attached)
+ attached->setPressed(false);
+ return false;
} default:
return false;
}
@@ -876,4 +922,155 @@ QAccessible::Role QQuickSwipeDelegate::accessibleRole() const
}
#endif
+class QQuickSwipeDelegateAttachedPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickSwipeDelegateAttached)
+
+public:
+ QQuickSwipeDelegateAttachedPrivate() :
+ pressed(false)
+ {
+ }
+
+ // True when left/right/behind is non-interactive and is pressed.
+ bool pressed;
+};
+
+/*!
+ \since QtQuick.Controls 2.1
+ \qmlattachedsignal QtQuick.Controls::SwipeDelegate::clicked()
+
+ This signal can be attached to a non-interactive item declared in
+ \c swipe.left, \c swipe.right, or \c swipe.behind, in order to react to
+ clicks. Items can only be clicked when \c swipe.complete is \c true.
+
+ For interactive controls (such as \l Button) declared in these
+ items, use their respective \c clicked() signal instead.
+
+ To respond to clicks on the SwipeDelegate itself, use its
+ \l {AbstractButton::}{clicked()} signal.
+
+ \note See the documentation for \l pressed for information on
+ how to use the event-related properties correctly.
+
+ \sa pressed
+*/
+
+QQuickSwipeDelegateAttached::QQuickSwipeDelegateAttached(QObject *object) :
+ QObject(*(new QQuickSwipeDelegateAttachedPrivate), object)
+{
+ QQuickItem *item = qobject_cast<QQuickItem *>(object);
+ if (item) {
+ // This allows us to be notified when an otherwise non-interactive item
+ // is pressed and clicked. The alternative is much more more complex:
+ // iterating through children that contain the event pos and finding
+ // the first one with an attached object.
+ item->setAcceptedMouseButtons(Qt::AllButtons);
+ } else {
+ qWarning() << "Attached properties of SwipeDelegate must be accessed through an Item";
+ }
+}
+
+/*!
+ \since QtQuick.Controls 2.1
+ \qmlattachedproperty bool QtQuick.Controls::SwipeDelegate::pressed
+ \readonly
+
+ This property can be attached to a non-interactive item declared in
+ \c swipe.left, \c swipe.right, or \c swipe.behind, in order to detect if it
+ is pressed. Items can only be pressed when \c swipe.complete is \c true.
+
+ For example:
+
+ \code
+ swipe.right: Label {
+ anchors.right: parent.right
+ height: parent.height
+ text: "Action"
+ color: "white"
+ padding: 12
+ background: Rectangle {
+ color: SwipeDelegate.pressed ? Qt.darker("tomato", 1.1) : "tomato"
+ }
+ }
+ \endcode
+
+ It is possible to have multiple items which individually receive mouse and
+ touch events. For example, to have two actions in the \c swipe.right item,
+ use the following code:
+
+ \code
+ swipe.right: Row {
+ anchors.right: parent.right
+ height: parent.height
+
+ Label {
+ id: moveLabel
+ text: qsTr("Move")
+ color: "white"
+ verticalAlignment: Label.AlignVCenter
+ padding: 12
+ height: parent.height
+
+ SwipeDelegate.onClicked: console.log("Moving...")
+
+ background: Rectangle {
+ color: moveLabel.SwipeDelegate.pressed ? Qt.darker("#ffbf47", 1.1) : "#ffbf47"
+ }
+ }
+ Label {
+ id: deleteLabel
+ text: qsTr("Delete")
+ color: "white"
+ verticalAlignment: Label.AlignVCenter
+ padding: 12
+ height: parent.height
+
+ SwipeDelegate.onClicked: console.log("Deleting...")
+
+ background: Rectangle {
+ color: deleteLabel.SwipeDelegate.pressed ? Qt.darker("tomato", 1.1) : "tomato"
+ }
+ }
+ }
+ \endcode
+
+ Note how the \c color assignment in each \l {Control::}{background} item
+ qualifies the attached property with the \c id of the label. This
+ is important; using the attached properties on an item causes that item
+ to accept events. Suppose we had left out the \c id in the previous example:
+
+ \code
+ color: SwipeDelegate.pressed ? Qt.darker("tomato", 1.1) : "tomato"
+ \endcode
+
+ The \l Rectangle background item is a child of the label, so it naturally
+ receives events before it. In practice, this means that the background
+ color will change, but the \c onClicked handler in the label will never
+ get called.
+
+ For interactive controls (such as \l Button) declared in these
+ items, use their respective \c pressed property instead.
+
+ For presses on the SwipeDelegate itself, use its
+ \l {AbstractButton::}{pressed} property.
+
+ \sa clicked()
+*/
+bool QQuickSwipeDelegateAttached::isPressed() const
+{
+ Q_D(const QQuickSwipeDelegateAttached);
+ return d->pressed;
+}
+
+void QQuickSwipeDelegateAttached::setPressed(bool pressed)
+{
+ Q_D(QQuickSwipeDelegateAttached);
+ if (pressed == d->pressed)
+ return;
+
+ d->pressed = pressed;
+ emit pressedChanged();
+}
+
QT_END_NAMESPACE
diff --git a/src/quicktemplates2/qquickswipedelegate_p.h b/src/quicktemplates2/qquickswipedelegate_p.h
index f94219cd..7ef995d1 100644
--- a/src/quicktemplates2/qquickswipedelegate_p.h
+++ b/src/quicktemplates2/qquickswipedelegate_p.h
@@ -54,6 +54,8 @@ QT_BEGIN_NAMESPACE
class QQuickSwipeDelegatePrivate;
class QQuickSwipe;
+class QQuickSwipeDelegateAttached;
+class QQuickSwipeDelegateAttachedPrivate;
class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickSwipeDelegate : public QQuickItemDelegate
{
@@ -65,6 +67,8 @@ public:
QQuickSwipe *swipe() const;
+ static QQuickSwipeDelegateAttached *qmlAttachedProperties(QObject *object);
+
protected:
bool childMouseEventFilter(QQuickItem *child, QEvent *event) override;
void mousePressEvent(QMouseEvent *event) override;
@@ -141,8 +145,29 @@ private:
Q_DECLARE_PRIVATE(QQuickSwipe)
};
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickSwipeDelegateAttached : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(bool pressed READ isPressed NOTIFY pressedChanged FINAL)
+
+public:
+ explicit QQuickSwipeDelegateAttached(QObject *object = nullptr);
+
+ bool isPressed() const;
+ void setPressed(bool pressed);
+
+Q_SIGNALS:
+ void pressedChanged();
+ void clicked();
+
+private:
+ Q_DISABLE_COPY(QQuickSwipeDelegateAttached)
+ Q_DECLARE_PRIVATE(QQuickSwipeDelegateAttached)
+};
+
QT_END_NAMESPACE
QML_DECLARE_TYPE(QQuickSwipeDelegate)
+QML_DECLARE_TYPEINFO(QQuickSwipeDelegate, QML_HAS_ATTACHED_PROPERTIES)
#endif // QQUICKSWIPEDELEGATE_P_H
diff --git a/tests/auto/controls/data/tst_swipedelegate.qml b/tests/auto/controls/data/tst_swipedelegate.qml
index b034ca36..e2f94076 100644
--- a/tests/auto/controls/data/tst_swipedelegate.qml
+++ b/tests/auto/controls/data/tst_swipedelegate.qml
@@ -40,6 +40,7 @@
import QtQuick 2.6
import QtTest 1.0
+import QtQuick.Layouts 1.1
import QtQuick.Controls 2.1
TestCase {
@@ -138,7 +139,7 @@ TestCase {
verify(control);
ignoreWarning(Qt.resolvedUrl("tst_swipedelegate.qml") +
- ":78:9: QML SwipeDelegate: cannot set both behind and left/right properties")
+ ":79:9: QML SwipeDelegate: cannot set both behind and left/right properties")
control.swipe.behind = itemComponent;
// Shouldn't be any warnings when unsetting delegates.
@@ -147,7 +148,7 @@ TestCase {
// right is still set.
ignoreWarning(Qt.resolvedUrl("tst_swipedelegate.qml") +
- ":78:9: QML SwipeDelegate: cannot set both behind and left/right properties")
+ ":79:9: QML SwipeDelegate: cannot set both behind and left/right properties")
control.swipe.behind = itemComponent;
control.swipe.right = null;
@@ -156,11 +157,11 @@ TestCase {
control.swipe.behind = itemComponent;
ignoreWarning(Qt.resolvedUrl("tst_swipedelegate.qml") +
- ":78:9: QML SwipeDelegate: cannot set both behind and left/right properties")
+ ":79:9: QML SwipeDelegate: cannot set both behind and left/right properties")
control.swipe.left = itemComponent;
ignoreWarning(Qt.resolvedUrl("tst_swipedelegate.qml") +
- ":78:9: QML SwipeDelegate: cannot set both behind and left/right properties")
+ ":79:9: QML SwipeDelegate: cannot set both behind and left/right properties")
control.swipe.right = itemComponent;
control.swipe.behind = null;
@@ -175,7 +176,7 @@ TestCase {
var oldLeft = control.swipe.left;
var oldLeftItem = control.swipe.leftItem;
ignoreWarning(Qt.resolvedUrl("tst_swipedelegate.qml") +
- ":78:9: QML SwipeDelegate: left/right/behind properties may only be set when swipe.position is 0")
+ ":79:9: QML SwipeDelegate: left/right/behind properties may only be set when swipe.position is 0")
control.swipe.left = null;
compare(control.swipe.left, oldLeft);
compare(control.swipe.leftItem, oldLeftItem);
@@ -186,7 +187,7 @@ TestCase {
var oldRight = control.swipe.right;
var oldRightItem = control.swipe.rightItem;
ignoreWarning(Qt.resolvedUrl("tst_swipedelegate.qml") +
- ":78:9: QML SwipeDelegate: left/right/behind properties may only be set when swipe.position is 0")
+ ":79:9: QML SwipeDelegate: left/right/behind properties may only be set when swipe.position is 0")
control.swipe.right = null;
compare(control.swipe.right, oldRight);
compare(control.swipe.rightItem, oldRightItem);
@@ -212,7 +213,7 @@ TestCase {
var oldBehind = control.swipe.behind;
var oldBehindItem = control.swipe.behindItem;
ignoreWarning(Qt.resolvedUrl("tst_swipedelegate.qml") +
- ":78:9: QML SwipeDelegate: left/right/behind properties may only be set when swipe.position is 0")
+ ":79:9: QML SwipeDelegate: left/right/behind properties may only be set when swipe.position is 0")
control.swipe.behind = null;
compare(control.swipe.behind, oldBehind);
compare(control.swipe.behindItem, oldBehindItem);
@@ -564,8 +565,6 @@ TestCase {
text: modelData
width: listView.width
- onClicked: if (swipe.complete) ListView.view.model.remove(index)
-
property alias removeAnimation: onRemoveAnimation
ListView.onRemove: SequentialAnimation {
@@ -590,9 +589,12 @@ TestCase {
}
swipe.left: Rectangle {
- color: rootDelegate.swipe.complete && rootDelegate.pressed ? "#333" : "#444"
+ objectName: "rectangle"
+ color: SwipeDelegate.pressed ? "#333" : "#444"
anchors.fill: parent
+ SwipeDelegate.onClicked: listView.model.remove(index)
+
Label {
objectName: "label"
text: "Remove"
@@ -615,11 +617,14 @@ TestCase {
verify(firstItem.pressed);
compare(firstItem.swipe.position, 0.0);
verify(!firstItem.swipe.complete);
+ verify(!firstItem.swipe.leftItem);
mouseMove(listView, firstItem.width * 1.1, firstItem.height / 2);
verify(firstItem.pressed);
compare(firstItem.swipe.position, 0.6);
verify(!firstItem.swipe.complete);
+ verify(firstItem.swipe.leftItem);
+ verify(!firstItem.swipe.leftItem.SwipeDelegate.pressed);
mouseRelease(listView, firstItem.width / 2, firstItem.height / 2);
verify(!firstItem.pressed);
@@ -630,9 +635,23 @@ TestCase {
// Wait for it to settle down.
tryCompare(firstItem.contentItem, "x", firstItem.leftPadding + firstItem.width);
- // Click the button to remove the item.
+ var leftClickedSpy = signalSpyComponent.createObject(firstItem.swipe.leftItem,
+ { target: firstItem.swipe.leftItem.SwipeDelegate, signalName: "clicked" });
+ verify(leftClickedSpy);
+ verify(leftClickedSpy.valid);
+
+ // Click the left item to remove the delegate from the list.
var contentItemX = firstItem.contentItem.x;
- mouseClick(listView, firstItem.width / 2, firstItem.height / 2);
+ mousePress(listView, firstItem.width / 2, firstItem.height / 2);
+ verify(firstItem.swipe.leftItem.SwipeDelegate.pressed);
+ compare(leftClickedSpy.count, 0);
+ verify(!firstItem.pressed);
+
+ mouseRelease(listView, firstItem.width / 2, firstItem.height / 2);
+ verify(!firstItem.swipe.leftItem.SwipeDelegate.pressed);
+ compare(leftClickedSpy.count, 1);
+ verify(!firstItem.pressed);
+ leftClickedSpy = null;
tryCompare(firstItem.removeAnimation, "running", true);
// There was a bug where the resizeContent() would be called because the height
// of the control was changing due to the animation. contentItem would then
@@ -955,4 +974,129 @@ TestCase {
control.destroy();
}
+
+ Component {
+ id: multiActionSwipeDelegateComponent
+
+ SwipeDelegate {
+ text: "SwipeDelegate"
+ width: 150
+
+ swipe.right: Item {
+ objectName: "rightItemRoot"
+ width: parent.width
+ height: parent.height
+
+ property alias firstAction: firstAction
+ property alias secondAction: secondAction
+
+ property int firstClickCount: 0
+ property int secondClickCount: 0
+
+ RowLayout {
+ anchors.fill: parent
+ anchors.margins: 5
+
+ Rectangle {
+ id: firstAction
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ color: "tomato"
+
+ SwipeDelegate.onClicked: ++firstClickCount
+ }
+ Rectangle {
+ id: secondAction
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ color: "navajowhite"
+
+ SwipeDelegate.onClicked: ++secondClickCount
+ }
+ }
+ }
+ }
+ }
+
+ // Tests that it's possible to have multiple non-interactive items in one delegate
+ // (e.g. left/right/behind) that can each receive clicks.
+ function test_multipleClickableActions() {
+ var control = multiActionSwipeDelegateComponent.createObject(testCase);
+ verify(control);
+
+ swipe(control, 0.0, -1.0);
+ verify(control.swipe.rightItem);
+ tryCompare(control.swipe, "complete", true);
+
+ var firstClickedSpy = signalSpyComponent.createObject(control,
+ { target: control.swipe.rightItem.firstAction.SwipeDelegate, signalName: "clicked" });
+ verify(firstClickedSpy);
+ verify(firstClickedSpy.valid);
+
+ // Clicked within rightItem, but not within an item using the attached properties.
+ mousePress(control, 2, 2);
+ compare(control.swipe.rightItem.firstAction.SwipeDelegate.pressed, false);
+ compare(firstClickedSpy.count, 0);
+
+ mouseRelease(control, 2, 2);
+ compare(control.swipe.rightItem.firstAction.SwipeDelegate.pressed, false);
+ compare(firstClickedSpy.count, 0);
+
+ // Click within the first item.
+ mousePress(control.swipe.rightItem.firstAction, 0, 0);
+ compare(control.swipe.rightItem.firstAction.SwipeDelegate.pressed, true);
+ compare(firstClickedSpy.count, 0);
+
+ mouseRelease(control.swipe.rightItem.firstAction, 0, 0);
+ compare(control.swipe.rightItem.firstAction.SwipeDelegate.pressed, false);
+ compare(firstClickedSpy.count, 1);
+ compare(control.swipe.rightItem.firstClickCount, 1);
+
+ var secondClickedSpy = signalSpyComponent.createObject(control,
+ { target: control.swipe.rightItem.secondAction.SwipeDelegate, signalName: "clicked" });
+ verify(secondClickedSpy);
+ verify(secondClickedSpy.valid);
+
+ // Click within the second item.
+ mousePress(control.swipe.rightItem.secondAction, 0, 0);
+ compare(control.swipe.rightItem.secondAction.SwipeDelegate.pressed, true);
+ compare(secondClickedSpy.count, 0);
+
+ mouseRelease(control.swipe.rightItem.secondAction, 0, 0);
+ compare(control.swipe.rightItem.secondAction.SwipeDelegate.pressed, false);
+ compare(secondClickedSpy.count, 1);
+ compare(control.swipe.rightItem.secondClickCount, 1);
+
+ control.destroy();
+ }
+
+ // Pressing on a "side action" and then dragging should eventually
+ // cause the ListView to grab the mouse and start changing its contentY.
+ // When this happens, it will grab the mouse and hence we must clear
+ // that action's pressed state so that it doesn't stay pressed after releasing.
+ function test_dragSideAction() {
+ var listView = removableDelegatesComponent.createObject(testCase);
+ verify(listView);
+
+ var control = listView.itemAt(0, 0);
+ verify(control);
+
+ // Expose the side action.
+ swipe(control, 0.0, 1.0);
+ verify(control.swipe.leftItem);
+ tryCompare(control.swipe, "complete", true);
+
+ var pressedSpy = signalSpyComponent.createObject(control,
+ { target: control.swipe.leftItem.SwipeDelegate, signalName: "pressedChanged" });
+ verify(pressedSpy);
+ verify(pressedSpy.valid);
+
+ mouseDrag(listView, 20, 20, 0, listView.height);
+ compare(pressedSpy.count, 2);
+ verify(listView.contentY !== 0);
+
+ compare(control.swipe.leftItem.SwipeDelegate.pressed, false);
+
+ listView.destroy();
+ }
}