aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/quick/items/qquickcanvas.cpp595
-rw-r--r--src/quick/items/qquickcanvas_p.h11
-rw-r--r--src/quick/items/qquickevents_p_p.h69
-rw-r--r--src/quick/items/qquickflickable.cpp58
-rw-r--r--src/quick/items/qquickitem.cpp7
-rw-r--r--src/quick/items/qquickitem.h2
-rw-r--r--src/quick/items/qquickmultipointtoucharea.cpp2
-rw-r--r--src/quick/items/qquickpincharea.cpp138
-rw-r--r--src/quick/items/qquickpincharea_p.h5
-rw-r--r--tests/auto/quick/qquickcanvas/tst_qquickcanvas.cpp229
-rw-r--r--tests/auto/quick/qquickmultipointtoucharea/tst_qquickmultipointtoucharea.cpp14
-rw-r--r--tests/auto/quick/qquickpincharea/data/pinchproperties.qml3
-rw-r--r--tests/auto/quick/qquickpincharea/tst_qquickpincharea.cpp156
-rw-r--r--tests/auto/quick/quick.pro1
-rw-r--r--tests/auto/quick/touchmouse/data/buttononflickable.qml42
-rw-r--r--tests/auto/quick/touchmouse/data/buttonontouch.qml100
-rw-r--r--tests/auto/quick/touchmouse/data/flickableonpinch.qml37
-rw-r--r--tests/auto/quick/touchmouse/data/mouseonflickableonpinch.qml47
-rw-r--r--tests/auto/quick/touchmouse/data/pinchonflickable.qml35
-rw-r--r--tests/auto/quick/touchmouse/data/singleitem.qml18
-rw-r--r--tests/auto/quick/touchmouse/data/twoitems.qml22
-rw-r--r--tests/auto/quick/touchmouse/touchmouse.pro17
-rw-r--r--tests/auto/quick/touchmouse/tst_touchmouse.cpp923
23 files changed, 2007 insertions, 524 deletions
diff --git a/src/quick/items/qquickcanvas.cpp b/src/quick/items/qquickcanvas.cpp
index 7c59a9df9e..37c238fd21 100644
--- a/src/quick/items/qquickcanvas.cpp
+++ b/src/quick/items/qquickcanvas.cpp
@@ -72,8 +72,6 @@
QT_BEGIN_NAMESPACE
-DEFINE_BOOL_CONFIG_OPTION(qmlTranslateTouchToMouse, QML_TRANSLATE_TOUCH_TO_MOUSE)
-
void QQuickCanvasPrivate::updateFocusItemTransform()
{
Q_Q(QQuickCanvas);
@@ -395,25 +393,39 @@ void QQuickCanvasPrivate::initRootItem()
rootItem->setHeight(q->height());
}
-static QQuickMouseEventEx touchToMouseEvent(QEvent::Type type, const QTouchEvent::TouchPoint &p)
+static QMouseEvent *touchToMouseEvent(QEvent::Type type, const QTouchEvent::TouchPoint &p, QTouchEvent *event, QQuickItem *item, bool transformNeeded = true)
{
- QQuickMouseEventEx me(type, p.pos(), p.scenePos(), p.screenPos(),
- Qt::LeftButton, Qt::LeftButton, 0);
- me.setVelocity(p.velocity());
+ // The touch point local position and velocity are not yet transformed.
+ QMouseEvent *me = new QMouseEvent(type, transformNeeded ? item->mapFromScene(p.scenePos()) : p.pos(), p.scenePos(), p.screenPos(),
+ Qt::LeftButton, Qt::LeftButton, event->modifiers());
+ me->setAccepted(true);
+ me->setTimestamp(event->timestamp());
+ QVector2D transformedVelocity = p.velocity();
+ if (transformNeeded) {
+ QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
+ QMatrix4x4 transformMatrix(itemPrivate->canvasToItemTransform());
+ transformedVelocity = transformMatrix.mapVector(p.velocity()).toVector2D();
+ }
+ QGuiApplicationPrivate::setMouseEventCapsAndVelocity(me, event->device()->capabilities(), transformedVelocity);
return me;
}
-void QQuickCanvasPrivate::translateTouchToMouse(QTouchEvent *event)
+bool QQuickCanvasPrivate::translateTouchToMouse(QQuickItem *item, QTouchEvent *event)
{
- if (event->type() == QEvent::TouchCancel) {
- touchMouseId = -1;
- if (mouseGrabberItem)
- mouseGrabberItem->ungrabMouse();
- return;
- }
+ Q_Q(QQuickCanvas);
+ // For each point, check if it is accepted, if not, try the next point.
+ // Any of the fingers can become the mouse one.
+ // This can happen because a mouse area might not accept an event at some point but another.
for (int i = 0; i < event->touchPoints().count(); ++i) {
- QTouchEvent::TouchPoint p = event->touchPoints().at(i);
+ const QTouchEvent::TouchPoint &p = event->touchPoints().at(i);
+ // A new touch point
if (touchMouseId == -1 && p.state() & Qt::TouchPointPressed) {
+ QPointF pos = item->mapFromScene(p.scenePos());
+
+ // probably redundant, we check bounds in the calling function (matchingNewPoints)
+ if (!item->contains(pos))
+ break;
+
bool doubleClick = event->timestamp() - touchMousePressTimestamp
< static_cast<ulong>(qApp->styleHints()->mouseDoubleClickInterval());
touchMousePressTimestamp = event->timestamp();
@@ -421,72 +433,89 @@ void QQuickCanvasPrivate::translateTouchToMouse(QTouchEvent *event)
// accepted. Cannot defer setting the new value because otherwise if the event
// handler spins the event loop all subsequent moves and releases get lost.
touchMouseId = p.id();
- QQuickMouseEventEx me = touchToMouseEvent(QEvent::MouseButtonPress, p);
- me.setTimestamp(event->timestamp());
- me.setAccepted(false);
- me.setCapabilities(event->device()->capabilities());
- deliverMouseEvent(&me);
- if (me.isAccepted())
- event->setAccepted(true);
- else
+ itemForTouchPointId[touchMouseId] = item;
+ QScopedPointer<QMouseEvent> mousePress(touchToMouseEvent(QEvent::MouseButtonPress, p, event, item));
+
+ // Send a single press and see if that's accepted
+ if (!mouseGrabberItem)
+ item->grabMouse();
+ item->grabTouchPoints(QVector<int>() << touchMouseId);
+
+ q->sendEvent(item, mousePress.data());
+ event->setAccepted(mousePress->isAccepted());
+ if (!mousePress->isAccepted()) {
touchMouseId = -1;
- if (doubleClick && me.isAccepted()) {
+ if (itemForTouchPointId.value(p.id()) == item)
+ itemForTouchPointId.remove(p.id());
+
+ if (mouseGrabberItem == item)
+ item->ungrabMouse();
+ }
+
+ if (doubleClick && mousePress->isAccepted()) {
touchMousePressTimestamp = 0;
- QQuickMouseEventEx me = touchToMouseEvent(QEvent::MouseButtonDblClick, p);
- me.setTimestamp(event->timestamp());
- me.setAccepted(false);
- me.setCapabilities(event->device()->capabilities());
- if (!mouseGrabberItem) {
- if (deliverInitialMousePressEvent(rootItem, &me))
- event->setAccepted(true);
- else
- touchMouseId = -1;
+ QScopedPointer<QMouseEvent> mouseDoubleClick(touchToMouseEvent(QEvent::MouseButtonDblClick, p, event, item));
+ q->sendEvent(item, mouseDoubleClick.data());
+ event->setAccepted(mouseDoubleClick->isAccepted());
+ if (mouseDoubleClick->isAccepted()) {
+ return true;
} else {
- deliverMouseEvent(&me);
- if (me.isAccepted())
- event->setAccepted(true);
- else
- touchMouseId = -1;
+ touchMouseId = -1;
}
}
+ // The event was accepted, we are done.
+ if (mousePress->isAccepted())
+ return true;
+ // The event was not accepted but touchMouseId was set.
if (touchMouseId != -1)
- break;
+ return false;
+ // try the next point
+
+ // Touch point was there before and moved
} else if (p.id() == touchMouseId) {
if (p.state() & Qt::TouchPointMoved) {
- QQuickMouseEventEx me = touchToMouseEvent(QEvent::MouseMove, p);
- me.setTimestamp(event->timestamp());
- me.setCapabilities(event->device()->capabilities());
- if (!mouseGrabberItem) {
+ if (mouseGrabberItem) {
+ QScopedPointer<QMouseEvent> me(touchToMouseEvent(QEvent::MouseMove, p, event, mouseGrabberItem));
+ q->sendEvent(mouseGrabberItem, me.data());
+ event->setAccepted(me->isAccepted());
+ if (me->isAccepted()) {
+ itemForTouchPointId[p.id()] = mouseGrabberItem; // N.B. the mouseGrabberItem may be different after returning from sendEvent()
+ return true;
+ }
+ } else {
+ // no grabber, check if we care about mouse hover
+ // FIXME: this should only happen once, not recursively... I'll ignore it just ignore hover now.
+ // hover for touch???
+ QScopedPointer<QMouseEvent> me(touchToMouseEvent(QEvent::MouseMove, p, event, item));
if (lastMousePosition.isNull())
- lastMousePosition = me.windowPos();
+ lastMousePosition = me->windowPos();
QPointF last = lastMousePosition;
- lastMousePosition = me.windowPos();
+ lastMousePosition = me->windowPos();
- bool accepted = me.isAccepted();
- bool delivered = deliverHoverEvent(rootItem, me.windowPos(), last, me.modifiers(), accepted);
+ bool accepted = me->isAccepted();
+ bool delivered = deliverHoverEvent(rootItem, me->windowPos(), last, me->modifiers(), accepted);
if (!delivered) {
//take care of any exits
accepted = clearHover();
}
- me.setAccepted(accepted);
+ me->setAccepted(accepted);
break;
}
-
- deliverMouseEvent(&me);
} else if (p.state() & Qt::TouchPointReleased) {
+ // currently handled point was released
touchMouseId = -1;
- if (!mouseGrabberItem)
- return;
- QQuickMouseEventEx me = touchToMouseEvent(QEvent::MouseButtonRelease, p);
- me.setTimestamp(event->timestamp());
- me.setCapabilities(event->device()->capabilities());
- deliverMouseEvent(&me);
- if (mouseGrabberItem)
- mouseGrabberItem->ungrabMouse();
+ if (mouseGrabberItem) {
+ QScopedPointer<QMouseEvent> me(touchToMouseEvent(QEvent::MouseButtonRelease, p, event, mouseGrabberItem));
+ q->sendEvent(mouseGrabberItem, me.data());
+ if (mouseGrabberItem) // might have ungrabbed due to event
+ mouseGrabberItem->ungrabMouse();
+ return me->isAccepted();
+ }
}
break;
}
}
+ return false;
}
void QQuickCanvasPrivate::transformTouchPoints(QList<QTouchEvent::TouchPoint> &touchPoints, const QTransform &transform)
@@ -1047,17 +1076,17 @@ bool QQuickCanvas::event(QEvent *e)
case QEvent::TouchBegin:
case QEvent::TouchUpdate:
- case QEvent::TouchEnd:
- case QEvent::TouchCancel:
- {
- QTouchEvent *touch = static_cast<QTouchEvent *>(e);
+ case QEvent::TouchEnd: {
+ QTouchEvent *touch = static_cast<QTouchEvent*>(e);
d->translateTouchEvent(touch);
- d->deliverTouchEvent(touch);
- if (qmlTranslateTouchToMouse())
- d->translateTouchToMouse(touch);
-
- return touch->isAccepted();
+ // return in order to avoid the QWindow::event below
+ return d->deliverTouchEvent(touch);
}
+ break;
+ case QEvent::TouchCancel:
+ // return in order to avoid the QWindow::event below
+ return d->deliverTouchCancelEvent(static_cast<QTouchEvent*>(e));
+ break;
case QEvent::Leave:
d->clearHover();
d->lastMousePosition = QPoint();
@@ -1102,6 +1131,19 @@ void QQuickCanvas::keyReleaseEvent(QKeyEvent *e)
sendEvent(d->activeFocusItem, e);
}
+QMouseEvent *QQuickCanvasPrivate::cloneMouseEvent(QMouseEvent *event, QPointF *transformedLocalPos)
+{
+ int caps = QGuiApplicationPrivate::mouseEventCaps(event);
+ QVector2D velocity = QGuiApplicationPrivate::mouseEventVelocity(event);
+ QMouseEvent *me = new QMouseEvent(event->type(),
+ transformedLocalPos ? *transformedLocalPos : event->localPos(),
+ event->windowPos(), event->screenPos(),
+ event->button(), event->buttons(), event->modifiers());
+ QGuiApplicationPrivate::setMouseEventCapsAndVelocity(me, caps, velocity);
+ me->setTimestamp(event->timestamp());
+ return me;
+}
+
bool QQuickCanvasPrivate::deliverInitialMousePressEvent(QQuickItem *item, QMouseEvent *event)
{
Q_Q(QQuickCanvas);
@@ -1126,16 +1168,14 @@ bool QQuickCanvasPrivate::deliverInitialMousePressEvent(QQuickItem *item, QMouse
}
if (itemPrivate->acceptedMouseButtons() & event->button()) {
- QPointF p = item->mapFromScene(event->windowPos());
- if (item->contains(p)) {
- QMouseEvent me(event->type(), p, event->windowPos(), event->screenPos(),
- event->button(), event->buttons(), event->modifiers());
- me.setTimestamp(event->timestamp());
- me.accept();
+ QPointF localPos = item->mapFromScene(event->windowPos());
+ if (item->contains(localPos)) {
+ QScopedPointer<QMouseEvent> me(cloneMouseEvent(event, &localPos));
+ me->accept();
item->grabMouse();
- q->sendEvent(item, &me);
- event->setAccepted(me.isAccepted());
- if (me.isAccepted())
+ q->sendEvent(item, me.data());
+ event->setAccepted(me->isAccepted());
+ if (me->isAccepted())
return true;
if (mouseGrabberItem)
mouseGrabberItem->ungrabMouse();
@@ -1162,21 +1202,12 @@ bool QQuickCanvasPrivate::deliverMouseEvent(QMouseEvent *event)
}
if (mouseGrabberItem) {
- QQuickItemPrivate *mgPrivate = QQuickItemPrivate::get(mouseGrabberItem);
- const QTransform &transform = mgPrivate->canvasToItemTransform();
- QQuickMouseEventEx me(event->type(), transform.map(event->windowPos()),
- event->windowPos(), event->screenPos(),
- event->button(), event->buttons(), event->modifiers());
- QQuickMouseEventEx *eventEx = QQuickMouseEventEx::extended(event);
- if (eventEx) {
- me.setVelocity(QMatrix4x4(transform).mapVector(eventEx->velocity()).toVector2D());
- me.setCapabilities(eventEx->capabilities());
- }
- me.setTimestamp(event->timestamp());
- me.accept();
- q->sendEvent(mouseGrabberItem, &me);
- event->setAccepted(me.isAccepted());
- if (me.isAccepted())
+ QPointF localPos = mouseGrabberItem->mapFromScene(event->windowPos());
+ QScopedPointer<QMouseEvent> me(cloneMouseEvent(event, &localPos));
+ me->accept();
+ q->sendEvent(mouseGrabberItem, me.data());
+ event->setAccepted(me->isAccepted());
+ if (me->isAccepted())
return true;
}
@@ -1187,8 +1218,6 @@ bool QQuickCanvasPrivate::deliverMouseEvent(QMouseEvent *event)
void QQuickCanvas::mousePressEvent(QMouseEvent *event)
{
Q_D(QQuickCanvas);
- if (qmlTranslateTouchToMouse())
- return; // We are using touch events
#ifdef MOUSE_DEBUG
qWarning() << "QQuickCanvas::mousePressEvent()" << event->pos() << event->button() << event->buttons();
#endif
@@ -1200,8 +1229,6 @@ void QQuickCanvas::mousePressEvent(QMouseEvent *event)
void QQuickCanvas::mouseReleaseEvent(QMouseEvent *event)
{
Q_D(QQuickCanvas);
- if (qmlTranslateTouchToMouse())
- return; // We are using touch events
#ifdef MOUSE_DEBUG
qWarning() << "QQuickCanvas::mouseReleaseEvent()" << event->pos() << event->button() << event->buttons();
#endif
@@ -1220,9 +1247,6 @@ void QQuickCanvas::mouseReleaseEvent(QMouseEvent *event)
void QQuickCanvas::mouseDoubleClickEvent(QMouseEvent *event)
{
Q_D(QQuickCanvas);
- if (qmlTranslateTouchToMouse())
- return; // We are using touch events
-
#ifdef MOUSE_DEBUG
qWarning() << "QQuickCanvas::mouseDoubleClickEvent()" << event->pos() << event->button() << event->buttons();
#endif
@@ -1258,8 +1282,6 @@ bool QQuickCanvasPrivate::sendHoverEvent(QEvent::Type type, QQuickItem *item,
void QQuickCanvas::mouseMoveEvent(QMouseEvent *event)
{
Q_D(QQuickCanvas);
- if (qmlTranslateTouchToMouse())
- return; // We are using touch events
#ifdef MOUSE_DEBUG
qWarning() << "QQuickCanvas::mouseMoveEvent()" << event->pos() << event->button() << event->buttons();
#endif
@@ -1402,98 +1424,100 @@ void QQuickCanvas::wheelEvent(QWheelEvent *event)
}
#endif // QT_NO_WHEELEVENT
+
+bool QQuickCanvasPrivate::deliverTouchCancelEvent(QTouchEvent *event)
+{
+#ifdef TOUCH_DEBUG
+ qWarning("touchCancelEvent");
+#endif
+ Q_Q(QQuickCanvas);
+ // A TouchCancel event will typically not contain any points.
+ // Deliver it to all items that have active touches.
+ QSet<QQuickItem *> cancelDelivered;
+ foreach (QQuickItem *item, itemForTouchPointId) {
+ if (cancelDelivered.contains(item))
+ continue;
+ cancelDelivered.insert(item);
+ q->sendEvent(item, event);
+ }
+ touchMouseId = -1;
+ if (mouseGrabberItem)
+ mouseGrabberItem->ungrabMouse();
+ // The next touch event can only be a TouchBegin so clean up.
+ itemForTouchPointId.clear();
+ return true;
+}
+
+// check what kind of touch we have (begin/update) and
+// call deliverTouchPoints to actually dispatch the points
bool QQuickCanvasPrivate::deliverTouchEvent(QTouchEvent *event)
{
#ifdef TOUCH_DEBUG
if (event->type() == QEvent::TouchBegin)
- qWarning("touchBeginEvent");
+ qWarning() << "touchBeginEvent";
else if (event->type() == QEvent::TouchUpdate)
- qWarning("touchUpdateEvent");
+ qWarning() << "touchUpdateEvent points";
else if (event->type() == QEvent::TouchEnd)
qWarning("touchEndEvent");
- else if (event->type() == QEvent::TouchCancel)
- qWarning("touchCancelEvent");
#endif
- Q_Q(QQuickCanvas);
-
+ // List of all items that received an event before
+ // When we have TouchBegin this is and will stay empty
QHash<QQuickItem *, QList<QTouchEvent::TouchPoint> > updatedPoints;
- if (event->type() == QTouchEvent::TouchBegin) { // all points are new touch points
- QSet<int> acceptedNewPoints;
- deliverTouchPoints(rootItem, event, event->touchPoints(), &acceptedNewPoints, &updatedPoints);
- if (acceptedNewPoints.count() > 0)
- event->accept();
- else
- event->ignore();
- return event->isAccepted();
- }
-
- if (event->type() == QTouchEvent::TouchCancel) {
- // A TouchCancel event will typically not contain any points.
- // Deliver it to all items that have active touches.
- QSet<QQuickItem *> cancelDelivered;
- foreach (QQuickItem *item, itemForTouchPointId) {
- if (cancelDelivered.contains(item))
- continue;
- cancelDelivered.insert(item);
- q->sendEvent(item, event);
- }
- // The next touch event can only be a TouchBegin so clean up.
- itemForTouchPointId.clear();
- return true;
- }
-
+ // Figure out who accepted a touch point last and put it in updatedPoints
+ // Add additional item to newPoints
const QList<QTouchEvent::TouchPoint> &touchPoints = event->touchPoints();
QList<QTouchEvent::TouchPoint> newPoints;
- QQuickItem *item = 0;
for (int i=0; i<touchPoints.count(); i++) {
- const QTouchEvent::TouchPoint &touchPoint = touchPoints[i];
- switch (touchPoint.state()) {
- case Qt::TouchPointPressed:
- newPoints << touchPoint;
- break;
- case Qt::TouchPointMoved:
- case Qt::TouchPointStationary:
- case Qt::TouchPointReleased:
- if (itemForTouchPointId.contains(touchPoint.id())) {
- item = itemForTouchPointId[touchPoint.id()];
- if (item)
- updatedPoints[item].append(touchPoint);
- }
- break;
- default:
- break;
+ const QTouchEvent::TouchPoint &touchPoint = touchPoints.at(i);
+ if (touchPoint.state() == Qt::TouchPointPressed) {
+ newPoints << touchPoint;
+ } else {
+ // TouchPointStationary is relevant only to items which
+ // are also receiving touch points with some other state.
+ // But we have not yet decided which points go to which item,
+ // so for now we must include all non-new points in updatedPoints.
+ if (itemForTouchPointId.contains(touchPoint.id())) {
+ QQuickItem *item = itemForTouchPointId.value(touchPoint.id());
+ if (item)
+ updatedPoints[item].append(touchPoint);
+ }
}
}
+ // Deliver the event, but only if there is at least one new point
+ // or some item accepted a point and should receive an update
if (newPoints.count() > 0 || updatedPoints.count() > 0) {
QSet<int> acceptedNewPoints;
- int prevCount = updatedPoints.count();
- deliverTouchPoints(rootItem, event, newPoints, &acceptedNewPoints, &updatedPoints);
- if (acceptedNewPoints.count() > 0 || updatedPoints.count() != prevCount)
- event->accept();
- else
- event->ignore();
+ event->setAccepted(deliverTouchPoints(rootItem, event, newPoints, &acceptedNewPoints, &updatedPoints));
} else
event->ignore();
+ // Remove released points from itemForTouchPointId
if (event->touchPointStates() & Qt::TouchPointReleased) {
for (int i=0; i<touchPoints.count(); i++) {
- if (touchPoints[i].state() == Qt::TouchPointReleased)
+ if (touchPoints[i].state() == Qt::TouchPointReleased) {
itemForTouchPointId.remove(touchPoints[i].id());
+ if (touchPoints[i].id() == touchMouseId)
+ touchMouseId = -1;
+ }
}
}
+ if (event->type() == QEvent::TouchEnd) {
+ Q_ASSERT(itemForTouchPointId.isEmpty());
+ }
+
return event->isAccepted();
}
+// This function recurses and sends the events to the individual items
bool QQuickCanvasPrivate::deliverTouchPoints(QQuickItem *item, QTouchEvent *event, const QList<QTouchEvent::TouchPoint> &newPoints, QSet<int> *acceptedNewPoints, QHash<QQuickItem *, QList<QTouchEvent::TouchPoint> > *updatedPoints)
{
- Q_Q(QQuickCanvas);
QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
- if (itemPrivate->opacity() == 0.0)
+ if (qFuzzyIsNull(itemPrivate->opacity()))
return false;
if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
@@ -1504,6 +1528,8 @@ bool QQuickCanvasPrivate::deliverTouchPoints(QQuickItem *item, QTouchEvent *even
}
}
+ // Check if our children want the event (or parts of it)
+ // This is the only point where touch event delivery recurses!
QList<QQuickItem *> children = itemPrivate->paintOrderChildItems();
for (int ii = children.count() - 1; ii >= 0; --ii) {
QQuickItem *child = children.at(ii);
@@ -1513,71 +1539,161 @@ bool QQuickCanvasPrivate::deliverTouchPoints(QQuickItem *item, QTouchEvent *even
return true;
}
- QList<QTouchEvent::TouchPoint> matchingPoints;
+ // None of the children accepted the event, so check the given item itself.
+ // First, construct matchingPoints as a list of TouchPoints which the
+ // given item might be interested in. Any newly-pressed point which is
+ // inside the item's bounds will be interesting, and also any updated point
+ // which was already accepted by that item when it was first pressed.
+ // (A point which was already accepted is effectively "grabbed" by the item.)
+
+ // set of IDs of "interesting" new points
+ QSet<int> matchingNewPoints;
+ // set of points which this item has previously accepted, for starters
+ QList<QTouchEvent::TouchPoint> matchingPoints = (*updatedPoints)[item];
+ // now add the new points which are inside this item's bounds
if (newPoints.count() > 0 && acceptedNewPoints->count() < newPoints.count()) {
- for (int i=0; i<newPoints.count(); i++) {
+ for (int i = 0; i < newPoints.count(); i++) {
if (acceptedNewPoints->contains(newPoints[i].id()))
continue;
QPointF p = item->mapFromScene(newPoints[i].scenePos());
- if (item->contains(p))
+ if (item->contains(p)) {
+ matchingNewPoints.insert(newPoints[i].id());
matchingPoints << newPoints[i];
+ }
}
}
+ // If there are no matching new points, and the existing points are all stationary,
+ // there's no need to send an event to this item. This is required by a test in
+ // tst_qquickcanvas::touchEvent_basic:
+ // a single stationary press on an item shouldn't cause an event
+ if (matchingNewPoints.isEmpty()) {
+ bool stationaryOnly = true;
+ Q_FOREACH (QTouchEvent::TouchPoint tp, matchingPoints)
+ if (tp.state() != Qt::TouchPointStationary)
+ stationaryOnly = false;
+ if (stationaryOnly)
+ matchingPoints.clear();
+ }
+
+ if (!matchingPoints.isEmpty()) {
+ // Now we know this item might be interested in the event. Copy and send it, but
+ // with only the subset of TouchPoints which are relevant to that item: that's matchingPoints.
+ QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
+ transformTouchPoints(matchingPoints, itemPrivate->canvasToItemTransform());
+ deliverMatchingPointsToItem(item, event, acceptedNewPoints, matchingNewPoints, matchingPoints);
+ }
- if (matchingPoints.count() > 0 || (*updatedPoints)[item].count() > 0) {
- QList<QTouchEvent::TouchPoint> &eventPoints = (*updatedPoints)[item];
- eventPoints.append(matchingPoints);
- transformTouchPoints(eventPoints, itemPrivate->canvasToItemTransform());
+ // record the fact that this item has been visited already
+ updatedPoints->remove(item);
- Qt::TouchPointStates eventStates;
- for (int i=0; i<eventPoints.count(); i++)
- eventStates |= eventPoints[i].state();
- // if all points have the same state, set the event type accordingly
- QEvent::Type eventType;
- switch (eventStates) {
- case Qt::TouchPointPressed:
- eventType = QEvent::TouchBegin;
- break;
- case Qt::TouchPointReleased:
- eventType = QEvent::TouchEnd;
- break;
- default:
- eventType = QEvent::TouchUpdate;
- break;
+ // recursion is done only if ALL touch points have been delivered
+ return (acceptedNewPoints->count() == newPoints.count() && updatedPoints->isEmpty());
+}
+
+// touchEventForItemBounds has no means to generate a touch event that contains
+// only the points that are relevant for this item. Thus the need for
+// matchingPoints to already be that set of interesting points.
+// They are all pre-transformed, too.
+bool QQuickCanvasPrivate::deliverMatchingPointsToItem(QQuickItem *item, QTouchEvent *event, QSet<int> *acceptedNewPoints, const QSet<int> &matchingNewPoints, const QList<QTouchEvent::TouchPoint> &matchingPoints)
+{
+ QScopedPointer<QTouchEvent> touchEvent(touchEventWithPoints(*event, matchingPoints));
+ touchEvent.data()->setTarget(item);
+ bool touchEventAccepted = false;
+
+ // First check whether the parent wants to be a filter,
+ // and if the parent accepts the event we are done.
+ if (sendFilteredTouchEvent(item->parentItem(), item, event)) {
+ event->accept();
+ return true;
+ }
+
+ // Since it can change in sendEvent, update itemForTouchPointId now
+ foreach (int id, matchingNewPoints)
+ itemForTouchPointId[id] = item;
+
+ // Deliver the touch event to the given item
+ QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
+ itemPrivate->deliverTouchEvent(touchEvent.data());
+ touchEventAccepted = touchEvent->isAccepted();
+
+ // If the touch event wasn't accepted, synthesize a mouse event and see if the item wants it.
+ if (!touchEventAccepted && (itemPrivate->acceptedMouseButtons() & Qt::LeftButton)) {
+ // send mouse event
+ event->setAccepted(translateTouchToMouse(item, event));
+ if (event->isAccepted()) {
+ touchEventAccepted = true;
}
+ }
- if (eventStates != Qt::TouchPointStationary) {
- QTouchEvent touchEvent(eventType);
- touchEvent.setWindow(event->window());
- touchEvent.setTarget(item);
- touchEvent.setDevice(event->device());
- touchEvent.setModifiers(event->modifiers());
- touchEvent.setTouchPointStates(eventStates);
- touchEvent.setTouchPoints(eventPoints);
- touchEvent.setTimestamp(event->timestamp());
-
- for (int i = 0; i < matchingPoints.count(); ++i)
- itemForTouchPointId[matchingPoints[i].id()] = item;
-
- touchEvent.accept();
- q->sendEvent(item, &touchEvent);
-
- if (touchEvent.isAccepted()) {
- for (int i = 0; i < matchingPoints.count(); ++i)
- acceptedNewPoints->insert(matchingPoints[i].id());
+ if (touchEventAccepted) {
+ // If the touch was accepted (regardless by whom or in what form),
+ // update acceptedNewPoints.
+ foreach (int id, matchingNewPoints)
+ acceptedNewPoints->insert(id);
+ } else {
+ // But if the event was not accepted then we know this item
+ // will not be interested in further updates for those touchpoint IDs either.
+ foreach (int id, matchingNewPoints)
+ if (itemForTouchPointId[id] == item)
+ itemForTouchPointId.remove(id);
+ }
+
+ return touchEventAccepted;
+}
+
+QTouchEvent *QQuickCanvasPrivate::touchEventForItemBounds(QQuickItem *target, const QTouchEvent &originalEvent)
+{
+ const QList<QTouchEvent::TouchPoint> &touchPoints = originalEvent.touchPoints();
+ QList<QTouchEvent::TouchPoint> pointsInBounds;
+ // if all points are stationary, the list of points should be empty to signal a no-op
+ if (originalEvent.touchPointStates() != Qt::TouchPointStationary) {
+ for (int i = 0; i < touchPoints.count(); ++i) {
+ const QTouchEvent::TouchPoint &tp = touchPoints.at(i);
+ if (tp.state() == Qt::TouchPointPressed) {
+ QPointF p = target->mapFromScene(tp.scenePos());
+ if (target->contains(p))
+ pointsInBounds.append(tp);
} else {
- for (int i = 0; i < matchingPoints.count(); ++i)
- if (itemForTouchPointId.value(matchingPoints[i].id()) == item)
- itemForTouchPointId.remove(matchingPoints[i].id());
+ pointsInBounds.append(tp);
}
}
+ transformTouchPoints(pointsInBounds, QQuickItemPrivate::get(target)->canvasToItemTransform());
}
- updatedPoints->remove(item);
- if (acceptedNewPoints->count() == newPoints.count() && updatedPoints->isEmpty())
- return true;
+ QTouchEvent* touchEvent = touchEventWithPoints(originalEvent, pointsInBounds);
+ touchEvent->setTarget(target);
+ return touchEvent;
+}
- return false;
+QTouchEvent *QQuickCanvasPrivate::touchEventWithPoints(const QTouchEvent &event, const QList<QTouchEvent::TouchPoint> &newPoints)
+{
+ Qt::TouchPointStates eventStates;
+ for (int i=0; i<newPoints.count(); i++)
+ eventStates |= newPoints[i].state();
+ // if all points have the same state, set the event type accordingly
+ QEvent::Type eventType = event.type();
+ switch (eventStates) {
+ case Qt::TouchPointPressed:
+ eventType = QEvent::TouchBegin;
+ break;
+ case Qt::TouchPointReleased:
+ eventType = QEvent::TouchEnd;
+ break;
+ default:
+ eventType = QEvent::TouchUpdate;
+ break;
+ }
+
+ QTouchEvent *touchEvent = new QTouchEvent(eventType);
+ touchEvent->setWindow(event.window());
+ touchEvent->setTarget(event.target());
+ touchEvent->setDevice(event.device());
+ touchEvent->setModifiers(event.modifiers());
+ touchEvent->setTouchPoints(newPoints);
+ touchEvent->setTouchPointStates(eventStates);
+ touchEvent->setTimestamp(event.timestamp());
+ touchEvent->accept();
+ return touchEvent;
}
#ifndef QT_NO_DRAGANDDROP
@@ -1702,6 +1818,59 @@ bool QQuickCanvasPrivate::deliverDragEvent(QQuickDragGrabber *grabber, QQuickIte
}
#endif // QT_NO_DRAGANDDROP
+bool QQuickCanvasPrivate::sendFilteredTouchEvent(QQuickItem *target, QQuickItem *item, QTouchEvent *event)
+{
+ if (!target)
+ return false;
+
+ QQuickItemPrivate *targetPrivate = QQuickItemPrivate::get(target);
+ if (targetPrivate->filtersChildMouseEvents) {
+ QScopedPointer<QTouchEvent> targetEvent(touchEventForItemBounds(target, *event));
+ if (!targetEvent->touchPoints().isEmpty()) {
+ QVector<int> touchIds;
+ for (int i = 0; i < event->touchPoints().size(); ++i)
+ touchIds.append(event->touchPoints().at(i).id());
+ if (target->childMouseEventFilter(item, targetEvent.data())) {
+ target->grabTouchPoints(touchIds);
+ if (mouseGrabberItem) {
+ mouseGrabberItem->ungrabMouse();
+ touchMouseId = -1;
+ }
+ return true;
+ }
+
+ // Only offer a mouse event to the filter if we have one point
+ if (targetEvent->touchPoints().count() == 1) {
+ QEvent::Type t;
+ const QTouchEvent::TouchPoint &tp = targetEvent->touchPoints().first();
+ switch (tp.state()) {
+ case Qt::TouchPointPressed:
+ t = QEvent::MouseButtonPress;
+ break;
+ case Qt::TouchPointReleased:
+ t = QEvent::MouseButtonRelease;
+ break;
+ default:
+ // move or stationary
+ t = QEvent::MouseMove;
+ break;
+ }
+
+ // targetEvent is already transformed wrt local position, velocity, etc.
+ QScopedPointer<QMouseEvent> mouseEvent(touchToMouseEvent(t, targetEvent->touchPoints().first(), event, item, false));
+ if (target->childMouseEventFilter(item, mouseEvent.data())) {
+ itemForTouchPointId[tp.id()] = target;
+ touchMouseId = tp.id();
+ target->grabMouse();
+ return true;
+ }
+ }
+ }
+ }
+
+ return sendFilteredTouchEvent(target->parentItem(), item, event);
+}
+
bool QQuickCanvasPrivate::sendFilteredMouseEvent(QQuickItem *target, QQuickItem *item, QEvent *event)
{
if (!target)
@@ -1721,14 +1890,13 @@ bool QQuickCanvasPrivate::sendFilteredMouseEvent(QQuickItem *target, QQuickItem
bool QQuickCanvasPrivate::dragOverThreshold(qreal d, Qt::Axis axis, QMouseEvent *event)
{
QStyleHints *styleHints = qApp->styleHints();
- QQuickMouseEventEx *extended = QQuickMouseEventEx::extended(event);
- bool dragVelocityLimitAvailable = extended
- && extended->capabilities().testFlag(QTouchDevice::Velocity)
+ int caps = QGuiApplicationPrivate::mouseEventCaps(event);
+ bool dragVelocityLimitAvailable = (caps & QTouchDevice::Velocity)
&& styleHints->startDragVelocity();
bool overThreshold = qAbs(d) > styleHints->startDragDistance();
if (dragVelocityLimitAvailable) {
- qreal velocity = axis == Qt::XAxis ? extended->velocity().x()
- : extended->velocity().y();
+ QVector2D velocityVec = QGuiApplicationPrivate::mouseEventVelocity(event);
+ qreal velocity = axis == Qt::XAxis ? velocityVec.x() : velocityVec.y();
overThreshold |= qAbs(velocity) > styleHints->startDragVelocity();
}
return overThreshold;
@@ -1768,6 +1936,7 @@ bool QQuickCanvas::sendEvent(QQuickItem *item, QEvent *e)
case QEvent::MouseMove:
// XXX todo - should sendEvent be doing this? how does it relate to forwarded events?
if (!d->sendFilteredMouseEvent(item->parentItem(), item, e)) {
+ // accept because qml items by default accept and have to explicitly opt out of accepting
e->accept();
QQuickItemPrivate::get(item)->deliverMouseEvent(static_cast<QMouseEvent *>(e));
}
@@ -1789,12 +1958,10 @@ bool QQuickCanvas::sendEvent(QQuickItem *item, QEvent *e)
case QEvent::TouchBegin:
case QEvent::TouchUpdate:
case QEvent::TouchEnd:
+ d->sendFilteredTouchEvent(item->parentItem(), item, static_cast<QTouchEvent *>(e));
+ break;
case QEvent::TouchCancel:
- // XXX todo - should sendEvent be doing this? how does it relate to forwarded events?
- if (!d->sendFilteredMouseEvent(item->parentItem(), item, e)) {
- e->accept();
- QQuickItemPrivate::get(item)->deliverTouchEvent(static_cast<QTouchEvent *>(e));
- }
+ QQuickItemPrivate::get(item)->deliverTouchEvent(static_cast<QTouchEvent *>(e));
break;
#ifndef QT_NO_DRAGANDDROP
case QEvent::DragEnter:
diff --git a/src/quick/items/qquickcanvas_p.h b/src/quick/items/qquickcanvas_p.h
index e08c342c44..1bbf36f541 100644
--- a/src/quick/items/qquickcanvas_p.h
+++ b/src/quick/items/qquickcanvas_p.h
@@ -110,6 +110,8 @@ public:
QQmlListProperty<QObject> data();
QQuickItem *activeFocusItem;
+
+ // Keeps track of the item currently receiving mouse events
QQuickItem *mouseGrabberItem;
#ifndef QT_NO_DRAGANDDROP
QQuickDragGrabber dragGrabber;
@@ -119,9 +121,10 @@ public:
// Mouse positions are saved in widget coordinates
QPointF lastMousePosition;
- void translateTouchToMouse(QTouchEvent *event);
+ bool translateTouchToMouse(QQuickItem *item, QTouchEvent *event);
void translateTouchEvent(QTouchEvent *touchEvent);
static void transformTouchPoints(QList<QTouchEvent::TouchPoint> &touchPoints, const QTransform &transform);
+ static QMouseEvent *cloneMouseEvent(QMouseEvent *event, QPointF *transformedLocalPos = 0);
bool deliverInitialMousePressEvent(QQuickItem *, QMouseEvent *);
bool deliverMouseEvent(QMouseEvent *);
bool sendFilteredMouseEvent(QQuickItem *, QQuickItem *, QEvent *);
@@ -129,7 +132,12 @@ public:
bool deliverTouchPoints(QQuickItem *, QTouchEvent *, const QList<QTouchEvent::TouchPoint> &, QSet<int> *,
QHash<QQuickItem *, QList<QTouchEvent::TouchPoint> > *);
bool deliverTouchEvent(QTouchEvent *);
+ bool deliverTouchCancelEvent(QTouchEvent *);
bool deliverHoverEvent(QQuickItem *, const QPointF &scenePos, const QPointF &lastScenePos, Qt::KeyboardModifiers modifiers, bool &accepted);
+ bool deliverMatchingPointsToItem(QQuickItem *item, QTouchEvent *event, QSet<int> *acceptedNewPoints, const QSet<int> &matchingNewPoints, const QList<QTouchEvent::TouchPoint> &matchingPoints);
+ QTouchEvent *touchEventForItemBounds(QQuickItem *target, const QTouchEvent &originalEvent);
+ QTouchEvent *touchEventWithPoints(const QTouchEvent &event, const QList<QTouchEvent::TouchPoint> &newPoints);
+ bool sendFilteredTouchEvent(QQuickItem *target, QQuickItem *item, QTouchEvent *event);
bool sendHoverEvent(QEvent::Type, QQuickItem *, const QPointF &scenePos, const QPointF &lastScenePos,
Qt::KeyboardModifiers modifiers, bool accepted);
bool clearHover();
@@ -195,6 +203,7 @@ public:
uint renderTargetId;
QSize renderTargetSize;
+ // Keeps track of which touch point (int) was last accepted by which item
QHash<int, QQuickItem *> itemForTouchPointId;
mutable QQuickCanvasIncubationController *incubationController;
diff --git a/src/quick/items/qquickevents_p_p.h b/src/quick/items/qquickevents_p_p.h
index 1809394ed4..0cf53f6a76 100644
--- a/src/quick/items/qquickevents_p_p.h
+++ b/src/quick/items/qquickevents_p_p.h
@@ -137,75 +137,6 @@ private:
bool _accepted;
};
-class QQuickMouseEventEx : public QMouseEvent
-{
-public:
- QQuickMouseEventEx(Type type, const QPointF &pos, Qt::MouseButton button,
- Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers)
- : QMouseEvent(type,pos,button,buttons,modifiers)
- {
- }
-
- QQuickMouseEventEx(Type type, const QPointF &pos, const QPointF &globalPos,
- Qt::MouseButton button, Qt::MouseButtons buttons,
- Qt::KeyboardModifiers modifiers)
- : QMouseEvent(type,pos,globalPos,button,buttons,modifiers)
- {
- }
-
- QQuickMouseEventEx(Type type, const QPointF &pos, const QPointF &windowPos, const QPointF &globalPos,
- Qt::MouseButton button, Qt::MouseButtons buttons,
- Qt::KeyboardModifiers modifiers)
- : QMouseEvent(type,pos,windowPos,globalPos,button,buttons,modifiers)
- {
- }
-
- QQuickMouseEventEx(const QMouseEvent &event)
- : QMouseEvent(event)
- {
- const QQuickMouseEventEx *eventEx = extended(&event);
- if (eventEx) {
- setVelocity(eventEx->velocity());
- setCapabilities(eventEx->capabilities());
- }
- }
-
- ~QQuickMouseEventEx()
- {
- d = 0;
- }
-
- static const QQuickMouseEventEx *extended(const QMouseEvent *e) {
- const QQuickMouseEventEx *ex = static_cast<const QQuickMouseEventEx*>(e);
- return reinterpret_cast<const QMouseEvent*>(ex->d) == e ? ex : 0;
- }
- static QQuickMouseEventEx *extended(QMouseEvent *e) {
- QQuickMouseEventEx *ex = static_cast<QQuickMouseEventEx*>(e);
- return reinterpret_cast<QMouseEvent*>(ex->d) == e ? ex : 0;
- }
-
- void setExtended() {
- d = reinterpret_cast<QEventPrivate*>(this);
- }
-
- void setVelocity(const QVector2D &v) {
- setExtended();
- _velocity = v;
- }
- QVector2D velocity() const { return _velocity; }
-
- void setCapabilities(QTouchDevice::Capabilities caps) {
- setExtended();
- _capabilities = caps;
- }
- QTouchDevice::Capabilities capabilities() const { return _capabilities; }
-
-private:
- QVector2D _velocity;
- QTouchDevice::Capabilities _capabilities;
-};
-
-
class QQuickWheelEvent : public QObject
{
Q_OBJECT
diff --git a/src/quick/items/qquickflickable.cpp b/src/quick/items/qquickflickable.cpp
index 9d690347b1..3a56dd1c23 100644
--- a/src/quick/items/qquickflickable.cpp
+++ b/src/quick/items/qquickflickable.cpp
@@ -51,6 +51,7 @@
#include <QtQml/qqmlinfo.h>
#include <QtGui/qevent.h>
#include <QtGui/qguiapplication.h>
+#include <QtGui/private/qguiapplication_p.h>
#include <QtGui/qstylehints.h>
#include "qplatformdefs.h"
@@ -970,7 +971,7 @@ void QQuickFlickablePrivate::handleMousePressEvent(QMouseEvent *event)
vData.dragMaxBound = q->maxYExtent();
fixupMode = Normal;
lastPos = QPointF();
- pressPos = event->localPos();
+ pressPos = event->windowPos();
hData.pressPos = hData.move.value();
vData.pressPos = vData.move.value();
bool wasFlicking = hData.flicking || vData.flicking;
@@ -1005,7 +1006,7 @@ void QQuickFlickablePrivate::handleMouseMoveEvent(QMouseEvent *event)
qint64 elapsedSincePress = computeCurrentTime(event) - lastPressTime;
if (q->yflick()) {
- qreal dy = event->localPos().y() - pressPos.y();
+ qreal dy = event->windowPos().y() - pressPos.y();
bool overThreshold = QQuickCanvasPrivate::dragOverThreshold(dy, Qt::YAxis, event);
if (overThreshold || elapsedSincePress > 200) {
if (!vMoved)
@@ -1039,7 +1040,7 @@ void QQuickFlickablePrivate::handleMouseMoveEvent(QMouseEvent *event)
}
if (q->xflick()) {
- qreal dx = event->localPos().x() - pressPos.x();
+ qreal dx = event->windowPos().x() - pressPos.x();
bool overThreshold = QQuickCanvasPrivate::dragOverThreshold(dx, Qt::XAxis, event);
if (overThreshold || elapsedSincePress > 200) {
if (!hMoved)
@@ -1096,25 +1097,24 @@ void QQuickFlickablePrivate::handleMouseMoveEvent(QMouseEvent *event)
if (elapsed <= 0)
return;
lastPosTime = currentTimestamp;
- QQuickMouseEventEx *extended = QQuickMouseEventEx::extended(event);
if (q->yflick() && !rejectY) {
- if (extended && extended->capabilities().testFlag(QTouchDevice::Velocity)) {
- vData.addVelocitySample(extended->velocity().y(), maxVelocity);
+ if (QGuiApplicationPrivate::mouseEventCaps(event) & QTouchDevice::Velocity) {
+ vData.addVelocitySample(QGuiApplicationPrivate::mouseEventVelocity(event).y(), maxVelocity);
} else {
- qreal dy = event->localPos().y() - (lastPos.isNull() ? pressPos.y() : lastPos.y());
+ qreal dy = event->windowPos().y() - (lastPos.isNull() ? pressPos.y() : lastPos.y());
vData.addVelocitySample(dy/elapsed, maxVelocity);
}
}
if (q->xflick() && !rejectX) {
- if (extended && extended->capabilities().testFlag(QTouchDevice::Velocity)) {
- hData.addVelocitySample(extended->velocity().x(), maxVelocity);
+ if (QGuiApplicationPrivate::mouseEventCaps(event) & QTouchDevice::Velocity) {
+ hData.addVelocitySample(QGuiApplicationPrivate::mouseEventVelocity(event).x(), maxVelocity);
} else {
- qreal dx = event->localPos().x() - (lastPos.isNull() ? pressPos.x() : lastPos.x());
+ qreal dx = event->windowPos().x() - (lastPos.isNull() ? pressPos.x() : lastPos.x());
hData.addVelocitySample(dx/elapsed, maxVelocity);
}
}
- lastPos = event->localPos();
+ lastPos = event->windowPos();
}
void QQuickFlickablePrivate::handleMouseReleaseEvent(QMouseEvent *event)
@@ -1141,9 +1141,8 @@ void QQuickFlickablePrivate::handleMouseReleaseEvent(QMouseEvent *event)
qreal vVelocity = 0;
if (elapsed < 100 && vData.velocity != 0.) {
- QQuickMouseEventEx *extended = QQuickMouseEventEx::extended(event);
- vVelocity = (extended && extended->capabilities().testFlag(QTouchDevice::Velocity))
- ? extended->velocity().y() : vData.velocity;
+ vVelocity = (QGuiApplicationPrivate::mouseEventCaps(event) & QTouchDevice::Velocity)
+ ? QGuiApplicationPrivate::mouseEventVelocity(event).y() : vData.velocity;
}
if ((vData.atBeginning && vVelocity > 0.) || (vData.atEnd && vVelocity < 0.)) {
vVelocity /= 2;
@@ -1157,9 +1156,8 @@ void QQuickFlickablePrivate::handleMouseReleaseEvent(QMouseEvent *event)
qreal hVelocity = 0;
if (elapsed < 100 && hData.velocity != 0.) {
- QQuickMouseEventEx *extended = QQuickMouseEventEx::extended(event);
- hVelocity = (extended && extended->capabilities().testFlag(QTouchDevice::Velocity))
- ? extended->velocity().x() : hData.velocity;
+ hVelocity = (QGuiApplicationPrivate::mouseEventCaps(event) & QTouchDevice::Velocity)
+ ? QGuiApplicationPrivate::mouseEventVelocity(event).x() : hData.velocity;
}
if ((hData.atBeginning && hVelocity > 0.) || (hData.atEnd && hVelocity < 0.)) {
hVelocity /= 2;
@@ -1175,7 +1173,7 @@ void QQuickFlickablePrivate::handleMouseReleaseEvent(QMouseEvent *event)
bool flickedV = false;
vVelocity *= flickBoost;
- if (q->yflick() && qAbs(vVelocity) > MinimumFlickVelocity && qAbs(event->localPos().y() - pressPos.y()) > FlickThreshold) {
+ if (q->yflick() && qAbs(vVelocity) > MinimumFlickVelocity && qAbs(event->windowPos().y() - pressPos.y()) > FlickThreshold) {
velocityTimeline.reset(vData.smoothVelocity);
vData.smoothVelocity.setValue(-vVelocity);
flickedV = flickY(vVelocity);
@@ -1185,7 +1183,7 @@ void QQuickFlickablePrivate::handleMouseReleaseEvent(QMouseEvent *event)
bool flickedH = false;
hVelocity *= flickBoost;
- if (q->xflick() && qAbs(hVelocity) > MinimumFlickVelocity && qAbs(event->localPos().x() - pressPos.x()) > FlickThreshold) {
+ if (q->xflick() && qAbs(hVelocity) > MinimumFlickVelocity && qAbs(event->windowPos().x() - pressPos.x()) > FlickThreshold) {
velocityTimeline.reset(hData.smoothVelocity);
hData.smoothVelocity.setValue(-hVelocity);
flickedH = flickX(hVelocity);
@@ -1305,7 +1303,7 @@ void QQuickFlickablePrivate::captureDelayedPress(QMouseEvent *event)
if (!isOutermostPressDelay())
return;
delayedPressTarget = q->canvas()->mouseGrabberItem();
- delayedPressEvent = new QQuickMouseEventEx(*event);
+ delayedPressEvent = QQuickCanvasPrivate::cloneMouseEvent(event);
delayedPressEvent->setAccepted(false);
delayedPressTimer.start(pressDelay, q);
}
@@ -1974,26 +1972,18 @@ bool QQuickFlickable::sendMouseEvent(QMouseEvent *event)
bool grabberDisabled = grabber && !grabber->isEnabled();
bool stealThisEvent = d->stealMouse;
if ((stealThisEvent || contains(localPos)) && (!grabber || !grabber->keepMouseGrab() || grabberDisabled)) {
- QQuickMouseEventEx mouseEvent(event->type(), localPos,
- event->windowPos(), event->screenPos(),
- event->button(), event->buttons(), event->modifiers());
- QQuickMouseEventEx *eventEx = QQuickMouseEventEx::extended(event);
- if (eventEx) {
- mouseEvent.setVelocity(eventEx->velocity());
- mouseEvent.setCapabilities(eventEx->capabilities());
- }
- mouseEvent.setTimestamp(event->timestamp());
- mouseEvent.setAccepted(false);
+ QScopedPointer<QMouseEvent> mouseEvent(QQuickCanvasPrivate::cloneMouseEvent(event, &localPos));
+ mouseEvent->setAccepted(false);
- switch (mouseEvent.type()) {
+ switch (mouseEvent->type()) {
case QEvent::MouseMove:
- d->handleMouseMoveEvent(&mouseEvent);
+ d->handleMouseMoveEvent(mouseEvent.data());
break;
case QEvent::MouseButtonPress:
if (d->pressed) // we are already pressed - this is a delayed replay
return false;
- d->handleMousePressEvent(&mouseEvent);
+ d->handleMousePressEvent(mouseEvent.data());
d->captureDelayedPress(event);
stealThisEvent = d->stealMouse; // Update stealThisEvent in case changed by function call above
break;
@@ -2013,7 +2003,7 @@ bool QQuickFlickable::sendMouseEvent(QMouseEvent *event)
d->pressed = false;
return true;
}
- d->handleMouseReleaseEvent(&mouseEvent);
+ d->handleMouseReleaseEvent(mouseEvent.data());
break;
default:
break;
diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp
index 02a0c22c5d..2cf12b6c03 100644
--- a/src/quick/items/qquickitem.cpp
+++ b/src/quick/items/qquickitem.cpp
@@ -2290,6 +2290,11 @@ void QQuickItemPrivate::derefCanvas()
QQuickCanvasPrivate *c = QQuickCanvasPrivate::get(canvas);
if (polishScheduled)
c->itemsToPolish.remove(q);
+ QMutableHashIterator<int, QQuickItem *> itemTouchMapIt(c->itemForTouchPointId);
+ while (itemTouchMapIt.hasNext()) {
+ if (itemTouchMapIt.next().value() == q)
+ itemTouchMapIt.remove();
+ }
if (c->mouseGrabberItem == q)
c->mouseGrabberItem = 0;
if ( hoverEnabled )
@@ -5131,7 +5136,7 @@ void QQuickItem::setKeepMouseGrab(bool keep)
\sa ungrabTouchPoints(), setKeepTouchGrab()
*/
-void QQuickItem::grabTouchPoints(const QList<int> &ids)
+void QQuickItem::grabTouchPoints(const QVector<int> &ids)
{
Q_D(QQuickItem);
if (!d->canvas)
diff --git a/src/quick/items/qquickitem.h b/src/quick/items/qquickitem.h
index c0fd01fb7e..7174edd057 100644
--- a/src/quick/items/qquickitem.h
+++ b/src/quick/items/qquickitem.h
@@ -284,7 +284,7 @@ public:
bool filtersChildMouseEvents() const;
void setFiltersChildMouseEvents(bool filter);
- void grabTouchPoints(const QList<int> &ids);
+ void grabTouchPoints(const QVector<int> &ids);
void ungrabTouchPoints();
bool keepTouchGrab() const;
void setKeepTouchGrab(bool);
diff --git a/src/quick/items/qquickmultipointtoucharea.cpp b/src/quick/items/qquickmultipointtoucharea.cpp
index f980fdce6c..f4e49bd66c 100644
--- a/src/quick/items/qquickmultipointtoucharea.cpp
+++ b/src/quick/items/qquickmultipointtoucharea.cpp
@@ -418,7 +418,7 @@ void QQuickMultiPointTouchArea::grabGesture()
grabMouse();
setKeepMouseGrab(true);
- grabTouchPoints(_touchPoints.keys());
+ grabTouchPoints(_touchPoints.keys().toVector());
setKeepTouchGrab(true);
}
diff --git a/src/quick/items/qquickpincharea.cpp b/src/quick/items/qquickpincharea.cpp
index 8c1c7bd096..f58990485e 100644
--- a/src/quick/items/qquickpincharea.cpp
+++ b/src/quick/items/qquickpincharea.cpp
@@ -247,6 +247,8 @@ QQuickPinchArea::QQuickPinchArea(QQuickItem *parent)
{
Q_D(QQuickPinchArea);
d->init();
+ setAcceptedMouseButtons(Qt::LeftButton);
+ setFiltersChildMouseEvents(true);
}
QQuickPinchArea::~QQuickPinchArea()
@@ -281,6 +283,20 @@ void QQuickPinchArea::touchEvent(QTouchEvent *event)
return;
}
+ // A common non-trivial starting scenario is the user puts down one finger,
+ // then that finger remains stationary while putting down a second one.
+ // However QQuickCanvas will not send TouchUpdates for TouchPoints which
+ // were not initially accepted; that would be inefficient and noisy.
+ // So even if there is only one touchpoint so far, it's important to accept it
+ // in order to get updates later on (and it's accepted by default anyway).
+ // If the user puts down one finger, we're waiting for the other finger to drop.
+ // Therefore updatePinch() must do the right thing for any combination of
+ // points and states that may occur, and there is no reason to ignore any event.
+ // One consequence though is that if PinchArea is on top of something else,
+ // it's always going to accept the touches, and that means the item underneath
+ // will not get them (unless the PA's parent is doing parent filtering,
+ // as the Flickable does, for example).
+
switch (event->type()) {
case QEvent::TouchBegin:
case QEvent::TouchUpdate:
@@ -329,17 +345,27 @@ void QQuickPinchArea::updatePinch()
setKeepMouseGrab(false);
return;
}
+
+ if (d->touchPoints.count() == 1) {
+ setKeepMouseGrab(false);
+ }
+
QTouchEvent::TouchPoint touchPoint1 = d->touchPoints.at(0);
QTouchEvent::TouchPoint touchPoint2 = d->touchPoints.at(d->touchPoints. count() >= 2 ? 1 : 0);
+ QRectF bounds = clipRect();
+ // Pinch is not started unless there are exactly two touch points
+ // AND one or more of the points has just now been pressed (wasn't pressed already)
+ // AND both points are inside the bounds.
if (d->touchPoints.count() == 2
- && (touchPoint1.state() & Qt::TouchPointPressed || touchPoint2.state() & Qt::TouchPointPressed)) {
+ && (touchPoint1.state() & Qt::TouchPointPressed || touchPoint2.state() & Qt::TouchPointPressed) &&
+ bounds.contains(touchPoint1.pos()) && bounds.contains(touchPoint2.pos())) {
d->id1 = touchPoint1.id();
d->sceneStartPoint1 = touchPoint1.scenePos();
d->sceneStartPoint2 = touchPoint2.scenePos();
d->pinchActivated = true;
d->initPinch = true;
}
- if (d->pinchActivated && !d->pinchRejected){
+ if (d->pinchActivated && !d->pinchRejected) {
const int dragThreshold = qApp->styleHints()->startDragDistance();
QPointF p1 = touchPoint1.scenePos();
QPointF p2 = touchPoint2.scenePos();
@@ -361,10 +387,10 @@ void QQuickPinchArea::updatePinch()
angle -= 360;
if (!d->inPinch || d->initPinch) {
if (d->touchPoints.count() >= 2
- && (qAbs(p1.x()-d->sceneStartPoint1.x()) > dragThreshold
- || qAbs(p1.y()-d->sceneStartPoint1.y()) > dragThreshold
- || qAbs(p2.x()-d->sceneStartPoint2.x()) > dragThreshold
- || qAbs(p2.y()-d->sceneStartPoint2.y()) > dragThreshold)) {
+ && (qAbs(p1.x()-d->sceneStartPoint1.x()) >= dragThreshold
+ || qAbs(p1.y()-d->sceneStartPoint1.y()) >= dragThreshold
+ || qAbs(p2.x()-d->sceneStartPoint2.x()) >= dragThreshold
+ || qAbs(p2.y()-d->sceneStartPoint2.y()) >= dragThreshold)) {
d->initPinch = false;
d->sceneStartCenter = sceneCenter;
d->sceneLastCenter = sceneCenter;
@@ -461,106 +487,24 @@ void QQuickPinchArea::updatePinch()
}
}
-void QQuickPinchArea::mousePressEvent(QMouseEvent *event)
-{
- Q_D(QQuickPinchArea);
- d->stealMouse = false;
- if (!d->enabled)
- QQuickItem::mousePressEvent(event);
- else {
- setKeepMouseGrab(false);
- event->setAccepted(true);
- }
-}
-
-void QQuickPinchArea::mouseMoveEvent(QMouseEvent *event)
-{
- Q_D(QQuickPinchArea);
- if (!d->enabled) {
- QQuickItem::mouseMoveEvent(event);
- return;
- }
-}
-
-void QQuickPinchArea::mouseReleaseEvent(QMouseEvent *event)
-{
- Q_D(QQuickPinchArea);
- d->stealMouse = false;
- if (!d->enabled) {
- QQuickItem::mouseReleaseEvent(event);
- } else {
- QQuickCanvas *c = canvas();
- if (c && c->mouseGrabberItem() == this)
- ungrabMouse();
- setKeepMouseGrab(false);
- }
-}
-
-void QQuickPinchArea::mouseUngrabEvent()
-{
- setKeepMouseGrab(false);
-}
-
-bool QQuickPinchArea::sendMouseEvent(QMouseEvent *event)
-{
- Q_D(QQuickPinchArea);
- QPointF localPos = mapFromScene(event->windowPos());
-
- QQuickCanvas *c = canvas();
- QQuickItem *grabber = c ? c->mouseGrabberItem() : 0;
- bool stealThisEvent = d->stealMouse;
- if ((stealThisEvent || contains(localPos)) && (!grabber || !grabber->keepMouseGrab())) {
- QMouseEvent mouseEvent(event->type(), localPos, event->windowPos(), event->screenPos(),
- event->button(), event->buttons(), event->modifiers());
- mouseEvent.setAccepted(false);
-
- switch (mouseEvent.type()) {
- case QEvent::MouseMove:
- mouseMoveEvent(&mouseEvent);
- break;
- case QEvent::MouseButtonPress:
- mousePressEvent(&mouseEvent);
- break;
- case QEvent::MouseButtonRelease:
- mouseReleaseEvent(&mouseEvent);
- break;
- default:
- break;
- }
- grabber = c->mouseGrabberItem();
- if (grabber && stealThisEvent && !grabber->keepMouseGrab() && grabber != this)
- grabMouse();
-
- return stealThisEvent;
- }
- if (event->type() == QEvent::MouseButtonRelease) {
- d->stealMouse = false;
- if (c && c->mouseGrabberItem() == this)
- ungrabMouse();
- setKeepMouseGrab(false);
- }
- return false;
-}
-
bool QQuickPinchArea::childMouseEventFilter(QQuickItem *i, QEvent *e)
{
Q_D(QQuickPinchArea);
if (!d->enabled || !isVisible())
return QQuickItem::childMouseEventFilter(i, e);
switch (e->type()) {
- case QEvent::MouseButtonPress:
- case QEvent::MouseMove:
- case QEvent::MouseButtonRelease:
- return sendMouseEvent(static_cast<QMouseEvent *>(e));
- break;
case QEvent::TouchBegin:
case QEvent::TouchUpdate: {
QTouchEvent *touch = static_cast<QTouchEvent*>(e);
- d->touchPoints.clear();
- for (int i = 0; i < touch->touchPoints().count(); ++i)
- if (!(touch->touchPoints().at(i).state() & Qt::TouchPointReleased))
- d->touchPoints << touch->touchPoints().at(i);
- updatePinch();
+ if (touch->touchPoints().count() > 1) {
+ touchEvent(touch);
+ } else {
+ d->touchPoints.clear();
+ for (int i = 0; i < touch->touchPoints().count(); ++i)
+ if (!(touch->touchPoints().at(i).state() & Qt::TouchPointReleased))
+ d->touchPoints << touch->touchPoints().at(i);
+ updatePinch();
+ }
}
return d->inPinch;
case QEvent::TouchEnd:
diff --git a/src/quick/items/qquickpincharea_p.h b/src/quick/items/qquickpincharea_p.h
index b7328b3cb8..3abe3bbc45 100644
--- a/src/quick/items/qquickpincharea_p.h
+++ b/src/quick/items/qquickpincharea_p.h
@@ -278,11 +278,6 @@ Q_SIGNALS:
void pinchFinished(QQuickPinchEvent *pinch);
protected:
- virtual void mousePressEvent(QMouseEvent *event);
- virtual void mouseReleaseEvent(QMouseEvent *event);
- virtual void mouseMoveEvent(QMouseEvent *event);
- virtual void mouseUngrabEvent();
- virtual bool sendMouseEvent(QMouseEvent *event);
virtual bool childMouseEventFilter(QQuickItem *i, QEvent *e);
virtual void touchEvent(QTouchEvent *event);
diff --git a/tests/auto/quick/qquickcanvas/tst_qquickcanvas.cpp b/tests/auto/quick/qquickcanvas/tst_qquickcanvas.cpp
index ed3dceb403..82af3678da 100644
--- a/tests/auto/quick/qquickcanvas/tst_qquickcanvas.cpp
+++ b/tests/auto/quick/qquickcanvas/tst_qquickcanvas.cpp
@@ -51,6 +51,7 @@
#include "../../shared/util.h"
#include <QSignalSpy>
#include <private/qquickcanvas_p.h>
+#include <private/qguiapplication_p.h>
struct TouchEventData {
QEvent::Type type;
@@ -144,7 +145,8 @@ class TestTouchItem : public QQuickRectangle
Q_OBJECT
public:
TestTouchItem(QQuickItem *parent = 0)
- : QQuickRectangle(parent), acceptEvents(true), mousePressId(0),
+ : QQuickRectangle(parent), acceptTouchEvents(true), acceptMouseEvents(true),
+ mousePressId(0),
spinLoopWhenPressed(false), touchEventCount(0)
{
border()->setWidth(1);
@@ -153,16 +155,20 @@ public:
}
void reset() {
- acceptEvents = true;
+ acceptTouchEvents = acceptMouseEvents = true;
setEnabled(true);
setOpacity(1.0);
lastEvent = makeTouchData(QEvent::None, canvas(), 0, QList<QTouchEvent::TouchPoint>());//CHECK_VALID
+
+ lastVelocity = lastVelocityFromMouseMove = QVector2D();
+ lastMousePos = QPointF();
+ lastMouseCapabilityFlags = 0;
}
static void clearMousePressCounter()
{
- mousePressNum = 0;
+ mousePressNum = mouseMoveNum = mouseReleaseNum = 0;
}
void clearTouchEventCounter()
@@ -170,40 +176,78 @@ public:
touchEventCount = 0;
}
- bool acceptEvents;
+ bool acceptTouchEvents;
+ bool acceptMouseEvents;
TouchEventData lastEvent;
int mousePressId;
bool spinLoopWhenPressed;
int touchEventCount;
+ QVector2D lastVelocity;
+ QVector2D lastVelocityFromMouseMove;
+ QPointF lastMousePos;
+ int lastMouseCapabilityFlags;
-protected:
- virtual void touchEvent(QTouchEvent *event) {
- if (!acceptEvents) {
+ void touchEvent(QTouchEvent *event) {
+ if (!acceptTouchEvents) {
event->ignore();
return;
}
++touchEventCount;
lastEvent = makeTouchData(event->type(), event->window(), event->touchPointStates(), event->touchPoints());
- event->accept();
+ if (event->device()->capabilities().testFlag(QTouchDevice::Velocity) && !event->touchPoints().isEmpty()) {
+ lastVelocity = event->touchPoints().first().velocity();
+ } else {
+ lastVelocity = QVector2D();
+ }
if (spinLoopWhenPressed && event->touchPointStates().testFlag(Qt::TouchPointPressed)) {
QCoreApplication::processEvents();
}
}
- virtual void mousePressEvent(QMouseEvent *) {
+ void mousePressEvent(QMouseEvent *e) {
+ if (!acceptMouseEvents) {
+ e->ignore();
+ return;
+ }
mousePressId = ++mousePressNum;
+ lastMousePos = e->pos();
+ lastMouseCapabilityFlags = QGuiApplicationPrivate::mouseEventCaps(e);
+ }
+
+ void mouseMoveEvent(QMouseEvent *e) {
+ if (!acceptMouseEvents) {
+ e->ignore();
+ return;
+ }
+ ++mouseMoveNum;
+ lastVelocityFromMouseMove = QGuiApplicationPrivate::mouseEventVelocity(e);
+ lastMouseCapabilityFlags = QGuiApplicationPrivate::mouseEventCaps(e);
+ lastMousePos = e->pos();
+ }
+
+ void mouseReleaseEvent(QMouseEvent *e) {
+ if (!acceptMouseEvents) {
+ e->ignore();
+ return;
+ }
+ ++mouseReleaseNum;
+ lastMousePos = e->pos();
+ lastMouseCapabilityFlags = QGuiApplicationPrivate::mouseEventCaps(e);
}
bool childMouseEventFilter(QQuickItem *, QEvent *event) {
+ // TODO Is it a bug if a QTouchEvent comes here?
if (event->type() == QEvent::MouseButtonPress)
mousePressId = ++mousePressNum;
return false;
}
- static int mousePressNum;
+ static int mousePressNum, mouseMoveNum, mouseReleaseNum;
};
int TestTouchItem::mousePressNum = 0;
+int TestTouchItem::mouseMoveNum = 0;
+int TestTouchItem::mouseReleaseNum = 0;
class ConstantUpdateItem : public QQuickItem
{
@@ -229,9 +273,13 @@ private slots:
void initTestCase()
{
QQmlDataTest::initTestCase();
- touchDevice = new QTouchDevice();
+ touchDevice = new QTouchDevice;
touchDevice->setType(QTouchDevice::TouchScreen);
QWindowSystemInterface::registerTouchDevice(touchDevice);
+ touchDeviceWithVelocity = new QTouchDevice;
+ touchDeviceWithVelocity->setType(QTouchDevice::TouchScreen);
+ touchDeviceWithVelocity->setCapabilities(QTouchDevice::Position | QTouchDevice::Velocity);
+ QWindowSystemInterface::registerTouchDevice(touchDeviceWithVelocity);
}
@@ -244,6 +292,9 @@ private slots:
void touchEvent_propagation_data();
void touchEvent_cancel();
void touchEvent_reentrant();
+ void touchEvent_velocity();
+
+ void mouseFromTouch_basic();
void clearCanvas();
@@ -262,6 +313,7 @@ private slots:
void ownershipRootItem();
private:
QTouchDevice *touchDevice;
+ QTouchDevice *touchDeviceWithVelocity;
};
//If the item calls update inside updatePaintNode, it should schedule another update
@@ -282,6 +334,7 @@ void tst_qquickcanvas::touchEvent_basic()
canvas->resize(250, 250);
canvas->setPos(100, 100);
canvas->show();
+ QTest::qWaitForWindowShown(canvas);
TestTouchItem *bottomItem = new TestTouchItem(canvas->rootItem());
bottomItem->setObjectName("Bottom Item");
@@ -307,7 +360,8 @@ void tst_qquickcanvas::touchEvent_basic()
QVERIFY(middleItem->lastEvent.touchPoints.isEmpty());
QVERIFY(bottomItem->lastEvent.touchPoints.isEmpty());
- TouchEventData d = makeTouchData(QEvent::TouchBegin, canvas, Qt::TouchPointPressed, makeTouchPoint(topItem,pos));
+ // At one point this was failing with kwin (KDE window manager) because canvas->setPos(100, 100)
+ // would put the decorated window at that position rather than the canvas itself.
COMPARE_TOUCH_DATA(topItem->lastEvent, makeTouchData(QEvent::TouchBegin, canvas, Qt::TouchPointPressed, makeTouchPoint(topItem, pos)));
topItem->reset();
@@ -356,6 +410,10 @@ void tst_qquickcanvas::touchEvent_basic()
COMPARE_TOUCH_DATA(bottomItem->lastEvent, makeTouchData(QEvent::TouchBegin, canvas, Qt::TouchPointPressed, makeTouchPoint(bottomItem, pos)));
topItem->reset();
bottomItem->reset();
+ // cleanup: what is pressed must be released
+ // Otherwise you will get an assertion failure:
+ // ASSERT: "itemForTouchPointId.isEmpty()" in file items/qquickcanvas.cpp
+ QTest::touchEvent(canvas, touchDevice).release(0, pos.toPoint(), canvas).release(1, pos.toPoint(), canvas);
// move touch point from top item to bottom, and release
QTest::touchEvent(canvas, touchDevice).press(0, topItem->mapToScene(pos).toPoint(),canvas);
@@ -395,7 +453,8 @@ void tst_qquickcanvas::touchEvent_propagation()
{
TestTouchItem::clearMousePressCounter();
- QFETCH(bool, acceptEvents);
+ QFETCH(bool, acceptTouchEvents);
+ QFETCH(bool, acceptMouseEvents);
QFETCH(bool, enableItem);
QFETCH(qreal, itemOpacity);
@@ -403,6 +462,7 @@ void tst_qquickcanvas::touchEvent_propagation()
canvas->resize(250, 250);
canvas->setPos(100, 100);
canvas->show();
+ QTest::qWaitForWindowShown(canvas);
TestTouchItem *bottomItem = new TestTouchItem(canvas->rootItem());
bottomItem->setObjectName("Bottom Item");
@@ -424,7 +484,8 @@ void tst_qquickcanvas::touchEvent_propagation()
QPoint pointInTopItem = topItem->mapToScene(pos).toPoint(); // (110, 110) overlaps with bottom & top items
// disable topItem
- topItem->acceptEvents = acceptEvents;
+ topItem->acceptTouchEvents = acceptTouchEvents;
+ topItem->acceptMouseEvents = acceptMouseEvents;
topItem->setEnabled(enableItem);
topItem->setOpacity(itemOpacity);
@@ -450,7 +511,8 @@ void tst_qquickcanvas::touchEvent_propagation()
middleItem->reset();
// disable middleItem as well
- middleItem->acceptEvents = acceptEvents;
+ middleItem->acceptTouchEvents = acceptTouchEvents;
+ middleItem->acceptMouseEvents = acceptMouseEvents;
middleItem->setEnabled(enableItem);
middleItem->setOpacity(itemOpacity);
@@ -467,7 +529,7 @@ void tst_qquickcanvas::touchEvent_propagation()
bottomItem->reset();
// disable bottom item as well
- bottomItem->acceptEvents = acceptEvents;
+ bottomItem->acceptTouchEvents = acceptTouchEvents;
bottomItem->setEnabled(enableItem);
bottomItem->setOpacity(itemOpacity);
@@ -485,7 +547,7 @@ void tst_qquickcanvas::touchEvent_propagation()
bottomItem->reset();
// disable middle item, touch on top item
- middleItem->acceptEvents = acceptEvents;
+ middleItem->acceptTouchEvents = acceptTouchEvents;
middleItem->setEnabled(enableItem);
middleItem->setOpacity(itemOpacity);
QTest::touchEvent(canvas, touchDevice).press(0, pointInTopItem, canvas);
@@ -514,13 +576,14 @@ void tst_qquickcanvas::touchEvent_propagation()
void tst_qquickcanvas::touchEvent_propagation_data()
{
- QTest::addColumn<bool>("acceptEvents");
+ QTest::addColumn<bool>("acceptTouchEvents");
+ QTest::addColumn<bool>("acceptMouseEvents");
QTest::addColumn<bool>("enableItem");
QTest::addColumn<qreal>("itemOpacity");
- QTest::newRow("disable events") << false << true << 1.0;
- QTest::newRow("disable item") << true << false << 1.0;
- QTest::newRow("opacity of 0") << true << true << 0.0;
+ QTest::newRow("disable events") << false << false << true << 1.0;
+ QTest::newRow("disable item") << true << true << false << 1.0;
+ QTest::newRow("opacity of 0") << true << true << true << 0.0;
}
void tst_qquickcanvas::touchEvent_cancel()
@@ -531,6 +594,7 @@ void tst_qquickcanvas::touchEvent_cancel()
canvas->resize(250, 250);
canvas->setPos(100, 100);
canvas->show();
+ QTest::qWaitForWindowShown(canvas);
TestTouchItem *item = new TestTouchItem(canvas->rootItem());
item->setPos(QPointF(50, 50));
@@ -562,6 +626,7 @@ void tst_qquickcanvas::touchEvent_reentrant()
canvas->resize(250, 250);
canvas->setPos(100, 100);
canvas->show();
+ QTest::qWaitForWindowShown(canvas);
TestTouchItem *item = new TestTouchItem(canvas->rootItem());
@@ -590,6 +655,126 @@ void tst_qquickcanvas::touchEvent_reentrant()
delete canvas;
}
+void tst_qquickcanvas::touchEvent_velocity()
+{
+ TestTouchItem::clearMousePressCounter();
+
+ QQuickCanvas *canvas = new QQuickCanvas;
+ canvas->resize(250, 250);
+ canvas->setPos(100, 100);
+ canvas->show();
+ QTest::qWaitForWindowShown(canvas);
+ QTest::qWait(10);
+
+ TestTouchItem *item = new TestTouchItem(canvas->rootItem());
+ item->setPos(QPointF(50, 50));
+ item->setSize(QSizeF(150, 150));
+
+ QList<QWindowSystemInterface::TouchPoint> points;
+ QWindowSystemInterface::TouchPoint tp;
+ tp.id = 1;
+ tp.state = Qt::TouchPointPressed;
+ QPoint pos = canvas->mapToGlobal(item->mapToScene(QPointF(10, 10)).toPoint());
+ tp.area = QRectF(pos, QSizeF(4, 4));
+ points << tp;
+ QWindowSystemInterface::handleTouchEvent(canvas, touchDeviceWithVelocity, points);
+ points[0].state = Qt::TouchPointMoved;
+ points[0].area.adjust(5, 5, 5, 5);
+ QVector2D velocity(1.5, 2.5);
+ points[0].velocity = velocity;
+ QWindowSystemInterface::handleTouchEvent(canvas, touchDeviceWithVelocity, points);
+ QCoreApplication::processEvents();
+ QCOMPARE(item->touchEventCount, 2);
+ QCOMPARE(item->lastEvent.touchPoints.count(), 1);
+ QCOMPARE(item->lastVelocity, velocity);
+
+ // Now have a transformation on the item and check if velocity and position are transformed accordingly.
+ item->setRotation(90); // clockwise
+ QMatrix4x4 transformMatrix;
+ transformMatrix.rotate(-90, 0, 0, 1); // counterclockwise
+ QVector2D transformedVelocity = transformMatrix.mapVector(velocity).toVector2D();
+ points[0].area.adjust(5, 5, 5, 5);
+ QWindowSystemInterface::handleTouchEvent(canvas, touchDeviceWithVelocity, points);
+ QCoreApplication::processEvents();
+ QCOMPARE(item->lastVelocity, transformedVelocity);
+ QPoint itemLocalPos = item->mapFromScene(canvas->mapFromGlobal(points[0].area.center().toPoint())).toPoint();
+ QPoint itemLocalPosFromEvent = item->lastEvent.touchPoints[0].pos().toPoint();
+ QCOMPARE(itemLocalPos, itemLocalPosFromEvent);
+
+ points[0].state = Qt::TouchPointReleased;
+ QWindowSystemInterface::handleTouchEvent(canvas, touchDeviceWithVelocity, points);
+ QCoreApplication::processEvents();
+ delete item;
+ delete canvas;
+}
+
+void tst_qquickcanvas::mouseFromTouch_basic()
+{
+ // Turn off accepting touch events with acceptTouchEvents. This
+ // should result in sending mouse events generated from the touch
+ // with the new event propagation system.
+
+ TestTouchItem::clearMousePressCounter();
+ QQuickCanvas *canvas = new QQuickCanvas;
+ canvas->resize(250, 250);
+ canvas->setPos(100, 100);
+ canvas->show();
+ QTest::qWaitForWindowShown(canvas);
+ QTest::qWait(10);
+
+ TestTouchItem *item = new TestTouchItem(canvas->rootItem());
+ item->setPos(QPointF(50, 50));
+ item->setSize(QSizeF(150, 150));
+ item->acceptTouchEvents = false;
+
+ QList<QWindowSystemInterface::TouchPoint> points;
+ QWindowSystemInterface::TouchPoint tp;
+ tp.id = 1;
+ tp.state = Qt::TouchPointPressed;
+ QPoint pos = canvas->mapToGlobal(item->mapToScene(QPointF(10, 10)).toPoint());
+ tp.area = QRectF(pos, QSizeF(4, 4));
+ points << tp;
+ QWindowSystemInterface::handleTouchEvent(canvas, touchDeviceWithVelocity, points);
+ points[0].state = Qt::TouchPointMoved;
+ points[0].area.adjust(5, 5, 5, 5);
+ QVector2D velocity(1.5, 2.5);
+ points[0].velocity = velocity;
+ QWindowSystemInterface::handleTouchEvent(canvas, touchDeviceWithVelocity, points);
+ points[0].state = Qt::TouchPointReleased;
+ QWindowSystemInterface::handleTouchEvent(canvas, touchDeviceWithVelocity, points);
+ QCoreApplication::processEvents();
+
+ // The item should have received a mouse press, move, and release.
+ QCOMPARE(item->mousePressNum, 1);
+ QCOMPARE(item->mouseMoveNum, 1);
+ QCOMPARE(item->mouseReleaseNum, 1);
+ QCOMPARE(item->lastMousePos.toPoint(), item->mapFromScene(canvas->mapFromGlobal(points[0].area.center().toPoint())).toPoint());
+ QCOMPARE(item->lastVelocityFromMouseMove, velocity);
+ QVERIFY((item->lastMouseCapabilityFlags & QTouchDevice::Velocity) != 0);
+
+ // Now the same with a transformation.
+ item->setRotation(90); // clockwise
+ QMatrix4x4 transformMatrix;
+ transformMatrix.rotate(-90, 0, 0, 1); // counterclockwise
+ QVector2D transformedVelocity = transformMatrix.mapVector(velocity).toVector2D();
+ points[0].state = Qt::TouchPointPressed;
+ points[0].velocity = velocity;
+ points[0].area = QRectF(pos, QSizeF(4, 4));
+ QWindowSystemInterface::handleTouchEvent(canvas, touchDeviceWithVelocity, points);
+ points[0].state = Qt::TouchPointMoved;
+ points[0].area.adjust(5, 5, 5, 5);
+ QWindowSystemInterface::handleTouchEvent(canvas, touchDeviceWithVelocity, points);
+ QCoreApplication::processEvents();
+ QCOMPARE(item->lastMousePos.toPoint(), item->mapFromScene(canvas->mapFromGlobal(points[0].area.center().toPoint())).toPoint());
+ QCOMPARE(item->lastVelocityFromMouseMove, transformedVelocity);
+
+ points[0].state = Qt::TouchPointReleased;
+ QWindowSystemInterface::handleTouchEvent(canvas, touchDeviceWithVelocity, points);
+ QCoreApplication::processEvents();
+ delete item;
+ delete canvas;
+}
+
void tst_qquickcanvas::clearCanvas()
{
QQuickCanvas *canvas = new QQuickCanvas;
@@ -613,6 +798,7 @@ void tst_qquickcanvas::mouseFiltering()
canvas->resize(250, 250);
canvas->setPos(100, 100);
canvas->show();
+ QTest::qWaitForWindowShown(canvas);
TestTouchItem *bottomItem = new TestTouchItem(canvas->rootItem());
bottomItem->setObjectName("Bottom Item");
@@ -820,6 +1006,7 @@ void tst_qquickcanvas::ignoreUnhandledMouseEvents()
QQuickCanvas* canvas = new QQuickCanvas;
canvas->resize(100, 100);
canvas->show();
+ QTest::qWaitForWindowShown(canvas);
QQuickItem* item = new QQuickItem;
item->setSize(QSizeF(100, 100));
diff --git a/tests/auto/quick/qquickmultipointtoucharea/tst_qquickmultipointtoucharea.cpp b/tests/auto/quick/qquickmultipointtoucharea/tst_qquickmultipointtoucharea.cpp
index c5ede2629e..9745e20d10 100644
--- a/tests/auto/quick/qquickmultipointtoucharea/tst_qquickmultipointtoucharea.cpp
+++ b/tests/auto/quick/qquickmultipointtoucharea/tst_qquickmultipointtoucharea.cpp
@@ -570,30 +570,24 @@ void tst_QQuickMultiPointTouchArea::inFlickable()
//moving one point vertically
QTest::touchEvent(canvas, device).press(0, p1);
- QTest::mousePress(canvas, Qt::LeftButton, 0, p1);
p1 += QPoint(0,15);
QTest::touchEvent(canvas, device).move(0, p1);
- QTest::mouseMove(canvas, p1);
p1 += QPoint(0,15);
QTest::touchEvent(canvas, device).move(0, p1);
- QTest::mouseMove(canvas, p1);
p1 += QPoint(0,15);
QTest::touchEvent(canvas, device).move(0, p1);
- QTest::mouseMove(canvas, p1);
p1 += QPoint(0,15);
QTest::touchEvent(canvas, device).move(0, p1);
- QTest::mouseMove(canvas, p1);
QVERIFY(flickable->contentY() < 0);
QCOMPARE(point11->pressed(), false);
QCOMPARE(point12->pressed(), false);
QTest::touchEvent(canvas, device).release(0, p1);
- QTest::mouseRelease(canvas,Qt::LeftButton, 0, p1);
QTest::qWait(50);
QTRY_VERIFY(!flickable->isMoving());
@@ -736,32 +730,26 @@ void tst_QQuickMultiPointTouchArea::inFlickable2()
// Check that we can still move the Flickable
p1 = QPoint(50,100);
QTest::touchEvent(canvas, device).press(0, p1);
- QTest::mousePress(canvas, Qt::LeftButton, 0, p1);
QCOMPARE(point11->pressed(), true);
p1 += QPoint(0,15);
QTest::touchEvent(canvas, device).move(0, p1);
- QTest::mouseMove(canvas, p1);
p1 += QPoint(0,15);
QTest::touchEvent(canvas, device).move(0, p1);
- QTest::mouseMove(canvas, p1);
p1 += QPoint(0,15);
QTest::touchEvent(canvas, device).move(0, p1);
- QTest::mouseMove(canvas, p1);
p1 += QPoint(0,15);
QTest::touchEvent(canvas, device).move(0, p1);
- QTest::mouseMove(canvas, p1);
QVERIFY(flickable->contentY() < 0);
QVERIFY(flickable->isMoving());
- QCOMPARE(point11->pressed(), false);
+ QCOMPARE(point11->pressed(), true);
QTest::touchEvent(canvas, device).release(0, p1);
- QTest::mouseRelease(canvas,Qt::LeftButton, 0, p1);
QTest::qWait(50);
QTRY_VERIFY(!flickable->isMoving());
diff --git a/tests/auto/quick/qquickpincharea/data/pinchproperties.qml b/tests/auto/quick/qquickpincharea/data/pinchproperties.qml
index 44d116184e..6665e2f597 100644
--- a/tests/auto/quick/qquickpincharea/data/pinchproperties.qml
+++ b/tests/auto/quick/qquickpincharea/data/pinchproperties.qml
@@ -4,6 +4,7 @@ Rectangle {
property variant center
property real scale
property int pointCount: 0
+ property bool pinchActive: false
width: 240; height: 320
color: "white"
Rectangle {
@@ -34,6 +35,7 @@ Rectangle {
whiteRect.center = pinch.center
whiteRect.scale = pinch.scale
whiteRect.pointCount = pinch.pointCount;
+ whiteRect.pinchActive = true;
}
onPinchUpdated: {
whiteRect.center = pinch.center
@@ -44,6 +46,7 @@ Rectangle {
whiteRect.center = pinch.center
whiteRect.scale = pinch.scale
whiteRect.pointCount = pinch.pointCount;
+ whiteRect.pinchActive = false;
}
}
}
diff --git a/tests/auto/quick/qquickpincharea/tst_qquickpincharea.cpp b/tests/auto/quick/qquickpincharea/tst_qquickpincharea.cpp
index 27efdf7e28..e0e4b6c4d8 100644
--- a/tests/auto/quick/qquickpincharea/tst_qquickpincharea.cpp
+++ b/tests/auto/quick/qquickpincharea/tst_qquickpincharea.cpp
@@ -229,31 +229,41 @@ void tst_QQuickPinchArea::scale()
QPoint p1(80, 80);
QPoint p2(100, 100);
-
- QTest::touchEvent(canvas, device).press(0, p1, canvas);
- QTest::touchEvent(canvas, device).stationary(0).press(1, p2, canvas);
- p1 -= QPoint(10,10);
- p2 += QPoint(10,10);
- QTest::touchEvent(canvas, device).move(0, p1,canvas).move(1, p2,canvas);
-
- QCOMPARE(root->property("scale").toReal(), 1.0);
-
- p1 -= QPoint(10,10);
- p2 += QPoint(10,10);
- QTest::touchEvent(canvas, device).move(0, p1,canvas).move(1, p2,canvas);
-
- QCOMPARE(root->property("scale").toReal(), 1.5);
- QCOMPARE(root->property("center").toPointF(), QPointF(40, 40)); // blackrect is at 50,50
- QCOMPARE(blackRect->scale(), 1.5);
+ {
+ QTest::QTouchEventSequence pinchSequence = QTest::touchEvent(canvas, device);
+ pinchSequence.press(0, p1, canvas).commit();
+ // In order for the stationary point to remember its previous position,
+ // we have to reuse the same pinchSequence object. Otherwise if we let it
+ // be destroyed and then start a new sequence, point 0 will default to being
+ // stationary at 0, 0, and PinchArea will filter out that touchpoint because
+ // it is outside its bounds.
+ pinchSequence.stationary(0).press(1, p2, canvas).commit();
+ p1 -= QPoint(10,10);
+ p2 += QPoint(10,10);
+ pinchSequence.move(0, p1,canvas).move(1, p2,canvas).commit();
+
+ QCOMPARE(root->property("scale").toReal(), 1.0);
+ QVERIFY(root->property("pinchActive").toBool());
+
+ p1 -= QPoint(10,10);
+ p2 += QPoint(10,10);
+ pinchSequence.move(0, p1,canvas).move(1, p2,canvas).commit();
+
+ QCOMPARE(root->property("scale").toReal(), 1.5);
+ QCOMPARE(root->property("center").toPointF(), QPointF(40, 40)); // blackrect is at 50,50
+ QCOMPARE(blackRect->scale(), 1.5);
+ }
// scale beyond bound
p1 -= QPoint(50,50);
p2 += QPoint(50,50);
- QTest::touchEvent(canvas, device).move(0, p1, canvas).move(1, p2, canvas);
-
- QCOMPARE(blackRect->scale(), 2.0);
-
- QTest::touchEvent(canvas, device).release(0, p1, canvas).release(1, p2, canvas);
+ {
+ QTest::QTouchEventSequence pinchSequence = QTest::touchEvent(canvas, device);
+ pinchSequence.move(0, p1, canvas).move(1, p2, canvas).commit();
+ QCOMPARE(blackRect->scale(), 2.0);
+ pinchSequence.release(0, p1, canvas).release(1, p2, canvas).commit();
+ }
+ QVERIFY(!root->property("pinchActive").toBool());
delete canvas;
}
@@ -282,21 +292,25 @@ void tst_QQuickPinchArea::pan()
QPoint p1(80, 80);
QPoint p2(100, 100);
-
- QTest::touchEvent(canvas, device).press(0, p1, canvas);
- QTest::touchEvent(canvas, device).stationary(0).press(1, p2, canvas);
- p1 += QPoint(10,10);
- p2 += QPoint(10,10);
- QTest::touchEvent(canvas, device).move(0, p1, canvas).move(1, p2, canvas);
-
- QCOMPARE(root->property("scale").toReal(), 1.0);
-
- p1 += QPoint(10,10);
- p2 += QPoint(10,10);
- QTest::touchEvent(canvas, device).move(0, p1, canvas).move(1, p2, canvas);
+ {
+ QTest::QTouchEventSequence pinchSequence = QTest::touchEvent(canvas, device);
+ pinchSequence.press(0, p1, canvas).commit();
+ // In order for the stationary point to remember its previous position,
+ // we have to reuse the same pinchSequence object.
+ pinchSequence.stationary(0).press(1, p2, canvas).commit();
+ p1 += QPoint(10,10);
+ p2 += QPoint(10,10);
+ pinchSequence.move(0, p1,canvas).move(1, p2,canvas).commit();
+
+ QCOMPARE(root->property("scale").toReal(), 1.0);
+ QVERIFY(root->property("pinchActive").toBool());
+
+ p1 += QPoint(10,10);
+ p2 += QPoint(10,10);
+ pinchSequence.move(0, p1,canvas).move(1, p2,canvas).commit();
+ }
QCOMPARE(root->property("center").toPointF(), QPointF(60, 60)); // blackrect is at 50,50
-
QCOMPARE(blackRect->x(), 60.0);
QCOMPARE(blackRect->y(), 60.0);
@@ -309,6 +323,7 @@ void tst_QQuickPinchArea::pan()
QCOMPARE(blackRect->y(), 160.0);
QTest::touchEvent(canvas, device).release(0, p1, canvas).release(1, p2, canvas);
+ QVERIFY(!root->property("pinchActive").toBool());
delete canvas;
}
@@ -341,57 +356,64 @@ void tst_QQuickPinchArea::retouch()
QPoint p1(80, 80);
QPoint p2(100, 100);
+ {
+ QTest::QTouchEventSequence pinchSequence = QTest::touchEvent(canvas, device);
+ pinchSequence.press(0, p1, canvas).commit();
+ // In order for the stationary point to remember its previous position,
+ // we have to reuse the same pinchSequence object.
+ pinchSequence.stationary(0).press(1, p2, canvas).commit();
+ p1 -= QPoint(10,10);
+ p2 += QPoint(10,10);
+ pinchSequence.move(0, p1,canvas).move(1, p2,canvas).commit();
- QTest::touchEvent(canvas, device).press(0, p1, canvas);
- QTest::touchEvent(canvas, device).stationary(0).press(1, p2, canvas);
- p1 -= QPoint(10,10);
- p2 += QPoint(10,10);
- QTest::touchEvent(canvas, device).move(0, p1, canvas).move(1, p2, canvas);
-
- QCOMPARE(root->property("scale").toReal(), 1.0);
+ QCOMPARE(root->property("scale").toReal(), 1.0);
+ QVERIFY(root->property("pinchActive").toBool());
- p1 -= QPoint(10,10);
- p2 += QPoint(10,10);
- QTest::touchEvent(canvas, device).move(0, p1, canvas).move(1, p2, canvas);
+ p1 -= QPoint(10,10);
+ p2 += QPoint(10,10);
+ pinchSequence.move(0, p1,canvas).move(1, p2,canvas).commit();
- QCOMPARE(startedSpy.count(), 1);
+ QCOMPARE(startedSpy.count(), 1);
- QCOMPARE(root->property("scale").toReal(), 1.5);
- QCOMPARE(root->property("center").toPointF(), QPointF(40, 40)); // blackrect is at 50,50
- QCOMPARE(blackRect->scale(), 1.5);
+ QCOMPARE(root->property("scale").toReal(), 1.5);
+ QCOMPARE(root->property("center").toPointF(), QPointF(40, 40)); // blackrect is at 50,50
+ QCOMPARE(blackRect->scale(), 1.5);
- QCOMPARE(canvas->rootObject()->property("pointCount").toInt(), 2);
+ QCOMPARE(canvas->rootObject()->property("pointCount").toInt(), 2);
- QCOMPARE(startedSpy.count(), 1);
- QCOMPARE(finishedSpy.count(), 0);
+ QCOMPARE(startedSpy.count(), 1);
+ QCOMPARE(finishedSpy.count(), 0);
- QTest::touchEvent(canvas, device).stationary(0).release(1, p2, canvas);
+ // Hold down the first finger but release the second one
+ pinchSequence.stationary(0).release(1, p2, canvas).commit();
- QCOMPARE(startedSpy.count(), 1);
- QCOMPARE(finishedSpy.count(), 0);
+ QCOMPARE(startedSpy.count(), 1);
+ QCOMPARE(finishedSpy.count(), 0);
- QCOMPARE(canvas->rootObject()->property("pointCount").toInt(), 1);
+ QCOMPARE(canvas->rootObject()->property("pointCount").toInt(), 1);
- QTest::touchEvent(canvas, device).stationary(0).press(1, p2, canvas);
- p1 -= QPoint(10,10);
- p2 += QPoint(10,10);
- QTest::touchEvent(canvas, device).move(0, p1, canvas).move(1, p2, canvas);
+ // Keep holding down the first finger and re-touch the second one, then move them both
+ pinchSequence.stationary(0).press(1, p2, canvas).commit();
+ p1 -= QPoint(10,10);
+ p2 += QPoint(10,10);
+ pinchSequence.move(0, p1, canvas).move(1, p2, canvas).commit();
- // Lifting and retouching results in onPinchStarted being called again
- QCOMPARE(startedSpy.count(), 2);
- QCOMPARE(finishedSpy.count(), 0);
+ // Lifting and retouching results in onPinchStarted being called again
+ QCOMPARE(startedSpy.count(), 2);
+ QCOMPARE(finishedSpy.count(), 0);
- QCOMPARE(canvas->rootObject()->property("pointCount").toInt(), 2);
+ QCOMPARE(canvas->rootObject()->property("pointCount").toInt(), 2);
- QTest::touchEvent(canvas, device).release(0, p1, canvas).release(1, p2, canvas);
+ pinchSequence.release(0, p1, canvas).release(1, p2, canvas).commit();
- QCOMPARE(startedSpy.count(), 2);
- QCOMPARE(finishedSpy.count(), 1);
+ QVERIFY(!root->property("pinchActive").toBool());
+ QCOMPARE(startedSpy.count(), 2);
+ QCOMPARE(finishedSpy.count(), 1);
+ }
delete canvas;
}
-
QQuickView *tst_QQuickPinchArea::createView()
{
QQuickView *canvas = new QQuickView(0);
diff --git a/tests/auto/quick/quick.pro b/tests/auto/quick/quick.pro
index 2ef6dc0357..fd78da2746 100644
--- a/tests/auto/quick/quick.pro
+++ b/tests/auto/quick/quick.pro
@@ -70,6 +70,7 @@ QUICKTESTS = \
qquickview \
qquickcanvasitem \
qquickscreen \
+ touchmouse \
SUBDIRS += $$PUBLICTESTS
diff --git a/tests/auto/quick/touchmouse/data/buttononflickable.qml b/tests/auto/quick/touchmouse/data/buttononflickable.qml
new file mode 100644
index 0000000000..95a993f806
--- /dev/null
+++ b/tests/auto/quick/touchmouse/data/buttononflickable.qml
@@ -0,0 +1,42 @@
+import QtQuick 2.0
+import Qt.test 1.0
+
+Rectangle {
+ id: root
+ width: 300
+ height: 500
+ color: "green"
+
+ Flickable {
+ objectName: "flickable"
+ anchors.fill: parent
+ contentHeight: 1000
+
+ Rectangle {
+ objectName: "button"
+ y: 100
+ height: 100
+ width: parent.width
+
+ EventItem {
+ objectName: "eventItem1"
+ height: 100
+ width: 300
+ }
+ }
+
+ Rectangle {
+ objectName: "button2"
+ y: 300
+ height: 100
+ width: parent.width
+
+ EventItem {
+ objectName: "eventItem2"
+ height: 100
+ width: 300
+ }
+ }
+ }
+}
+
diff --git a/tests/auto/quick/touchmouse/data/buttonontouch.qml b/tests/auto/quick/touchmouse/data/buttonontouch.qml
new file mode 100644
index 0000000000..dcd2573f2e
--- /dev/null
+++ b/tests/auto/quick/touchmouse/data/buttonontouch.qml
@@ -0,0 +1,100 @@
+import QtQuick 2.0
+import Qt.test 1.0
+
+Rectangle {
+ id: root
+ width: 300
+ height: 800
+ color: "green"
+
+ Rectangle {
+ color: "blue"
+ height: 400
+ width: parent.width
+
+
+ PinchArea {
+ pinch.target: button1
+ objectName: "pincharea"
+ anchors.fill: parent
+
+ pinch.minimumScale: 0.1
+ pinch.maximumScale: 10.0
+ }
+
+ Rectangle {
+
+ id: button1
+ objectName: "button1"
+ y: 100
+ height: 100
+ width: parent.width
+ Text { text: "Button 1" }
+
+ EventItem {
+ objectName: "eventItem1"
+ height: 100
+ width: 300
+ }
+ }
+
+ Rectangle {
+ objectName: "button2"
+ y: 300
+ height: 100
+ width: parent.width
+ Text { text: "Button 2" }
+
+ EventItem {
+ objectName: "eventItem2"
+ height: 100
+ width: 300
+ }
+ }
+ }
+
+ Rectangle {
+ y: 400
+ width: parent.width
+ height: parent.height
+ color: "red"
+
+ MultiPointTouchArea {
+ objectName: "toucharea"
+ anchors.fill: parent
+
+ y: 400
+ height: 400
+
+ Rectangle {
+ objectName: "button3"
+ y: 100
+ height: 100
+ width: parent.width
+ Text { text: "Button 3" }
+
+ EventItem {
+ objectName: "eventItem3"
+ height: 100
+ width: 300
+ }
+ }
+
+ Rectangle {
+ objectName: "button4"
+ y: 300
+ height: 100
+ width: parent.width
+ Text { text: "Button 4" }
+
+ EventItem {
+ objectName: "eventItem4"
+ height: 100
+ width: 300
+ }
+ }
+
+ }
+ }
+}
+
diff --git a/tests/auto/quick/touchmouse/data/flickableonpinch.qml b/tests/auto/quick/touchmouse/data/flickableonpinch.qml
new file mode 100644
index 0000000000..9c9a197d66
--- /dev/null
+++ b/tests/auto/quick/touchmouse/data/flickableonpinch.qml
@@ -0,0 +1,37 @@
+import QtQuick 2.0
+import Qt.test 1.0
+
+Rectangle {
+ id: root
+ width: 600
+ height: 600
+ color: "green"
+
+ PinchArea {
+ objectName: "pincharea"
+ pinch.target: rect
+ anchors.fill: parent
+
+ pinch.minimumScale: 1.0
+ pinch.maximumScale: 10.0
+
+ Flickable {
+ objectName: "flickable"
+ anchors.fill: parent
+ contentHeight: 1000
+ contentWidth: 1000
+
+ Rectangle {
+ objectName: "rect"
+ id: rect
+ color: "blue"
+ x: 200
+ y: 200
+ width: 400
+ height: 400
+ }
+ }
+ }
+
+}
+
diff --git a/tests/auto/quick/touchmouse/data/mouseonflickableonpinch.qml b/tests/auto/quick/touchmouse/data/mouseonflickableonpinch.qml
new file mode 100644
index 0000000000..015391f291
--- /dev/null
+++ b/tests/auto/quick/touchmouse/data/mouseonflickableonpinch.qml
@@ -0,0 +1,47 @@
+import QtQuick 2.0
+import Qt.test 1.0
+
+Rectangle {
+ id: root
+ width: 600
+ height: 600
+ color: "green"
+
+ PinchArea {
+ objectName: "pincharea"
+ pinch.target: rect
+ anchors.fill: parent
+
+ pinch.minimumScale: 1.0
+ pinch.maximumScale: 10.0
+
+ Flickable {
+ objectName: "flickable"
+ anchors.fill: parent
+ contentHeight: 1000
+ contentWidth: 1000
+
+ MouseArea {
+ anchors.fill: parent
+ onClicked: {
+ if (rect.color == "#000000")
+ rect.color = "#00ff00"
+ else
+ rect.color = "#000000"
+ }
+ }
+
+ Rectangle {
+ objectName: "rect"
+ id: rect
+ color: "blue"
+ x: 200
+ y: 200
+ width: 400
+ height: 400
+ }
+ }
+ }
+
+}
+
diff --git a/tests/auto/quick/touchmouse/data/pinchonflickable.qml b/tests/auto/quick/touchmouse/data/pinchonflickable.qml
new file mode 100644
index 0000000000..2a7a91006e
--- /dev/null
+++ b/tests/auto/quick/touchmouse/data/pinchonflickable.qml
@@ -0,0 +1,35 @@
+import QtQuick 2.0
+//import Qt.test 1.0
+
+Rectangle {
+ id: root
+ width: 600
+ height: 600
+ color: "green"
+
+ Flickable {
+ objectName: "flickable"
+ anchors.fill: parent
+ contentHeight: 1000
+ contentWidth: 1000
+
+ Rectangle {
+ objectName: "rect"
+ id: rect
+ color: "blue"
+ x: 200
+ y: 200
+ width: 400
+ height: 400
+ }
+ PinchArea {
+ objectName: "pincharea"
+ pinch.target: rect
+ anchors.fill: parent
+
+ pinch.minimumScale: 1.0
+ pinch.maximumScale: 10.0
+ }
+ }
+}
+
diff --git a/tests/auto/quick/touchmouse/data/singleitem.qml b/tests/auto/quick/touchmouse/data/singleitem.qml
new file mode 100644
index 0000000000..76d3a51da9
--- /dev/null
+++ b/tests/auto/quick/touchmouse/data/singleitem.qml
@@ -0,0 +1,18 @@
+import QtQuick 2.0
+import Qt.test 1.0
+
+Rectangle {
+ id: root
+ width: 320
+ height: 480
+ color: "green"
+
+ EventItem {
+ objectName: "eventItem1"
+ x: 5
+ y: 5
+ height: 30
+ width: 30
+ }
+}
+
diff --git a/tests/auto/quick/touchmouse/data/twoitems.qml b/tests/auto/quick/touchmouse/data/twoitems.qml
new file mode 100644
index 0000000000..afbf35fe1a
--- /dev/null
+++ b/tests/auto/quick/touchmouse/data/twoitems.qml
@@ -0,0 +1,22 @@
+import QtQuick 2.0
+import Qt.test 1.0
+
+Rectangle {
+ id: root
+ width: 320
+ height: 480
+ color: "green"
+
+ EventItem {
+ objectName: "eventItem1"
+ height: 200
+ width: 100
+
+ EventItem {
+ objectName: "eventItem2"
+ height: 100
+ width: 100
+ }
+ }
+}
+
diff --git a/tests/auto/quick/touchmouse/touchmouse.pro b/tests/auto/quick/touchmouse/touchmouse.pro
new file mode 100644
index 0000000000..d0b0fa79f2
--- /dev/null
+++ b/tests/auto/quick/touchmouse/touchmouse.pro
@@ -0,0 +1,17 @@
+CONFIG += testcase
+
+TARGET = tst_touchmouse
+QT += core-private gui-private qml-private quick-private v8-private testlib
+
+macx:CONFIG -= app_bundle
+
+SOURCES += tst_touchmouse.cpp
+
+include (../../shared/util.pri)
+
+TESTDATA = data/*
+
+# OTHER_FILES += data/foo.qml
+
+CONFIG += parallel_test
+
diff --git a/tests/auto/quick/touchmouse/tst_touchmouse.cpp b/tests/auto/quick/touchmouse/tst_touchmouse.cpp
new file mode 100644
index 0000000000..7ab9387ea7
--- /dev/null
+++ b/tests/auto/quick/touchmouse/tst_touchmouse.cpp
@@ -0,0 +1,923 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 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 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtTest/QtTest>
+
+#include <QtGui/qstylehints.h>
+
+#include <QtQuick/qquickview.h>
+#include <QtQuick/qquickitem.h>
+#include <QtQuick/private/qquickmousearea_p.h>
+#include <QtQuick/private/qquickmultipointtoucharea_p.h>
+#include <QtQuick/private/qquickpincharea_p.h>
+#include <QtQuick/private/qquickflickable_p.h>
+
+#include <private/qquickcanvas_p.h>
+
+#include <QtQml/qqmlengine.h>
+#include <QtQml/qqmlproperty.h>
+
+#include "../../shared/util.h"
+
+struct Event
+{
+ Event(QEvent::Type t, QPoint mouse, QPoint global)
+ :type(t), mousePos(mouse), mousePosGlobal(global)
+ {}
+
+ Event(QEvent::Type t, QList<QTouchEvent::TouchPoint> touch)
+ :type(t), points(touch)
+ {}
+
+ QEvent::Type type;
+ QPoint mousePos;
+ QPoint mousePosGlobal;
+ QList<QTouchEvent::TouchPoint> points;
+};
+
+class EventItem : public QQuickItem
+{
+ Q_OBJECT
+public:
+ EventItem(QQuickItem *parent = 0)
+ : QQuickItem(parent), acceptMouse(false), acceptTouch(false), filterTouch(false)
+ {}
+
+ void touchEvent(QTouchEvent *event)
+ {
+ eventList.append(Event(event->type(), event->touchPoints()));
+ event->setAccepted(acceptTouch);
+ }
+ void mousePressEvent(QMouseEvent *event)
+ {
+ eventList.append(Event(event->type(), event->pos(), event->globalPos()));
+ event->setAccepted(acceptMouse);
+ }
+ void mouseMoveEvent(QMouseEvent *event)
+ {
+ eventList.append(Event(event->type(), event->pos(), event->globalPos()));
+ event->setAccepted(acceptMouse);
+ }
+ void mouseReleaseEvent(QMouseEvent *event)
+ {
+ eventList.append(Event(event->type(), event->pos(), event->globalPos()));
+ event->setAccepted(acceptMouse);
+ }
+ void mouseDoubleClickEvent(QMouseEvent *event)
+ {
+ eventList.append(Event(event->type(), event->pos(), event->globalPos()));
+ event->setAccepted(acceptMouse);
+ }
+ bool event(QEvent *event) {
+ if (event->type() == QEvent::UngrabMouse) {
+ eventList.append(Event(event->type(), QPoint(0,0), QPoint(0,0)));
+ }
+ return QQuickItem::event(event);
+ }
+
+ QList<Event> eventList;
+ bool acceptMouse;
+ bool acceptTouch;
+ bool filterTouch; // when used as event filter
+
+ bool eventFilter(QObject *, QEvent *event)
+ {
+ if (event->type() == QEvent::TouchBegin ||
+ event->type() == QEvent::TouchUpdate ||
+ event->type() == QEvent::TouchCancel ||
+ event->type() == QEvent::TouchEnd) {
+ QTouchEvent *touch = static_cast<QTouchEvent*>(event);
+ eventList.append(Event(event->type(), touch->touchPoints()));
+ if (filterTouch)
+ event->accept();
+ return true;
+ }
+ return false;
+ }
+};
+
+class tst_TouchMouse : public QQmlDataTest
+{
+ Q_OBJECT
+public:
+ tst_TouchMouse()
+ :device(0)
+ {}
+
+private slots:
+ void initTestCase();
+
+ void simpleTouchEvent();
+ void eventFilter();
+ void mouse();
+ void touchOverMouse();
+ void mouseOverTouch();
+
+ void buttonOnFlickable();
+ void buttonOnTouch();
+
+ void pinchOnFlickable();
+ void flickableOnPinch();
+ void mouseOnFlickableOnPinch();
+
+private:
+ QQuickView *createView();
+ QTouchDevice *device;
+};
+
+QQuickView *tst_TouchMouse::createView()
+{
+ QQuickView *canvas = new QQuickView(0);
+ canvas->setGeometry(0,0,240,320);
+
+ return canvas;
+}
+
+void tst_TouchMouse::initTestCase()
+{
+ // This test assumes that we don't get synthesized mouse events from QGuiApplication
+ qApp->setAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents, false);
+
+ QQmlDataTest::initTestCase();
+ qmlRegisterType<EventItem>("Qt.test", 1, 0, "EventItem");
+ if (!device) {
+ device = new QTouchDevice;
+ device->setType(QTouchDevice::TouchScreen);
+ QWindowSystemInterface::registerTouchDevice(device);
+ }
+}
+
+void tst_TouchMouse::simpleTouchEvent()
+{
+ QQuickView *canvas = createView();
+
+ canvas->setSource(testFileUrl("singleitem.qml"));
+ canvas->show();
+ canvas->requestActivateWindow();
+ QTest::qWaitForWindowShown(canvas);
+ QVERIFY(canvas->rootObject() != 0);
+
+ EventItem *eventItem1 = canvas->rootObject()->findChild<EventItem*>("eventItem1");
+ QVERIFY(eventItem1);
+
+ // Do not accept touch or mouse
+ QPoint p1;
+ p1 = QPoint(20, 20);
+ QTest::touchEvent(canvas, device).press(0, p1, canvas);
+ QCOMPARE(eventItem1->eventList.size(), 1);
+ QCOMPARE(eventItem1->eventList.at(0).type, QEvent::TouchBegin);
+ p1 += QPoint(10, 0);
+ QTest::touchEvent(canvas, device).move(0, p1, canvas);
+ QCOMPARE(eventItem1->eventList.size(), 1);
+ QTest::touchEvent(canvas, device).release(0, p1, canvas);
+ QCOMPARE(eventItem1->eventList.size(), 1);
+ eventItem1->eventList.clear();
+
+ // Accept touch
+ eventItem1->acceptTouch = true;
+ p1 = QPoint(20, 20);
+ QTest::touchEvent(canvas, device).press(0, p1, canvas);
+ QCOMPARE(eventItem1->eventList.size(), 1);
+ p1 += QPoint(10, 0);
+ QTest::touchEvent(canvas, device).move(0, p1, canvas);
+ QCOMPARE(eventItem1->eventList.size(), 2);
+ QTest::touchEvent(canvas, device).release(0, p1, canvas);
+ QCOMPARE(eventItem1->eventList.size(), 3);
+ eventItem1->eventList.clear();
+
+ // wait to avoid getting a double click event
+ QTest::qWait(qApp->styleHints()->mouseDoubleClickInterval() + 10);
+
+ // Accept mouse
+ eventItem1->acceptTouch = false;
+ eventItem1->acceptMouse = true;
+ eventItem1->setAcceptedMouseButtons(Qt::LeftButton);
+ p1 = QPoint(20, 20);
+ QTest::touchEvent(canvas, device).press(0, p1, canvas);
+ QCOMPARE(eventItem1->eventList.size(), 2);
+ QCOMPARE(eventItem1->eventList.at(0).type, QEvent::TouchBegin);
+ QCOMPARE(eventItem1->eventList.at(1).type, QEvent::MouseButtonPress);
+ QQuickCanvasPrivate *canvasPriv = QQuickCanvasPrivate::get(canvas);
+ QCOMPARE(canvasPriv->mouseGrabberItem, eventItem1);
+
+ QPoint localPos = eventItem1->mapFromScene(p1).toPoint();
+ QPoint globalPos = canvas->mapToGlobal(p1);
+ QPoint scenePos = p1; // item is at 0,0
+ QCOMPARE(eventItem1->eventList.at(0).points.at(0).pos().toPoint(), localPos);
+ QCOMPARE(eventItem1->eventList.at(0).points.at(0).scenePos().toPoint(), scenePos);
+ QCOMPARE(eventItem1->eventList.at(0).points.at(0).screenPos().toPoint(), globalPos);
+ QCOMPARE(eventItem1->eventList.at(1).mousePos, localPos);
+ QCOMPARE(eventItem1->eventList.at(1).mousePosGlobal, globalPos);
+
+ p1 += QPoint(10, 0);
+ QTest::touchEvent(canvas, device).move(0, p1, canvas);
+ QCOMPARE(eventItem1->eventList.size(), 4);
+ QCOMPARE(eventItem1->eventList.at(2).type, QEvent::TouchUpdate);
+ QCOMPARE(eventItem1->eventList.at(3).type, QEvent::MouseMove);
+ QTest::touchEvent(canvas, device).release(0, p1, canvas);
+ QCOMPARE(eventItem1->eventList.size(), 6);
+ QCOMPARE(eventItem1->eventList.at(4).type, QEvent::TouchEnd);
+ QCOMPARE(eventItem1->eventList.at(5).type, QEvent::MouseButtonRelease);
+ eventItem1->eventList.clear();
+
+ // wait to avoid getting a double click event
+ QTest::qWait(qApp->styleHints()->mouseDoubleClickInterval() + 10);
+
+ // Accept mouse buttons but not the event
+ eventItem1->acceptTouch = false;
+ eventItem1->acceptMouse = false;
+ eventItem1->setAcceptedMouseButtons(Qt::LeftButton);
+ p1 = QPoint(20, 20);
+ QTest::touchEvent(canvas, device).press(0, p1, canvas);
+ QCOMPARE(eventItem1->eventList.size(), 2);
+ QCOMPARE(eventItem1->eventList.at(0).type, QEvent::TouchBegin);
+ QCOMPARE(eventItem1->eventList.at(1).type, QEvent::MouseButtonPress);
+ p1 += QPoint(10, 0);
+ QTest::touchEvent(canvas, device).move(0, p1, canvas);
+ QCOMPARE(eventItem1->eventList.size(), 2);
+ QTest::touchEvent(canvas, device).release(0, p1, canvas);
+ QCOMPARE(eventItem1->eventList.size(), 2);
+ eventItem1->eventList.clear();
+
+ // wait to avoid getting a double click event
+ QTest::qWait(qApp->styleHints()->mouseDoubleClickInterval() + 10);
+
+ // Accept touch and mouse
+ eventItem1->acceptTouch = true;
+ eventItem1->setAcceptedMouseButtons(Qt::LeftButton);
+ p1 = QPoint(20, 20);
+ QTest::touchEvent(canvas, device).press(0, p1, canvas);
+ QCOMPARE(eventItem1->eventList.size(), 1);
+ QCOMPARE(eventItem1->eventList.at(0).type, QEvent::TouchBegin);
+ p1 += QPoint(10, 0);
+ QTest::touchEvent(canvas, device).move(0, p1, canvas);
+ QCOMPARE(eventItem1->eventList.size(), 2);
+ QCOMPARE(eventItem1->eventList.at(1).type, QEvent::TouchUpdate);
+ QTest::touchEvent(canvas, device).release(0, p1, canvas);
+ QCOMPARE(eventItem1->eventList.size(), 3);
+ QCOMPARE(eventItem1->eventList.at(2).type, QEvent::TouchEnd);
+ eventItem1->eventList.clear();
+
+ delete canvas;
+}
+
+void tst_TouchMouse::eventFilter()
+{
+// // install event filter on item and see that it can grab events
+// QQuickView *canvas = createView();
+
+// canvas->setSource(testFileUrl("singleitem.qml"));
+// canvas->show();
+// canvas->requestActivateWindow();
+// QVERIFY(canvas->rootObject() != 0);
+
+// EventItem *eventItem1 = canvas->rootObject()->findChild<EventItem*>("eventItem1");
+// QVERIFY(eventItem1);
+// eventItem1->acceptTouch = true;
+
+// EventItem *filter = new EventItem;
+// filter->filterTouch = true;
+// eventItem1->installEventFilter(filter);
+
+// QPoint p1 = QPoint(20, 20);
+// QTest::touchEvent(canvas, device).press(0, p1, canvas);
+// // QEXPECT_FAIL("", "We do not implement event filters correctly", Abort);
+// QCOMPARE(eventItem1->eventList.size(), 0);
+// QCOMPARE(filter->eventList.size(), 1);
+// QTest::touchEvent(canvas, device).release(0, p1, canvas);
+// QCOMPARE(eventItem1->eventList.size(), 0);
+// QCOMPARE(filter->eventList.size(), 2);
+
+// delete filter;
+// delete canvas;
+}
+
+void tst_TouchMouse::mouse()
+{
+ // eventItem1
+ // - eventItem2
+
+ QTest::qWait(qApp->styleHints()->mouseDoubleClickInterval() + 10);
+ QQuickView *canvas = createView();
+
+ canvas->setSource(testFileUrl("twoitems.qml"));
+ canvas->show();
+ canvas->requestActivateWindow();
+ QVERIFY(canvas->rootObject() != 0);
+
+ EventItem *eventItem1 = canvas->rootObject()->findChild<EventItem*>("eventItem1");
+ QVERIFY(eventItem1);
+ EventItem *eventItem2 = canvas->rootObject()->findChild<EventItem*>("eventItem2");
+ QVERIFY(eventItem2);
+ QTest::qWaitForWindowShown(canvas);
+
+ // bottom item likes mouse, top likes touch
+ eventItem1->setAcceptedMouseButtons(Qt::LeftButton);
+ eventItem1->acceptMouse = true;
+ // item 2 doesn't accept anything, thus it sees a touch pass by
+ QPoint p1 = QPoint(30, 30);
+ QTest::touchEvent(canvas, device).press(0, p1, canvas);
+
+ QCOMPARE(eventItem1->eventList.size(), 2);
+ QCOMPARE(eventItem1->eventList.at(0).type, QEvent::TouchBegin);
+ QCOMPARE(eventItem1->eventList.at(1).type, QEvent::MouseButtonPress);
+
+ delete canvas;
+}
+
+void tst_TouchMouse::touchOverMouse()
+{
+ // eventItem1
+ // - eventItem2
+
+ QQuickView *canvas = createView();
+
+ canvas->setSource(testFileUrl("twoitems.qml"));
+ canvas->show();
+ canvas->requestActivateWindow();
+ QVERIFY(canvas->rootObject() != 0);
+
+ EventItem *eventItem1 = canvas->rootObject()->findChild<EventItem*>("eventItem1");
+ QVERIFY(eventItem1);
+ EventItem *eventItem2 = canvas->rootObject()->findChild<EventItem*>("eventItem2");
+ QVERIFY(eventItem2);
+
+ // bottom item likes mouse, top likes touch
+ eventItem1->setAcceptedMouseButtons(Qt::LeftButton);
+ eventItem2->acceptTouch = true;
+
+ QTest::qWaitForWindowShown(canvas);
+
+ QCOMPARE(eventItem1->eventList.size(), 0);
+ QPoint p1 = QPoint(20, 20);
+ QTest::touchEvent(canvas, device).press(0, p1, canvas);
+ QCOMPARE(eventItem1->eventList.size(), 0);
+ QCOMPARE(eventItem2->eventList.size(), 1);
+ QCOMPARE(eventItem2->eventList.at(0).type, QEvent::TouchBegin);
+ p1 += QPoint(10, 0);
+ QTest::touchEvent(canvas, device).move(0, p1, canvas);
+ QCOMPARE(eventItem2->eventList.size(), 2);
+ QCOMPARE(eventItem2->eventList.at(1).type, QEvent::TouchUpdate);
+ QTest::touchEvent(canvas, device).release(0, p1, canvas);
+ QCOMPARE(eventItem2->eventList.size(), 3);
+ QCOMPARE(eventItem2->eventList.at(2).type, QEvent::TouchEnd);
+ eventItem2->eventList.clear();
+
+ delete canvas;
+}
+
+void tst_TouchMouse::mouseOverTouch()
+{
+ // eventItem1
+ // - eventItem2
+
+ QQuickView *canvas = createView();
+
+ canvas->setSource(testFileUrl("twoitems.qml"));
+ canvas->show();
+ canvas->requestActivateWindow();
+ QVERIFY(canvas->rootObject() != 0);
+
+ EventItem *eventItem1 = canvas->rootObject()->findChild<EventItem*>("eventItem1");
+ QVERIFY(eventItem1);
+ EventItem *eventItem2 = canvas->rootObject()->findChild<EventItem*>("eventItem2");
+ QVERIFY(eventItem2);
+
+ // bottom item likes mouse, top likes touch
+ eventItem1->acceptTouch = true;
+ eventItem2->setAcceptedMouseButtons(Qt::LeftButton);
+ eventItem2->acceptMouse = true;
+
+ QTest::qWaitForWindowShown(canvas);
+
+ QPoint p1 = QPoint(20, 20);
+ QTest::qWait(qApp->styleHints()->mouseDoubleClickInterval() + 10);
+ QTest::touchEvent(canvas, device).press(0, p1, canvas);
+ QCOMPARE(eventItem1->eventList.size(), 0);
+ QCOMPARE(eventItem2->eventList.size(), 2);
+ QCOMPARE(eventItem2->eventList.at(0).type, QEvent::TouchBegin);
+ QCOMPARE(eventItem2->eventList.at(1).type, QEvent::MouseButtonPress);
+
+
+// p1 += QPoint(10, 0);
+// QTest::touchEvent(canvas, device).move(0, p1, canvas);
+// QCOMPARE(eventItem2->eventList.size(), 1);
+// QTest::touchEvent(canvas, device).release(0, p1, canvas);
+// QCOMPARE(eventItem2->eventList.size(), 1);
+// eventItem2->eventList.clear();
+
+ delete canvas;
+}
+
+void tst_TouchMouse::buttonOnFlickable()
+{
+ // flickable - height 500 / 1000
+ // - eventItem1 y: 100, height 100
+ // - eventItem2 y: 300, height 100
+
+ QQuickView *canvas = createView();
+
+ canvas->setSource(testFileUrl("buttononflickable.qml"));
+ canvas->show();
+ canvas->requestActivateWindow();
+ QVERIFY(canvas->rootObject() != 0);
+
+ QQuickFlickable *flickable = canvas->rootObject()->findChild<QQuickFlickable*>("flickable");
+ QVERIFY(flickable);
+
+ // should a mouse area button be clickable on top of flickable? yes :)
+ EventItem *eventItem1 = canvas->rootObject()->findChild<EventItem*>("eventItem1");
+ QVERIFY(eventItem1);
+ eventItem1->setAcceptedMouseButtons(Qt::LeftButton);
+ eventItem1->acceptMouse = true;
+
+ // should a touch button be touchable on top of flickable? yes :)
+ EventItem *eventItem2 = canvas->rootObject()->findChild<EventItem*>("eventItem2");
+ QVERIFY(eventItem2);
+ QCOMPARE(eventItem2->eventList.size(), 0);
+ eventItem2->acceptTouch = true;
+
+ // wait to avoid getting a double click event
+ QTest::qWait(qApp->styleHints()->mouseDoubleClickInterval() + 10);
+
+ // check that buttons are clickable
+ // mouse button
+ QCOMPARE(eventItem1->eventList.size(), 0);
+ QPoint p1 = QPoint(20, 130);
+ QTest::touchEvent(canvas, device).press(0, p1, canvas);
+ QCOMPARE(eventItem1->eventList.size(), 2);
+ QCOMPARE(eventItem1->eventList.at(0).type, QEvent::TouchBegin);
+ QCOMPARE(eventItem1->eventList.at(1).type, QEvent::MouseButtonPress);
+ QTest::touchEvent(canvas, device).release(0, p1, canvas);
+ QCOMPARE(eventItem1->eventList.size(), 4);
+ QCOMPARE(eventItem1->eventList.at(2).type, QEvent::TouchEnd);
+ QCOMPARE(eventItem1->eventList.at(3).type, QEvent::MouseButtonRelease);
+ eventItem1->eventList.clear();
+
+ // touch button
+ p1 = QPoint(10, 310);
+ QTest::touchEvent(canvas, device).press(0, p1, canvas);
+ QCOMPARE(eventItem2->eventList.size(), 1);
+ QCOMPARE(eventItem2->eventList.at(0).type, QEvent::TouchBegin);
+ QTest::touchEvent(canvas, device).release(0, p1, canvas);
+ QCOMPARE(eventItem2->eventList.size(), 2);
+ QCOMPARE(eventItem2->eventList.at(1).type, QEvent::TouchEnd);
+ QCOMPARE(eventItem1->eventList.size(), 0);
+ eventItem2->eventList.clear();
+
+ // wait to avoid getting a double click event
+ QTest::qWait(qApp->styleHints()->mouseDoubleClickInterval() + 10);
+
+ // click above button, no events please
+ p1 = QPoint(10, 90);
+ QTest::touchEvent(canvas, device).press(0, p1, canvas);
+ QCOMPARE(eventItem1->eventList.size(), 0);
+ QTest::touchEvent(canvas, device).release(0, p1, canvas);
+ QCOMPARE(eventItem1->eventList.size(), 0);
+ eventItem1->eventList.clear();
+
+ // wait to avoid getting a double click event
+ QTest::qWait(qApp->styleHints()->mouseDoubleClickInterval() + 10);
+
+ // check that flickable moves - mouse button
+ QCOMPARE(eventItem1->eventList.size(), 0);
+ p1 = QPoint(10, 110);
+ QTest::touchEvent(canvas, device).press(0, p1, canvas);
+ QCOMPARE(eventItem1->eventList.size(), 2);
+ QCOMPARE(eventItem1->eventList.at(0).type, QEvent::TouchBegin);
+ QCOMPARE(eventItem1->eventList.at(1).type, QEvent::MouseButtonPress);
+
+ QQuickCanvasPrivate *canvasPriv = QQuickCanvasPrivate::get(canvas);
+ QCOMPARE(canvasPriv->touchMouseId, 0);
+ QCOMPARE(canvasPriv->itemForTouchPointId[0], eventItem1);
+ QCOMPARE(canvasPriv->mouseGrabberItem, eventItem1);
+
+ p1 += QPoint(0, -10);
+ QPoint p2 = p1 + QPoint(0, -10);
+ QPoint p3 = p2 + QPoint(0, -10);
+ QTest::qWait(10);
+ QTest::touchEvent(canvas, device).move(0, p1, canvas);
+ QTest::qWait(10);
+ QTest::touchEvent(canvas, device).move(0, p2, canvas);
+ QTest::qWait(10);
+ QTest::touchEvent(canvas, device).move(0, p3, canvas);
+
+ // we cannot really know when the events get grabbed away
+ QVERIFY(eventItem1->eventList.size() >= 4);
+ QCOMPARE(eventItem1->eventList.at(2).type, QEvent::TouchUpdate);
+ QCOMPARE(eventItem1->eventList.at(3).type, QEvent::MouseMove);
+
+ QCOMPARE(canvasPriv->mouseGrabberItem, flickable);
+ QVERIFY(flickable->isMovingVertically());
+
+ QTest::touchEvent(canvas, device).release(0, p3, canvas);
+ delete canvas;
+}
+
+void tst_TouchMouse::buttonOnTouch()
+{
+ // 400x800
+ // PinchArea - height 400
+ // - eventItem1 y: 100, height 100
+ // - eventItem2 y: 300, height 100
+ // MultiPointTouchArea - height 400
+ // - eventItem1 y: 100, height 100
+ // - eventItem2 y: 300, height 100
+
+ QQuickView *canvas = createView();
+ canvas->setSource(testFileUrl("buttonontouch.qml"));
+ canvas->show();
+ canvas->requestActivateWindow();
+ QVERIFY(canvas->rootObject() != 0);
+
+ QQuickPinchArea *pinchArea = canvas->rootObject()->findChild<QQuickPinchArea*>("pincharea");
+ QVERIFY(pinchArea);
+ QQuickItem *button1 = canvas->rootObject()->findChild<QQuickItem*>("button1");
+ QVERIFY(button1);
+ EventItem *eventItem1 = canvas->rootObject()->findChild<EventItem*>("eventItem1");
+ QVERIFY(eventItem1);
+ EventItem *eventItem2 = canvas->rootObject()->findChild<EventItem*>("eventItem2");
+ QVERIFY(eventItem2);
+
+ QQuickMultiPointTouchArea *touchArea = canvas->rootObject()->findChild<QQuickMultiPointTouchArea*>("toucharea");
+ QVERIFY(touchArea);
+ EventItem *eventItem3 = canvas->rootObject()->findChild<EventItem*>("eventItem3");
+ QVERIFY(eventItem3);
+ EventItem *eventItem4 = canvas->rootObject()->findChild<EventItem*>("eventItem4");
+ QVERIFY(eventItem4);
+
+
+ // Test the common case of a mouse area on top of pinch
+ eventItem1->setAcceptedMouseButtons(Qt::LeftButton);
+ eventItem1->acceptMouse = true;
+
+
+ // wait to avoid getting a double click event
+ QTest::qWait(qApp->styleHints()->mouseDoubleClickInterval() + 10);
+
+ // Normal touch click
+ QPoint p1 = QPoint(10, 110);
+ QTest::touchEvent(canvas, device).press(0, p1, canvas);
+ QTest::touchEvent(canvas, device).release(0, p1, canvas);
+ QCOMPARE(eventItem1->eventList.size(), 4);
+ QCOMPARE(eventItem1->eventList.at(0).type, QEvent::TouchBegin);
+ QCOMPARE(eventItem1->eventList.at(1).type, QEvent::MouseButtonPress);
+ QCOMPARE(eventItem1->eventList.at(2).type, QEvent::TouchEnd);
+ QCOMPARE(eventItem1->eventList.at(3).type, QEvent::MouseButtonRelease);
+ eventItem1->eventList.clear();
+
+ // Normal mouse click
+ QTest::mouseClick(canvas, Qt::LeftButton, 0, p1);
+ QCOMPARE(eventItem1->eventList.size(), 2);
+ QCOMPARE(eventItem1->eventList.at(0).type, QEvent::MouseButtonPress);
+ QCOMPARE(eventItem1->eventList.at(1).type, QEvent::MouseButtonRelease);
+ eventItem1->eventList.clear();
+
+ // Pinch starting on the PinchArea should work
+ p1 = QPoint(40, 10);
+ QPoint p2 = QPoint(60, 10);
+
+ // Start the events after each other
+ QTest::touchEvent(canvas, device).press(0, p1, canvas);
+ QTest::touchEvent(canvas, device).stationary(0).press(1, p2, canvas);
+
+ QCOMPARE(button1->scale(), 1.0);
+
+ // This event seems to be discarded, let's ignore it for now until someone digs into pincharea
+ p1 -= QPoint(10, 0);
+ p2 += QPoint(10, 0);
+ QTest::touchEvent(canvas, device).move(0, p1, canvas).move(1, p2, canvas);
+
+ p1 -= QPoint(10, 0);
+ p2 += QPoint(10, 0);
+ QTest::touchEvent(canvas, device).move(0, p1, canvas).move(1, p2, canvas);
+// QCOMPARE(button1->scale(), 1.5);
+ qDebug() << "Button scale: " << button1->scale();
+
+ p1 -= QPoint(10, 0);
+ p2 += QPoint(10, 0);
+ QTest::touchEvent(canvas, device).move(0, p1, canvas).move(1, p2, canvas);
+// QCOMPARE(button1->scale(), 2.0);
+ qDebug() << "Button scale: " << button1->scale();
+
+ QTest::touchEvent(canvas, device).release(0, p1, canvas).release(1, p2, canvas);
+// QVERIFY(eventItem1->eventList.isEmpty());
+// QCOMPARE(button1->scale(), 2.0);
+ qDebug() << "Button scale: " << button1->scale();
+
+
+ // wait to avoid getting a double click event
+ QTest::qWait(qApp->styleHints()->mouseDoubleClickInterval() + 10);
+
+ // Start pinching while on the button
+ button1->setScale(1.0);
+ p1 = QPoint(40, 110);
+ p2 = QPoint(60, 110);
+ QTest::touchEvent(canvas, device).press(0, p1, canvas).press(1, p2, canvas);
+ QCOMPARE(button1->scale(), 1.0);
+ QCOMPARE(eventItem1->eventList.count(), 2);
+ QCOMPARE(eventItem1->eventList.at(0).type, QEvent::TouchBegin);
+ QCOMPARE(eventItem1->eventList.at(1).type, QEvent::MouseButtonPress);
+
+ // This event seems to be discarded, let's ignore it for now until someone digs into pincharea
+ p1 -= QPoint(10, 0);
+ p2 += QPoint(10, 0);
+ QTest::touchEvent(canvas, device).move(0, p1, canvas).move(1, p2, canvas);
+
+ p1 -= QPoint(10, 0);
+ p2 += QPoint(10, 0);
+ QTest::touchEvent(canvas, device).move(0, p1, canvas).move(1, p2, canvas);
+ //QCOMPARE(button1->scale(), 1.5);
+ qDebug() << button1->scale();
+
+ p1 -= QPoint(10, 0);
+ p2 += QPoint(10, 0);
+ QTest::touchEvent(canvas, device).move(0, p1, canvas).move(1, p2, canvas);
+ qDebug() << button1->scale();
+ //QCOMPARE(button1->scale(), 2.0);
+
+ QTest::touchEvent(canvas, device).release(0, p1, canvas).release(1, p2, canvas);
+// QCOMPARE(eventItem1->eventList.size(), 99);
+ qDebug() << button1->scale();
+ //QCOMPARE(button1->scale(), 2.0);
+
+ delete canvas;
+}
+
+void tst_TouchMouse::pinchOnFlickable()
+{
+ QQuickView *canvas = createView();
+ canvas->setSource(testFileUrl("pinchonflickable.qml"));
+ canvas->show();
+ canvas->requestActivateWindow();
+ QVERIFY(canvas->rootObject() != 0);
+
+ QQuickPinchArea *pinchArea = canvas->rootObject()->findChild<QQuickPinchArea*>("pincharea");
+ QVERIFY(pinchArea);
+ QQuickFlickable *flickable = canvas->rootObject()->findChild<QQuickFlickable*>("flickable");
+ QVERIFY(flickable);
+ QQuickItem *rect = canvas->rootObject()->findChild<QQuickItem*>("rect");
+ QVERIFY(rect);
+
+ // flickable - single touch point
+ QVERIFY(flickable->contentX() == 0.0);
+ QPoint p = QPoint(100, 100);
+ QTest::touchEvent(canvas, device).press(0, p, canvas);
+ QCOMPARE(rect->pos(), QPointF(200.0, 200.0));
+ p -= QPoint(10, 0);
+ QTest::touchEvent(canvas, device).move(0, p, canvas);
+ p -= QPoint(10, 0);
+ QTest::touchEvent(canvas, device).move(0, p, canvas);
+ QTest::qWait(10);
+ p -= QPoint(10, 0);
+ QTest::touchEvent(canvas, device).move(0, p, canvas);
+ QTest::qWait(10);
+ p -= QPoint(10, 0);
+ QTest::touchEvent(canvas, device).move(0, p, canvas);
+ QTest::touchEvent(canvas, device).release(0, p, canvas);
+
+ QGuiApplication::processEvents();
+ QTest::qWait(10);
+ QVERIFY(!flickable->isAtXBeginning());
+ // wait until flicking is done
+ QTRY_VERIFY(!flickable->isFlicking());
+
+ // pinch
+ QPoint p1 = QPoint(40, 20);
+ QPoint p2 = QPoint(60, 20);
+
+ QTest::QTouchEventSequence pinchSequence = QTest::touchEvent(canvas, device);
+ pinchSequence.press(0, p1, canvas).commit();
+ // In order for the stationary point to remember its previous position,
+ // we have to reuse the same pinchSequence object. Otherwise if we let it
+ // be destroyed and then start a new sequence, point 0 will default to being
+ // stationary at 0, 0, and PinchArea will filter out that touchpoint because
+ // it is outside its bounds.
+ pinchSequence.stationary(0).press(1, p2, canvas).commit();
+ p1 -= QPoint(10,10);
+ p2 += QPoint(10,10);
+ pinchSequence.move(0, p1, canvas).move(1, p2, canvas).commit();
+ QCOMPARE(rect->scale(), 1.0);
+ p1 -= QPoint(10, 0);
+ p2 += QPoint(10, 0);
+ pinchSequence.move(0, p1, canvas).move(1, p2, canvas).commit();
+ p1 -= QPoint(10, 0);
+ p2 += QPoint(10, 0);
+ pinchSequence.move(0, p1, canvas).move(1, p2, canvas).commit();
+ p1 -= QPoint(10, 0);
+ p2 += QPoint(10, 0);
+ pinchSequence.move(0, p1, canvas).move(1, p2, canvas).commit();
+ pinchSequence.release(0, p1, canvas).release(1, p2, canvas).commit();
+ QVERIFY(rect->scale() > 1.0);
+}
+
+void tst_TouchMouse::flickableOnPinch()
+{
+ QQuickView *canvas = createView();
+ canvas->setSource(testFileUrl("flickableonpinch.qml"));
+ canvas->show();
+ canvas->requestActivateWindow();
+ QVERIFY(canvas->rootObject() != 0);
+
+ QQuickPinchArea *pinchArea = canvas->rootObject()->findChild<QQuickPinchArea*>("pincharea");
+ QVERIFY(pinchArea);
+ QQuickFlickable *flickable = canvas->rootObject()->findChild<QQuickFlickable*>("flickable");
+ QVERIFY(flickable);
+ QQuickItem *rect = canvas->rootObject()->findChild<QQuickItem*>("rect");
+ QVERIFY(rect);
+
+ // flickable - single touch point
+ QVERIFY(flickable->contentX() == 0.0);
+ QPoint p = QPoint(100, 100);
+ QTest::touchEvent(canvas, device).press(0, p, canvas);
+ QCOMPARE(rect->pos(), QPointF(200.0, 200.0));
+ p -= QPoint(10, 0);
+ QTest::touchEvent(canvas, device).move(0, p, canvas);
+ p -= QPoint(10, 0);
+ QTest::touchEvent(canvas, device).move(0, p, canvas);
+
+ QTest::qWait(1000);
+
+ p -= QPoint(10, 0);
+ QTest::touchEvent(canvas, device).move(0, p, canvas);
+ QTest::touchEvent(canvas, device).release(0, p, canvas);
+
+ QTest::qWait(1000);
+
+ //QVERIFY(flickable->isMovingHorizontally());
+ qDebug() << "Pos: " << rect->pos();
+ // wait until flicking is done
+ QTRY_VERIFY(!flickable->isFlicking());
+
+ // pinch
+ QPoint p1 = QPoint(40, 20);
+ QPoint p2 = QPoint(60, 20);
+ QTest::QTouchEventSequence pinchSequence = QTest::touchEvent(canvas, device);
+ pinchSequence.press(0, p1, canvas).commit();
+ // In order for the stationary point to remember its previous position,
+ // we have to reuse the same pinchSequence object. Otherwise if we let it
+ // be destroyed and then start a new sequence, point 0 will default to being
+ // stationary at 0, 0, and PinchArea will filter out that touchpoint because
+ // it is outside its bounds.
+ pinchSequence.stationary(0).press(1, p2, canvas).commit();
+ p1 -= QPoint(10,10);
+ p2 += QPoint(10,10);
+ pinchSequence.move(0, p1, canvas).move(1, p2, canvas).commit();
+ QCOMPARE(rect->scale(), 1.0);
+ p1 -= QPoint(10, 0);
+ p2 += QPoint(10, 0);
+ pinchSequence.move(0, p1, canvas).move(1, p2, canvas).commit();
+ p1 -= QPoint(10, 0);
+ p2 += QPoint(10, 0);
+ pinchSequence.move(0, p1, canvas).move(1, p2, canvas).commit();
+ p1 -= QPoint(10, 0);
+ p2 += QPoint(10, 0);
+ pinchSequence.move(0, p1, canvas).move(1, p2, canvas).commit();
+ pinchSequence.release(0, p1, canvas).release(1, p2, canvas).commit();
+ QVERIFY(rect->scale() > 1.0);
+}
+
+void tst_TouchMouse::mouseOnFlickableOnPinch()
+{
+ QQuickView *canvas = createView();
+ canvas->setSource(testFileUrl("mouseonflickableonpinch.qml"));
+ canvas->show();
+ canvas->requestActivateWindow();
+ QVERIFY(canvas->rootObject() != 0);
+
+ QQuickPinchArea *pinchArea = canvas->rootObject()->findChild<QQuickPinchArea*>("pincharea");
+ QVERIFY(pinchArea);
+ QQuickFlickable *flickable = canvas->rootObject()->findChild<QQuickFlickable*>("flickable");
+ QVERIFY(flickable);
+ QQuickItem *rect = canvas->rootObject()->findChild<QQuickItem*>("rect");
+ QVERIFY(rect);
+
+ // flickable - single touch point
+ QVERIFY(flickable->contentX() == 0.0);
+ QPoint p = QPoint(100, 100);
+ QTest::touchEvent(canvas, device).press(0, p, canvas);
+ QCOMPARE(rect->pos(), QPointF(200.0, 200.0));
+ p -= QPoint(10, 0);
+ QTest::touchEvent(canvas, device).move(0, p, canvas);
+ p -= QPoint(10, 0);
+ QTest::touchEvent(canvas, device).move(0, p, canvas);
+
+ QTest::qWait(1000);
+
+ p -= QPoint(10, 0);
+ QTest::touchEvent(canvas, device).move(0, p, canvas);
+ QTest::touchEvent(canvas, device).release(0, p, canvas);
+
+ QTest::qWait(1000);
+
+ //QVERIFY(flickable->isMovingHorizontally());
+ qDebug() << "Pos: " << rect->pos();
+
+ // pinch
+ QPoint p1 = QPoint(40, 20);
+ QPoint p2 = QPoint(60, 20);
+ QTest::QTouchEventSequence pinchSequence = QTest::touchEvent(canvas, device);
+ pinchSequence.press(0, p1, canvas).commit();
+ // In order for the stationary point to remember its previous position,
+ // we have to reuse the same pinchSequence object. Otherwise if we let it
+ // be destroyed and then start a new sequence, point 0 will default to being
+ // stationary at 0, 0, and PinchArea will filter out that touchpoint because
+ // it is outside its bounds.
+ pinchSequence.stationary(0).press(1, p2, canvas).commit();
+ p1 -= QPoint(10,10);
+ p2 += QPoint(10,10);
+ pinchSequence.move(0, p1, canvas).move(1, p2, canvas).commit();
+ QCOMPARE(rect->scale(), 1.0);
+ p1 -= QPoint(10, 0);
+ p2 += QPoint(10, 0);
+ pinchSequence.move(0, p1, canvas).move(1, p2, canvas).commit();
+ p1 -= QPoint(10, 0);
+ p2 += QPoint(10, 0);
+ pinchSequence.move(0, p1, canvas).move(1, p2, canvas).commit();
+ p1 -= QPoint(10, 0);
+ p2 += QPoint(10, 0);
+ pinchSequence.move(0, p1, canvas).move(1, p2, canvas).commit();
+ pinchSequence.release(0, p1, canvas).release(1, p2, canvas).commit();
+ QVERIFY(rect->scale() > 1.0);
+
+ // PinchArea should steal the event after flicking started
+ rect->setScale(1.0);
+ flickable->setContentX(0.0);
+ p = QPoint(100, 100);
+ pinchSequence.press(0, p, canvas).commit();
+ QCOMPARE(rect->pos(), QPointF(200.0, 200.0));
+ p -= QPoint(10, 0);
+ pinchSequence.move(0, p, canvas).commit();
+ p -= QPoint(10, 0);
+ pinchSequence.move(0, p, canvas).commit();
+ QTest::qWait(1000);
+ p -= QPoint(10, 0);
+ pinchSequence.move(0, p, canvas).commit();
+
+ QQuickCanvasPrivate *canvasPriv = QQuickCanvasPrivate::get(canvas);
+ QCOMPARE(canvasPriv->mouseGrabberItem, flickable);
+ qDebug() << "Mouse Grabber: " << canvasPriv->mouseGrabberItem << " itemForTouchPointId: " << canvasPriv->itemForTouchPointId;
+
+ // Add a second finger, this should lead to stealing
+ p1 = QPoint(40, 100);
+ p2 = QPoint(60, 100);
+ pinchSequence.stationary(0).press(1, p2, canvas).commit();
+ QCOMPARE(rect->scale(), 1.0);
+
+ p1 -= QPoint(5, 0);
+ p2 += QPoint(5, 0);
+ pinchSequence.move(0, p1, canvas).move(1, p2, canvas).commit();
+ p1 -= QPoint(5, 0);
+ p2 += QPoint(5, 0);
+ pinchSequence.move(0, p1, canvas).move(1, p2, canvas).commit();
+ p1 -= QPoint(5, 0);
+ p2 += QPoint(5, 0);
+ pinchSequence.move(0, p1, canvas).move(1, p2, canvas).commit();
+ pinchSequence.release(0, p1, canvas).release(1, p2, canvas).commit();
+ QVERIFY(rect->scale() > 1.0);
+ pinchSequence.release(0, p, canvas).commit();
+}
+
+QTEST_MAIN(tst_TouchMouse)
+
+#include "tst_touchmouse.moc"
+