summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBradley T. Hughes <bradley.hughes@nokia.com>2009-05-18 13:32:39 (GMT)
committerBradley T. Hughes <bradley.hughes@nokia.com>2009-05-18 13:32:39 (GMT)
commit6cc1e0106845a0dfe9433c4413b3c064c73ccfe2 (patch)
treea0372fb3e03000dc1e1f93a4154adecd70fd5119
parent86edc526684d80e405bcd1c63b5a314b70408679 (diff)
parent537243d70de1474cf234880b215c75e83e80abcd (diff)
downloadQt-6cc1e0106845a0dfe9433c4413b3c064c73ccfe2.zip
Qt-6cc1e0106845a0dfe9433c4413b3c064c73ccfe2.tar.gz
Qt-6cc1e0106845a0dfe9433c4413b3c064c73ccfe2.tar.bz2
Merge branch 'master' of git@scm.dev.nokia.troll.no:qt/qt-multitouch
-rw-r--r--src/gui/graphicsview/qgraphicsitem.cpp44
-rw-r--r--src/gui/graphicsview/qgraphicsitem_p.h6
-rw-r--r--src/gui/graphicsview/qgraphicsproxywidget.cpp16
-rw-r--r--src/gui/graphicsview/qgraphicsscene.cpp120
-rw-r--r--src/gui/graphicsview/qgraphicsscene_p.h5
-rw-r--r--src/gui/graphicsview/qgraphicssceneevent.cpp9
-rw-r--r--src/gui/graphicsview/qgraphicssceneevent.h1
-rw-r--r--src/gui/graphicsview/qgraphicsview.cpp1
-rw-r--r--src/gui/kernel/qapplication.cpp9
-rw-r--r--src/gui/kernel/qapplication_p.h3
-rw-r--r--src/gui/kernel/qgesture.h6
-rw-r--r--src/gui/kernel/qgesture_p.h4
-rw-r--r--src/gui/kernel/qgesturemanager.cpp142
-rw-r--r--src/gui/kernel/qgesturemanager_p.h11
-rw-r--r--src/gui/kernel/qgesturerecognizer.cpp3
-rw-r--r--src/gui/kernel/qgesturerecognizer.h2
-rw-r--r--src/gui/kernel/qwidget.cpp22
-rw-r--r--src/gui/kernel/qwidget_p.h1
-rw-r--r--tests/auto/gestures/customgesturerecognizer.cpp105
-rw-r--r--tests/auto/gestures/customgesturerecognizer.h147
-rw-r--r--tests/auto/gestures/gestures.pro3
-rw-r--r--tests/auto/gestures/tst_gestures.cpp487
22 files changed, 1035 insertions, 112 deletions
diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp
index 747d510..ae33674 100644
--- a/src/gui/graphicsview/qgraphicsitem.cpp
+++ b/src/gui/graphicsview/qgraphicsitem.cpp
@@ -5857,6 +5857,7 @@ QVariant QGraphicsItem::inputMethodQuery(Qt::InputMethodQuery query) const
*/
int QGraphicsItem::grabGesture(Qt::GestureType gesture)
{
+ /// TODO: if we are QGraphicsProxyWidget we should subscribe the widget to gesture as well.
return grabGesture(qt_getStandardGestureTypeName(gesture));
}
@@ -5872,12 +5873,30 @@ int QGraphicsItem::grabGesture(Qt::GestureType gesture)
int QGraphicsItem::grabGesture(const QString &gesture)
{
int id = QGestureManager::instance()->makeGestureId(gesture);
- d_ptr->gestures << id;
- if (d_ptr->scene)
- d_ptr->scene->d_func()->grabGesture(this, id);
+ d_ptr->grabGesture(id);
return id;
}
+void QGraphicsItemPrivate::grabGesture(int id)
+{
+ Q_Q(QGraphicsItem);
+ gestures << id;
+ if (scene)
+ scene->d_func()->grabGesture(q, id);
+}
+
+bool QGraphicsItemPrivate::releaseGesture(int id)
+{
+ Q_Q(QGraphicsItem);
+ if (gestures.contains(id)) {
+ if (scene)
+ scene->d_func()->releaseGesture(q, id);
+ gestures.remove(id);
+ return true;
+ }
+ return false;
+}
+
/*!
\since 4.6
@@ -5888,10 +5907,9 @@ int QGraphicsItem::grabGesture(const QString &gesture)
*/
void QGraphicsItem::releaseGesture(int gestureId)
{
- if (d_ptr->scene)
- d_ptr->scene->d_func()->releaseGesture(this, gestureId);
- QGestureManager::instance()->releaseGestureId(gestureId);
- d_ptr->gestures.remove(gestureId);
+ /// TODO: if we are QGraphicsProxyWidget we should unsubscribe the widget from gesture as well.
+ if (d_ptr->releaseGesture(gestureId))
+ QGestureManager::instance()->releaseGestureId(gestureId);
}
/*!
@@ -5909,6 +5927,18 @@ void QGraphicsItem::setGestureEnabled(int gestureId, bool enable)
//###
}
+bool QGraphicsItemPrivate::hasGesture(const QString &name) const
+{
+ QGestureManager *gm = QGestureManager::instance();
+ QSet<int>::const_iterator it = gestures.begin(),
+ e = gestures.end();
+ for (; it != e; ++it) {
+ if (gm->gestureNameFromId(*it) == name)
+ return true;
+ }
+ return false;
+}
+
/*!
This virtual function is called by QGraphicsItem to notify custom items
that some part of the item's state changes. By reimplementing this
diff --git a/src/gui/graphicsview/qgraphicsitem_p.h b/src/gui/graphicsview/qgraphicsitem_p.h
index b6daa85..091a461 100644
--- a/src/gui/graphicsview/qgraphicsitem_p.h
+++ b/src/gui/graphicsview/qgraphicsitem_p.h
@@ -305,7 +305,11 @@ public:
int depth;
QSet<int> gestures;
- // Packed 32 bits
+ bool hasGesture(const QString &gesture) const;
+ void grabGesture(int id);
+ bool releaseGesture(int id);
+
+ // Packed 32 bytes
quint32 acceptedMouseButtons : 5;
quint32 visible : 1;
quint32 explicitlyHidden : 1;
diff --git a/src/gui/graphicsview/qgraphicsproxywidget.cpp b/src/gui/graphicsview/qgraphicsproxywidget.cpp
index 01b7593..5641068 100644
--- a/src/gui/graphicsview/qgraphicsproxywidget.cpp
+++ b/src/gui/graphicsview/qgraphicsproxywidget.cpp
@@ -48,6 +48,7 @@
#include "private/qgraphicsproxywidget_p.h"
#include "private/qwidget_p.h"
#include "private/qapplication_p.h"
+#include "private/qgesturemanager_p.h"
#include <QtCore/qdebug.h>
#include <QtGui/qevent.h>
@@ -275,7 +276,7 @@ void QGraphicsProxyWidgetPrivate::sendWidgetMouseEvent(QGraphicsSceneMouseEvent
QWidget *embeddedMouseGrabberPtr = (QWidget *)embeddedMouseGrabber;
QApplicationPrivate::sendMouseEvent(receiver, mouseEvent, alienWidget, widget,
- &embeddedMouseGrabberPtr, lastWidgetUnderMouse);
+ &embeddedMouseGrabberPtr, lastWidgetUnderMouse, event->spontaneous());
embeddedMouseGrabber = embeddedMouseGrabberPtr;
// Handle enter/leave events when last button is released from mouse
@@ -648,6 +649,9 @@ void QGraphicsProxyWidgetPrivate::setWidget_helper(QWidget *newWidget, bool auto
q->setAttribute(Qt::WA_OpaquePaintEvent);
widget = newWidget;
+ foreach(int gestureId, widget->d_func()->gestures) {
+ grabGesture(gestureId);
+ }
// Changes only go from the widget to the proxy.
enabledChangeMode = QGraphicsProxyWidgetPrivate::WidgetToProxyMode;
@@ -871,6 +875,16 @@ bool QGraphicsProxyWidget::event(QEvent *event)
}
break;
}
+ case QEvent::GraphicsSceneGesture: {
+ qDebug() << "QGraphicsProxyWidget: graphicsscenegesture";
+ if (d->widget && d->widget->isVisible()) {
+ QGraphicsSceneGestureEvent *ge = static_cast<QGraphicsSceneGestureEvent*>(event);
+ //### TODO: widget->childAt(): decompose gesture event and find widget under hotspots.
+ //QGestureManager::instance()->sendGestureEvent(d->widget, ge->gestures().toSet(), ge->cancelledGestures());
+ return true;
+ }
+ break;
+ }
default:
break;
}
diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp
index 4d0d991..8e5ebdb 100644
--- a/src/gui/graphicsview/qgraphicsscene.cpp
+++ b/src/gui/graphicsview/qgraphicsscene.cpp
@@ -248,6 +248,7 @@ static const int QGRAPHICSSCENE_INDEXTIMER_TIMEOUT = 2000;
#include <private/qt_x11_p.h>
#endif
#include <private/qgesturemanager_p.h>
+#include <private/qgesture_p.h>
QT_BEGIN_NAMESPACE
@@ -3919,40 +3920,44 @@ bool QGraphicsScene::event(QEvent *event)
update();
break;
case QEvent::GraphicsSceneGesture: {
+ qDebug() << "GraphicsSceneGesture";
QGraphicsSceneGestureEvent *ev = static_cast<QGraphicsSceneGestureEvent*>(event);
- QList<QString> gestureTypes = ev->gestureTypes();
QGraphicsView *view = qobject_cast<QGraphicsView*>(ev->widget());
if (!view) {
qWarning("QGraphicsScene::event: gesture event was received without a view");
break;
}
- // find graphics items that intersects with gestures hot spots.
- QPolygonF poly;
- QMap<QString, QPointF> sceneHotSpots;
- foreach(const QString &type, gestureTypes) {
- QPointF pt = ev->mapToScene(ev->gesture(type)->hotSpot());
- sceneHotSpots.insert(type, pt);
- poly << pt;
+ // get a list of gestures that just started.
+ QSet<QGesture*> startedGestures;
+ QList<QGesture*> gestures = ev->gestures();
+ for(QList<QGesture*>::const_iterator it = gestures.begin(), e = gestures.end();
+ it != e; ++it) {
+ QGesture *g = *it;
+ QGesturePrivate *gd = g->d_func();
+ if (g->state() == Qt::GestureStarted || gd->singleshot) {
+ startedGestures.insert(g);
+ }
}
- QList<QGraphicsItem*> itemsInGestureArea = items(poly, Qt::IntersectsItemBoundingRect);
-
- foreach(QGraphicsItem *item, itemsInGestureArea) {
- QMap<QString, QPointF>::const_iterator it = sceneHotSpots.begin(),
- e = sceneHotSpots.end();
- for(; it != e; ++it) {
- if (item->contains(item->mapFromScene(it.value()))) {
- const QString gestureName = it.key();
- foreach(int gestureId, item->d_ptr->gestures) {
- if (QGestureManager::instance()->gestureNameFromId(gestureId) == gestureName) {
- d->sendEvent(item, ev);
- if (ev->isAccepted())
- break;
- }
+ if (!startedGestures.isEmpty()) {
+ // find a target for each started gesture.
+ for(QSet<QGesture*>::const_iterator it = startedGestures.begin(), e = startedGestures.end();
+ it != e; ++it) {
+ QGesture *g = *it;
+ QGesturePrivate *gd = g->d_func();
+ QList<QGraphicsItem*> itemsInGestureArea = items(g->hotSpot());
+ const QString gestureName = g->type();
+ foreach(QGraphicsItem *item, itemsInGestureArea) {
+ if (item->d_func()->hasGesture(gestureName)) {
+ Q_ASSERT(gd->graphicsItem == 0);
+ gd->graphicsItem = item;
+ d->itemsWithGestures[item].insert(g);
+ break;
}
}
}
}
+ d->sendGestureEvent(ev->gestures().toSet(), ev->cancelledGestures());
}
break;
case QEvent::GraphicsSceneTouchBegin:
@@ -3976,6 +3981,74 @@ bool QGraphicsScene::event(QEvent *event)
return true;
}
+void QGraphicsScenePrivate::sendGestureEvent(const QSet<QGesture*> &gestures, const QSet<QString> &cancelled)
+{
+ qDebug() << "QGraphicsScenePrivate::sendGestureEvent:" << gestures;
+ Q_Q(QGraphicsScene);
+ typedef QMap<QGraphicsItem*, QSet<QGesture*> > ItemGesturesMap;
+ ItemGesturesMap itemGestures;
+ QSet<QGesture*> startedGestures;
+ for(QSet<QGesture*>::const_iterator it = gestures.begin(), e = gestures.end();
+ it != e; ++it) {
+ QGesture *g = *it;
+ Q_ASSERT(g != 0);
+ QGesturePrivate *gd = g->d_func();
+ if (gd->graphicsItem != 0) {
+ itemGestures[gd->graphicsItem].insert(g);
+ if (g->state() == Qt::GestureStarted || gd->singleshot)
+ startedGestures.insert(g);
+ }
+ }
+
+ qDebug() << "QGraphicsScenePrivate::sendGestureEvent: started: " << startedGestures;
+ QSet<QGesture*> ignoredGestures;
+ for(ItemGesturesMap::const_iterator it = itemGestures.begin(), e = itemGestures.end();
+ it != e; ++it) {
+ QGraphicsItem *receiver = it.key();
+ Q_ASSERT(receiver != 0);
+ QGraphicsSceneGestureEvent event;
+ event.setGestures(it.value());
+ event.setCancelledGestures(cancelled);
+ qDebug() << "QGraphicsScenePrivate::sendGestureEvent: sending to " << receiver << it.value();
+ bool processed = sendEvent(receiver, &event);
+ QSet<QGesture*> started = startedGestures.intersect(it.value());
+ if (event.isAccepted())
+ foreach(QGesture *g, started)
+ g->accept();
+ if (!started.isEmpty() && !(processed && event.isAccepted())) {
+ // there are started gestures event that weren't
+ // accepted, so propagating each gesture independently.
+ QSet<QGesture*>::const_iterator it = started.begin(),
+ e = started.end();
+ for(; it != e; ++it) {
+ QGesture *g = *it;
+ qDebug() << "result: " << g << ":" << processed << g->isAccepted();
+ if (processed && g->isAccepted()) {
+ continue;
+ }
+ QGesturePrivate *gd = g->d_func();
+ QGraphicsItem *item = gd->graphicsItem;
+ gd->graphicsItem = 0;
+
+ //### THIS IS BS, DONT FORGET TO REWRITE THIS CODE
+ // need to make sure we try to deliver event just once to each widget
+ const QString gestureType = g->type();
+ QList<QGraphicsItem*> itemsUnderGesture = q->items(g->hotSpot());
+ for (int i = 0; i < itemsUnderGesture.size(); ++i) {
+ QGraphicsItem *item = itemsUnderGesture.at(i);
+ if (item != receiver && item->d_func()->hasGesture(gestureType)) {
+ ignoredGestures.insert(g);
+ gd->graphicsItem = item;
+ break;
+ }
+ }
+ }
+ }
+ }
+ if (!ignoredGestures.isEmpty())
+ sendGestureEvent(ignoredGestures, cancelled);
+}
+
/*!
\reimp
@@ -5606,12 +5679,13 @@ void QGraphicsScenePrivate::grabGesture(QGraphicsItem *item, int gestureId)
foreach(QGraphicsView *view, views)
view->d_func()->grabGesture(gestureId);
}
- itemsWithGestures << item;
+ (void)itemsWithGestures[item];
grabbedGestures << gestureId;
}
void QGraphicsScenePrivate::releaseGesture(QGraphicsItem *item, int gestureId)
{
+ itemsWithGestures.remove(item);
//###
}
diff --git a/src/gui/graphicsview/qgraphicsscene_p.h b/src/gui/graphicsview/qgraphicsscene_p.h
index 7928a45..160ba49 100644
--- a/src/gui/graphicsview/qgraphicsscene_p.h
+++ b/src/gui/graphicsview/qgraphicsscene_p.h
@@ -74,6 +74,7 @@ QT_BEGIN_NAMESPACE
class QGraphicsView;
class QGraphicsWidget;
+class QGesture;
class QGraphicsScenePrivate : public QObjectPrivate
{
@@ -267,10 +268,12 @@ public:
void resolvePalette();
void updatePalette(const QPalette &palette);
- QSet<QGraphicsItem*> itemsWithGestures;
+ // items with gestures -> list of started gestures.
+ QMap<QGraphicsItem*, QSet<QGesture*> > itemsWithGestures;
QSet<int> grabbedGestures;
void grabGesture(QGraphicsItem *item, int gestureId);
void releaseGesture(QGraphicsItem *item, int gestureId);
+ void sendGestureEvent(const QSet<QGesture*> &gestures, const QSet<QString> &cancelled);
mutable QVector<QTransform> sceneTransformCache;
mutable QBitArray validTransforms;
diff --git a/src/gui/graphicsview/qgraphicssceneevent.cpp b/src/gui/graphicsview/qgraphicssceneevent.cpp
index d5d0fb9..2c5c946 100644
--- a/src/gui/graphicsview/qgraphicssceneevent.cpp
+++ b/src/gui/graphicsview/qgraphicssceneevent.cpp
@@ -1895,6 +1895,15 @@ void QGraphicsSceneGestureEvent::setGestures(const QList<QGesture*> &gestures)
}
/*!
+ Set a list of gesture objects containing extended information about \a gestures.
+*/
+void QGraphicsSceneGestureEvent::setGestures(const QSet<QGesture*> &gestures)
+{
+ foreach(QGesture *g, gestures)
+ m_gestures.insert(g->type(), g);
+}
+
+/*!
Sets the accept flag of the all gestures inside the event object,
the equivalent of calling \l{QEvent::accept()}{accept()} or
\l{QEvent::setAccepted()}{setAccepted(true)}.
diff --git a/src/gui/graphicsview/qgraphicssceneevent.h b/src/gui/graphicsview/qgraphicssceneevent.h
index 01cdab9..8b24d33 100644
--- a/src/gui/graphicsview/qgraphicssceneevent.h
+++ b/src/gui/graphicsview/qgraphicssceneevent.h
@@ -325,6 +325,7 @@ public:
const QGesture* gesture(const QString &type) const;
QList<QGesture*> gestures() const;
void setGestures(const QList<QGesture*> &gestures);
+ void setGestures(const QSet<QGesture*> &gestures);
QSet<QString> cancelledGestures() const;
void setCancelledGestures(const QSet<QString> &cancelledGestures);
diff --git a/src/gui/graphicsview/qgraphicsview.cpp b/src/gui/graphicsview/qgraphicsview.cpp
index b75619c..2babce9 100644
--- a/src/gui/graphicsview/qgraphicsview.cpp
+++ b/src/gui/graphicsview/qgraphicsview.cpp
@@ -2875,6 +2875,7 @@ bool QGraphicsView::viewportEvent(QEvent *event)
gestureEvent.setGestures(ev->gestures());
gestureEvent.setCancelledGestures(ev->cancelledGestures());
QApplication::sendEvent(d->scene, &gestureEvent);
+ event->setAccepted(gestureEvent.isAccepted());
if (gestureEvent.isAccepted())
return true;
}
diff --git a/src/gui/kernel/qapplication.cpp b/src/gui/kernel/qapplication.cpp
index 204cff6..b142f2e 100644
--- a/src/gui/kernel/qapplication.cpp
+++ b/src/gui/kernel/qapplication.cpp
@@ -2874,7 +2874,8 @@ QWidget *QApplicationPrivate::pickMouseReceiver(QWidget *candidate, const QPoint
*/
bool QApplicationPrivate::sendMouseEvent(QWidget *receiver, QMouseEvent *event,
QWidget *alienWidget, QWidget *nativeWidget,
- QWidget **buttonDown, QPointer<QWidget> &lastMouseReceiver)
+ QWidget **buttonDown, QPointer<QWidget> &lastMouseReceiver,
+ bool spontaneous)
{
Q_ASSERT(receiver);
Q_ASSERT(event);
@@ -2927,7 +2928,11 @@ bool QApplicationPrivate::sendMouseEvent(QWidget *receiver, QMouseEvent *event,
// We need this quard in case someone opens a modal dialog / popup. If that's the case
// leaveAfterRelease is set to null, but we shall not update lastMouseReceiver.
const bool wasLeaveAfterRelease = leaveAfterRelease != 0;
- bool result = QApplication::sendSpontaneousEvent(receiver, event);
+ bool result;
+ if (spontaneous)
+ result = QApplication::sendSpontaneousEvent(receiver, event);
+ else
+ result = QApplication::sendEvent(receiver, event);
if (!graphicsWidget && leaveAfterRelease && event->type() == QEvent::MouseButtonRelease
&& !event->buttons() && QWidget::mouseGrabber() != leaveAfterRelease) {
diff --git a/src/gui/kernel/qapplication_p.h b/src/gui/kernel/qapplication_p.h
index 096c349..08020fb 100644
--- a/src/gui/kernel/qapplication_p.h
+++ b/src/gui/kernel/qapplication_p.h
@@ -424,7 +424,8 @@ public:
QEvent::Type type, Qt::MouseButtons buttons,
QWidget *buttonDown, QWidget *alienWidget);
static bool sendMouseEvent(QWidget *receiver, QMouseEvent *event, QWidget *alienWidget,
- QWidget *native, QWidget **buttonDown, QPointer<QWidget> &lastMouseReceiver);
+ QWidget *native, QWidget **buttonDown, QPointer<QWidget> &lastMouseReceiver,
+ bool spontaneous = true);
#if defined(Q_WS_WIN) || defined(Q_WS_X11)
void sendSyntheticEnterLeave(QWidget *widget);
#endif
diff --git a/src/gui/kernel/qgesture.h b/src/gui/kernel/qgesture.h
index d220232..64a1424 100644
--- a/src/gui/kernel/qgesture.h
+++ b/src/gui/kernel/qgesture.h
@@ -73,8 +73,8 @@ class Q_GUI_EXPORT QGesture : public QObject
Q_PROPERTY(QPoint pos READ pos)
public:
- explicit QGesture(QObject *parent, const QString &type,
- Qt::GestureState state = Qt::GestureStarted);
+ QGesture(QObject *parent, const QString &type,
+ Qt::GestureState state = Qt::GestureStarted);
QGesture(QObject *parent,
const QString &type, const QPoint &startPos,
const QPoint &lastPos, const QPoint &pos, const QRect &rect,
@@ -110,6 +110,8 @@ private:
friend class QGestureManager;
friend class QApplication;
+ friend class QGraphicsScene;
+ friend class QGraphicsScenePrivate;
friend class QGestureRecognizerPan;
friend class QDoubleTapGestureRecognizer;
friend class QTapAndHoldGestureRecognizer;
diff --git a/src/gui/kernel/qgesture_p.h b/src/gui/kernel/qgesture_p.h
index d2d77cc..0f2e791 100644
--- a/src/gui/kernel/qgesture_p.h
+++ b/src/gui/kernel/qgesture_p.h
@@ -60,13 +60,14 @@
QT_BEGIN_NAMESPACE
+class QGraphicsItem;
class QGesturePrivate : public QObjectPrivate
{
Q_DECLARE_PUBLIC(QGesture)
public:
QGesturePrivate()
- : state(Qt::NoGesture), singleshot(0), duration(0) { }
+ : state(Qt::NoGesture), graphicsItem(0), singleshot(0), duration(0) { }
void init(const QPoint &startPos, const QPoint &lastPos,
const QPoint &pos, const QRect &rect,
@@ -86,6 +87,7 @@ public:
Qt::GestureState state;
QPointer<QWidget> widget;
+ QGraphicsItem *graphicsItem;
uint singleshot:1;
QRect rect;
diff --git a/src/gui/kernel/qgesturemanager.cpp b/src/gui/kernel/qgesturemanager.cpp
index c7341f2..9e8a5bb 100644
--- a/src/gui/kernel/qgesturemanager.cpp
+++ b/src/gui/kernel/qgesturemanager.cpp
@@ -139,7 +139,7 @@ bool QGestureManager::filterEvent(QWidget *receiver, QEvent *event)
notGestures << r;
}
}
- activeGestures -= newMaybeGestures;
+ Q_ASSERT(activeGestures.isEmpty());
activeGestures += startedGestures;
for(QMap<QGestureRecognizer*, int>::iterator it = maybeGestures.begin();
it != maybeGestures.end();) {
@@ -160,27 +160,24 @@ bool QGestureManager::filterEvent(QWidget *receiver, QEvent *event)
maybeGestures.insert(r, timerId);
}
}
- if (!finishedGestures.isEmpty() || !activeGestures.isEmpty()) {
+ if (!finishedGestures.isEmpty() || !startedGestures.isEmpty()) {
// gesture found!
ret = true;
- DEBUG() << "QGestureManager: sending gesture event for: "
- << activeGestures << " and " << finishedGestures;
-
- QSet<QGesture*> gestures;
+ QSet<QGesture*> started;
foreach(QGestureRecognizer *r, finishedGestures) {
if (QGesture *gesture = r->getGesture()) {
- gestures << gesture;
+ started << gesture;
gesture->d_func()->singleshot = true;
}
}
- foreach(QGestureRecognizer *r, activeGestures) {
+ foreach(QGestureRecognizer *r, startedGestures) {
if (QGesture *gesture = r->getGesture()) {
- gestures << gesture;
+ started << gesture;
gesture->d_func()->singleshot = false;
}
}
- Q_ASSERT(!gestures.isEmpty());
- ret = sendGestureEvent(receiver, gestures);
+ Q_ASSERT(!started.isEmpty());
+ ret = sendGestureEvent(receiver, started, QSet<QGesture*>());
if (!activeGestures.isEmpty()) {
DEBUG() << "QGestureManager: new state = Gesture";
@@ -243,16 +240,16 @@ bool QGestureManager::filterEvent(QWidget *receiver, QEvent *event)
}
}
}
- // TODO: make sure that if gesture recognizer ignored the event we dont swallow it.
- activeGestures -= newMaybeGestures;
- activeGestures -= cancelledGestures;
- activeGestures += startedGestures;
- foreach(QGestureRecognizer *r, startedGestures+finishedGestures+notGestures) {
- QMap<QGestureRecognizer*, int>::iterator it = maybeGestures.find(r);
- if (it != maybeGestures.end()) {
+ for(QMap<QGestureRecognizer*, int>::iterator it = maybeGestures.begin();
+ it != maybeGestures.end();) {
+ QGestureRecognizer *r = it.key();
+ if (startedGestures.contains(r) || finishedGestures.contains(r) ||
+ notGestures.contains(r)) {
killTimer(it.value());
- maybeGestures.erase(it);
+ it = maybeGestures.erase(it);
+ } else {
+ ++it;
}
}
foreach(QGestureRecognizer *r, newMaybeGestures) {
@@ -263,33 +260,37 @@ bool QGestureManager::filterEvent(QWidget *receiver, QEvent *event)
maybeGestures.insert(r, timerId);
}
}
- QSet<QGesture*> gestures;
- if (!finishedGestures.isEmpty() || !activeGestures.isEmpty()) {
+ QSet<QGesture*> started, updated;
+ if (!finishedGestures.isEmpty() || !startedGestures.isEmpty()) {
// another gesture found!
ret = true;
- DEBUG() << "QGestureManager: sending gesture event for: "
- << activeGestures << " and " << finishedGestures;
-
foreach(QGestureRecognizer *r, finishedGestures) {
if (QGesture *gesture = r->getGesture()) {
- gestures << gesture;
- gesture->d_func()->singleshot = activeGestures.contains(r);
+ gesture->d_func()->singleshot = !activeGestures.contains(r);
+ if (gesture->d_func()->singleshot)
+ started << gesture;
+ else
+ updated << gesture;
}
}
- activeGestures -= finishedGestures;
- foreach(QGestureRecognizer *r, activeGestures) {
+ foreach(QGestureRecognizer *r, startedGestures) {
if (QGesture *gesture = r->getGesture()) {
- gestures << gesture;
- gesture->d_func()->singleshot = false;
+ gesture->d_func()->singleshot = !activeGestures.contains(r);
+ if (gesture->d_func()->singleshot)
+ started << gesture;
+ else
+ updated << gesture;
}
}
}
+ activeGestures -= newMaybeGestures;
+ activeGestures -= cancelledGestures;
+ activeGestures += startedGestures;
+ activeGestures -= finishedGestures;
QSet<QString> cancelledGestureNames;
foreach(QGestureRecognizer *r, cancelledGestures)
cancelledGestureNames << r->gestureType();
- if(!gestures.isEmpty()) {
- ret = sendGestureEvent(receiver, gestures, cancelledGestureNames);
- }
+ ret = sendGestureEvent(receiver, started, updated, cancelledGestureNames);
foreach(QGestureRecognizer *r, finishedGestures)
r->reset();
@@ -488,40 +489,29 @@ void QGestureManager::recognizerStateChanged(QGestureRecognizer::Result result)
}
}
-bool QGestureManager::widgetHasGesture(QWidget *widget, QGesture *gesture) const
-{
- const QString gestureName = gesture->type();
- QSet<int>::iterator it = widget->d_func()->gestures.begin(),
- e = widget->d_func()->gestures.end();
- for (; it != e; ++it) {
- if (gestureNameFromId(*it) == gestureName)
- return true;
- }
- return false;
-}
-
-bool QGestureManager::sendGestureEvent(QWidget *receiver, const QSet<QGesture*> &gestures,
+bool QGestureManager::sendGestureEvent(QWidget *receiver,
+ const QSet<QGesture*> &startedGestures,
+ const QSet<QGesture*> &updatedGestures,
const QSet<QString> &cancelled)
{
- if (gestures.isEmpty())
- return false;
DEBUG() << "QGestureManager::sendGestureEvent: sending to" << receiver
- << "gestures:" << gestures << "; cancelled:" << cancelled;
- QSet<QGesture*> startedGestures;
+ << "gestures:" << startedGestures << "," << updatedGestures
+ << "cancelled:" << cancelled;
// grouping gesture objects by receiver widgets.
typedef QMap<QWidget*, QSet<QGesture*> > WidgetGesturesMap;
WidgetGesturesMap widgetGestures;
- for(QSet<QGesture*>::const_iterator it = gestures.begin(), e = gestures.end();
+ for(QSet<QGesture*>::const_iterator it = startedGestures.begin(), e = startedGestures.end();
it != e; ++it) {
QGesture *g = *it;
QGesturePrivate *gd = g->d_func();
- if (!gd->widget && (g->state() == Qt::GestureStarted || g->state() == Qt::GestureFinished)) {
- startedGestures.insert(g);
+ if (receiver) {
// find the target widget
+ gd->widget = 0;
QWidget *w = receiver;
QPoint offset;
+ const QString gestureType = g->type();
while (w) {
- if (widgetHasGesture(w, g))
+ if (w->d_func()->hasGesture(gestureType))
break;
if (w->isWindow()) {
w = 0;
@@ -530,10 +520,11 @@ bool QGestureManager::sendGestureEvent(QWidget *receiver, const QSet<QGesture*>
offset += w->pos();
w = w->parentWidget();
}
- if (!w) // no widget in the tree that accepts this gesture.
- continue;
+ if (w && w != gd->widget) {
+ DEBUG() << "QGestureManager::sendGestureEvent:" << g << "propagating to widget" << w << "offset" << offset;
+ g->translate(offset);
+ }
gd->widget = w;
- g->translate(offset);
}
if (!gd->widget) {
DEBUG() << "QGestureManager: didn't find a widget to send gesture event ("
@@ -550,13 +541,25 @@ bool QGestureManager::sendGestureEvent(QWidget *receiver, const QSet<QGesture*>
it != e; ++it) {
QWidget *receiver = it.key();
Q_ASSERT(receiver != 0 /*should be taken care above*/);
+ QSet<QGesture*> gestures = it.value();
+ // mark all gestures as ignored by default
+ for(QSet<QGesture*>::iterator it = gestures.begin(), e = gestures.end(); it != e; ++it)
+ (*it)->ignore();
// TODO: send cancelled gesture event to the widget that received the original gesture!
- QGestureEvent event(it.value(), cancelled);
+ QGestureEvent event(gestures, cancelled);
+ DEBUG() << "QGestureManager::sendGestureEvent: sending now to" << receiver
+ << "gestures" << gestures;
bool processed = qt_sendSpontaneousEvent(receiver, &event);
- QSet<QGesture*> started = startedGestures.intersect(it.value());
+ QSet<QGesture*> started = startedGestures & gestures;
+ DEBUG() << "QGestureManager::sendGestureEvent:" <<
+ (event.isAccepted() ? "" : "not") << "all gestures were accepted";
if (!started.isEmpty() && !(processed && event.isAccepted())) {
- // there are started gestures event that weren't
+ // there are started gestures events that weren't
// accepted, so propagating each gesture independently.
+ if (event.isAccepted()) {
+ foreach(QGesture *g, started)
+ g->accept();
+ }
QSet<QGesture*>::const_iterator it = started.begin(),
e = started.end();
for(; it != e; ++it) {
@@ -571,14 +574,17 @@ bool QGestureManager::sendGestureEvent(QWidget *receiver, const QSet<QGesture*>
QWidget *w = gd->widget;
gd->widget = 0;
- if (!w->isWindow()) {
+ if (w && !w->isWindow()) {
g->translate(w->pos());
w = w->parentWidget();
QPoint offset;
+ const QString gestureType = g->type();
while (w) {
- if (widgetHasGesture(w, g)) {
- DEBUG() << "QGestureManager: sendGestureEvent:" << w << "didn't accept gesture" << g;
+ if (w->d_func()->hasGesture(gestureType)) {
+ DEBUG() << "QGestureManager::sendGestureEvent:" << receiver
+ << "didn't accept gesture" << g << "propagating to" << w;
ignoredGestures.insert(g);
+ gd->widget = w;
break;
}
if (w->isWindow()) {
@@ -588,14 +594,20 @@ bool QGestureManager::sendGestureEvent(QWidget *receiver, const QSet<QGesture*>
offset += w->pos();
w = w->parentWidget();
}
- if (w)
+ if (w) {
g->translate(offset);
+ } else {
+ DEBUG() << "QGestureManager::sendGestureEvent:" << receiver
+ << "didn't accept gesture" << g << "and nobody wants it";
+ }
}
}
}
}
+ if (ignoredGestures.isEmpty())
+ return ret;
// try to send all gestures that were ignored to the next parent
- return sendGestureEvent(0, ignoredGestures, cancelled) || ret;
+ return sendGestureEvent(0, ignoredGestures, QSet<QGesture*>(), cancelled) || ret;
}
int QGestureManager::eventDeliveryDelay() const
diff --git a/src/gui/kernel/qgesturemanager_p.h b/src/gui/kernel/qgesturemanager_p.h
index 963edf9..745feb3 100644
--- a/src/gui/kernel/qgesturemanager_p.h
+++ b/src/gui/kernel/qgesturemanager_p.h
@@ -64,7 +64,7 @@
QT_BEGIN_NAMESPACE
class QWidget;
-class Q_GUI_EXPORT QGestureManager : public QObject
+class Q_AUTOTEST_EXPORT QGestureManager : public QObject
{
Q_OBJECT
public:
@@ -86,6 +86,11 @@ public:
// declared in qapplication.cpp
static QGestureManager* instance();
+ bool sendGestureEvent(QWidget *receiver,
+ const QSet<QGesture*> &startedGestures,
+ const QSet<QGesture*> &updatedGestures,
+ const QSet<QString> &cancelled = QSet<QString>());
+
protected:
void timerEvent(QTimerEvent *event);
@@ -93,10 +98,6 @@ private slots:
void recognizerStateChanged(QGestureRecognizer::Result);
private:
- bool widgetHasGesture(QWidget *widget, QGesture *gesture) const;
- bool sendGestureEvent(QWidget *receiver, const QSet<QGesture*> &gestures,
- const QSet<QString> &cancelled = QSet<QString>());
-
QSet<QGestureRecognizer*> activeGestures;
QMap<QGestureRecognizer*, int> maybeGestures;
QSet<QGestureRecognizer*> recognizers;
diff --git a/src/gui/kernel/qgesturerecognizer.cpp b/src/gui/kernel/qgesturerecognizer.cpp
index 41160cd..879f557 100644
--- a/src/gui/kernel/qgesturerecognizer.cpp
+++ b/src/gui/kernel/qgesturerecognizer.cpp
@@ -108,6 +108,9 @@ QString qt_getStandardGestureTypeName(Qt::GestureType gestureType);
to QGestureRecognizer::GestureStarted or
QGestureRecognizer::GestureFinished.
+ The returned QGesture object must point to the same object in a
+ single gesture sequence.
+
The gesture object is owned by the recognizer itself.
*/
diff --git a/src/gui/kernel/qgesturerecognizer.h b/src/gui/kernel/qgesturerecognizer.h
index 8bc8b97..67d7949 100644
--- a/src/gui/kernel/qgesturerecognizer.h
+++ b/src/gui/kernel/qgesturerecognizer.h
@@ -60,7 +60,7 @@ public:
{
Ignore,
NotGesture,
- GestureStarted,
+ GestureStarted, //TODO: rename to just Gesture?
GestureFinished,
MaybeGesture
};
diff --git a/src/gui/kernel/qwidget.cpp b/src/gui/kernel/qwidget.cpp
index 3a146e5..7920139 100644
--- a/src/gui/kernel/qwidget.cpp
+++ b/src/gui/kernel/qwidget.cpp
@@ -10970,7 +10970,10 @@ QWindowSurface *QWidget::windowSurface() const
int QWidget::grabGesture(const QString &gesture)
{
Q_D(QWidget);
- return d->grabGesture(QGestureManager::instance()->makeGestureId(gesture));
+ int id = d->grabGesture(QGestureManager::instance()->makeGestureId(gesture));
+ if (d->extra && d->extra->proxyWidget)
+ d->extra->proxyWidget->QGraphicsItem::d_ptr->grabGesture(id);
+ return id;
}
int QWidgetPrivate::grabGesture(int gestureId)
@@ -10993,6 +10996,18 @@ bool QWidgetPrivate::releaseGesture(int gestureId)
return false;
}
+bool QWidgetPrivate::hasGesture(const QString &name) const
+{
+ QGestureManager *gm = QGestureManager::instance();
+ QSet<int>::const_iterator it = gestures.begin(),
+ e = gestures.end();
+ for (; it != e; ++it) {
+ if (gm->gestureNameFromId(*it) == name)
+ return true;
+ }
+ return false;
+}
+
/*!
\since 4.6
@@ -11018,8 +11033,11 @@ int QWidget::grabGesture(Qt::GestureType gesture)
void QWidget::releaseGesture(int gestureId)
{
Q_D(QWidget);
- if (d->releaseGesture(gestureId))
+ if (d->releaseGesture(gestureId)) {
+ if (d->extra && d->extra->proxyWidget)
+ d->extra->proxyWidget->QGraphicsItem::d_ptr->releaseGesture(gestureId);
QGestureManager::instance()->releaseGestureId(gestureId);
+ }
}
/*!
diff --git a/src/gui/kernel/qwidget_p.h b/src/gui/kernel/qwidget_p.h
index a603b44..b2ae75e 100644
--- a/src/gui/kernel/qwidget_p.h
+++ b/src/gui/kernel/qwidget_p.h
@@ -521,6 +521,7 @@ public:
QSet<int> gestures;
int grabGesture(int gestureId);
bool releaseGesture(int gestureId);
+ bool hasGesture(const QString &type) const;
// Bit fields.
uint high_attributes[3]; // the low ones are in QWidget::widget_attributes
diff --git a/tests/auto/gestures/customgesturerecognizer.cpp b/tests/auto/gestures/customgesturerecognizer.cpp
new file mode 100644
index 0000000..906fd32
--- /dev/null
+++ b/tests/auto/gestures/customgesturerecognizer.cpp
@@ -0,0 +1,105 @@
+#include "customgesturerecognizer.h"
+#include "qgesture.h"
+
+const char* SingleshotGestureRecognizer::Name = "SingleshotGesture";
+const char* PinchGestureRecognizer::Name = "PinchGesture";
+const char* SecondFingerGestureRecognizer::Name = "SecondFingerGesture";
+
+SingleshotGestureRecognizer::SingleshotGestureRecognizer(QObject *parent)
+ : QGestureRecognizer(QString(SingleshotGestureRecognizer::Name), parent)
+{
+ gesture = new SingleshotGesture(this, SingleshotGestureRecognizer::Name);
+}
+
+QGestureRecognizer::Result SingleshotGestureRecognizer::filterEvent(const QEvent *event)
+{
+ if (event->type() == SingleshotEvent::Type) {
+ return QGestureRecognizer::GestureFinished;
+ }
+ return QGestureRecognizer::NotGesture;
+}
+
+void SingleshotGestureRecognizer::reset()
+{
+ gesture->offset = QPoint();
+}
+
+PinchGestureRecognizer::PinchGestureRecognizer(QObject *parent)
+ : QGestureRecognizer(PinchGestureRecognizer::Name, parent)
+{
+ gesture = new PinchGesture(this, PinchGestureRecognizer::Name);
+}
+
+QGestureRecognizer::Result PinchGestureRecognizer::filterEvent(const QEvent *event)
+{
+ if (event->type() != TouchEvent::Type)
+ return QGestureRecognizer::Ignore;
+
+ const TouchEvent *e = static_cast<const TouchEvent*>(event);
+ if (e->points[0].state == TouchPoint::Begin)
+ gesture->startPoints[0] = e->points[0];
+ if (e->points[1].state == TouchPoint::Begin)
+ gesture->startPoints[1] = e->points[1];
+ gesture->lastPoints[0] = gesture->points[0];
+ gesture->lastPoints[1] = gesture->points[1];
+ gesture->points[0] = e->points[0];
+ gesture->points[1] = e->points[1];
+ if (((e->points[0].state == TouchPoint::Begin || e->points[0].state == TouchPoint::Update))) {
+ if (e->points[1].state == TouchPoint::End || e->points[1].state == TouchPoint::None)
+ return MaybeGesture;
+ return GestureStarted;
+ } else if (((e->points[1].state == TouchPoint::Begin || e->points[1].state == TouchPoint::Update))) {
+ if (e->points[0].state == TouchPoint::End || e->points[0].state == TouchPoint::None)
+ return MaybeGesture;
+ return GestureStarted;
+ } else if ((e->points[0].state == TouchPoint::End && e->points[1].state == TouchPoint::End) ||
+ (e->points[0].state == TouchPoint::End && e->points[1].state == TouchPoint::None) ||
+ (e->points[0].state == TouchPoint::None && e->points[1].state == TouchPoint::End)) {
+ return QGestureRecognizer::NotGesture;
+ }
+ return QGestureRecognizer::NotGesture;
+}
+
+void PinchGestureRecognizer::reset()
+{
+ gesture->startPoints[0] = TouchPoint();
+ gesture->startPoints[1] = TouchPoint();
+ gesture->lastPoints[0] = TouchPoint();
+ gesture->lastPoints[1] = TouchPoint();
+ gesture->points[0] = TouchPoint();
+ gesture->points[1] = TouchPoint();
+ gesture->offset = QPoint();
+}
+
+SecondFingerGestureRecognizer::SecondFingerGestureRecognizer(QObject *parent)
+ : QGestureRecognizer(SecondFingerGestureRecognizer::Name, parent)
+{
+ gesture = new SecondFingerGesture(this, SecondFingerGestureRecognizer::Name);
+}
+
+QGestureRecognizer::Result SecondFingerGestureRecognizer::filterEvent(const QEvent *event)
+{
+ if (event->type() != TouchEvent::Type)
+ return QGestureRecognizer::Ignore;
+
+ const TouchEvent *e = static_cast<const TouchEvent*>(event);
+ if (e->points[1].state != TouchPoint::None) {
+ if (e->points[1].state == TouchPoint::Begin)
+ gesture->startPoint = e->points[1];
+ gesture->lastPoint = gesture->point;
+ gesture->point = e->points[1];
+ if (e->points[1].state == TouchPoint::End)
+ return QGestureRecognizer::GestureFinished;
+ else if (e->points[1].state != TouchPoint::None)
+ return QGestureRecognizer::GestureStarted;
+ }
+ return QGestureRecognizer::NotGesture;
+}
+
+void SecondFingerGestureRecognizer::reset()
+{
+ gesture->startPoint = TouchPoint();
+ gesture->lastPoint = TouchPoint();
+ gesture->point = TouchPoint();
+ gesture->offset = QPoint();
+}
diff --git a/tests/auto/gestures/customgesturerecognizer.h b/tests/auto/gestures/customgesturerecognizer.h
new file mode 100644
index 0000000..b9ab421
--- /dev/null
+++ b/tests/auto/gestures/customgesturerecognizer.h
@@ -0,0 +1,147 @@
+#ifndef CUSTOMGESTURERECOGNIZER_H
+#define CUSTOMGESTURERECOGNIZER_H
+
+#include "qgesturerecognizer.h"
+#include "qgesture.h"
+#include "qevent.h"
+
+class SingleshotEvent : public QEvent
+{
+public:
+ static const int Type = QEvent::User + 1;
+ SingleshotEvent() : QEvent(QEvent::Type(Type)) { }
+};
+
+class SingleshotGesture : public QGesture
+{
+ Q_OBJECT
+public:
+ SingleshotGesture(QObject *parent, const QString &type)
+ : QGesture(parent, type) { }
+
+ QPoint offset;
+
+protected:
+ void translate(const QPoint &pt)
+ {
+ offset += pt;
+ }
+};
+
+class SingleshotGestureRecognizer : public QGestureRecognizer
+{
+ Q_OBJECT
+public:
+ static const char *Name;
+
+ SingleshotGestureRecognizer(QObject *parent = 0);
+
+ QGestureRecognizer::Result filterEvent(const QEvent *event);
+ QGesture* getGesture() { return gesture; }
+ void reset();
+
+private:
+ SingleshotGesture *gesture;
+};
+
+struct TouchPoint {
+ enum State
+ {
+ None,
+ Begin,
+ Update,
+ End
+ };
+ int id;
+ QPoint pt;
+ State state;
+ TouchPoint() : id(0), state(None) { }
+ TouchPoint(int id_, int x_, int y_, State state_) : id(id_), pt(x_, y_), state(state_) { }
+};
+
+class TouchEvent : public QEvent
+{
+public:
+ static const int Type = QEvent::User + 2;
+
+ TouchEvent()
+ : QEvent(QEvent::Type(Type))
+ {
+ }
+
+ TouchPoint points[2];
+};
+
+class PinchGesture : public QGesture
+{
+ Q_OBJECT
+public:
+ PinchGesture(QObject *parent, const QString &type)
+ : QGesture(parent, type) { }
+
+ TouchPoint startPoints[2];
+ TouchPoint lastPoints[2];
+ TouchPoint points[2];
+
+ QPoint offset;
+
+protected:
+ void translate(const QPoint &pt)
+ {
+ offset += pt;
+ }
+};
+
+class PinchGestureRecognizer : public QGestureRecognizer
+{
+ Q_OBJECT
+public:
+ static const char *Name;
+
+ PinchGestureRecognizer(QObject *parent = 0);
+
+ QGestureRecognizer::Result filterEvent(const QEvent *event);
+ QGesture* getGesture() { return gesture; }
+ void reset();
+
+private:
+ PinchGesture *gesture;
+};
+
+class SecondFingerGesture : public QGesture
+{
+ Q_OBJECT
+public:
+ SecondFingerGesture(QObject *parent, const QString &type)
+ : QGesture(parent, type) { }
+
+ TouchPoint startPoint;
+ TouchPoint lastPoint;
+ TouchPoint point;
+
+ QPoint offset;
+
+protected:
+ void translate(const QPoint &pt)
+ {
+ offset += pt;
+ }
+};
+
+class SecondFingerGestureRecognizer : public QGestureRecognizer
+{
+ Q_OBJECT
+public:
+ static const char *Name;
+
+ SecondFingerGestureRecognizer(QObject *parent = 0);
+
+ QGestureRecognizer::Result filterEvent(const QEvent *event);
+ QGesture* getGesture() { return gesture; }
+ void reset();
+
+private:
+ SecondFingerGesture *gesture;
+};
+
+#endif
diff --git a/tests/auto/gestures/gestures.pro b/tests/auto/gestures/gestures.pro
new file mode 100644
index 0000000..ac99b19
--- /dev/null
+++ b/tests/auto/gestures/gestures.pro
@@ -0,0 +1,3 @@
+load(qttest_p4)
+SOURCES += tst_gestures.cpp customgesturerecognizer.cpp
+HEADERS += customgesturerecognizer.h
diff --git a/tests/auto/gestures/tst_gestures.cpp b/tests/auto/gestures/tst_gestures.cpp
new file mode 100644
index 0000000..eb692e9
--- /dev/null
+++ b/tests/auto/gestures/tst_gestures.cpp
@@ -0,0 +1,487 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <qapplication.h>
+#include <qlayout.h>
+
+#include <QtTest/QtTest>
+
+#include "customgesturerecognizer.h"
+
+//TESTED_CLASS=
+//TESTED_FILES=
+
+// color generator for syntax highlighting from QQ-26 by Helder Correia
+QVector<QColor> highlight(const QColor &bg, const
+ QColor &fg, int noColors)
+{
+ QVector<QColor> colors;
+ const int HUE_BASE = (bg.hue() == -1) ? 90 : bg.hue();
+ int h, s, v;
+ for (int i = 0; i < noColors; i++) {
+ h = int(HUE_BASE + (360.0 / noColors * i)) % 360;
+ s = 240;
+ v = int(qMax(bg.value(), fg.value()) * 0.85);
+
+ const int M = 35;
+ if ((h < bg.hue() + M && h > bg.hue() - M)
+ || (h < fg.hue() + M && h > fg.hue() - M))
+ {
+ h = ((bg.hue() + fg.hue()) / (i+1)) % 360;
+ s = ((bg.saturation() + fg.saturation() + 2*i)
+ / 2) % 256;
+ v = ((bg.value() + fg.value() + 2*i) / 2)
+ % 256;
+ }
+ colors.append(QColor::fromHsv(h, s, v));
+ }
+ return colors;
+}
+
+
+// a hack to mark an event as spontaneous.
+class QETWidget
+{
+public:
+ static void setSpont(QEvent *event, bool spont) { event->spont = spont; }
+};
+
+class GestureWidget : public QWidget
+{
+ Q_OBJECT
+ static QVector<QColor> colors;
+ static int numberOfWidgets;
+
+public:
+ enum Type { DoNotGrabGestures, GrabAllGestures, GrabSingleshot, GrabPinch, GrabSecondFinger };
+
+ static const int LeftMargin = 10;
+ static const int TopMargin = 20;
+
+ GestureWidget(Type type = GrabAllGestures)
+ {
+ if (colors.isEmpty()) {
+ colors = highlight(palette().color(QPalette::Window), palette().color(QPalette::Text), 5);
+ }
+ QPalette p = palette();
+ p.setColor(QPalette::Window, colors[numberOfWidgets % colors.size()]);
+ setPalette(p);
+ setAutoFillBackground(true);
+ ++numberOfWidgets;
+
+ QVBoxLayout *l = new QVBoxLayout(this);
+ l->setSpacing(0);
+ l->setContentsMargins(LeftMargin, TopMargin, LeftMargin, TopMargin);
+
+ singleshotGestureId = -1;
+ pinchGestureId = -1;
+ secondFingerGestureId = -1;
+ if (type == GrabAllGestures || type == GrabSingleshot) {
+ singleshotGestureId = grabGesture(SingleshotGestureRecognizer::Name);
+ }
+ if (type == GrabAllGestures || type == GrabPinch) {
+ pinchGestureId = grabGesture(PinchGestureRecognizer::Name);
+ }
+ if (type == GrabAllGestures || type == GrabSecondFinger) {
+ secondFingerGestureId = grabGesture(SecondFingerGestureRecognizer::Name);
+ }
+
+ reset();
+ }
+ ~GestureWidget()
+ {
+ --numberOfWidgets;
+ ungrabGestures();
+ }
+
+ void grabSingleshotGesture()
+ {
+ singleshotGestureId = grabGesture(SingleshotGestureRecognizer::Name);
+ }
+ void grabPinchGesture()
+ {
+ pinchGestureId = grabGesture(PinchGestureRecognizer::Name);
+ }
+ void grabSecondFingerGesture()
+ {
+ secondFingerGestureId = grabGesture(SecondFingerGestureRecognizer::Name);
+ }
+ void ungrabGestures()
+ {
+ releaseGesture(singleshotGestureId);
+ singleshotGestureId = -1;
+ releaseGesture(pinchGestureId);
+ pinchGestureId = -1;
+ releaseGesture(secondFingerGestureId);
+ secondFingerGestureId = -1;
+ }
+
+ int singleshotGestureId;
+ int pinchGestureId;
+ int secondFingerGestureId;
+
+ bool shouldAcceptSingleshotGesture;
+ bool shouldAcceptPinchGesture;
+ bool shouldAcceptSecondFingerGesture;
+
+ int seenGestureEvent;
+ struct LastGestureEvent
+ {
+ struct SingleshotGesture
+ {
+ bool delivered;
+ QPoint offset;
+ } singleshot;
+ struct PinchGesture
+ {
+ bool delivered;
+ TouchPoint startPoints[2];
+ TouchPoint lastPoints[2];
+ TouchPoint points[2];
+ QPoint offset;
+ } pinch;
+ struct SecondFingerGesture
+ {
+ bool delivered;
+ TouchPoint startPoint;
+ TouchPoint lastPoint;
+ TouchPoint point;
+ QPoint offset;
+ } secondfinger;
+ QSet<QString> cancelled;
+ } last;
+ void reset()
+ {
+ seenGestureEvent = 0;
+ last.singleshot.delivered = false;
+ last.singleshot.offset = QPoint();
+ last.pinch.delivered = false;
+ last.pinch.startPoints[0] = TouchPoint();
+ last.pinch.startPoints[1] = TouchPoint();
+ last.pinch.lastPoints[0] = TouchPoint();
+ last.pinch.lastPoints[1] = TouchPoint();
+ last.pinch.points[0] = TouchPoint();
+ last.pinch.points[1] = TouchPoint();
+ last.pinch.offset = QPoint();
+ last.secondfinger.delivered = false;
+ last.secondfinger.startPoint = TouchPoint();
+ last.secondfinger.lastPoint = TouchPoint();
+ last.secondfinger.point = TouchPoint();
+ last.secondfinger.offset = QPoint();
+ last.cancelled.clear();
+
+ shouldAcceptSingleshotGesture = true;
+ shouldAcceptPinchGesture = true;
+ shouldAcceptSecondFingerGesture = true;
+ }
+
+protected:
+ bool event(QEvent *event)
+ {
+ if (event->type() == QEvent::Gesture) {
+ QGestureEvent *e = static_cast<QGestureEvent*>(event);
+ ++seenGestureEvent;
+ if (SingleshotGesture *g = (SingleshotGesture*)e->gesture(SingleshotGestureRecognizer::Name)) {
+ last.singleshot.delivered = true;
+ last.singleshot.offset = g->offset;
+ if (shouldAcceptSingleshotGesture)
+ g->accept();
+ }
+ if (PinchGesture *g = (PinchGesture*)e->gesture(PinchGestureRecognizer::Name)) {
+ last.pinch.delivered = true;
+ last.pinch.startPoints[0] = g->startPoints[0];
+ last.pinch.startPoints[1] = g->startPoints[1];
+ last.pinch.lastPoints[0] = g->lastPoints[0];
+ last.pinch.lastPoints[1] = g->lastPoints[1];
+ last.pinch.points[0] = g->points[0];
+ last.pinch.points[1] = g->points[1];
+ last.pinch.offset = g->offset;
+ if (shouldAcceptPinchGesture)
+ g->accept();
+ }
+ if (SecondFingerGesture *g = (SecondFingerGesture*)e->gesture(SecondFingerGestureRecognizer::Name)) {
+ last.secondfinger.delivered = true;
+ last.secondfinger.startPoint = g->startPoint;
+ last.secondfinger.lastPoint = g->lastPoint;
+ last.secondfinger.point = g->point;
+ last.secondfinger.offset = g->offset;
+ if (shouldAcceptSecondFingerGesture)
+ g->accept();
+ }
+ last.cancelled = e->cancelledGestures();
+ return true;
+ }
+ return QWidget::event(event);
+ }
+};
+QVector<QColor> GestureWidget::colors;
+int GestureWidget::numberOfWidgets = 0;
+
+class tst_Gestures : public QObject
+{
+ Q_OBJECT
+
+public:
+ tst_Gestures();
+ virtual ~tst_Gestures();
+
+public slots:
+ void initTestCase();
+ void cleanupTestCase();
+ void init();
+ void cleanup();
+
+private slots:
+ void singleshotGesture();
+ void pinchGesture();
+
+ void simplePropagation();
+ void simplePropagation2();
+ void acceptedGesturePropagation();
+
+private:
+ SingleshotGestureRecognizer *singleshotRecognizer;
+ PinchGestureRecognizer *pinchRecognizer;
+ SecondFingerGestureRecognizer *secondFingerRecognizer;
+ GestureWidget *mainWidget;
+
+ bool sendSpontaneousEvent(QWidget *receiver, QEvent *event);
+ void sendPinchEvents(QWidget *receiver, const QPoint &fromFinger1, const QPoint &fromFinger2);
+};
+
+tst_Gestures::tst_Gestures()
+{
+ singleshotRecognizer = new SingleshotGestureRecognizer;
+ pinchRecognizer = new PinchGestureRecognizer;
+ secondFingerRecognizer = new SecondFingerGestureRecognizer;
+ qApp->addGestureRecognizer(singleshotRecognizer);
+ qApp->addGestureRecognizer(pinchRecognizer);
+ qApp->addGestureRecognizer(secondFingerRecognizer);
+}
+
+tst_Gestures::~tst_Gestures()
+{
+}
+
+
+void tst_Gestures::initTestCase()
+{
+ mainWidget = new GestureWidget(GestureWidget::DoNotGrabGestures);
+ mainWidget->setObjectName("MainGestureWidget");
+ mainWidget->resize(500, 600);
+ mainWidget->show();
+}
+
+void tst_Gestures::cleanupTestCase()
+{
+ delete mainWidget; mainWidget = 0;
+}
+
+void tst_Gestures::init()
+{
+ // TODO: Add initialization code here.
+ // This will be executed immediately before each test is run.
+ mainWidget->reset();
+}
+
+void tst_Gestures::cleanup()
+{
+}
+
+bool tst_Gestures::sendSpontaneousEvent(QWidget *receiver, QEvent *event)
+{
+ QETWidget::setSpont(event, true);
+ return qApp->notify(receiver, event);
+}
+
+void tst_Gestures::singleshotGesture()
+{
+ mainWidget->grabSingleshotGesture();
+ SingleshotEvent event;
+ sendSpontaneousEvent(mainWidget, &event);
+ QVERIFY(mainWidget->seenGestureEvent);
+ QVERIFY(mainWidget->last.singleshot.delivered);
+ QVERIFY(mainWidget->last.cancelled.isEmpty());
+}
+
+void tst_Gestures::sendPinchEvents(QWidget *receiver, const QPoint &fromFinger1, const QPoint &fromFinger2)
+{
+ int x1 = fromFinger1.x();
+ int y1 = fromFinger1.x();
+ int x2 = fromFinger2.x();
+ int y2 = fromFinger2.x();
+
+ TouchEvent event;
+ event.points[0] = TouchPoint(0,x1,y1, TouchPoint::Begin);
+ event.points[1] = TouchPoint();
+ sendSpontaneousEvent(receiver, &event);
+ event.points[0] = TouchPoint(0, x1+=2,y1+=2, TouchPoint::Update);
+ event.points[1] = TouchPoint();
+ sendSpontaneousEvent(receiver, &event);
+ event.points[0] = TouchPoint(0, x1,y1, TouchPoint::Update);
+ event.points[1] = TouchPoint(1, x2,y2, TouchPoint::Begin);
+ sendSpontaneousEvent(receiver, &event);
+ event.points[0] = TouchPoint(0, x1+=5,y1+=10, TouchPoint::End);
+ event.points[1] = TouchPoint(1, x2+=3,y2+=6, TouchPoint::Update);
+ sendSpontaneousEvent(receiver, &event);
+ event.points[0] = TouchPoint();
+ event.points[1] = TouchPoint(1, x2+=10,y2+=15, TouchPoint::Update);
+ sendSpontaneousEvent(receiver, &event);
+ event.points[0] = TouchPoint();
+ event.points[1] = TouchPoint(1, x2,y2, TouchPoint::End);
+ sendSpontaneousEvent(receiver, &event);
+}
+
+void tst_Gestures::pinchGesture()
+{
+ mainWidget->grabPinchGesture();
+ sendPinchEvents(mainWidget, QPoint(10,10), QPoint(20,20));
+
+ QVERIFY(mainWidget->seenGestureEvent);
+ QVERIFY(!mainWidget->last.singleshot.delivered);
+ QVERIFY(mainWidget->last.cancelled.isEmpty());
+ QVERIFY(mainWidget->last.pinch.delivered);
+ QCOMPARE(mainWidget->last.pinch.startPoints[0].pt, QPoint(10,10));
+ QCOMPARE(mainWidget->last.pinch.startPoints[1].pt, QPoint(20,20));
+ QCOMPARE(mainWidget->last.pinch.offset, QPoint(0,0));
+}
+
+void tst_Gestures::simplePropagation()
+{
+ mainWidget->grabSingleshotGesture();
+ GestureWidget offsetWidget(GestureWidget::DoNotGrabGestures);
+ offsetWidget.setFixedSize(30, 30);
+ mainWidget->layout()->addWidget(&offsetWidget);
+ GestureWidget nonGestureWidget(GestureWidget::DoNotGrabGestures);
+ mainWidget->layout()->addWidget(&nonGestureWidget);
+ QApplication::processEvents();
+
+ SingleshotEvent event;
+ sendSpontaneousEvent(&nonGestureWidget, &event);
+ QVERIFY(!offsetWidget.seenGestureEvent);
+ QVERIFY(!nonGestureWidget.seenGestureEvent);
+ QVERIFY(mainWidget->seenGestureEvent);
+ QVERIFY(mainWidget->last.cancelled.isEmpty());
+ QVERIFY(mainWidget->last.singleshot.delivered);
+ QCOMPARE(mainWidget->last.singleshot.offset, QPoint(GestureWidget::LeftMargin, 30 + GestureWidget::TopMargin));
+}
+
+void tst_Gestures::simplePropagation2()
+{
+ mainWidget->grabSingleshotGesture();
+ mainWidget->grabPinchGesture();
+ GestureWidget nonGestureMiddleWidget(GestureWidget::DoNotGrabGestures);
+ GestureWidget secondGestureWidget(GestureWidget::GrabPinch);
+ nonGestureMiddleWidget.layout()->addWidget(&secondGestureWidget);
+ mainWidget->layout()->addWidget(&nonGestureMiddleWidget);
+ QApplication::processEvents();
+
+ SingleshotEvent event;
+ sendSpontaneousEvent(&secondGestureWidget, &event);
+ QVERIFY(!secondGestureWidget.seenGestureEvent);
+ QVERIFY(!nonGestureMiddleWidget.seenGestureEvent);
+ QVERIFY(mainWidget->seenGestureEvent);
+ QVERIFY(mainWidget->last.singleshot.delivered);
+ QVERIFY(mainWidget->last.cancelled.isEmpty());
+ QCOMPARE(mainWidget->last.singleshot.offset, QPoint(GestureWidget::LeftMargin*2,GestureWidget::TopMargin*2));
+
+ mainWidget->reset();
+ nonGestureMiddleWidget.reset();
+ secondGestureWidget.reset();
+
+ sendPinchEvents(&secondGestureWidget, QPoint(10,10), QPoint(20,20));
+ QVERIFY(secondGestureWidget.seenGestureEvent);
+ QVERIFY(!secondGestureWidget.last.singleshot.delivered);
+ QVERIFY(secondGestureWidget.last.pinch.delivered);
+ QCOMPARE(secondGestureWidget.last.pinch.startPoints[0].pt, QPoint(10,10));
+ QCOMPARE(secondGestureWidget.last.pinch.startPoints[1].pt, QPoint(20,20));
+ QCOMPARE(secondGestureWidget.last.pinch.offset, QPoint(0,0));
+ QVERIFY(!nonGestureMiddleWidget.seenGestureEvent);
+ QVERIFY(!mainWidget->seenGestureEvent);
+}
+
+void tst_Gestures::acceptedGesturePropagation()
+{
+ mainWidget->grabSingleshotGesture();
+ mainWidget->grabPinchGesture();
+ mainWidget->grabSecondFingerGesture();
+ GestureWidget nonGestureMiddleWidget(GestureWidget::DoNotGrabGestures);
+ nonGestureMiddleWidget.setObjectName("nonGestureMiddleWidget");
+ GestureWidget secondGestureWidget(GestureWidget::GrabSecondFinger);
+ secondGestureWidget.setObjectName("secondGestureWidget");
+ nonGestureMiddleWidget.layout()->addWidget(&secondGestureWidget);
+ mainWidget->layout()->addWidget(&nonGestureMiddleWidget);
+ QApplication::processEvents();
+
+ sendPinchEvents(&secondGestureWidget, QPoint(10, 10), QPoint(40, 40));
+ QVERIFY(secondGestureWidget.seenGestureEvent);
+ QVERIFY(!secondGestureWidget.last.singleshot.delivered);
+ QVERIFY(!secondGestureWidget.last.pinch.delivered);
+ QVERIFY(secondGestureWidget.last.secondfinger.delivered);
+ QCOMPARE(secondGestureWidget.last.secondfinger.startPoint.pt, QPoint(40,40));
+ QVERIFY(!nonGestureMiddleWidget.seenGestureEvent);
+ QVERIFY(mainWidget->seenGestureEvent);
+ QVERIFY(!mainWidget->last.singleshot.delivered);
+ QVERIFY(!mainWidget->last.secondfinger.delivered);
+ QVERIFY(mainWidget->last.pinch.delivered);
+ QCOMPARE(mainWidget->last.pinch.startPoints[0].pt, QPoint(10,10));
+ QCOMPARE(mainWidget->last.pinch.startPoints[1].pt, QPoint(40,40));
+
+ mainWidget->reset();
+ nonGestureMiddleWidget.reset();
+ secondGestureWidget.reset();
+
+ // don't accept it and make sure it propagates to parent
+ secondGestureWidget.shouldAcceptSecondFingerGesture = false;
+ sendPinchEvents(&secondGestureWidget, QPoint(10, 10), QPoint(40, 40));
+ QVERIFY(secondGestureWidget.seenGestureEvent);
+ QVERIFY(secondGestureWidget.last.secondfinger.delivered);
+ QVERIFY(!nonGestureMiddleWidget.seenGestureEvent);
+ QVERIFY(mainWidget->seenGestureEvent);
+ QVERIFY(!mainWidget->last.singleshot.delivered);
+ QVERIFY(mainWidget->last.secondfinger.delivered);
+ QVERIFY(mainWidget->last.pinch.delivered);
+}
+
+
+QTEST_MAIN(tst_Gestures)
+#include "tst_gestures.moc"