summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDenis Dzyubenko <denis.dzyubenko@nokia.com>2009-10-28 21:40:14 +0100
committerDenis Dzyubenko <denis.dzyubenko@nokia.com>2009-11-03 11:26:06 +0100
commitcfcfae65778f2e1e7fc3936c66689e3685f1cc77 (patch)
tree728c38f0e9603e174e0d6391ab50542693ed2191
parent4843b437b90800d238f14e7a4558045ddc37cd4b (diff)
Modified gesture events propagation.
By default if the gesture is ignored, only gestures in the started state are propagated, and accepting a gesture in the started state adds an implicit grab meaning all the following events in the gesture sequence will be delivered to that widget. This is similar to the way QTouchEvent is propagated. Also added a hint, which specifies if gestures in any state can be propagated to the widget which has enabled the hint. Reviewed-by: Thomas Zander
-rw-r--r--src/corelib/global/qnamespace.h12
-rw-r--r--src/corelib/global/qnamespace.qdoc18
-rw-r--r--src/gui/graphicsview/qgraphicsscene.cpp13
-rw-r--r--src/gui/kernel/qapplication.cpp7
-rw-r--r--src/gui/kernel/qgesturemanager.cpp16
-rw-r--r--tests/auto/gestures/tst_gestures.cpp121
6 files changed, 150 insertions, 37 deletions
diff --git a/src/corelib/global/qnamespace.h b/src/corelib/global/qnamespace.h
index aeaca54f71..561ffc1c51 100644
--- a/src/corelib/global/qnamespace.h
+++ b/src/corelib/global/qnamespace.h
@@ -1715,14 +1715,19 @@ public:
LastGestureType = ~0u
};
- enum GestureContext
+ enum GestureContextFlag
{
WidgetGesture = 0,
WidgetWithChildrenGesture = 3,
- ItemGesture = WidgetGesture,
- ItemWithChildrenGesture = WidgetWithChildrenGesture
+ ItemGesture = WidgetGesture,
+ ItemWithChildrenGesture = WidgetWithChildrenGesture,
+
+ GestureContext_Mask = 0x00ff,
+ AcceptPartialGesturesHint = 0x0100,
+ GestureContextHint_Mask = 0xff00
};
+ Q_DECLARE_FLAGS(GestureContext, GestureContextFlag)
enum NavigationMode
{
@@ -1757,6 +1762,7 @@ Q_DECLARE_OPERATORS_FOR_FLAGS(Qt::MatchFlags)
Q_DECLARE_OPERATORS_FOR_FLAGS(Qt::TextInteractionFlags)
Q_DECLARE_OPERATORS_FOR_FLAGS(Qt::InputMethodHints)
Q_DECLARE_OPERATORS_FOR_FLAGS(Qt::TouchPointStates)
+Q_DECLARE_OPERATORS_FOR_FLAGS(Qt::GestureContext)
typedef bool (*qInternalCallback)(void **);
diff --git a/src/corelib/global/qnamespace.qdoc b/src/corelib/global/qnamespace.qdoc
index 3fcbe57928..f2a8882855 100644
--- a/src/corelib/global/qnamespace.qdoc
+++ b/src/corelib/global/qnamespace.qdoc
@@ -2917,11 +2917,11 @@
QApplication::registerGestureRecognizer() function which generates a custom gesture ID
in the range of values from CustomGesture to LastGestureType.
- \sa QGesture, QWidget::grabGesture()
+ \sa QGesture, QWidget::grabGesture(), QGraphicsObject::grabGesture()
*/
/*!
- \enum Qt::GestureContext
+ \enum Qt::GestureContextFlag
\since 4.6
This enum type describes the context of a gesture.
@@ -2937,7 +2937,19 @@
\value ItemWithChildrenGesture Gestures can start on the item or over
any of its children.
- \sa QWidget::grabGesture()
+ \value AcceptPartialGesturesHint Allows any ignored gesture events to be
+ propagated to parent widgets which have specified this hint. By default
+ only gestures that are in the Qt::GestureStarted state are propagated and
+ the widget only gets the full gesture sequence starting with a gesture in
+ the Qt::GestureStarted state and ending with a gesture in the
+ Qt::GestureFinished or Qt::GestureCanceled states.
+
+ \value GestureContext_Mask A mask for extracting the context type of the
+ context flags.
+ \value GestureContextHint_Mask A mask for extracting additional hints for
+ the context.
+
+ \sa QWidget::grabGesture(), QGraphicsObject::grabGesture()
*/
/*!
diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp
index 9279fe36cc..f5bb408a7a 100644
--- a/src/gui/graphicsview/qgraphicsscene.cpp
+++ b/src/gui/graphicsview/qgraphicsscene.cpp
@@ -5900,7 +5900,12 @@ void QGraphicsScenePrivate::gestureEventHandler(QGestureEvent *event)
QGraphicsItemPrivate *gid = item->QGraphicsItem::d_func();
foreach(QGesture *g, alreadyIgnoredGestures) {
- if (gid->gestureContext.contains(g->gestureType()))
+ QMap<Qt::GestureType, Qt::GestureContext>::iterator contextit =
+ gid->gestureContext.find(g->gestureType());
+ bool deliver = contextit != gid->gestureContext.end() &&
+ (g->state() == Qt::GestureStarted ||
+ (contextit.value() & Qt::GestureContextHint_Mask) & Qt::AcceptPartialGesturesHint);
+ if (deliver)
gestures += g;
}
if (gestures.isEmpty())
@@ -5913,8 +5918,12 @@ void QGraphicsScenePrivate::gestureEventHandler(QGestureEvent *event)
sendEvent(item, &ev);
QSet<QGesture *> ignoredGestures;
foreach (QGesture *g, gestures) {
- if (!ev.isAccepted() && !ev.isAccepted(g))
+ if (!ev.isAccepted() && !ev.isAccepted(g)) {
ignoredGestures.insert(g);
+ } else {
+ if (g->state() == Qt::GestureStarted)
+ gestureTargets[g] = item;
+ }
}
if (!ignoredGestures.isEmpty()) {
// get a list of items under the (current) hotspot of each ignored
diff --git a/src/gui/kernel/qapplication.cpp b/src/gui/kernel/qapplication.cpp
index 06787eb2bc..b9e7d527e7 100644
--- a/src/gui/kernel/qapplication.cpp
+++ b/src/gui/kernel/qapplication.cpp
@@ -4161,7 +4161,12 @@ bool QApplication::notify(QObject *receiver, QEvent *e)
for (int i = 0; i < allGestures.size();) {
QGesture *g = allGestures.at(i);
Qt::GestureType type = g->gestureType();
- if (wd->gestureContext.contains(type)) {
+ QMap<Qt::GestureType, Qt::GestureContext>::iterator contextit =
+ wd->gestureContext.find(type);
+ bool deliver = contextit != wd->gestureContext.end() &&
+ (g->state() == Qt::GestureStarted || w == receiver ||
+ (contextit.value() & Qt::GestureContextHint_Mask) & Qt::AcceptPartialGesturesHint);
+ if (deliver) {
allGestures.removeAt(i);
gestures.append(g);
} else {
diff --git a/src/gui/kernel/qgesturemanager.cpp b/src/gui/kernel/qgesturemanager.cpp
index 318d4b5638..e4a1eb4630 100644
--- a/src/gui/kernel/qgesturemanager.cpp
+++ b/src/gui/kernel/qgesturemanager.cpp
@@ -448,7 +448,7 @@ bool QGestureManager::filterEvent(QWidget *receiver, QEvent *event)
{
for (ContextIterator it = w->d_func()->gestureContext.begin(),
e = w->d_func()->gestureContext.end(); it != e; ++it) {
- if (it.value() == Qt::WidgetWithChildrenGesture) {
+ if ((it.value() & Qt::GestureContext_Mask) == Qt::WidgetWithChildrenGesture) {
if (!types.contains(it.key())) {
types.insert(it.key());
contexts.insertMulti(w, it.key());
@@ -482,7 +482,7 @@ bool QGestureManager::filterEvent(QGraphicsObject *receiver, QEvent *event)
typedef QMap<Qt::GestureType, Qt::GestureContext>::const_iterator ContextIterator;
for (ContextIterator it = item->QGraphicsItem::d_func()->gestureContext.begin(),
e = item->QGraphicsItem::d_func()->gestureContext.end(); it != e; ++it) {
- if (it.value() == Qt::ItemWithChildrenGesture) {
+ if ((it.value() & Qt::GestureContext_Mask) == Qt::ItemWithChildrenGesture) {
if (!types.contains(it.key())) {
types.insert(it.key());
contexts.insertMulti(item, it.key());
@@ -525,7 +525,7 @@ void QGestureManager::getGestureTargets(const QSet<QGesture*> &gestures,
= w->d_func()->gestureContext.find(type);
if (it != w->d_func()->gestureContext.end()) {
// i.e. 'w' listens to gesture 'type'
- Qt::GestureContext context = it.value();
+ Qt::GestureContext context = it.value() & Qt::GestureContext_Mask;
if (context == Qt::WidgetWithChildrenGesture && w != widget) {
// conflicting gesture!
(*conflicts)[widget].append(gestures[widget]);
@@ -645,6 +645,16 @@ void QGestureManager::deliverEvents(const QSet<QGesture *> &gestures,
<< "gestures:" << it.value();
QGestureEvent event(it.value());
QApplication::sendEvent(it.key(), &event);
+ bool eventAccepted = event.isAccepted();
+ foreach (QGesture *gesture, event.allGestures()) {
+ if (gesture->state() == Qt::GestureStarted &&
+ (eventAccepted || event.isAccepted(gesture))) {
+ QWidget *w = event.d_func()->targetWidgets.value(gesture->gestureType(), 0);
+ Q_ASSERT(w);
+ DEBUG() << "started gesture was delivered and accepted by" << w;
+ m_gestureTargets[gesture] = w;
+ }
+ }
}
}
}
diff --git a/tests/auto/gestures/tst_gestures.cpp b/tests/auto/gestures/tst_gestures.cpp
index 79de8239d3..9b2bc577fe 100644
--- a/tests/auto/gestures/tst_gestures.cpp
+++ b/tests/auto/gestures/tst_gestures.cpp
@@ -543,7 +543,9 @@ void tst_Gestures::conflictingGestures()
parent.reset();
child->reset();
- // nobody accepts the override, we will send normal events to the closest context (to the child)
+ // nobody accepts the override, we will send normal events to the closest
+ // context (i.e. to the child widget) and it will be propagated and
+ // accepted by the parent widget
parent.acceptGestureOverride = false;
child->acceptGestureOverride = false;
child->ignoredGestures << CustomGesture::GestureType;
@@ -552,6 +554,41 @@ void tst_Gestures::conflictingGestures()
sendCustomGesture(&event, child);
QCOMPARE(child->gestureOverrideEventsReceived, 1);
+ QCOMPARE(child->gestureEventsReceived, 1);
+ QCOMPARE(parent.gestureOverrideEventsReceived, 1);
+ QCOMPARE(parent.gestureEventsReceived, TotalGestureEventsCount);
+
+ parent.reset();
+ child->reset();
+
+ // nobody accepts the override, and nobody accepts the gesture event
+ parent.acceptGestureOverride = false;
+ child->acceptGestureOverride = false;
+ parent.ignoredGestures << CustomGesture::GestureType;
+ child->ignoredGestures << CustomGesture::GestureType;
+
+ // sending events to the child and making sure there is no conflict
+ sendCustomGesture(&event, child);
+
+ QCOMPARE(child->gestureOverrideEventsReceived, 1);
+ QCOMPARE(child->gestureEventsReceived, TotalGestureEventsCount);
+ QCOMPARE(parent.gestureOverrideEventsReceived, 1);
+ QCOMPARE(parent.gestureEventsReceived, 1);
+
+ parent.reset();
+ child->reset();
+
+ // we set an attribute to make sure all gesture events are propagated
+ parent.grabGesture(CustomGesture::GestureType, Qt::WidgetWithChildrenGesture | Qt::AcceptPartialGesturesHint);
+ parent.acceptGestureOverride = false;
+ child->acceptGestureOverride = false;
+ parent.ignoredGestures << CustomGesture::GestureType;
+ child->ignoredGestures << CustomGesture::GestureType;
+
+ // sending events to the child and making sure there is no conflict
+ sendCustomGesture(&event, child);
+
+ QCOMPARE(child->gestureOverrideEventsReceived, 1);
QCOMPARE(child->gestureEventsReceived, TotalGestureEventsCount);
QCOMPARE(parent.gestureOverrideEventsReceived, 1);
QCOMPARE(parent.gestureEventsReceived, TotalGestureEventsCount);
@@ -851,7 +888,7 @@ void tst_Gestures::graphicsItemTreeGesture()
QCOMPARE(item1_child2->gestureEventsReceived, 0);
QCOMPARE(item1_child2->gestureOverrideEventsReceived, 0);
QCOMPARE(item1->gestureOverrideEventsReceived, 1);
- QCOMPARE(item1->gestureEventsReceived, TotalGestureEventsCount);
+ QCOMPARE(item1->gestureEventsReceived, 1);
}
void tst_Gestures::explicitGraphicsObjectTarget()
@@ -966,7 +1003,39 @@ void tst_Gestures::gestureOverChildGraphicsItem()
event.hasHotSpot = true;
sendCustomGesture(&event, item0, &scene);
- QCOMPARE(item0->customEventsReceived, TotalCustomEventsCount);
+ QCOMPARE(item2_child1->gestureEventsReceived, 0);
+ QCOMPARE(item2_child1->gestureOverrideEventsReceived, 0);
+ QCOMPARE(item2->gestureEventsReceived, 1);
+ QCOMPARE(item2->gestureOverrideEventsReceived, 1);
+ QCOMPARE(item1->gestureEventsReceived, TotalGestureEventsCount);
+ QCOMPARE(item1->gestureOverrideEventsReceived, 1);
+
+ item0->reset(); item1->reset(); item2->reset(); item2_child1->reset();
+ item2->grabGesture(CustomGesture::GestureType);
+ item2->ignoredGestures << CustomGesture::GestureType;
+ item1->ignoredGestures << CustomGesture::GestureType;
+
+ event.hotSpot = mapToGlobal(QPointF(10, 10), item2_child1, &view);
+ event.hasHotSpot = true;
+ sendCustomGesture(&event, item0, &scene);
+
+ QCOMPARE(item2_child1->gestureEventsReceived, 0);
+ QCOMPARE(item2_child1->gestureOverrideEventsReceived, 0);
+ QCOMPARE(item2->gestureEventsReceived, TotalGestureEventsCount);
+ QCOMPARE(item2->gestureOverrideEventsReceived, 1);
+ QCOMPARE(item1->gestureEventsReceived, 1);
+ QCOMPARE(item1->gestureOverrideEventsReceived, 1);
+
+ item0->reset(); item1->reset(); item2->reset(); item2_child1->reset();
+ item2->grabGesture(CustomGesture::GestureType);
+ item2->ignoredGestures << CustomGesture::GestureType;
+ item1->ignoredGestures << CustomGesture::GestureType;
+ item1->grabGesture(CustomGesture::GestureType, Qt::WidgetWithChildrenGesture | Qt::AcceptPartialGesturesHint);
+
+ event.hotSpot = mapToGlobal(QPointF(10, 10), item2_child1, &view);
+ event.hasHotSpot = true;
+ sendCustomGesture(&event, item0, &scene);
+
QCOMPARE(item2_child1->gestureEventsReceived, 0);
QCOMPARE(item2_child1->gestureOverrideEventsReceived, 0);
QCOMPARE(item2->gestureEventsReceived, TotalGestureEventsCount);
@@ -1025,15 +1094,16 @@ void tst_Gestures::multipleGesturesInTree()
Qt::GestureType SecondGesture = QApplication::registerGestureRecognizer(new CustomGestureRecognizer);
Qt::GestureType ThirdGesture = QApplication::registerGestureRecognizer(new CustomGestureRecognizer);
- A->grabGesture(FirstGesture, Qt::WidgetWithChildrenGesture); // A [1 3]
- A->grabGesture(ThirdGesture, Qt::WidgetWithChildrenGesture); // |
- B->grabGesture(SecondGesture, Qt::WidgetWithChildrenGesture); // B [ 2 3]
- B->grabGesture(ThirdGesture, Qt::WidgetWithChildrenGesture); // |
- C->grabGesture(FirstGesture, Qt::WidgetWithChildrenGesture); // C [1 2 3]
- C->grabGesture(SecondGesture, Qt::WidgetWithChildrenGesture); // |
- C->grabGesture(ThirdGesture, Qt::WidgetWithChildrenGesture); // D [1 3]
- D->grabGesture(FirstGesture, Qt::WidgetWithChildrenGesture);
- D->grabGesture(ThirdGesture, Qt::WidgetWithChildrenGesture);
+ Qt::GestureContext context = Qt::WidgetWithChildrenGesture | Qt::AcceptPartialGesturesHint;
+ A->grabGesture(FirstGesture, context); // A [1 3]
+ A->grabGesture(ThirdGesture, context); // |
+ B->grabGesture(SecondGesture, context); // B [ 2 3]
+ B->grabGesture(ThirdGesture, context); // |
+ C->grabGesture(FirstGesture, context); // C [1 2 3]
+ C->grabGesture(SecondGesture, context); // |
+ C->grabGesture(ThirdGesture, context); // D [1 3]
+ D->grabGesture(FirstGesture, context);
+ D->grabGesture(ThirdGesture, context);
// make sure all widgets ignore events, so they get propagated.
A->ignoredGestures << FirstGesture << ThirdGesture;
@@ -1100,19 +1170,20 @@ void tst_Gestures::multipleGesturesInComplexTree()
Qt::GestureType SixthGesture = QApplication::registerGestureRecognizer(new CustomGestureRecognizer);
Qt::GestureType SeventhGesture = QApplication::registerGestureRecognizer(new CustomGestureRecognizer);
- A->grabGesture(FirstGesture, Qt::WidgetWithChildrenGesture); // A [1,3,4]
- A->grabGesture(ThirdGesture, Qt::WidgetWithChildrenGesture); // |
- A->grabGesture(FourthGesture, Qt::WidgetWithChildrenGesture); // B [2,3,5]
- B->grabGesture(SecondGesture, Qt::WidgetWithChildrenGesture); // |
- B->grabGesture(ThirdGesture, Qt::WidgetWithChildrenGesture); // C [1,2,3,6]
- B->grabGesture(FifthGesture, Qt::WidgetWithChildrenGesture); // |
- C->grabGesture(FirstGesture, Qt::WidgetWithChildrenGesture); // D [1,3,7]
- C->grabGesture(SecondGesture, Qt::WidgetWithChildrenGesture);
- C->grabGesture(ThirdGesture, Qt::WidgetWithChildrenGesture);
- C->grabGesture(SixthGesture, Qt::WidgetWithChildrenGesture);
- D->grabGesture(FirstGesture, Qt::WidgetWithChildrenGesture);
- D->grabGesture(ThirdGesture, Qt::WidgetWithChildrenGesture);
- D->grabGesture(SeventhGesture, Qt::WidgetWithChildrenGesture);
+ Qt::GestureContext context = Qt::WidgetWithChildrenGesture | Qt::AcceptPartialGesturesHint;
+ A->grabGesture(FirstGesture, context); // A [1,3,4]
+ A->grabGesture(ThirdGesture, context); // |
+ A->grabGesture(FourthGesture, context); // B [2,3,5]
+ B->grabGesture(SecondGesture, context); // |
+ B->grabGesture(ThirdGesture, context); // C [1,2,3,6]
+ B->grabGesture(FifthGesture, context); // |
+ C->grabGesture(FirstGesture, context); // D [1,3,7]
+ C->grabGesture(SecondGesture, context);
+ C->grabGesture(ThirdGesture, context);
+ C->grabGesture(SixthGesture, context);
+ D->grabGesture(FirstGesture, context);
+ D->grabGesture(ThirdGesture, context);
+ D->grabGesture(SeventhGesture, context);
// make sure all widgets ignore events, so they get propagated.
QSet<Qt::GestureType> allGestureTypes;