From 9f9904c52d3d598b91e589c435fa96333ef1232f Mon Sep 17 00:00:00 2001 From: Denis Dzyubenko Date: Thu, 7 May 2009 21:07:50 +0200 Subject: Improved gesture target widget detection. Gesture is now associated with a target widget and whenever several gesture events occur at the same time if they are supposed to be handled by different widgets, each widget will receive only gestures related to itself. For example this makes possible to use gesture framework with multitouch when user interacts with two widgets at the same time. GraphicsView implements is not implemented yet. --- src/gui/kernel/qevent.h | 1 + src/gui/kernel/qgesture_p.h | 2 + src/gui/kernel/qgesturemanager.cpp | 86 +++++++++++++++++++++++++------------- src/gui/kernel/qgesturemanager_p.h | 6 +-- 4 files changed, 61 insertions(+), 34 deletions(-) diff --git a/src/gui/kernel/qevent.h b/src/gui/kernel/qevent.h index 280ca79..666cd3f 100644 --- a/src/gui/kernel/qevent.h +++ b/src/gui/kernel/qevent.h @@ -736,6 +736,7 @@ protected: QSet m_cancelledGestures; friend class QApplication; + friend class QGestureManager; }; #ifndef QT_NO_DEBUG_STREAM diff --git a/src/gui/kernel/qgesture_p.h b/src/gui/kernel/qgesture_p.h index cf4e760..22d6d7f 100644 --- a/src/gui/kernel/qgesture_p.h +++ b/src/gui/kernel/qgesture_p.h @@ -85,6 +85,8 @@ public: QString type; Qt::GestureState state; + QPointer widget; + QRect rect; QPoint hotSpot; QDateTime startTime; diff --git a/src/gui/kernel/qgesturemanager.cpp b/src/gui/kernel/qgesturemanager.cpp index ef4b3d0..a93248a 100644 --- a/src/gui/kernel/qgesturemanager.cpp +++ b/src/gui/kernel/qgesturemanager.cpp @@ -41,6 +41,7 @@ #include "qgesturemanager_p.h" #include "qgesture.h" +#include "qgesture_p.h" #include "qevent.h" #include "qapplication.h" @@ -66,7 +67,7 @@ bool qt_sendSpontaneousEvent(QObject *receiver, QEvent *event); static const unsigned int MaximumGestureRecognitionTimeout = 2000; QGestureManager::QGestureManager(QObject *parent) - : QObject(parent), targetWidget(0), eventDeliveryDelayTimeout(300), + : QObject(parent), eventDeliveryDelayTimeout(300), delayedPressTimer(0), lastMousePressReceiver(0), lastMousePressEvent(QEvent::None, QPoint(), Qt::NoButton, 0, 0), lastGestureId(0), state(NotGesture) { @@ -95,16 +96,6 @@ void QGestureManager::removeRecognizer(QGestureRecognizer *recognizer) bool QGestureManager::filterEvent(QWidget *receiver, QEvent *event) { - if (state != Gesture) { - // find the target widget - QWidget *w = receiver; - while (w && w->d_func()->gestures.isEmpty()) - w = w->parentWidget(); - if (!w) // no widget in the tree that accepts gestures. - return false; - targetWidget = w; - } - QPoint currentPos; switch (event->type()) { case QEvent::MouseButtonPress: @@ -127,7 +118,6 @@ bool QGestureManager::filterEvent(QWidget *receiver, QEvent *event) DEBUG() << "QGestureManager: current event processing state: " << (state == NotGesture ? "NotGesture" : "MaybeGesture"); - Q_ASSERT(targetWidget != 0); QSet stillMaybeGestures; // try other recognizers. foreach(QGestureRecognizer *r, recognizers) { @@ -186,9 +176,7 @@ bool QGestureManager::filterEvent(QWidget *receiver, QEvent *event) gestures << gesture; } Q_ASSERT(!gestures.isEmpty()); - QGestureEvent event(gestures); - ret = sendGestureEvent(targetWidget, &event); - ret = ret && event.isAccepted(); + ret = sendGestureEvent(receiver, gestures); if (!activeGestures.isEmpty()) { DEBUG() << "QGestureManager: new state = Gesture"; @@ -251,6 +239,7 @@ 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; @@ -291,9 +280,7 @@ bool QGestureManager::filterEvent(QWidget *receiver, QEvent *event) foreach(QGestureRecognizer *r, cancelledGestures) cancelledGestureNames << r->gestureType(); if(!gestures.isEmpty()) { - QGestureEvent event(gestures, cancelledGestureNames); - ret = sendGestureEvent(targetWidget, &event); - ret = ret && event.isAccepted(); + ret = sendGestureEvent(receiver, gestures, cancelledGestureNames); } foreach(QGestureRecognizer *r, finishedGestures) @@ -343,6 +330,7 @@ bool QGestureManager::filterEvent(QWidget *receiver, QEvent *event) } lastMousePressReceiver = 0; } + lastMousePressReceiver = 0; killTimer(delayedPressTimer); delayedPressTimer = 0; } else if (state == MaybeGesture && event->type() == QEvent::MouseButtonPress @@ -394,6 +382,7 @@ void QGestureManager::timerEvent(QTimerEvent *event) lastMousePressReceiver = 0; } + lastMousePressReceiver = 0; killTimer(delayedPressTimer); delayedPressTimer = 0; } else { @@ -425,11 +414,6 @@ bool QGestureManager::inGestureMode() return state == Gesture; } -void QGestureManager::setGestureTargetWidget(QWidget *widget) -{ - targetWidget = widget; -} - void QGestureManager::recognizerStateChanged(QGestureRecognizer::Result result) { QGestureRecognizer *recognizer = qobject_cast(sender()); @@ -459,8 +443,7 @@ void QGestureManager::recognizerStateChanged(QGestureRecognizer::Result result) if (QGesture *gesture = recognizer->getGesture()) gestures << gesture; if(!gestures.isEmpty()) { - QGestureEvent event(gestures); - sendGestureEvent(targetWidget, &event); + //FIXME: sendGestureEvent(targetWidget, gestures); } if (result == QGestureRecognizer::GestureFinished) recognizer->reset(); @@ -469,9 +452,7 @@ void QGestureManager::recognizerStateChanged(QGestureRecognizer::Result result) case QGestureRecognizer::MaybeGesture: { DEBUG() << "QGestureManager: maybe gesture: " << recognizer; if (activeGestures.contains(recognizer)) { - QGestureEvent event(QList(), - QSet() << recognizer->gestureType()); - sendGestureEvent(targetWidget, &event); + //FIXME: sendGestureEvent(targetWidget, QList(), QSet() << recognizer->gestureType()); } if (!maybeGestures.contains(recognizer)) { int timerId = startTimer(MaximumGestureRecognitionTimeout); @@ -499,9 +480,54 @@ void QGestureManager::recognizerStateChanged(QGestureRecognizer::Result result) } } -bool QGestureManager::sendGestureEvent(QWidget *receiver, QGestureEvent *event) +bool QGestureManager::sendGestureEvent(QWidget *receiver, const QList &gestures, + const QSet &cancelled) { - return qt_sendSpontaneousEvent(receiver, event); + typedef QMap > WidgetGesturesMap; + WidgetGesturesMap widgetGestures; + for(QList::const_iterator it = gestures.begin(), e = gestures.end(); + it != e; ++it) { + QGesture *g = *it; + QGesturePrivate *gd = g->d_func(); + if (g->state() == Qt::GestureStarted) { + // find the target widget + QWidget *w = receiver; + while (w) { + QSet::iterator it = w->d_func()->gestures.begin(), + e = w->d_func()->gestures.end(); + for (; it != e; ++it) { + if (gestureNameFromId(*it) == g->type()) + break; + } + if (it != e) + break; + w = w->parentWidget(); + } + if (!w) // no widget in the tree that accepts this gesture. + continue; + gd->widget = w; + } + if (!gd->widget) { + DEBUG() << "QGestureManager: didn't find a widget to send gesture event (" + << g->type() << ") for tree:" << receiver; + continue; + } + widgetGestures[gd->widget].append(g); + } + + // we return true and stop original from being delivered if any of + // the gesture events were accepted by a receiver. + bool ret = false; + for(WidgetGesturesMap::const_iterator it = widgetGestures.begin(), e = widgetGestures.end(); + it != e; ++it) { + QWidget *receiver = it.key(); + Q_ASSERT(receiver != 0 /*should be taken care above*/); + // TODO: send cancelled gesture event to the widget that received the original gesture! + QGestureEvent event(it.value(), cancelled); + if (qt_sendSpontaneousEvent(receiver, &event) && event.isAccepted()) + ret = true; + } + return ret; } int QGestureManager::eventDeliveryDelay() const diff --git a/src/gui/kernel/qgesturemanager_p.h b/src/gui/kernel/qgesturemanager_p.h index 2b86fcd..beed323 100644 --- a/src/gui/kernel/qgesturemanager_p.h +++ b/src/gui/kernel/qgesturemanager_p.h @@ -70,8 +70,6 @@ class Q_GUI_EXPORT QGestureManager : public QObject public: QGestureManager(QObject *parent); - void setGestureTargetWidget(QWidget *widget); - int eventDeliveryDelay() const; void setEventDeliveryDelay(int ms); @@ -95,13 +93,13 @@ private slots: void recognizerStateChanged(QGestureRecognizer::Result); private: - bool sendGestureEvent(QWidget *receiver, QGestureEvent *event); + bool sendGestureEvent(QWidget *receiver, const QList &gestures, + const QSet &cancelled = QSet()); QSet activeGestures; QMap maybeGestures; QSet recognizers; - QWidget *targetWidget; QPoint lastPos; int eventDeliveryDelayTimeout; -- cgit v0.12