diff options
author | Denis Dzyubenko <denis.dzyubenko@nokia.com> | 2009-05-08 16:46:44 (GMT) |
---|---|---|
committer | Denis Dzyubenko <denis.dzyubenko@nokia.com> | 2009-05-11 14:52:04 (GMT) |
commit | 81a64345258f2f2ad5cf77355f7ecbd3ebad9734 (patch) | |
tree | 6fa024d2cadedae9ecd4e1718f704281112a78b5 | |
parent | 0edf9fc7ede35995ec37197b5fb5ef92a4ccf60f (diff) | |
download | Qt-81a64345258f2f2ad5cf77355f7ecbd3ebad9734.zip Qt-81a64345258f2f2ad5cf77355f7ecbd3ebad9734.tar.gz Qt-81a64345258f2f2ad5cf77355f7ecbd3ebad9734.tar.bz2 |
Improved gesture propagation.
Each gesture can now be accepted separately and not accepted gestures
will be propagated to parent widget that are subscribed to them.
Added an internal flag to specify that gesture is a "singleshot" - aka
if the gesture is not continious and will not have a GestureStarted
state, but only GestureFinished.
Asynchronous gestures still need to fixed, as well as QGraphicsView.
-rw-r--r-- | src/gui/kernel/qapplication.cpp | 31 | ||||
-rw-r--r-- | src/gui/kernel/qevent.cpp | 51 | ||||
-rw-r--r-- | src/gui/kernel/qevent.h | 11 | ||||
-rw-r--r-- | src/gui/kernel/qgesture.cpp | 2 | ||||
-rw-r--r-- | src/gui/kernel/qgesture.h | 8 | ||||
-rw-r--r-- | src/gui/kernel/qgesture_p.h | 3 | ||||
-rw-r--r-- | src/gui/kernel/qgesturemanager.cpp | 120 | ||||
-rw-r--r-- | src/gui/kernel/qgesturemanager_p.h | 3 |
8 files changed, 167 insertions, 62 deletions
diff --git a/src/gui/kernel/qapplication.cpp b/src/gui/kernel/qapplication.cpp index 9772e0f..ba105e0 100644 --- a/src/gui/kernel/qapplication.cpp +++ b/src/gui/kernel/qapplication.cpp @@ -4019,37 +4019,6 @@ bool QApplication::notify(QObject *receiver, QEvent *e) } break; #endif - - case QEvent::Gesture: { - QWidget *w = static_cast<QWidget*>(receiver); - QGestureEvent *ge = static_cast<QGestureEvent*>(e); - QSet<QString> eventGestures; - foreach(const QString &gesture, ge->gestureTypes()) - eventGestures << gesture; - bool eventAccepted = ge->isAccepted(); - - QPoint offset; - while (w) { - QSet<int> widgetGestures = w->d_func()->gestures; - foreach(int gestureId, widgetGestures) { - if (eventGestures.contains(QGestureManager::instance()->gestureNameFromId(gestureId))) { - foreach(QGesture *gesture, ge->gestures()) - gesture->translate(offset); - offset = QPoint(); - res = d->notify_helper(w, ge); - ge->spont = false; - eventAccepted = ge->isAccepted(); - if (res && eventAccepted) - break; - } - } - if (w->isWindow()) - break; - offset += w->pos(); - w = w->parentWidget(); - } - break; - } case QEvent::TouchBegin: // Note: TouchUpdate and TouchEnd events are sent to d->currentMultitouchWidget and never propagated { diff --git a/src/gui/kernel/qevent.cpp b/src/gui/kernel/qevent.cpp index f24f186..fa85bf2 100644 --- a/src/gui/kernel/qevent.cpp +++ b/src/gui/kernel/qevent.cpp @@ -3532,10 +3532,11 @@ QMenubarUpdatedEvent::QMenubarUpdatedEvent(QMenuBar * const menuBar) are being executed and a list of gesture that were cancelled (\a cancelledGestures). */ -QGestureEvent::QGestureEvent(const QList<QGesture*> &gestures, +QGestureEvent::QGestureEvent(const QSet<QGesture*> &gestures, const QSet<QString> &cancelledGestures) : QEvent(QEvent::Gesture), m_cancelledGestures(cancelledGestures) { + setAccepted(false); foreach(QGesture *r, gestures) m_gestures.insert(r->type(), r); } @@ -3606,6 +3607,54 @@ QSet<QString> QGestureEvent::cancelledGestures() const return m_cancelledGestures; } +/*! + 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)}. + + Setting the accept parameter indicates that the event receiver + wants the gesture. Unwanted gestures might be propagated to the parent + widget. +*/ +void QGestureEvent::acceptAll() +{ + QHash<QString, QGesture*>::iterator it = m_gestures.begin(), + e = m_gestures.end(); + for(; it != e; ++it) + it.value()->accept(); + setAccepted(true); +} + +/*! + Sets the accept flag of the specified gesture inside the event + object, the equivalent of calling + \l{QGestureEvent::gesture()}{gesture(type)}->\l{QGesture::accept()}{accept()} + + Setting the accept parameter indicates that the event receiver + wants the gesture. Unwanted gestures might be propagated to the parent + widget. +*/ +void QGestureEvent::accept(Qt::GestureType type) +{ + if (QGesture *g = m_gestures.value(qt_getStandardGestureTypeName(type), 0)) + g->accept(); +} + +/*! + Sets the accept flag of the specified gesture inside the event + object, the equivalent of calling + \l{QGestureEvent::gesture()}{gesture(type)}->\l{QGesture::accept()}{accept()} + + Setting the accept parameter indicates that the event receiver + wants the gesture. Unwanted gestures might be propagated to the parent + widget. +*/ +void QGestureEvent::accept(const QString &type) +{ + if (QGesture *g = m_gestures.value(type, 0)) + g->accept(); +} + /*! \class QTouchEvent \brief The QTouchEvent class contains parameters that describe a touch event . diff --git a/src/gui/kernel/qevent.h b/src/gui/kernel/qevent.h index 666cd3f..ea4f577 100644 --- a/src/gui/kernel/qevent.h +++ b/src/gui/kernel/qevent.h @@ -716,7 +716,7 @@ private: class Q_GUI_EXPORT QGestureEvent : public QEvent { public: - QGestureEvent(const QList<QGesture*> &gestures, + QGestureEvent(const QSet<QGesture*> &gestures, const QSet<QString> &cancelledGestures = QSet<QString>()); ~QGestureEvent(); @@ -731,6 +731,15 @@ public: QSet<QString> cancelledGestures() const; + void acceptAll(); +#ifndef Q_NO_USING_KEYWORD + using QEvent::accept; +#else + inline void accept() { QEvent::accept(); } +#endif + void accept(Qt::GestureType type); + void accept(const QString &type); + protected: QHash<QString, QGesture*> m_gestures; QSet<QString> m_cancelledGestures; diff --git a/src/gui/kernel/qgesture.cpp b/src/gui/kernel/qgesture.cpp index 4d492f8..7437ed3 100644 --- a/src/gui/kernel/qgesture.cpp +++ b/src/gui/kernel/qgesture.cpp @@ -79,7 +79,7 @@ QString qt_getStandardGestureTypeName(Qt::GestureType type); QGestureRecognizer classes. */ QGesture::QGesture(QObject *parent, const QString &type, Qt::GestureState state) - : QObject(*new QGesturePrivate, parent) + : QObject(*new QGesturePrivate, parent), m_accept(0) { Q_D(QGesture); d->type = type; diff --git a/src/gui/kernel/qgesture.h b/src/gui/kernel/qgesture.h index da1bc90..d220232 100644 --- a/src/gui/kernel/qgesture.h +++ b/src/gui/kernel/qgesture.h @@ -82,6 +82,12 @@ public: uint duration, Qt::GestureState state); virtual ~QGesture(); + inline void setAccepted(bool accepted) { m_accept = accepted; } + inline bool isAccepted() const { return m_accept; } + + inline void accept() { m_accept = true; } + inline void ignore() { m_accept = false; } + QString type() const; Qt::GestureState state() const; @@ -100,6 +106,8 @@ protected: virtual void translate(const QPoint &offset); private: + ushort m_accept : 1; + friend class QGestureManager; friend class QApplication; friend class QGestureRecognizerPan; diff --git a/src/gui/kernel/qgesture_p.h b/src/gui/kernel/qgesture_p.h index 22d6d7f..d2d77cc 100644 --- a/src/gui/kernel/qgesture_p.h +++ b/src/gui/kernel/qgesture_p.h @@ -66,7 +66,7 @@ class QGesturePrivate : public QObjectPrivate public: QGesturePrivate() - : duration(0) { } + : state(Qt::NoGesture), singleshot(0), duration(0) { } void init(const QPoint &startPos, const QPoint &lastPos, const QPoint &pos, const QRect &rect, @@ -86,6 +86,7 @@ public: Qt::GestureState state; QPointer<QWidget> widget; + uint singleshot:1; QRect rect; QPoint hotSpot; diff --git a/src/gui/kernel/qgesturemanager.cpp b/src/gui/kernel/qgesturemanager.cpp index a93248a..c7341f2 100644 --- a/src/gui/kernel/qgesturemanager.cpp +++ b/src/gui/kernel/qgesturemanager.cpp @@ -166,14 +166,18 @@ bool QGestureManager::filterEvent(QWidget *receiver, QEvent *event) DEBUG() << "QGestureManager: sending gesture event for: " << activeGestures << " and " << finishedGestures; - QList<QGesture*> gestures; + QSet<QGesture*> gestures; foreach(QGestureRecognizer *r, finishedGestures) { - if (QGesture *gesture = r->getGesture()) + if (QGesture *gesture = r->getGesture()) { gestures << gesture; + gesture->d_func()->singleshot = true; + } } foreach(QGestureRecognizer *r, activeGestures) { - if (QGesture *gesture = r->getGesture()) + if (QGesture *gesture = r->getGesture()) { gestures << gesture; + gesture->d_func()->singleshot = false; + } } Q_ASSERT(!gestures.isEmpty()); ret = sendGestureEvent(receiver, gestures); @@ -243,7 +247,6 @@ bool QGestureManager::filterEvent(QWidget *receiver, QEvent *event) activeGestures -= newMaybeGestures; activeGestures -= cancelledGestures; - activeGestures -= finishedGestures; activeGestures += startedGestures; foreach(QGestureRecognizer *r, startedGestures+finishedGestures+notGestures) { QMap<QGestureRecognizer*, int>::iterator it = maybeGestures.find(r); @@ -260,7 +263,7 @@ bool QGestureManager::filterEvent(QWidget *receiver, QEvent *event) maybeGestures.insert(r, timerId); } } - QList<QGesture*> gestures; + QSet<QGesture*> gestures; if (!finishedGestures.isEmpty() || !activeGestures.isEmpty()) { // another gesture found! ret = true; @@ -268,12 +271,17 @@ bool QGestureManager::filterEvent(QWidget *receiver, QEvent *event) << activeGestures << " and " << finishedGestures; foreach(QGestureRecognizer *r, finishedGestures) { - if (QGesture *gesture = r->getGesture()) + if (QGesture *gesture = r->getGesture()) { gestures << gesture; + gesture->d_func()->singleshot = activeGestures.contains(r); + } } + activeGestures -= finishedGestures; foreach(QGestureRecognizer *r, activeGestures) { - if (QGesture *gesture = r->getGesture()) + if (QGesture *gesture = r->getGesture()) { gestures << gesture; + gesture->d_func()->singleshot = false; + } } } QSet<QString> cancelledGestureNames; @@ -439,7 +447,7 @@ void QGestureManager::recognizerStateChanged(QGestureRecognizer::Result result) killTimer(maybeGestures.value(recognizer)); maybeGestures.remove(recognizer); } - QList<QGesture*> gestures; + QSet<QGesture*> gestures; if (QGesture *gesture = recognizer->getGesture()) gestures << gesture; if(!gestures.isEmpty()) { @@ -452,7 +460,7 @@ void QGestureManager::recognizerStateChanged(QGestureRecognizer::Result result) case QGestureRecognizer::MaybeGesture: { DEBUG() << "QGestureManager: maybe gesture: " << recognizer; if (activeGestures.contains(recognizer)) { - //FIXME: sendGestureEvent(targetWidget, QList<QGesture*>(), QSet<QString>() << recognizer->gestureType()); + //FIXME: sendGestureEvent(targetWidget, QSet<QGesture*>(), QSet<QString>() << recognizer->gestureType()); } if (!maybeGestures.contains(recognizer)) { int timerId = startTimer(MaximumGestureRecognitionTimeout); @@ -480,43 +488,63 @@ void QGestureManager::recognizerStateChanged(QGestureRecognizer::Result result) } } -bool QGestureManager::sendGestureEvent(QWidget *receiver, const QList<QGesture*> &gestures, +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, const QSet<QString> &cancelled) { - typedef QMap<QWidget*, QList<QGesture*> > WidgetGesturesMap; + if (gestures.isEmpty()) + return false; + DEBUG() << "QGestureManager::sendGestureEvent: sending to" << receiver + << "gestures:" << gestures << "; cancelled:" << cancelled; + QSet<QGesture*> startedGestures; + // grouping gesture objects by receiver widgets. + typedef QMap<QWidget*, QSet<QGesture*> > WidgetGesturesMap; WidgetGesturesMap widgetGestures; - for(QList<QGesture*>::const_iterator it = gestures.begin(), e = gestures.end(); + for(QSet<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) { + if (!gd->widget && (g->state() == Qt::GestureStarted || g->state() == Qt::GestureFinished)) { + startedGestures.insert(g); // find the target widget QWidget *w = receiver; + QPoint offset; while (w) { - QSet<int>::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) + if (widgetHasGesture(w, g)) break; + if (w->isWindow()) { + w = 0; + break; + } + offset += w->pos(); w = w->parentWidget(); } if (!w) // no widget in the tree that accepts this gesture. continue; gd->widget = w; + g->translate(offset); } if (!gd->widget) { DEBUG() << "QGestureManager: didn't find a widget to send gesture event (" << g->type() << ") for tree:" << receiver; + // TODO: maybe we should reset gesture recognizers when nobody interested in its gestures. continue; } - widgetGestures[gd->widget].append(g); + widgetGestures[gd->widget].insert(g); } - // we return true and stop original from being delivered if any of - // the gesture events were accepted by a receiver. + QSet<QGesture*> ignoredGestures; bool ret = false; for(WidgetGesturesMap::const_iterator it = widgetGestures.begin(), e = widgetGestures.end(); it != e; ++it) { @@ -524,10 +552,50 @@ bool QGestureManager::sendGestureEvent(QWidget *receiver, const QList<QGesture*> 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; + bool processed = qt_sendSpontaneousEvent(receiver, &event); + QSet<QGesture*> started = startedGestures.intersect(it.value()); + 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; + if (processed && g->isAccepted()) { + ret = true; + continue; + } + // if it wasn't accepted, find the first parent widget + // that is subscribed to the gesture. + QGesturePrivate *gd = g->d_func(); + QWidget *w = gd->widget; + gd->widget = 0; + + if (!w->isWindow()) { + g->translate(w->pos()); + w = w->parentWidget(); + QPoint offset; + while (w) { + if (widgetHasGesture(w, g)) { + DEBUG() << "QGestureManager: sendGestureEvent:" << w << "didn't accept gesture" << g; + ignoredGestures.insert(g); + break; + } + if (w->isWindow()) { + w = 0; + break; + } + offset += w->pos(); + w = w->parentWidget(); + } + if (w) + g->translate(offset); + } + } + } } - return ret; + // try to send all gestures that were ignored to the next parent + return sendGestureEvent(0, ignoredGestures, cancelled) || ret; } int QGestureManager::eventDeliveryDelay() const diff --git a/src/gui/kernel/qgesturemanager_p.h b/src/gui/kernel/qgesturemanager_p.h index beed323..963edf9 100644 --- a/src/gui/kernel/qgesturemanager_p.h +++ b/src/gui/kernel/qgesturemanager_p.h @@ -93,7 +93,8 @@ private slots: void recognizerStateChanged(QGestureRecognizer::Result); private: - bool sendGestureEvent(QWidget *receiver, const QList<QGesture*> &gestures, + bool widgetHasGesture(QWidget *widget, QGesture *gesture) const; + bool sendGestureEvent(QWidget *receiver, const QSet<QGesture*> &gestures, const QSet<QString> &cancelled = QSet<QString>()); QSet<QGestureRecognizer*> activeGestures; |