summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/corelib/global/qnamespace.h48
-rw-r--r--src/corelib/kernel/qcoreevent.cpp8
-rw-r--r--src/corelib/kernel/qcoreevent.h13
-rw-r--r--src/gui/graphicsview/qgraphicsitem.cpp105
-rw-r--r--src/gui/graphicsview/qgraphicsitem.h7
-rw-r--r--src/gui/graphicsview/qgraphicsitem_p.h5
-rw-r--r--src/gui/graphicsview/qgraphicsscene.cpp322
-rw-r--r--src/gui/graphicsview/qgraphicsscene.h2
-rw-r--r--src/gui/graphicsview/qgraphicsscene_p.h22
-rw-r--r--src/gui/graphicsview/qgraphicssceneevent.cpp401
-rw-r--r--src/gui/graphicsview/qgraphicssceneevent.h81
-rw-r--r--src/gui/graphicsview/qgraphicsview.cpp86
-rw-r--r--src/gui/graphicsview/qgraphicsview_p.h2
-rw-r--r--src/gui/kernel/kernel.pri17
-rw-r--r--src/gui/kernel/qapplication.cpp178
-rw-r--r--src/gui/kernel/qapplication.h9
-rw-r--r--src/gui/kernel/qapplication_p.h42
-rw-r--r--src/gui/kernel/qapplication_win.cpp271
-rw-r--r--src/gui/kernel/qapplication_x11.cpp2
-rw-r--r--src/gui/kernel/qdirectionrecognizer.cpp176
-rw-r--r--src/gui/kernel/qdirectionrecognizer_p.h105
-rw-r--r--src/gui/kernel/qdirectionsimplificator_p.h172
-rw-r--r--src/gui/kernel/qevent.cpp374
-rw-r--r--src/gui/kernel/qevent.h96
-rw-r--r--src/gui/kernel/qevent_p.h17
-rw-r--r--src/gui/kernel/qgesture.cpp290
-rw-r--r--src/gui/kernel/qgesture.h145
-rw-r--r--src/gui/kernel/qgesture_p.h111
-rw-r--r--src/gui/kernel/qgesturemanager.cpp630
-rw-r--r--src/gui/kernel/qgesturemanager_p.h125
-rw-r--r--src/gui/kernel/qgesturerecognizer.cpp156
-rw-r--r--src/gui/kernel/qgesturerecognizer.h87
-rw-r--r--src/gui/kernel/qgesturerecognizer_p.h72
-rw-r--r--src/gui/kernel/qgesturestandardrecognizers.cpp306
-rw-r--r--src/gui/kernel/qgesturestandardrecognizers_p.h130
-rw-r--r--src/gui/kernel/qwidget.cpp89
-rw-r--r--src/gui/kernel/qwidget.h9
-rw-r--r--src/gui/kernel/qwidget_p.h6
-rw-r--r--src/gui/kernel/qwidget_win.cpp4
-rw-r--r--src/gui/widgets/qabstractscrollarea.cpp1
-rw-r--r--src/network/kernel/qauthenticator.cpp2
41 files changed, 4676 insertions, 48 deletions
diff --git a/src/corelib/global/qnamespace.h b/src/corelib/global/qnamespace.h
index 3367581..29f6701 100644
--- a/src/corelib/global/qnamespace.h
+++ b/src/corelib/global/qnamespace.h
@@ -491,6 +491,9 @@ public:
WA_WState_WindowOpacitySet = 119, // internal
WA_TranslucentBackground = 120,
+ WA_AcceptTouchEvents = 121,
+ WA_AcceptedTouchBeginEvent = 122,
+
// Add new attributes before this line
WA_AttributeCount
};
@@ -1541,6 +1544,51 @@ public:
BottomLeftSection,
TitleBarArea // For move
};
+
+ enum TouchPointState {
+ TouchPointPressed,
+ TouchPointMoved,
+ TouchPointStationary,
+ TouchPointReleased
+ };
+
+ enum GestureType
+ {
+ UnknownGesture,
+ TapGesture,
+ DoubleTapGesture,
+ TrippleTapGesture,
+ TapAndHoldGesture,
+ PanGesture,
+ PinchGesture
+ };
+
+
+ enum GestureState
+ {
+ NoGesture,
+ GestureStarted = 1,
+ GestureUpdated = 2,
+ GestureFinished = 3
+ };
+
+ enum DirectionType
+ {
+ NoDirection = 0,
+ LeftDownDirection = 1,
+ DownLeftDirection = LeftDownDirection,
+ DownDirection = 2,
+ RightDownDirection = 3,
+ DownRightDirection = RightDownDirection,
+ LeftDirection = 4,
+ RightDirection = 6,
+ LeftUpDirection = 7,
+ UpLeftDirection = LeftUpDirection,
+ UpDirection = 8,
+ RightUpDirection = 9,
+ UpRightDirection = RightUpDirection
+ };
+
}
#ifdef Q_MOC_RUN
;
diff --git a/src/corelib/kernel/qcoreevent.cpp b/src/corelib/kernel/qcoreevent.cpp
index 11a2d3c..7e25c60 100644
--- a/src/corelib/kernel/qcoreevent.cpp
+++ b/src/corelib/kernel/qcoreevent.cpp
@@ -222,6 +222,14 @@ QT_BEGIN_NAMESPACE
\value ZOrderChange The widget's z-order has changed. This event is never sent to top level windows.
\value KeyboardLayoutChange The keyboard layout has changed.
\value DynamicPropertyChange A dynamic property was added, changed or removed from the object.
+ \value TouchBegin Beginning of a sequence of touch-screen and/or track-pad events (QTouchEvent)
+ \value TouchUpdate Touch-screen event (QTouchEvent)
+ \value TouchEnd End of touch-event sequence (QTouchEvent)
+ \value GraphicsSceneTouchBegin Beginning of a sequence of touch-screen and/or track-pad events in a graphics scene (QGraphicsSceneTouchEvent)
+ \value GraphicsSceneTouchUpdate Touch-screen event in a graphics scene (QGraphicsSceneTouchEvent)
+ \value GraphicsSceneTouchEnd End of touch-event sequence in a graphics scene (QGraphicsSceneTouchEvent)
+ \value Gesture A gesture has occured.
+ \value GraphicsSceneGesture A gesture has occured on a graphics scene.
User events should have values between \c User and \c{MaxUser}:
diff --git a/src/corelib/kernel/qcoreevent.h b/src/corelib/kernel/qcoreevent.h
index fa472e6..84ab390 100644
--- a/src/corelib/kernel/qcoreevent.h
+++ b/src/corelib/kernel/qcoreevent.h
@@ -266,6 +266,16 @@ public:
CocoaRequestModal = 190, // Internal for requesting an application modal Cocoa Window
MacGLClearDrawable = 191, // Internal Cocoa, the window has changed, so we must clear
+ TouchBegin = 192,
+ TouchUpdate = 193,
+ TouchEnd = 194,
+ GraphicsSceneTouchBegin = 195,
+ GraphicsSceneTouchUpdate = 196,
+ GraphicsSceneTouchEnd = 197,
+
+ Gesture = 198,
+ GraphicsSceneGesture = 199,
+
// 512 reserved for Qt Jambi's MetaCall event
// 513 reserved for Qt Jambi's DeleteOnMainThread event
@@ -304,6 +314,9 @@ private:
friend class Q3AccelManager;
friend class QShortcutMap;
friend class QETWidget;
+ friend class QGraphicsView;
+ friend class QGraphicsViewPrivate;
+ friend class QGraphicsScenePrivate;
};
class Q_CORE_EXPORT QTimerEvent : public QEvent
diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp
index 743c16d..e2b8115 100644
--- a/src/gui/graphicsview/qgraphicsitem.cpp
+++ b/src/gui/graphicsview/qgraphicsitem.cpp
@@ -521,6 +521,7 @@
#include <private/qtextcontrol_p.h>
#include <private/qtextdocumentlayout_p.h>
#include <private/qtextengine_p.h>
+#include <private/qgesturemanager_p.h>
#ifdef Q_WS_X11
#include <private/qt_x11_p.h>
@@ -561,6 +562,8 @@ public:
};
Q_GLOBAL_STATIC(QGraphicsItemCustomDataStore, qt_dataStore)
+QString qt_getStandardGestureTypeName(Qt::GestureType type);
+
/*!
\internal
@@ -2106,6 +2109,31 @@ void QGraphicsItem::setAcceptsHoverEvents(bool enabled)
setAcceptHoverEvents(enabled);
}
+/*! \since 4.6
+
+ Returns true if an item accepts touch events
+ (QGraphicsSceneTouchEvent); otherwise, returns false. By default,
+ items do not accept touch events.
+
+ \sa setAcceptTouchEvents()
+*/
+bool QGraphicsItem::acceptTouchEvents() const
+{
+ return d_ptr->acceptTouchEvents;
+}
+
+/*!
+ \since 4.6
+
+ If \a enabled is true, this item will accept touch events;
+ otherwise, it will ignore them. By default, items do not accept
+ touch events.
+*/
+void QGraphicsItem::setAcceptTouchEvents(bool enabled)
+{
+ d_ptr->acceptTouchEvents = quint32(enabled);
+}
+
/*!
Returns true if this item handles child events (i.e., all events
intended for any of its children are instead sent to this item);
@@ -5764,6 +5792,69 @@ QVariant QGraphicsItem::inputMethodQuery(Qt::InputMethodQuery query) const
}
/*!
+ \since 4.6
+
+ Subscribes the graphics item to the specified \a gesture type.
+
+ Returns the id of the gesture.
+
+ \sa releaseGesture(), setGestureEnabled()
+*/
+int QGraphicsItem::grabGesture(Qt::GestureType gesture)
+{
+ return grabGesture(qt_getStandardGestureTypeName(gesture));
+}
+
+/*!
+ \since 4.6
+
+ Subscribes the graphics item to the specified \a gesture type.
+
+ Returns the id of the gesture.
+
+ \sa releaseGesture(), setGestureEnabled()
+*/
+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);
+ return id;
+}
+
+/*!
+ \since 4.6
+
+ Unsubscribes the graphics item from a gesture, which is specified
+ by the \a gestureId.
+
+ \sa grabGesture(), setGestureEnabled()
+*/
+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);
+}
+
+/*!
+ \since 4.6
+
+ If \a enable is true, the gesture with the given \a gestureId is
+ enabled; otherwise the gesture is disabled.
+
+ The id of the gesture is returned by the grabGesture().
+
+ \sa grabGesture(), releaseGesture()
+*/
+void QGraphicsItem::setGestureEnabled(int gestureId, bool enable)
+{
+ //###
+}
+
+/*!
This virtual function is called by QGraphicsItem to notify custom items
that some part of the item's state changes. By reimplementing this
function, your can react to a change, and in some cases, (depending on \a
@@ -5787,6 +5878,20 @@ QVariant QGraphicsItem::inputMethodQuery(Qt::InputMethodQuery query) const
QVariant QGraphicsItem::itemChange(GraphicsItemChange change, const QVariant &value)
{
Q_UNUSED(change);
+ if (change == QGraphicsItem::ItemSceneChange) {
+ if (!qVariantValue<QGraphicsScene*>(value)) {
+ // the item has been removed from a scene, unsubscribe gestures.
+ Q_ASSERT(d_ptr->scene);
+ foreach(int id, d_ptr->gestures)
+ d_ptr->scene->d_func()->releaseGesture(this, id);
+ }
+ } else if (change == QGraphicsItem::ItemSceneHasChanged) {
+ if (QGraphicsScene *scene = qVariantValue<QGraphicsScene*>(value)) {
+ // item has been added to the scene
+ foreach(int id, d_ptr->gestures)
+ scene->d_func()->grabGesture(this, id);
+ }
+ }
return value;
}
diff --git a/src/gui/graphicsview/qgraphicsitem.h b/src/gui/graphicsview/qgraphicsitem.h
index b98882d..37d8f78 100644
--- a/src/gui/graphicsview/qgraphicsitem.h
+++ b/src/gui/graphicsview/qgraphicsitem.h
@@ -203,6 +203,8 @@ public:
void setAcceptsHoverEvents(bool enabled); // obsolete
bool acceptHoverEvents() const;
void setAcceptHoverEvents(bool enabled);
+ bool acceptTouchEvents() const;
+ void setAcceptTouchEvents(bool enabled);
bool handlesChildEvents() const;
void setHandlesChildEvents(bool enabled);
@@ -336,6 +338,11 @@ public:
QVariant data(int key) const;
void setData(int key, const QVariant &value);
+ int grabGesture(Qt::GestureType gesture);
+ int grabGesture(const QString &gesture);
+ void releaseGesture(int gestureId);
+ void setGestureEnabled(int gestureId, bool enable = true);
+
enum {
Type = 1,
UserType = 65536
diff --git a/src/gui/graphicsview/qgraphicsitem_p.h b/src/gui/graphicsview/qgraphicsitem_p.h
index 2936cf1..1d3a316 100644
--- a/src/gui/graphicsview/qgraphicsitem_p.h
+++ b/src/gui/graphicsview/qgraphicsitem_p.h
@@ -54,6 +54,7 @@
//
#include "qgraphicsitem.h"
+#include "qset.h"
#if !defined(QT_NO_GRAPHICSVIEW) || (QT_EDITION & QT_MODULE_GRAPHICSVIEW) != QT_MODULE_GRAPHICSVIEW
@@ -143,6 +144,7 @@ public:
emptyClipPath(0),
inSetPosHelper(0),
allChildrenCombineOpacity(1),
+ acceptTouchEvents(0),
globalStackingOrder(-1),
sceneTransformIndex(-1),
q_ptr(0)
@@ -296,6 +298,7 @@ public:
int siblingIndex;
int index;
int depth;
+ QSet<int> gestures;
// Packed 32 bytes
quint32 acceptedMouseButtons : 5;
@@ -327,6 +330,8 @@ public:
quint32 emptyClipPath : 1;
quint32 inSetPosHelper : 1;
quint32 allChildrenCombineOpacity : 1;
+ quint32 acceptTouchEvents : 1;
+ quint32 acceptedTouchBeginEvent : 1;
// Optional stacking order
int globalStackingOrder;
diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp
index 69e08d1..3d4bb5c 100644
--- a/src/gui/graphicsview/qgraphicsscene.cpp
+++ b/src/gui/graphicsview/qgraphicsscene.cpp
@@ -247,6 +247,7 @@ static const int QGRAPHICSSCENE_INDEXTIMER_TIMEOUT = 2000;
#ifdef Q_WS_X11
#include <private/qt_x11_p.h>
#endif
+#include <private/qgesturemanager_p.h>
QT_BEGIN_NAMESPACE
@@ -1335,6 +1336,7 @@ void QGraphicsScenePrivate::mousePressEventHandler(QGraphicsSceneMouseEvent *mou
// event is converted to a press. Known limitation:
// Triple-clicking will not generate a doubleclick, though.
QGraphicsSceneMouseEvent mousePress(QEvent::GraphicsSceneMousePress);
+ mousePress.spont = mouseEvent->spont;
mousePress.accept();
mousePress.setButton(mouseEvent->button());
mousePress.setButtons(mouseEvent->buttons());
@@ -3796,6 +3798,9 @@ bool QGraphicsScene::event(QEvent *event)
case QEvent::GraphicsSceneHoverEnter:
case QEvent::GraphicsSceneHoverLeave:
case QEvent::GraphicsSceneHoverMove:
+ case QEvent::GraphicsSceneTouchBegin:
+ case QEvent::GraphicsSceneTouchUpdate:
+ case QEvent::GraphicsSceneTouchEnd:
// Reset the under-mouse list to ensure that this event gets fresh
// item-under-mouse data. Be careful about this list; if people delete
// items from inside event handlers, this list can quickly end up
@@ -3947,6 +3952,48 @@ bool QGraphicsScene::event(QEvent *event)
// geometries that do not have an explicit style set.
update();
break;
+ case QEvent::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;
+ }
+ 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;
+ }
+ }
+ }
+ }
+ }
+ }
+ break;
+ case QEvent::GraphicsSceneTouchBegin:
+ case QEvent::GraphicsSceneTouchUpdate:
+ case QEvent::GraphicsSceneTouchEnd:
+ d->touchEventHandler(static_cast<QGraphicsSceneTouchEvent *>(event));
+ break;
case QEvent::Timer:
if (d->indexTimerId && static_cast<QTimerEvent *>(event)->timerId() == d->indexTimerId) {
if (d->restartIndexTimer) {
@@ -5574,6 +5621,281 @@ void QGraphicsScene::setActiveWindow(QGraphicsWidget *widget)
}
}
+void QGraphicsScenePrivate::addView(QGraphicsView *view)
+{
+ views << view;
+ foreach(int gestureId, grabbedGestures)
+ view->d_func()->grabGesture(gestureId);
+}
+
+void QGraphicsScenePrivate::removeView(QGraphicsView *view)
+{
+ views.removeAll(view);
+ foreach(int gestureId, grabbedGestures)
+ view->releaseGesture(gestureId);
+}
+
+void QGraphicsScenePrivate::grabGesture(QGraphicsItem *item, int gestureId)
+{
+ if (!grabbedGestures.contains(gestureId)) {
+ foreach(QGraphicsView *view, views)
+ view->d_func()->grabGesture(gestureId);
+ }
+ itemsWithGestures << item;
+ grabbedGestures << gestureId;
+}
+
+void QGraphicsScenePrivate::releaseGesture(QGraphicsItem *item, int gestureId)
+{
+ //###
+}
+
+void QGraphicsScenePrivate::updateTouchPointsForItem(QGraphicsItem *item,
+ QGraphicsSceneTouchEvent *touchEvent)
+{
+ QList<QGraphicsSceneTouchEvent::TouchPoint *> touchPoints = touchEvent->touchPoints();
+ for (int i = 0; i < touchPoints.count(); ++i) {
+ QGraphicsSceneTouchEvent::TouchPoint *touchPoint = touchPoints.at(i);
+ touchPoint->setPos(item->d_ptr->genericMapFromScene(touchPoint->scenePos(), touchEvent->widget()));
+ touchPoint->setStartPos(item->d_ptr->genericMapFromScene(touchPoint->startScenePos(), touchEvent->widget()));
+ touchPoint->setLastPos(item->d_ptr->genericMapFromScene(touchPoint->lastScenePos(), touchEvent->widget()));
+ }
+}
+
+QGraphicsSceneTouchEvent::TouchPoint *QGraphicsScenePrivate::findClosestTouchPoint(const QList<QGraphicsSceneTouchEvent::TouchPoint *> &sceneActiveTouchPoints,
+ const QPointF &scenePos)
+{
+ QGraphicsSceneTouchEvent::TouchPoint *closestTouchPoint = 0;
+ qreal closestDistance;
+ for (int i = 0; i < sceneActiveTouchPoints.count(); ++i) {
+ QGraphicsSceneTouchEvent::TouchPoint *touchPoint = sceneActiveTouchPoints.at(i);
+ qreal distance = QLineF(scenePos, touchPoint->scenePos()).length();
+ if (!closestTouchPoint || distance < closestDistance) {
+ closestTouchPoint = touchPoint;
+ closestDistance = distance;
+ }
+ }
+ return closestTouchPoint;
+}
+
+QEvent::Type QGraphicsScenePrivate::appendTouchPoint(QGraphicsSceneTouchEvent::TouchPoint *touchPoint,
+ QList<QGraphicsSceneTouchEvent::TouchPoint *> *currentTouchPoints)
+{
+ QEvent::Type eventType = currentTouchPoints->isEmpty()
+ ? QEvent::GraphicsSceneTouchBegin
+ : QEvent::GraphicsSceneTouchUpdate;
+
+ // insort touch point (for the app)
+ int at = 0;
+ for (; at < sceneCurrentTouchPoints.count(); ++at) {
+ if (sceneCurrentTouchPoints.at(at)->id() > touchPoint->id())
+ break;
+ }
+ sceneCurrentTouchPoints.insert(at, touchPoint);
+ // again, for the items's currentTouchPoints
+ for (at = 0; at < currentTouchPoints->count(); ++at) {
+ if (currentTouchPoints->at(at)->id() > touchPoint->id())
+ break;
+ }
+ currentTouchPoints->insert(at, touchPoint);
+
+ return eventType;
+}
+
+QEvent::Type QGraphicsScenePrivate::removeTouchPoint(QGraphicsSceneTouchEvent::TouchPoint *touchPoint,
+ QList<QGraphicsSceneTouchEvent::TouchPoint *> *currentTouchPoints)
+{
+ // remove touch point from all known touch points
+ for (int i = qMin(sceneCurrentTouchPoints.count() - 1, touchPoint->id()); i >= 0; --i) {
+ if (sceneCurrentTouchPoints.at(i) == touchPoint) {
+ sceneCurrentTouchPoints.removeAt(i);
+ break;
+ }
+ }
+ // again, for the items's currentTouchPoints
+ for (int i = qMin(currentTouchPoints->count() - 1, touchPoint->id()); i >= 0; --i) {
+ if (currentTouchPoints->at(i) == touchPoint) {
+ currentTouchPoints->removeAt(i);
+ break;
+ }
+ }
+
+ return currentTouchPoints->isEmpty() ? QEvent::GraphicsSceneTouchEnd : QEvent::GraphicsSceneTouchUpdate;
+}
+
+void QGraphicsScenePrivate::touchEventHandler(QGraphicsSceneTouchEvent *sceneTouchEvent)
+{
+ QList<QGraphicsSceneTouchEvent::TouchPoint *> sceneActiveTouchPoints = sceneCurrentTouchPoints;
+
+ QHash<QGraphicsItem *, QGraphicsSceneTouchEvent *> itemsNeedingEvents;
+ for (int i = 0; i < sceneTouchEvent->touchPoints().count(); ++i) {
+ QGraphicsSceneTouchEvent::TouchPoint *touchPoint = sceneTouchEvent->touchPoints().at(i);
+
+ // update state
+ QGraphicsItem *item = 0;
+ QEvent::Type eventType = QEvent::None;
+ QList<QGraphicsSceneTouchEvent::TouchPoint *> activeTouchPoints;
+ if (touchPoint->state() == Qt::TouchPointPressed) {
+ // determine which item this event will go to
+ cachedItemsUnderMouse = itemsAtPosition(touchPoint->screenPos().toPoint(),
+ touchPoint->scenePos(),
+ sceneTouchEvent->widget());
+ item = cachedItemsUnderMouse.isEmpty() ? 0 : cachedItemsUnderMouse.first();
+ QGraphicsSceneTouchEvent::TouchPoint *closestTouchPoint = findClosestTouchPoint(sceneActiveTouchPoints, touchPoint->scenePos());
+ if (closestTouchPoint) {
+ QGraphicsItem *closestItem = itemForTouchPointId.value(closestTouchPoint->id());
+ if (!item
+ || (closestItem
+ && (item->isAncestorOf(closestItem)
+ || closestItem->isAncestorOf(item)))) {
+ item = closestItem;
+ }
+ }
+ if (!item)
+ continue;
+
+ itemForTouchPointId.insert(touchPoint->id(), item);
+
+ QList<QGraphicsSceneTouchEvent::TouchPoint *> &currentTouchPoints = itemCurrentTouchPoints[item];
+ eventType = appendTouchPoint(touchPoint, &currentTouchPoints);
+ // make sure new points are added to activeTouchPoints as well
+ sceneActiveTouchPoints = sceneCurrentTouchPoints;
+ activeTouchPoints = currentTouchPoints;
+ } else if (touchPoint->state() == Qt::TouchPointReleased) {
+ item = itemForTouchPointId.take(touchPoint->id());
+ if (!item)
+ continue;
+
+ QList<QGraphicsSceneTouchEvent::TouchPoint *> &currentTouchPoints = itemCurrentTouchPoints[item];
+ sceneActiveTouchPoints = sceneCurrentTouchPoints;
+ activeTouchPoints = currentTouchPoints;
+ eventType = removeTouchPoint(touchPoint, &currentTouchPoints);
+ } else {
+ item = itemForTouchPointId.value(touchPoint->id());
+ if (!item)
+ continue;
+
+ sceneActiveTouchPoints = sceneCurrentTouchPoints;
+ activeTouchPoints = itemCurrentTouchPoints.value(item);
+ eventType = QEvent::GraphicsSceneTouchUpdate;
+ }
+ Q_ASSERT(eventType != QEvent::None);
+
+ if (touchPoint->state() != Qt::TouchPointStationary) {
+ QGraphicsSceneTouchEvent *&touchEvent = itemsNeedingEvents[item];
+ if (!touchEvent) {
+ touchEvent = new QGraphicsSceneTouchEvent(eventType);
+ touchEvent->setWidget(sceneTouchEvent->widget());
+ touchEvent->setModifiers(sceneTouchEvent->modifiers());
+ }
+ Q_ASSERT(touchEvent->type() == eventType);
+ touchEvent->setTouchPoints(activeTouchPoints);
+ }
+ }
+
+ if (itemsNeedingEvents.isEmpty()) {
+ sceneTouchEvent->ignore();
+ return;
+ }
+
+ bool acceptSceneTouchEvent = false;
+ QHash<QGraphicsItem *, QGraphicsSceneTouchEvent *>::ConstIterator it = itemsNeedingEvents.constBegin();
+ const QHash<QGraphicsItem *, QGraphicsSceneTouchEvent *>::ConstIterator end = itemsNeedingEvents.constEnd();
+ for (; it != end; ++it) {
+ QGraphicsItem *item = it.key();
+
+ QGraphicsSceneTouchEvent *touchEvent = it.value();
+
+ switch (touchEvent->type()) {
+ case QEvent::GraphicsSceneTouchBegin:
+ {
+ // if the TouchBegin handler recurses, we assume that means the event
+ // has been implicitly accepted and continue to send touch events
+ item->d_ptr->acceptedTouchBeginEvent = true;
+ bool res = sendTouchBeginEvent(item, touchEvent)
+ && touchEvent->isAccepted();
+ acceptSceneTouchEvent = acceptSceneTouchEvent || res;
+ break;
+ }
+ case QEvent::GraphicsSceneTouchEnd:
+ {
+ QList<QGraphicsSceneTouchEvent::TouchPoint *> currentTouchPoints = itemCurrentTouchPoints.take(item);
+ if (!currentTouchPoints.isEmpty()) {
+ qFatal("Qt: INTERNAL ERROR, the widget's currentTouchPoints should be empty!");
+ }
+ // fall-through intended
+ }
+ default:
+ if (item->d_ptr->acceptedTouchBeginEvent) {
+ updateTouchPointsForItem(item, touchEvent);
+ (void) sendEvent(item, touchEvent);
+ acceptSceneTouchEvent = true;
+ }
+ break;
+ }
+
+ delete touchEvent;
+ }
+ sceneTouchEvent->setAccepted(acceptSceneTouchEvent);
+}
+
+bool QGraphicsScenePrivate::sendTouchBeginEvent(QGraphicsItem *origin, QGraphicsSceneTouchEvent *touchEvent)
+{
+ Q_Q(QGraphicsScene);
+
+ if (cachedItemsUnderMouse.isEmpty() || cachedItemsUnderMouse.first() != origin) {
+ QGraphicsSceneTouchEvent::TouchPoint *firstTouchPoint = touchEvent->touchPoints().first();
+ cachedItemsUnderMouse = itemsAtPosition(firstTouchPoint->screenPos().toPoint(),
+ firstTouchPoint->scenePos(),
+ touchEvent->widget());
+ }
+ Q_ASSERT(cachedItemsUnderMouse.first() == origin);
+
+ // Set focus on the topmost enabled item that can take focus.
+ bool setFocus = false;
+ foreach (QGraphicsItem *item, cachedItemsUnderMouse) {
+ if (item->isEnabled() && (item->flags() & QGraphicsItem::ItemIsFocusable)) {
+ if (!item->isWidget() || ((QGraphicsWidget *)item)->focusPolicy() & Qt::ClickFocus) {
+ setFocus = true;
+ if (item != q->focusItem())
+ q->setFocusItem(item, Qt::MouseFocusReason);
+ break;
+ }
+ }
+ }
+
+ // If nobody could take focus, clear it.
+ if (!stickyFocus && !setFocus)
+ q->setFocusItem(0, Qt::MouseFocusReason);
+
+ bool res = false;
+ bool eventAccepted = touchEvent->isAccepted();
+ foreach (QGraphicsItem *item, cachedItemsUnderMouse) {
+ // first, try to deliver the touch event
+ updateTouchPointsForItem(item, touchEvent);
+ touchEvent->ignore();
+ res = item->acceptTouchEvents()
+ && sendEvent(item, touchEvent);
+ eventAccepted = touchEvent->isAccepted();
+ item->d_ptr->acceptedTouchBeginEvent = (res && eventAccepted);
+ touchEvent->spont = false;
+ if (res && eventAccepted) {
+ // the first item to accept the TouchBegin gets an implicit grab.
+ for (int i = 0; i < touchEvent->touchPoints().count(); ++i) {
+ QGraphicsSceneTouchEvent::TouchPoint *touchPoint = touchEvent->touchPoints().at(i);
+ itemForTouchPointId[touchPoint->id()] = item;
+ }
+ if (origin != item)
+ itemCurrentTouchPoints.remove(origin);
+ itemCurrentTouchPoints[item] = touchEvent->touchPoints();
+ break;
+ }
+ }
+
+ touchEvent->setAccepted(eventAccepted);
+ return res;
+}
+
QT_END_NAMESPACE
#include "moc_qgraphicsscene.cpp"
diff --git a/src/gui/graphicsview/qgraphicsscene.h b/src/gui/graphicsview/qgraphicsscene.h
index 9802f87..a76b348 100644
--- a/src/gui/graphicsview/qgraphicsscene.h
+++ b/src/gui/graphicsview/qgraphicsscene.h
@@ -50,6 +50,7 @@
#include <QtGui/qtransform.h>
#include <QtGui/qmatrix.h>
#include <QtGui/qpen.h>
+#include <QtGui/qevent.h>
QT_BEGIN_HEADER
@@ -79,6 +80,7 @@ class QGraphicsSceneHelpEvent;
class QGraphicsSceneHoverEvent;
class QGraphicsSceneMouseEvent;
class QGraphicsSceneWheelEvent;
+class QGraphicsSceneGestureEvent;
class QGraphicsSimpleTextItem;
class QGraphicsTextItem;
class QGraphicsView;
diff --git a/src/gui/graphicsview/qgraphicsscene_p.h b/src/gui/graphicsview/qgraphicsscene_p.h
index 9ace725..7928a45 100644
--- a/src/gui/graphicsview/qgraphicsscene_p.h
+++ b/src/gui/graphicsview/qgraphicsscene_p.h
@@ -57,6 +57,7 @@
#if !defined(QT_NO_GRAPHICSVIEW) || (QT_EDITION & QT_MODULE_GRAPHICSVIEW) != QT_MODULE_GRAPHICSVIEW
+#include "qgraphicssceneevent.h"
#include "qgraphicsscene_bsp_p.h"
#include "qgraphicsitem_p.h"
@@ -181,6 +182,9 @@ public:
void storeMouseButtonsForMouseGrabber(QGraphicsSceneMouseEvent *event);
QList<QGraphicsView *> views;
+ void addView(QGraphicsView *view);
+ void removeView(QGraphicsView *view);
+
bool painterStateProtection;
QMultiMap<QGraphicsItem *, QGraphicsItem *> sceneEventFilters;
@@ -263,9 +267,27 @@ public:
void resolvePalette();
void updatePalette(const QPalette &palette);
+ QSet<QGraphicsItem*> itemsWithGestures;
+ QSet<int> grabbedGestures;
+ void grabGesture(QGraphicsItem *item, int gestureId);
+ void releaseGesture(QGraphicsItem *item, int gestureId);
+
mutable QVector<QTransform> sceneTransformCache;
mutable QBitArray validTransforms;
mutable QVector<int> freeSceneTransformSlots;
+
+ QList<QGraphicsSceneTouchEvent::TouchPoint *> sceneCurrentTouchPoints;
+ QHash<QGraphicsItem *, QList<QGraphicsSceneTouchEvent::TouchPoint *> > itemCurrentTouchPoints;
+ QHash<int, QGraphicsItem *> itemForTouchPointId;
+ static void updateTouchPointsForItem(QGraphicsItem *item, QGraphicsSceneTouchEvent *touchEvent);
+ static QGraphicsSceneTouchEvent::TouchPoint *findClosestTouchPoint(const QList<QGraphicsSceneTouchEvent::TouchPoint *> &activeTouchPoints,
+ const QPointF &scenePos);
+ QEvent::Type appendTouchPoint(QGraphicsSceneTouchEvent::TouchPoint *touchPoint,
+ QList<QGraphicsSceneTouchEvent::TouchPoint *> *currentTouchPoints);
+ QEvent::Type removeTouchPoint(QGraphicsSceneTouchEvent::TouchPoint *touchPoint,
+ QList<QGraphicsSceneTouchEvent::TouchPoint *> *currentTouchPoints);
+ void touchEventHandler(QGraphicsSceneTouchEvent *touchEvent);
+ bool sendTouchBeginEvent(QGraphicsItem *item, QGraphicsSceneTouchEvent *touchEvent);
};
QT_END_NAMESPACE
diff --git a/src/gui/graphicsview/qgraphicssceneevent.cpp b/src/gui/graphicsview/qgraphicssceneevent.cpp
index b819c2c..d5d0fb9 100644
--- a/src/gui/graphicsview/qgraphicssceneevent.cpp
+++ b/src/gui/graphicsview/qgraphicssceneevent.cpp
@@ -76,14 +76,14 @@
received by the view (see
\l{QGraphicsSceneMouseEvent::}{lastScreenPos()},
\l{QGraphicsSceneMouseEvent::}{lastScenePos()}, and
- \l{QGraphicsSceneMouseEvent::}{lastPos()}).
+ \l{QGraphicsSceneMouseEvent::}{lastPos()}).
\sa QEvent
*/
/*!
\class QGraphicsSceneMouseEvent
- \brief The QGraphicsSceneMouseEvent class provides mouse events
+ \brief The QGraphicsSceneMouseEvent class provides mouse events
in the graphics view framework.
\since 4.2
\ingroup multimedia
@@ -106,7 +106,7 @@
/*!
\class QGraphicsSceneWheelEvent
- \brief The QGraphicsSceneWheelEvent class provides wheel events
+ \brief The QGraphicsSceneWheelEvent class provides wheel events
in the graphics view framework.
\brief The QGraphicsSceneWheelEvent class provides wheel events in the
graphics view framework.
@@ -157,7 +157,7 @@
/*!
\class QGraphicsSceneHoverEvent
- \brief The QGraphicsSceneHoverEvent class provides hover events
+ \brief The QGraphicsSceneHoverEvent class provides hover events
in the graphics view framework.
\since 4.2
\ingroup multimedia
@@ -173,7 +173,7 @@
/*!
\class QGraphicsSceneHelpEvent
- \brief The QGraphicsSceneHelpEvent class provides events when a
+ \brief The QGraphicsSceneHelpEvent class provides events when a
tooltip is requested.
\since 4.2
\ingroup multimedia
@@ -199,7 +199,7 @@
/*!
\class QGraphicsSceneDragDropEvent
\brief The QGraphicsSceneDragDropEvent class provides events for
- drag and drop in the graphics view framework.
+ drag and drop in the graphics view framework.
\since 4.2
\ingroup multimedia
\ingroup graphicsview-api
@@ -257,6 +257,37 @@
QGraphicsItem::ItemPositionHasChanged
*/
+/*!
+ \class QGraphicsSceneTouchEvent
+ \brief The QGraphicsSceneTouchEvent class provides touch events in the graphics view framework.
+ \since 4.6
+ \ingroup multimedia
+ \ingroup graphicsview-api
+
+ When a QGraphicsView receives a QTouchEvent, it translates it to a
+ QGraphicsSceneTouchEvent. The event is then forwarded to the
+ QGraphicsScene associated with the view.
+
+ The touchPoints() function returns a list of touch points for the
+ event. In addition to containing the item, scene, and screen
+ coordinates, each touch point also contains its starting and
+ previous coordinates.
+
+ \sa QTouchEvent
+*/
+
+/*!
+ \class QGraphicsSceneTouchEvent::TouchPoint
+ \brief The QGraphicsSceneTouchEvent::TouchPoint class represents a single touch point in a QGraphicsSceneTouchEvent.
+ \since 4.6
+ \ingroup multimedia
+ \ingroup graphicsview-api
+
+ Each touch point in a QGraphicsSceneTouchEvent has an id() and
+ state() in addition to current, starting, and previous coordinates
+ for the touch point in item, scene, and screen coordinates.
+*/
+
#include "qgraphicssceneevent.h"
#ifndef QT_NO_GRAPHICSVIEW
@@ -268,9 +299,14 @@
#include <QtCore/qpoint.h>
#include <QtCore/qsize.h>
#include <QtCore/qstring.h>
+#include "qgraphicsview.h"
+#include "qgraphicsitem.h"
+#include <private/qevent_p.h>
QT_BEGIN_NAMESPACE
+QString qt_getStandardGestureTypeName(Qt::GestureType type);
+
class QGraphicsSceneEventPrivate
{
public:
@@ -522,7 +558,7 @@ void QGraphicsSceneMouseEvent::setLastPos(const QPointF &pos)
}
/*!
- Returns the last recorded mouse cursor position in scene
+ Returns the last recorded mouse cursor position in scene
coordinates. The last recorded position is the position of
the previous mouse event received by the view that created
the event.
@@ -545,7 +581,7 @@ void QGraphicsSceneMouseEvent::setLastScenePos(const QPointF &pos)
}
/*!
- Returns the last recorded mouse cursor position in screen
+ Returns the last recorded mouse cursor position in screen
coordinates. The last recorded position is the position of
the previous mouse event received by the view that created
the event.
@@ -1275,7 +1311,7 @@ QGraphicsSceneDragDropEvent::~QGraphicsSceneDragDropEvent()
/*!
Returns the mouse position of the event relative to the
view that sent the event.
-
+
\sa QGraphicsView, screenPos(), scenePos()
*/
QPointF QGraphicsSceneDragDropEvent::pos() const
@@ -1373,7 +1409,7 @@ void QGraphicsSceneDragDropEvent::setButtons(Qt::MouseButtons buttons)
/*!
Returns the keyboard modifiers that were pressed when the drag
- and drop event was created.
+ and drop event was created.
\sa Qt::KeyboardModifiers
*/
@@ -1428,7 +1464,7 @@ void QGraphicsSceneDragDropEvent::setPossibleActions(Qt::DropActions actions)
The action must be one of the possible actions as defined by
\c possibleActions().
- \sa Qt::DropAction, possibleActions()
+ \sa Qt::DropAction, possibleActions()
*/
Qt::DropAction QGraphicsSceneDragDropEvent::proposedAction() const
@@ -1673,6 +1709,349 @@ void QGraphicsSceneMoveEvent::setNewPos(const QPointF &pos)
d->newPos = pos;
}
+/*!
+ \class QGraphicsSceneGestureEvent
+ \brief The QGraphicsSceneGestureEvent class provides gesture events for
+ the graphics view framework.
+ \since 4.6
+ \ingroup multimedia
+ \ingroup graphicsview-api
+
+ QGraphicsSceneGestureEvent extends information provided by
+ QGestureEvent by adding some convenience functions like
+ \l{QGraphicsSceneEvent::}{widget()} to get a widget that received
+ original gesture event, and convenience functions mapToScene(),
+ mapToItem() for converting positions of the gesture into
+ QGraphicsScene and QGraphicsItem coordinate system respectively.
+
+ The scene sends the event to the first QGraphicsItem under the
+ mouse cursor that accepts gestures; a graphics item is set to accept
+ gestures with \l{QGraphicsItem::}{grabGesture()}.
+
+ \sa QGestureEvent
+*/
+
+/*!
+ Constructs a QGraphicsSceneGestureEvent.
+*/
+QGraphicsSceneGestureEvent::QGraphicsSceneGestureEvent()
+ : QGraphicsSceneEvent(QEvent::GraphicsSceneGesture)
+{
+}
+
+/*!
+ Destroys a QGraphicsSceneGestureEvent.
+*/
+QGraphicsSceneGestureEvent::~QGraphicsSceneGestureEvent()
+{
+}
+
+/*!
+ Returns true if the gesture event contains gesture of specific \a
+ type; returns false otherwise.
+*/
+bool QGraphicsSceneGestureEvent::contains(const QString &type) const
+{
+ return gesture(type) != 0;
+}
+
+/*!
+ Returns true if the gesture event contains gesture of specific \a
+ type; returns false otherwise.
+*/
+bool QGraphicsSceneGestureEvent::contains(Qt::GestureType type) const
+{
+ return contains(qt_getStandardGestureTypeName(type));
+}
+
+/*!
+ Returns a list of gesture names that this event contains.
+*/
+QList<QString> QGraphicsSceneGestureEvent::gestureTypes() const
+{
+ return m_gestures.keys();
+}
+
+/*!
+ Returns extended information about a gesture of specific \a type.
+*/
+const QGesture* QGraphicsSceneGestureEvent::gesture(const QString &type) const
+{
+ return m_gestures.value(type, 0);
+}
+
+/*!
+ Returns extended information about a gesture of specific \a type.
+*/
+const QGesture* QGraphicsSceneGestureEvent::gesture(Qt::GestureType type) const
+{
+ return gesture(qt_getStandardGestureTypeName(type));
+}
+
+/*!
+ Returns extended information about all gestures in the event.
+*/
+QList<QGesture*> QGraphicsSceneGestureEvent::gestures() const
+{
+ return m_gestures.values();
+}
+
+/*!
+ Returns a set of gesture names that used to be executed, but were
+ cancelled (i.e. they were not finished properly).
+*/
+QSet<QString> QGraphicsSceneGestureEvent::cancelledGestures() const
+{
+ return m_cancelledGestures;
+}
+
+/*!
+ Sets a list of gesture names \a cancelledGestures that used to be
+ executed, but were cancelled (i.e. they were not finished
+ properly).
+*/
+void QGraphicsSceneGestureEvent::setCancelledGestures(const QSet<QString> &cancelledGestures)
+{
+ m_cancelledGestures = cancelledGestures;
+}
+
+/*!
+ Maps the point \a point, which is in a view coordinate system, to
+ scene coordinate system, and returns the mapped coordinate.
+
+ A \a point is in coordinate system of the widget that received
+ gesture event.
+
+ \sa mapToItem(), {The Graphics View Coordinate System}
+*/
+QPointF QGraphicsSceneGestureEvent::mapToScene(const QPoint &point) const
+{
+ if (QGraphicsView *view = qobject_cast<QGraphicsView*>(widget()))
+ return view->mapToScene(point);
+ return QPointF();
+}
+
+/*!
+ Maps the rectangular \a rect, which is in a view coordinate system, to
+ scene coordinate system, and returns the mapped coordinate.
+
+ A \a rect is in coordinate system of the widget that received
+ gesture event.
+
+ \sa mapToItem(), {The Graphics View Coordinate System}
+*/
+QPolygonF QGraphicsSceneGestureEvent::mapToScene(const QRect &rect) const
+{
+ if (QGraphicsView *view = qobject_cast<QGraphicsView*>(widget()))
+ return view->mapToScene(rect);
+ return QPolygonF();
+}
+
+/*!
+ Maps the point \a point, which is in a view coordinate system, to
+ item's \a item coordinate system, and returns the mapped coordinate.
+
+ If \a item is 0, this function returns the same as mapToScene().
+
+ \sa mapToScene(), {The Graphics View Coordinate System}
+*/
+QPointF QGraphicsSceneGestureEvent::mapToItem(const QPoint &point, QGraphicsItem *item) const
+{
+ if (item) {
+ if (QGraphicsView *view = qobject_cast<QGraphicsView*>(widget()))
+ return item->mapFromScene(view->mapToScene(point));
+ } else {
+ return mapToScene(point);
+ }
+ return QPointF();
+}
+
+/*!
+ Maps the rectangualar \a rect, which is in a view coordinate system, to
+ item's \a item coordinate system, and returns the mapped coordinate.
+
+ If \a item is 0, this function returns the same as mapToScene().
+
+ \sa mapToScene(), {The Graphics View Coordinate System}
+*/
+QPolygonF QGraphicsSceneGestureEvent::mapToItem(const QRect &rect, QGraphicsItem *item) const
+{
+ if (item) {
+ if (QGraphicsView *view = qobject_cast<QGraphicsView*>(widget()))
+ return item->mapFromScene(view->mapToScene(rect));
+ } else {
+ return mapToScene(rect);
+ }
+ return QPolygonF();
+}
+
+/*!
+ Set a list of gesture objects containing extended information about \a gestures.
+*/
+void QGraphicsSceneGestureEvent::setGestures(const QList<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)}.
+
+ Setting the accept parameter indicates that the event receiver
+ wants the gesture. Unwanted gestures might be propagated to the parent
+ widget.
+*/
+void QGraphicsSceneGestureEvent::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 QGraphicsSceneGestureEvent::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 QGraphicsSceneGestureEvent::accept(const QString &type)
+{
+ if (QGesture *g = m_gestures.value(type, 0))
+ g->accept();
+}
+
+class QGraphicsSceneTouchEventPrivate : public QGraphicsSceneEventPrivate
+{
+ Q_DECLARE_PUBLIC(QGraphicsSceneTouchEvent)
+public:
+ inline QGraphicsSceneTouchEventPrivate()
+ : modifiers(Qt::NoModifier)
+ { }
+
+ QList<QGraphicsSceneTouchEvent::TouchPoint *> touchPoints;
+ Qt::KeyboardModifiers modifiers;
+};
+
+/*!
+ \internal
+
+ Constructs a generic QGraphicsSceneTouchEvent of type \a type.
+*/
+QGraphicsSceneTouchEvent::QGraphicsSceneTouchEvent(Type type)
+ : QGraphicsSceneEvent(*new QGraphicsSceneTouchEventPrivate, type)
+{ }
+
+/*!
+ Destroys the QGraphicsSceneTouchEvent.
+*/
+QGraphicsSceneTouchEvent::~QGraphicsSceneTouchEvent()
+{ }
+
+/*!
+ Returns the list of touch points for this event.
+
+ \sa QGraphicsSceneTouchEvent::TouchPoint
+*/
+const QList<QGraphicsSceneTouchEvent::TouchPoint *> &QGraphicsSceneTouchEvent::touchPoints() const
+{
+ Q_D(const QGraphicsSceneTouchEvent);
+ return d->touchPoints;
+}
+
+/*! \internal */
+void QGraphicsSceneTouchEvent::setTouchPoints(const QList<QGraphicsSceneTouchEvent::TouchPoint *> &touchPoints)
+{
+ Q_D(QGraphicsSceneTouchEvent);
+ d->touchPoints = touchPoints;
+}
+
+/*!
+ Returns the keyboard modifiers in use at the time the event was
+ sent.
+*/
+Qt::KeyboardModifiers QGraphicsSceneTouchEvent::modifiers() const
+{
+ Q_D(const QGraphicsSceneTouchEvent);
+ return d->modifiers;
+}
+
+/*! \internal */
+void QGraphicsSceneTouchEvent::setModifiers(Qt::KeyboardModifiers modifiers)
+{
+ Q_D(QGraphicsSceneTouchEvent);
+ d->modifiers = modifiers;
+}
+
+/*!
+ Returns the current position of this touch point in scene coordinates.
+
+ \sa pos(), screenPos()
+*/
+QPointF QGraphicsSceneTouchEvent::TouchPoint::scenePos() const
+{
+ return d->scenePos;
+}
+
+/*! \internal */
+void QGraphicsSceneTouchEvent::TouchPoint::setScenePos(const QPointF &scenePos)
+{
+ d->scenePos = scenePos;
+}
+
+/*!
+ Returns the starting position of this touch point in scene coordinates.
+
+ \sa startPos(), startScreenPos()
+*/
+QPointF QGraphicsSceneTouchEvent::TouchPoint::startScenePos() const
+{
+ return d->startScenePos;
+}
+
+/*! \internal */
+void QGraphicsSceneTouchEvent::TouchPoint::setStartScenePos(const QPointF &startScenePos)
+{
+ d->startScenePos = startScenePos;
+}
+
+/*!
+ Returns the previous position of this touch point in scene coordinates.
+
+ \sa lastPos(), lastScreenPos()
+*/
+QPointF QGraphicsSceneTouchEvent::TouchPoint::lastScenePos() const
+{
+ return d->lastScenePos;
+}
+
+/*! \internal */
+void QGraphicsSceneTouchEvent::TouchPoint::setLastScenePos(const QPointF &lastScenePos)
+{
+ d->lastScenePos = lastScenePos;
+}
+
QT_END_NAMESPACE
#endif // QT_NO_GRAPHICSVIEW
diff --git a/src/gui/graphicsview/qgraphicssceneevent.h b/src/gui/graphicsview/qgraphicssceneevent.h
index be50e96..01cdab9 100644
--- a/src/gui/graphicsview/qgraphicssceneevent.h
+++ b/src/gui/graphicsview/qgraphicssceneevent.h
@@ -42,8 +42,12 @@
#ifndef QGRAPHICSSCENEEVENT_H
#define QGRAPHICSSCENEEVENT_H
-#include <QtCore/qcoreevent.h>
+#include <QtGui/qevent.h>
#include <QtCore/qpoint.h>
+#include <QtCore/qrect.h>
+#include <QtGui/qpolygon.h>
+#include <QtCore/qset.h>
+#include <QtCore/qhash.h>
QT_BEGIN_HEADER
@@ -302,6 +306,81 @@ public:
void setNewPos(const QPointF &pos);
};
+class QGesture;
+class QGraphicsItem;
+class QGraphicsSceneGestureEventPrivate;
+class Q_GUI_EXPORT QGraphicsSceneGestureEvent : public QGraphicsSceneEvent
+{
+ Q_DECLARE_PRIVATE(QGraphicsSceneGestureEvent)
+public:
+ QGraphicsSceneGestureEvent();
+ ~QGraphicsSceneGestureEvent();
+
+ bool contains(const QString &type) const;
+ bool contains(Qt::GestureType type) const;
+
+ QList<QString> gestureTypes() const;
+
+ const QGesture* gesture(Qt::GestureType type) const;
+ const QGesture* gesture(const QString &type) const;
+ QList<QGesture*> gestures() const;
+ void setGestures(const QList<QGesture*> &gestures);
+
+ QSet<QString> cancelledGestures() const;
+ void setCancelledGestures(const QSet<QString> &cancelledGestures);
+
+ 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);
+
+ QPointF mapToScene(const QPoint &point) const;
+ QPolygonF mapToScene(const QRect &rect) const;
+ QPointF mapToItem(const QPoint &point, QGraphicsItem *item) const;
+ QPolygonF mapToItem(const QRect &rect, QGraphicsItem *item) const;
+
+protected:
+ QHash<QString, QGesture*> m_gestures;
+ QSet<QString> m_cancelledGestures;
+};
+
+class QGraphicsSceneTouchEventPrivate;
+class Q_GUI_EXPORT QGraphicsSceneTouchEvent : public QGraphicsSceneEvent
+{
+public:
+ class Q_GUI_EXPORT TouchPoint : public QTouchEvent::TouchPoint
+ {
+ public:
+ QPointF scenePos() const;
+ void setScenePos(const QPointF &scenePos);
+
+ QPointF startScenePos() const;
+ void setStartScenePos(const QPointF &startScenePos);
+
+ QPointF lastScenePos() const;
+ void setLastScenePos(const QPointF &lastScenePos);
+
+ qreal pressure() const; // 0.0 -> 1.0
+ void setPressure(qreal pressure);
+ };
+
+ QGraphicsSceneTouchEvent(Type type = None);
+ ~QGraphicsSceneTouchEvent();
+
+ const QList<QGraphicsSceneTouchEvent::TouchPoint *> &touchPoints() const;
+ void setTouchPoints(const QList<QGraphicsSceneTouchEvent::TouchPoint *> &touchPoints);
+
+ Qt::KeyboardModifiers modifiers() const;
+ void setModifiers(Qt::KeyboardModifiers modifiers);
+
+private:
+ Q_DECLARE_PRIVATE(QGraphicsSceneTouchEvent);
+};
+
#endif // QT_NO_GRAPHICSVIEW
QT_END_NAMESPACE
diff --git a/src/gui/graphicsview/qgraphicsview.cpp b/src/gui/graphicsview/qgraphicsview.cpp
index 5e33896..2d2113c 100644
--- a/src/gui/graphicsview/qgraphicsview.cpp
+++ b/src/gui/graphicsview/qgraphicsview.cpp
@@ -295,6 +295,8 @@ static const int QGRAPHICSVIEW_PREALLOC_STYLE_OPTIONS = 503; // largest prime <
QT_BEGIN_NAMESPACE
+bool qt_sendSpontaneousEvent(QObject *receiver, QEvent *event);
+
inline int q_round_bound(qreal d) //### (int)(qreal) INT_MAX != INT_MAX for single precision
{
if (d <= (qreal) INT_MIN)
@@ -304,6 +306,30 @@ inline int q_round_bound(qreal d) //### (int)(qreal) INT_MAX != INT_MAX for sing
return d >= 0.0 ? int(d + 0.5) : int(d - int(d-1) + 0.5) + int(d-1);
}
+static void qt_convertTouchEventToGraphicsSceneTouchEvent(QGraphicsViewPrivate *d,
+ QTouchEvent *originalEvent,
+ QGraphicsSceneTouchEvent *touchEvent)
+{
+ QList<QTouchEvent::TouchPoint *> originalTouchPoints = originalEvent->touchPoints();
+ QList<QGraphicsSceneTouchEvent::TouchPoint *> touchPoints;
+ for (int i = 0; i < originalTouchPoints.count(); ++i) {
+ QGraphicsSceneTouchEvent::TouchPoint *touchPoint =
+ static_cast<QGraphicsSceneTouchEvent::TouchPoint *>(originalTouchPoints.at(i));
+ // the scene will set the pos before delivering to an item
+ touchPoint->setScenePos(d->mapToScene(touchPoint->pos()));
+ // the scene will set the startPos before delivering to an item
+ touchPoint->setStartScenePos(d->mapToScene(touchPoint->startPos()));
+ // the scene will set the lastPos before delivering to an item
+ touchPoint->setLastScenePos(d->mapToScene(touchPoint->lastScreenPos()));
+ // lastScreenPos is already set in the originalTouchPoint
+
+ touchPoints.append(touchPoint);
+ }
+
+ touchEvent->setTouchPoints(touchPoints);
+ touchEvent->setModifiers(originalEvent->modifiers());
+}
+
/*!
\internal
*/
@@ -602,7 +628,7 @@ void QGraphicsViewPrivate::mouseMoveEventHandler(QMouseEvent *event)
lastMouseMoveScenePoint = mouseEvent.scenePos();
lastMouseMoveScreenPoint = mouseEvent.screenPos();
mouseEvent.setAccepted(false);
- QApplication::sendEvent(scene, &mouseEvent);
+ qt_sendSpontaneousEvent(scene, &mouseEvent);
// Remember whether the last event was accepted or not.
lastMouseEvent.setAccepted(mouseEvent.isAccepted());
@@ -1690,7 +1716,7 @@ void QGraphicsView::setScene(QGraphicsScene *scene)
this, SLOT(updateScene(QList<QRectF>)));
disconnect(d->scene, SIGNAL(sceneRectChanged(QRectF)),
this, SLOT(updateSceneRect(QRectF)));
- d->scene->d_func()->views.removeAll(this);
+ d->scene->d_func()->removeView(this);
d->connectedToScene = false;
}
@@ -1699,7 +1725,7 @@ void QGraphicsView::setScene(QGraphicsScene *scene)
connect(d->scene, SIGNAL(sceneRectChanged(QRectF)),
this, SLOT(updateSceneRect(QRectF)));
d->updateSceneSlotReimplementedChecked = false;
- d->scene->d_func()->views << this;
+ d->scene->d_func()->addView(this);
d->recalculateContentSize();
d->lastCenterPoint = sceneRect().center();
d->keepLastCenterPoint = true;
@@ -2861,6 +2887,9 @@ bool QGraphicsView::event(QEvent *event)
}
}
break;
+ case QEvent::Gesture:
+ viewportEvent(event);
+ break;
default:
break;
}
@@ -2941,6 +2970,43 @@ bool QGraphicsView::viewportEvent(QEvent *event)
d->scene->d_func()->updateAll = false;
}
break;
+ case QEvent::Gesture: {
+ QGraphicsSceneGestureEvent gestureEvent;
+ gestureEvent.setWidget(this);
+ QGestureEvent *ev = static_cast<QGestureEvent*>(event);
+ gestureEvent.setGestures(ev->gestures());
+ gestureEvent.setCancelledGestures(ev->cancelledGestures());
+ QApplication::sendEvent(d->scene, &gestureEvent);
+ if (gestureEvent.isAccepted())
+ return true;
+ }
+ break;
+ case QEvent::TouchBegin:
+ case QEvent::TouchUpdate:
+ case QEvent::TouchEnd:
+ {
+ if (!isEnabled())
+ return false;
+
+ if (d->scene && d->sceneInteractionAllowed) {
+ // Convert and deliver the touch event to the scene.
+ QEvent::Type eventType = event->type() == QEvent::TouchBegin
+ ? QEvent::GraphicsSceneTouchBegin
+ : event->type() == QEvent::TouchEnd
+ ? QEvent::GraphicsSceneTouchEnd
+ : QEvent::GraphicsSceneTouchUpdate;
+ QGraphicsSceneTouchEvent touchEvent(eventType);
+ touchEvent.setWidget(viewport());
+ qt_convertTouchEventToGraphicsSceneTouchEvent(d,
+ static_cast<QTouchEvent *>(event),
+ &touchEvent);
+ touchEvent.setAccepted(false);
+ QApplication::sendEvent(d->scene, &touchEvent);
+ event->setAccepted(touchEvent.isAccepted());
+ }
+
+ return true;
+ }
default:
break;
}
@@ -3199,7 +3265,7 @@ void QGraphicsView::mouseDoubleClickEvent(QMouseEvent *event)
mouseEvent.setAccepted(false);
mouseEvent.setButton(event->button());
mouseEvent.setModifiers(event->modifiers());
- QApplication::sendEvent(d->scene, &mouseEvent);
+ qt_sendSpontaneousEvent(d->scene, &mouseEvent);
}
/*!
@@ -3238,7 +3304,7 @@ void QGraphicsView::mousePressEvent(QMouseEvent *event)
mouseEvent.setButton(event->button());
mouseEvent.setModifiers(event->modifiers());
mouseEvent.setAccepted(false);
- QApplication::sendEvent(d->scene, &mouseEvent);
+ qt_sendSpontaneousEvent(d->scene, &mouseEvent);
// Update the original mouse event accepted state.
bool isAccepted = mouseEvent.isAccepted();
@@ -3408,7 +3474,7 @@ void QGraphicsView::mouseReleaseEvent(QMouseEvent *event)
mouseEvent.setButton(event->button());
mouseEvent.setModifiers(event->modifiers());
mouseEvent.setAccepted(false);
- QApplication::sendEvent(d->scene, &mouseEvent);
+ qt_sendSpontaneousEvent(d->scene, &mouseEvent);
// Update the last mouse event selected state.
d->lastMouseEvent.setAccepted(mouseEvent.isAccepted());
@@ -3879,6 +3945,14 @@ void QGraphicsView::resetTransform()
setTransform(QTransform());
}
+QPointF QGraphicsViewPrivate::mapToScene(const QPointF &point) const
+{
+ QPointF p = point;
+ p.rx() += horizontalScroll();
+ p.ry() += verticalScroll();
+ return identityMatrix ? p : matrix.inverted().map(p);
+}
+
QT_END_NAMESPACE
#include "moc_qgraphicsview.cpp"
diff --git a/src/gui/graphicsview/qgraphicsview_p.h b/src/gui/graphicsview/qgraphicsview_p.h
index d573e8f..779b638 100644
--- a/src/gui/graphicsview/qgraphicsview_p.h
+++ b/src/gui/graphicsview/qgraphicsview_p.h
@@ -181,6 +181,8 @@ public:
const QTransform &worldTransform,
bool allItems,
const QRegion &exposedRegion) const;
+
+ QPointF mapToScene(const QPointF &point) const;
};
QT_END_NAMESPACE
diff --git a/src/gui/kernel/kernel.pri b/src/gui/kernel/kernel.pri
index a1b982a..3016afb 100644
--- a/src/gui/kernel/kernel.pri
+++ b/src/gui/kernel/kernel.pri
@@ -41,7 +41,15 @@ HEADERS += \
kernel/qwidgetaction.h \
kernel/qwidgetaction_p.h \
kernel/qwindowdefs.h \
- kernel/qkeymapper_p.h
+ kernel/qkeymapper_p.h \
+ kernel/qgesture.h \
+ kernel/qgesture_p.h \
+ kernel/qgesturemanager_p.h \
+ kernel/qgesturerecognizer_p.h \
+ kernel/qgesturerecognizer.h \
+ kernel/qgesturestandardrecognizers_p.h \
+ kernel/qdirectionrecognizer_p.h \
+ kernel/qdirectionsimplificator_p.h
SOURCES += \
kernel/qaction.cpp \
@@ -70,7 +78,12 @@ SOURCES += \
kernel/qwhatsthis.cpp \
kernel/qwidget.cpp \
kernel/qwidgetaction.cpp \
- kernel/qkeymapper.cpp
+ kernel/qkeymapper.cpp \
+ kernel/qgesture.cpp \
+ kernel/qgesturemanager.cpp \
+ kernel/qgesturerecognizer.cpp \
+ kernel/qgesturestandardrecognizers.cpp \
+ kernel/qdirectionrecognizer.cpp
win32 {
DEFINES += QT_NO_DIRECTDRAW
diff --git a/src/gui/kernel/qapplication.cpp b/src/gui/kernel/qapplication.cpp
index b9ebf55..e46ccf1 100644
--- a/src/gui/kernel/qapplication.cpp
+++ b/src/gui/kernel/qapplication.cpp
@@ -85,10 +85,13 @@
#include <stdlib.h>
#include "qapplication_p.h"
+#include "qevent_p.h"
#include "qwidget_p.h"
#include "qapplication.h"
+#include <private/qgesturemanager_p.h>
+
#ifdef Q_WS_WINCE
#include "qdatetime.h"
#include "qguifunctions_wince.h"
@@ -97,6 +100,8 @@ extern bool qt_wince_is_mobile(); //qguifunctions_wince.cpp
extern bool qt_wince_is_pocket_pc(); //qguifunctions_wince.cpp
#endif
+#include "qdatetime.h"
+
//#define ALIEN_DEBUG
static void initResources()
@@ -132,6 +137,14 @@ int QApplicationPrivate::autoMaximizeThreshold = -1;
bool QApplicationPrivate::autoSipEnabled = false;
#endif
+QGestureManager* QGestureManager::instance()
+{
+ QApplicationPrivate *d = qApp->d_func();
+ if (!d->gestureManager)
+ d->gestureManager = new QGestureManager(qApp);
+ return d->gestureManager;
+}
+
QApplicationPrivate::QApplicationPrivate(int &argc, char **argv, QApplication::Type type)
: QCoreApplicationPrivate(argc, argv)
{
@@ -155,6 +168,8 @@ QApplicationPrivate::QApplicationPrivate(int &argc, char **argv, QApplication::T
directPainters = 0;
#endif
+ gestureManager = 0;
+
if (!self)
self = this;
}
@@ -3573,6 +3588,18 @@ bool QApplication::notify(QObject *receiver, QEvent *e)
#endif // !QT_NO_WHEELEVENT || !QT_NO_TABLETEVENT
}
+ if (!d->grabbedGestures.isEmpty() && e->spontaneous() && receiver->isWidgetType()) {
+ const QEvent::Type t = e->type();
+ if (t == QEvent::MouseButtonPress || t == QEvent::MouseButtonRelease || t == QEvent::MouseMove
+ || t == QEvent::MouseButtonDblClick || t == QEvent::Wheel
+ || t == QEvent::KeyPress || t == QEvent::KeyRelease
+ || t == QEvent::TabletPress || t == QEvent::TabletRelease || t == QEvent::TabletMove
+ || t >= QEvent::User) {
+ if (QGestureManager::instance()->filterEvent(static_cast<QWidget*>(receiver), e))
+ return true;
+ }
+ }
+
// User input and window activation makes tooltips sleep
switch (e->type()) {
case QEvent::Wheel:
@@ -3700,19 +3727,10 @@ bool QApplication::notify(QObject *receiver, QEvent *e)
QPoint relpos = mouse->pos();
if (e->spontaneous()) {
-
if (e->type() == QEvent::MouseButtonPress) {
- QWidget *fw = w;
- while (fw) {
- if (fw->isEnabled()
- && QApplicationPrivate::shouldSetFocus(fw, Qt::ClickFocus)) {
- fw->setFocus(Qt::MouseFocusReason);
- break;
- }
- if (fw->isWindow())
- break;
- fw = fw->parentWidget();
- }
+ QApplicationPrivate::giveFocusAccordingToFocusPolicy(w,
+ Qt::ClickFocus,
+ Qt::MouseFocusReason);
}
if (e->type() == QEvent::MouseMove && mouse->buttons() == 0) {
@@ -3794,17 +3812,9 @@ bool QApplication::notify(QObject *receiver, QEvent *e)
bool eventAccepted = wheel->isAccepted();
if (e->spontaneous()) {
- QWidget *fw = w;
- while (fw) {
- if (fw->isEnabled()
- && QApplicationPrivate::shouldSetFocus(fw, Qt::WheelFocus)) {
- fw->setFocus(Qt::MouseFocusReason);
- break;
- }
- if (fw->isWindow())
- break;
- fw = fw->parentWidget();
- }
+ QApplicationPrivate::giveFocusAccordingToFocusPolicy(w,
+ Qt::WheelFocus,
+ Qt::MouseFocusReason);
}
while (w) {
@@ -4009,7 +4019,48 @@ bool QApplication::notify(QObject *receiver, QEvent *e)
}
break;
#endif
+ case QEvent::TouchBegin:
+ // Note: TouchUpdate and TouchEnd events are sent to d->currentMultitouchWidget and never propagated
+ {
+ QWidget *widget = static_cast<QWidget *>(receiver);
+ QWidget *origin = widget;
+ QTouchEvent *touchEvent = static_cast<QTouchEvent *>(e);
+ bool eventAccepted = touchEvent->isAccepted();
+ if (widget->testAttribute(Qt::WA_AcceptTouchEvents) && e->spontaneous()) {
+ // give the widget focus if the focus policy allows it
+ QApplicationPrivate::giveFocusAccordingToFocusPolicy(widget,
+ Qt::ClickFocus,
+ Qt::MouseFocusReason);
+ }
+ while (widget) {
+ // first, try to deliver the touch event
+ touchEvent->ignore();
+ res = widget->testAttribute(Qt::WA_AcceptTouchEvents)
+ && d->notify_helper(widget, touchEvent);
+ eventAccepted = touchEvent->isAccepted();
+ widget->setAttribute(Qt::WA_AcceptedTouchBeginEvent, res && eventAccepted);
+ touchEvent->spont = false;
+ if (res && eventAccepted) {
+ // the first widget to accept the TouchBegin gets an implicit grab.
+ for (int i = 0; i < touchEvent->_touchPoints.count(); ++i) {
+ QTouchEvent::TouchPoint *touchPoint = touchEvent->_touchPoints.at(i);
+ d->widgetForTouchPointId[touchPoint->d->id] = widget;
+ }
+ if (origin != widget)
+ d->widgetCurrentTouchPoints.remove(origin);
+ d->widgetCurrentTouchPoints[widget] = touchEvent->_touchPoints;
+ break;
+ } else if (widget->isWindow() || widget->testAttribute(Qt::WA_NoMousePropagation)) {
+ break;
+ }
+ widget = widget->parentWidget();
+ d->updateTouchPointsForWidget(widget, touchEvent);
+ }
+
+ touchEvent->setAccepted(eventAccepted);
+ break;
+ }
default:
res = d->notify_helper(receiver, e);
break;
@@ -4976,6 +5027,23 @@ Qt::LayoutDirection QApplication::keyboardInputDirection()
return qt_keymapper_private()->keyboardInputDirection;
}
+void QApplicationPrivate::giveFocusAccordingToFocusPolicy(QWidget *widget,
+ Qt::FocusPolicy focusPolicy,
+ Qt::FocusReason focusReason)
+{
+ QWidget *focusWidget = widget;
+ while (focusWidget) {
+ if (focusWidget->isEnabled()
+ && QApplicationPrivate::shouldSetFocus(focusWidget, focusPolicy)) {
+ focusWidget->setFocus(focusReason);
+ break;
+ }
+ if (focusWidget->isWindow())
+ break;
+ focusWidget = focusWidget->parentWidget();
+ }
+}
+
bool QApplicationPrivate::shouldSetFocus(QWidget *w, Qt::FocusPolicy policy)
{
QWidget *f = w;
@@ -4989,6 +5057,57 @@ bool QApplicationPrivate::shouldSetFocus(QWidget *w, Qt::FocusPolicy policy)
return true;
}
+/*!
+ \since 4.6
+
+ Adds custom gesture \a recognizer object.
+
+ Qt takes ownership of the provided \a recognizer.
+
+ \sa Qt::AA_EnableGestures, QGestureEvent
+*/
+void QApplication::addGestureRecognizer(QGestureRecognizer *recognizer)
+{
+ QGestureManager::instance()->addRecognizer(recognizer);
+}
+
+/*!
+ \since 4.6
+
+ Removes custom gesture \a recognizer object.
+
+ \sa Qt::AA_EnableGestures, QGestureEvent
+*/
+void QApplication::removeGestureRecognizer(QGestureRecognizer *recognizer)
+{
+ Q_D(QApplication);
+ if (!d->gestureManager)
+ return;
+ d->gestureManager->removeRecognizer(recognizer);
+}
+
+/*!
+ \property QApplication::eventDeliveryDelayForGestures
+ \since 4.6
+
+ Specifies the \a delay before input events are delivered to the
+ gesture enabled widgets.
+
+ The delay allows to postpone widget's input event handling until
+ gestures framework can successfully recognize a gesture.
+
+ \sa QWidget::grabGesture
+*/
+void QApplication::setEventDeliveryDelayForGestures(int delay)
+{
+ QGestureManager::instance()->setEventDeliveryDelay(delay);
+}
+
+int QApplication::eventDeliveryDelayForGestures()
+{
+ return QGestureManager::instance()->eventDeliveryDelay();
+}
+
/*! \fn QDecoration &QApplication::qwsDecoration()
Return the QWSDecoration used for decorating windows.
@@ -5120,6 +5239,19 @@ bool QApplicationPrivate::shouldSetFocus(QWidget *w, Qt::FocusPolicy policy)
This normally takes some time. Does nothing on other platforms.
*/
+void QApplicationPrivate::updateTouchPointsForWidget(QWidget *widget, QTouchEvent *touchEvent)
+{
+ for (int i = 0; i < touchEvent->_touchPoints.count(); ++i) {
+ QTouchEvent::TouchPoint *touchPoint = touchEvent->_touchPoints.at(i);
+
+ // preserve the sub-pixel resolution
+ const QPointF delta = touchPoint->d->screenPos - touchPoint->d->screenPos.toPoint();
+ touchPoint->d->pos = widget->mapFromGlobal(touchPoint->d->screenPos.toPoint()) + delta;
+ touchPoint->d->startPos = widget->mapFromGlobal(touchPoint->d->startScreenPos.toPoint()) + delta;
+ touchPoint->d->lastPos = widget->mapFromGlobal(touchPoint->d->lastScreenPos.toPoint()) + delta;
+ }
+}
+
QT_END_NAMESPACE
#include "moc_qapplication.cpp"
diff --git a/src/gui/kernel/qapplication.h b/src/gui/kernel/qapplication.h
index 2baf6dc..e09ea08 100644
--- a/src/gui/kernel/qapplication.h
+++ b/src/gui/kernel/qapplication.h
@@ -71,6 +71,7 @@ class QStyle;
class QEventLoop;
class QIcon;
class QInputContext;
+class QGestureRecognizer;
template <typename T> class QList;
class QLocale;
#if defined(Q_WS_QWS)
@@ -106,6 +107,7 @@ class Q_GUI_EXPORT QApplication : public QCoreApplication
Q_PROPERTY(int autoMaximizeThreshold READ autoMaximizeThreshold WRITE setAutoMaximizeThreshold)
Q_PROPERTY(bool autoSipEnabled READ autoSipEnabled WRITE setAutoSipEnabled)
#endif
+ Q_PROPERTY(int eventDeliveryDelayForGestures READ eventDeliveryDelayForGestures WRITE setEventDeliveryDelayForGestures)
public:
enum Type { Tty, GuiClient, GuiServer };
@@ -266,6 +268,12 @@ public:
static bool keypadNavigationEnabled();
#endif
+ void addGestureRecognizer(QGestureRecognizer *recognizer);
+ void removeGestureRecognizer(QGestureRecognizer *recognizer);
+
+ void setEventDeliveryDelayForGestures(int delay);
+ int eventDeliveryDelayForGestures();
+
Q_SIGNALS:
void lastWindowClosed();
void focusChanged(QWidget *old, QWidget *now);
@@ -374,6 +382,7 @@ private:
friend class QDirectPainter;
friend class QDirectPainterPrivate;
#endif
+ friend class QGestureManager;
#if defined(Q_WS_WIN)
friend QApplicationPrivate* getQApplicationPrivateInternal();
diff --git a/src/gui/kernel/qapplication_p.h b/src/gui/kernel/qapplication_p.h
index 7e97418..096c349 100644
--- a/src/gui/kernel/qapplication_p.h
+++ b/src/gui/kernel/qapplication_p.h
@@ -55,6 +55,7 @@
//
#include "QtGui/qapplication.h"
+#include "QtGui/qevent.h"
#include "QtGui/qfont.h"
#include "QtGui/qcursor.h"
#include "QtGui/qregion.h"
@@ -77,11 +78,9 @@ class QClipboard;
class QGraphicsScene;
class QGraphicsSystem;
class QInputContext;
-class QKeyEvent;
-class QMouseEvent;
class QObject;
-class QWheelEvent;
class QWidget;
+class QGestureManager;
extern bool qt_is_gui_used;
#ifndef QT_NO_CLIPBOARD
@@ -189,6 +188,12 @@ extern "C" {
}
#endif
+#if defined(Q_WS_WIN)
+typedef BOOL (WINAPI *qt_RegisterTouchWindowPtr)(HWND, ULONG);
+typedef BOOL (WINAPI *qt_GetTouchInputInfoPtr)(HANDLE, UINT, PVOID, int);
+typedef BOOL (WINAPI *qt_CloseTouchInputHandlePtr)(HANDLE);
+#endif
+
class QScopedLoopLevelCounter
{
QThreadData *threadData;
@@ -424,12 +429,43 @@ public:
void sendSyntheticEnterLeave(QWidget *widget);
#endif
+ QGestureManager *gestureManager;
+ // map<gesture name -> number of widget subscribed to it>
+ QMap<QString, int> grabbedGestures;
+
+ QHash<int, QWidget *> widgetForTouchPointId;
+ QMap<QWidget *, QList<QTouchEvent::TouchPoint *> > widgetCurrentTouchPoints;
+ static void updateTouchPointsForWidget(QWidget *widget, QTouchEvent *touchEvent);
+
+#if defined(Q_WS_WIN)
+ static qt_RegisterTouchWindowPtr RegisterTouchWindow;
+ static qt_GetTouchInputInfoPtr GetTouchInputInfo;
+ static qt_CloseTouchInputHandlePtr CloseTouchInputHandle;
+
+ QHash<DWORD, int> touchInputIDToTouchPointID;
+ QVector<QTouchEvent::TouchPoint *> appAllTouchPoints;
+ QList<QTouchEvent::TouchPoint *> appCurrentTouchPoints;
+
+ void initializeMultitouch();
+ static QTouchEvent::TouchPoint *findClosestTouchPoint(const QList<QTouchEvent::TouchPoint *> &activeTouchPoints,
+ const QPointF &screenPos);
+ QEvent::Type appendTouchPoint(QTouchEvent::TouchPoint *touchPoint,
+ QList<QTouchEvent::TouchPoint *> *currentTouchPoints);
+ QEvent::Type removeTouchPoint(QTouchEvent::TouchPoint *touchPoint,
+ QList<QTouchEvent::TouchPoint *> *currentTouchPoints);
+ bool translateTouchEvent(const MSG &msg);
+#endif
+
private:
#ifdef Q_WS_QWS
QMap<const QScreen*, QRect> maxWindowRects;
#endif
static QApplicationPrivate *self;
+
+ static void giveFocusAccordingToFocusPolicy(QWidget *w,
+ Qt::FocusPolicy focusPolicy,
+ Qt::FocusReason focusReason);
static bool shouldSetFocus(QWidget *w, Qt::FocusPolicy policy);
};
diff --git a/src/gui/kernel/qapplication_win.cpp b/src/gui/kernel/qapplication_win.cpp
index 6237657..f537805 100644
--- a/src/gui/kernel/qapplication_win.cpp
+++ b/src/gui/kernel/qapplication_win.cpp
@@ -88,6 +88,7 @@ extern void qt_wince_hide_taskbar(HWND hwnd); //defined in qguifunctions_wince.c
#include "qdebug.h"
#include <private/qkeymapper_p.h>
#include <private/qlocale_p.h>
+#include "qevent_p.h"
//#define ALIEN_DEBUG
@@ -112,6 +113,39 @@ extern void qt_wince_hide_taskbar(HWND hwnd); //defined in qguifunctions_wince.c
# include <winable.h>
#endif
+#ifndef WM_TOUCHMOVE
+
+# define WM_TOUCHMOVE 0x0240
+# define WM_TOUCHDOWN 0x0241
+# define WM_TOUCHUP 0x0242
+
+# define TOUCHEVENTF_MOVE 0x0001
+# define TOUCHEVENTF_DOWN 0x0002
+# define TOUCHEVENTF_UP 0x0004
+# define TOUCHEVENTF_INRANGE 0x0008
+# define TOUCHEVENTF_PRIMARY 0x0010
+# define TOUCHEVENTF_NOCOALESCE 0x0020
+# define TOUCHEVENTF_PEN 0x0040
+
+# define TOUCHINPUTMASKF_TIMEFROMSYSTEM 0x0001
+# define TOUCHINPUTMASKF_EXTRAINFO 0x0002
+# define TOUCHINPUTMASKF_CONTACTAREA 0x0004
+
+typedef struct tagTOUCHINPUT
+{
+ LONG x;
+ LONG y;
+ HANDLE hSource;
+ DWORD dwID;
+ DWORD dwFlags;
+ DWORD dwMask;
+ DWORD dwTime;
+ ULONG_PTR dwExtraInfo;
+ DWORD cxContact;
+ DWORD cyContact;
+} TOUCHINPUT, *PTOUCHINPUT;
+
+#endif
#ifndef FLASHW_STOP
typedef struct {
@@ -853,6 +887,8 @@ void qt_init(QApplicationPrivate *priv, int)
if (ptrUpdateLayeredWindow && !ptrUpdateLayeredWindowIndirect)
ptrUpdateLayeredWindowIndirect = qt_updateLayeredWindowIndirect;
#endif
+
+ priv->initializeMultitouch();
}
/*****************************************************************************
@@ -1716,6 +1752,11 @@ LRESULT CALLBACK QtWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam
result = widget->translateWheelEvent(msg);
} else {
switch (message) {
+ case WM_TOUCHMOVE:
+ case WM_TOUCHDOWN:
+ case WM_TOUCHUP:
+ result = getQApplicationPrivateInternal()->translateTouchEvent(msg);
+ break;
case WM_KEYDOWN: // keyboard event
case WM_SYSKEYDOWN:
qt_keymapper_private()->updateKeyMap(msg);
@@ -3956,4 +3997,234 @@ void QSessionManager::cancel()
#endif //QT_NO_SESSIONMANAGER
+qt_RegisterTouchWindowPtr QApplicationPrivate::RegisterTouchWindow = 0;
+qt_GetTouchInputInfoPtr QApplicationPrivate::GetTouchInputInfo = 0;
+qt_CloseTouchInputHandlePtr QApplicationPrivate::CloseTouchInputHandle = 0;
+
+void QApplicationPrivate::initializeMultitouch()
+{
+ QLibrary library(QLatin1String("user32"));
+ RegisterTouchWindow = static_cast<qt_RegisterTouchWindowPtr>(library.resolve("RegisterTouchWindow"));
+ GetTouchInputInfo = static_cast<qt_GetTouchInputInfoPtr>(library.resolve("GetTouchInputInfo"));
+ CloseTouchInputHandle = static_cast<qt_CloseTouchInputHandlePtr>(library.resolve("CloseTouchInputHandle"));
+
+ widgetForTouchPointId.clear();
+ widgetCurrentTouchPoints.clear();
+ touchInputIDToTouchPointID.clear();
+ appAllTouchPoints.clear();
+ appCurrentTouchPoints.clear();
+}
+
+QTouchEvent::TouchPoint *QApplicationPrivate::findClosestTouchPoint(const QList<QTouchEvent::TouchPoint *> &appActiveTouchPoints,
+ const QPointF &screenPos)
+{
+ QTouchEvent::TouchPoint *closestTouchPoint = 0;
+ qreal closestDistance;
+ for (int i = 0; i < appActiveTouchPoints.count(); ++i) {
+ QTouchEvent::TouchPoint *touchPoint = appActiveTouchPoints.at(i);
+ qreal distance = QLineF(screenPos, touchPoint->d->screenPos).length();
+ if (!closestTouchPoint || distance < closestDistance) {
+ closestTouchPoint = touchPoint;
+ closestDistance = distance;
+ }
+ }
+ return closestTouchPoint;
+}
+
+QEvent::Type QApplicationPrivate::appendTouchPoint(QTouchEvent::TouchPoint *touchPoint,
+ QList<QTouchEvent::TouchPoint *> *currentTouchPoints)
+{
+ QEvent::Type eventType = currentTouchPoints->isEmpty()
+ ? QEvent::TouchBegin
+ : QEvent::TouchUpdate;
+
+ // insort touch point (for the app)
+ int at = 0;
+ for (; at < appCurrentTouchPoints.count(); ++at) {
+ if (appCurrentTouchPoints.at(at)->id() > touchPoint->id())
+ break;
+ }
+ appCurrentTouchPoints.insert(at, touchPoint);
+ // again, for the widget's currentTouchPoints
+ for (at = 0; at < currentTouchPoints->count(); ++at) {
+ if (currentTouchPoints->at(at)->id() > touchPoint->id())
+ break;
+ }
+ currentTouchPoints->insert(at, touchPoint);
+
+ if (appCurrentTouchPoints.count() > appAllTouchPoints.count()) {
+ qFatal("Qt: INTERNAL ERROR: appCurrentTouchPoints.count() (%d) > appAllTouchPoints.count() (%d)",
+ appCurrentTouchPoints.count(),
+ appAllTouchPoints.count());
+ }
+
+ return eventType;
+}
+
+QEvent::Type QApplicationPrivate::removeTouchPoint(QTouchEvent::TouchPoint *touchPoint,
+ QList<QTouchEvent::TouchPoint *> *currentTouchPoints)
+{
+ // remove touch point from all known touch points
+ for (int i = qMin(appCurrentTouchPoints.count() - 1, touchPoint->id()); i >= 0; --i) {
+ if (appCurrentTouchPoints.at(i) == touchPoint) {
+ appCurrentTouchPoints.removeAt(i);
+ break;
+ }
+ }
+ // again, for the widget's currentTouchPoints
+ for (int i = qMin(currentTouchPoints->count() - 1, touchPoint->id()); i >= 0; --i) {
+ if (currentTouchPoints->at(i) == touchPoint) {
+ currentTouchPoints->removeAt(i);
+ break;
+ }
+ }
+
+ return currentTouchPoints->isEmpty() ? QEvent::TouchEnd : QEvent::TouchUpdate;
+}
+
+bool QApplicationPrivate::translateTouchEvent(const MSG &msg)
+{
+ Q_Q(QApplication);
+
+ QWidget *widgetForHwnd = QWidget::find(msg.hwnd);
+ if (!widgetForHwnd)
+ return false;
+
+ QList<QTouchEvent::TouchPoint *> appActiveTouchPoints = appCurrentTouchPoints;
+
+ QHash<QWidget *, QTouchEvent> widgetsNeedingEvents;
+ QVector<TOUCHINPUT> winTouchInputs(msg.wParam);
+ memset(winTouchInputs.data(), 0, sizeof(TOUCHINPUT) * winTouchInputs.count());
+ QApplicationPrivate::GetTouchInputInfo((HANDLE) msg.lParam, msg.wParam, winTouchInputs.data(), sizeof(TOUCHINPUT));
+ for (int i = 0; i < winTouchInputs.count(); ++i) {
+ const TOUCHINPUT &touchInput = winTouchInputs.at(i);
+
+ int touchPointID = touchInputIDToTouchPointID.value(touchInput.dwID, -1);
+ if (touchPointID == -1) {
+ touchPointID = touchInputIDToTouchPointID.count();
+ touchInputIDToTouchPointID.insert(touchInput.dwID, touchPointID);
+ }
+
+ if (appAllTouchPoints.count() <= touchPointID)
+ appAllTouchPoints.resize(touchPointID + 1);
+
+ QTouchEvent::TouchPoint *touchPoint = appAllTouchPoints.at(touchPointID);
+ if (!touchPoint)
+ touchPoint = appAllTouchPoints[touchPointID] = new QTouchEvent::TouchPoint(touchPointID);
+
+ // update state
+ QWidget *widget = 0;
+ bool down = touchPoint->d->state != Qt::TouchPointReleased;
+ QPointF screenPos(qreal(touchInput.x) / qreal(100.), qreal(touchInput.y) / qreal(100.));
+ QEvent::Type eventType = QEvent::None;
+
+ QList<QTouchEvent::TouchPoint *> activeTouchPoints;
+ if (!down && (touchInput.dwFlags & TOUCHEVENTF_DOWN)) {
+ // determine which widget this event will go to
+ widget = widgetForHwnd->childAt(widgetForHwnd->mapFromGlobal(screenPos.toPoint()));
+ if (!widget)
+ widget = widgetForHwnd;
+
+ QTouchEvent::TouchPoint *closestTouchPoint = findClosestTouchPoint(appActiveTouchPoints, screenPos);
+ if (closestTouchPoint) {
+ QWidget *closestWidget = widgetForTouchPointId.value(closestTouchPoint->d->id);
+ if (closestWidget
+ && (widget->isAncestorOf(closestWidget)
+ || closestWidget->isAncestorOf(widget)))
+ widget = closestWidget;
+ }
+ widgetForTouchPointId[touchPoint->d->id] = widget;
+
+ QList<QTouchEvent::TouchPoint *> &currentTouchPoints = widgetCurrentTouchPoints[widget];
+ eventType = appendTouchPoint(touchPoint, &currentTouchPoints);
+ // make sure new points are added to activeTouchPoints as well
+ appActiveTouchPoints = appCurrentTouchPoints;
+ activeTouchPoints = currentTouchPoints;
+
+ touchPoint->d->state = Qt::TouchPointPressed;
+ touchPoint->d->screenPos
+ = touchPoint->d->startScreenPos
+ = touchPoint->d->lastScreenPos
+ = screenPos;
+ touchPoint->d->pressure = qreal(1.);
+ } else if (down && (touchInput.dwFlags & TOUCHEVENTF_UP)) {
+ widget = widgetForTouchPointId.take(touchPoint->d->id);
+ QList<QTouchEvent::TouchPoint *> &currentTouchPoints = widgetCurrentTouchPoints[widget];
+ appActiveTouchPoints = appCurrentTouchPoints;
+ activeTouchPoints = currentTouchPoints;
+ eventType = removeTouchPoint(touchPoint, &currentTouchPoints);
+
+ touchPoint->d->state = Qt::TouchPointReleased;
+ touchPoint->d->lastScreenPos = touchPoint->d->screenPos;
+ touchPoint->d->screenPos = screenPos;
+ touchPoint->d->pressure = qreal(0.);
+ } else if (down) {
+ widget = widgetForTouchPointId.value(touchPoint->d->id);
+ appActiveTouchPoints = appCurrentTouchPoints;
+ activeTouchPoints = widgetCurrentTouchPoints.value(widget);
+ eventType = QEvent::TouchUpdate;
+ touchPoint->d->state = screenPos == touchPoint->d->screenPos
+ ? Qt::TouchPointStationary
+ : Qt::TouchPointMoved;
+ touchPoint->d->lastScreenPos = touchPoint->d->screenPos;
+ touchPoint->d->screenPos = screenPos;
+ // pressure should still be 1.
+ }
+ Q_ASSERT(widget != 0 && eventType != QEvent::None);
+
+ if (touchPoint->d->state != Qt::TouchPointStationary) {
+ widgetsNeedingEvents.insert(widget,
+ QTouchEvent(eventType, q->keyboardModifiers(), activeTouchPoints));
+ }
+ }
+ QApplicationPrivate::CloseTouchInputHandle((HANDLE) msg.lParam);
+
+ if (widgetsNeedingEvents.isEmpty())
+ return false;
+
+ bool returnValue = false;
+ qt_tabletChokeMouse = false;
+
+ QHash<QWidget *, QTouchEvent>::ConstIterator it = widgetsNeedingEvents.constBegin();
+ const QHash<QWidget *, QTouchEvent>::ConstIterator end = widgetsNeedingEvents.constEnd();
+ for (; it != end; ++it) {
+ QWidget *widget = it.key();
+ if (!QApplicationPrivate::tryModalHelper(widget, 0))
+ continue;
+
+ QTouchEvent touchEvent = it.value();
+ updateTouchPointsForWidget(widget, &touchEvent);
+
+ switch (touchEvent.type()) {
+ case QEvent::TouchBegin:
+ {
+ // if the TouchBegin handler recurses, we assume that means the event
+ // has been implicitly accepted and continue to send touch events
+ widget->setAttribute(Qt::WA_AcceptedTouchBeginEvent);
+ bool res = QApplication::sendSpontaneousEvent(widget, &touchEvent)
+ && touchEvent.isAccepted();
+ returnValue = returnValue || (qt_tabletChokeMouse = qt_tabletChokeMouse || res);
+ break;
+ }
+ case QEvent::TouchEnd:
+ {
+ QList<QTouchEvent::TouchPoint *> currentTouchPoints = widgetCurrentTouchPoints.take(widget);
+ if (!currentTouchPoints.isEmpty()) {
+ qFatal("Qt: INTERNAL ERROR, the widget's currentTouchPoints should be empty!");
+ }
+ // fall-through intended
+ }
+ default:
+ if (widget->testAttribute(Qt::WA_AcceptedTouchBeginEvent)) {
+ (void) QApplication::sendSpontaneousEvent(widget, &touchEvent);
+ qt_tabletChokeMouse = true;
+ }
+ returnValue = returnValue || qt_tabletChokeMouse;
+ break;
+ }
+ }
+
+ return returnValue;
+}
+
QT_END_NAMESPACE
diff --git a/src/gui/kernel/qapplication_x11.cpp b/src/gui/kernel/qapplication_x11.cpp
index 90376b3..060e948 100644
--- a/src/gui/kernel/qapplication_x11.cpp
+++ b/src/gui/kernel/qapplication_x11.cpp
@@ -4414,7 +4414,6 @@ bool QETWidget::translateMouseEvent(const XEvent *event)
QMouseEvent e(type, pos, globalPos, button, buttons, modifiers);
QApplicationPrivate::sendMouseEvent(widget, &e, alienWidget, this, &qt_button_down,
qt_last_mouse_receiver);
-
if (type == QEvent::MouseButtonPress
&& button == Qt::RightButton
&& (openPopupCount == oldOpenPopupCount)) {
@@ -5022,6 +5021,7 @@ bool QETWidget::translatePropertyEvent(const XEvent *event)
return true;
}
+
//
// Paint event translation
//
diff --git a/src/gui/kernel/qdirectionrecognizer.cpp b/src/gui/kernel/qdirectionrecognizer.cpp
new file mode 100644
index 0000000..2896523
--- /dev/null
+++ b/src/gui/kernel/qdirectionrecognizer.cpp
@@ -0,0 +1,176 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial Usage
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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 "qdirectionrecognizer_p.h"
+
+#include <math.h>
+
+QT_BEGIN_NAMESPACE
+
+static const int SIZE = 20;
+
+QDirectionSimpleRecognizer::QDirectionSimpleRecognizer()
+{
+}
+
+Direction QDirectionSimpleRecognizer::addPosition(const QPoint &pos)
+{
+ if (!directions.isEmpty()) {
+ const QPoint tmp = pos - directions.back().point;
+ if (tmp.manhattanLength() < 5)
+ return Direction();
+ }
+ if (lastPoint.isNull()) {
+ lastPoint = pos;
+ return Direction();
+ }
+ int dx = pos.x() - lastPoint.x();
+ int dy = pos.y() - lastPoint.y();
+ Qt::DirectionType direction = Qt::NoDirection;
+ if (dx < 0) {
+ if (-1*dx >= SIZE/2)
+ direction = Qt::LeftDirection;
+ } else {
+ if (dx >= SIZE/2)
+ direction = Qt::RightDirection;
+ }
+ if (dy < 0) {
+ if (-1*dy >= SIZE/2)
+ direction = Qt::UpDirection;
+ } else {
+ if (dy >= SIZE/2)
+ direction = Qt::DownDirection;
+ }
+ if (direction == Qt::NoDirection)
+ return Direction();
+
+ lastPoint = pos;
+ directions.push_back(Direction(direction, pos));
+ return Direction(direction, pos);
+}
+
+
+DirectionList QDirectionSimpleRecognizer::getDirections() const
+{
+ return directions;
+}
+
+void QDirectionSimpleRecognizer::reset()
+{
+ directions.clear();
+ lastPoint = QPoint();
+}
+
+
+/// QDirectionDiagonalRecognizer
+
+QDirectionDiagonalRecognizer::QDirectionDiagonalRecognizer()
+{
+}
+
+Direction QDirectionDiagonalRecognizer::addPosition(const QPoint &pos)
+{
+ if (!directions.isEmpty()) {
+ const QPoint tmp = pos - directions.back().point;
+ if (tmp.manhattanLength() < 5)
+ return Direction();
+ }
+ if (lastPoint.isNull()) {
+ lastPoint = pos;
+ return Direction();
+ }
+ int dx = pos.x() - lastPoint.x();
+ int dy = pos.y() - lastPoint.y();
+ int distance = sqrt(static_cast<double>(dx*dx + dy*dy));
+ if (distance < SIZE/2)
+ return Direction();
+
+ Qt::DirectionType direction = Qt::NoDirection;
+ double angle = atan(1.0*qAbs(lastPoint.y() - pos.y())/qAbs(pos.x() - lastPoint.x())) * 180. / M_PI;
+ if (dx < 0 && dy <= 0) {
+ angle = 180 - angle;
+ } else if (dx <= 0 && dy > 0) {
+ angle += 180;
+ } else if (dx > 0 && dy > 0) {
+ angle = 360-angle;
+ }
+ if (angle < 0)
+ angle += 360;
+ if (angle <= 20)
+ direction = Qt::RightDirection;
+ else if (angle <= 65)
+ direction = Qt::RightUpDirection;
+ else if (angle <= 110)
+ direction = Qt::UpDirection;
+ else if (angle <= 155)
+ direction = Qt::LeftUpDirection;
+ else if (angle <= 200)
+ direction = Qt::LeftDirection;
+ else if (angle <= 245)
+ direction = Qt::LeftDownDirection;
+ else if (angle <= 290)
+ direction = Qt::DownDirection;
+ else if (angle <= 335)
+ direction = Qt::RightDownDirection;
+ else
+ direction = Qt::RightDirection;
+
+ if (direction == Qt::NoDirection)
+ return Direction();
+
+ lastPoint = pos;
+ directions.push_back(Direction(direction, pos));
+ return Direction(direction, pos);
+}
+
+
+DirectionList QDirectionDiagonalRecognizer::getDirections() const
+{
+ return directions;
+}
+
+void QDirectionDiagonalRecognizer::reset()
+{
+ directions.clear();
+ lastPoint = QPoint();
+}
+
+QT_END_NAMESPACE
diff --git a/src/gui/kernel/qdirectionrecognizer_p.h b/src/gui/kernel/qdirectionrecognizer_p.h
new file mode 100644
index 0000000..ca3d1c1
--- /dev/null
+++ b/src/gui/kernel/qdirectionrecognizer_p.h
@@ -0,0 +1,105 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial Usage
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QDIRECTIONRECOGNIZER_P_H
+#define QDIRECTIONRECOGNIZER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qpoint.h"
+#include "qlist.h"
+
+QT_BEGIN_NAMESPACE
+
+struct Direction
+{
+ Qt::DirectionType direction;
+ QPoint point;
+
+ Direction(Qt::DirectionType dir, const QPoint &pt)
+ : direction(dir), point(pt) { }
+ Direction()
+ : direction(Qt::NoDirection) { }
+
+ inline bool isEmpty() const { return direction == Qt::NoDirection; }
+ inline bool isNull() const { return direction == Qt::NoDirection; }
+};
+
+typedef QList<Direction> DirectionList;
+
+class QDirectionSimpleRecognizer
+{
+public:
+ QDirectionSimpleRecognizer();
+ Direction addPosition(const QPoint &pos);
+ DirectionList getDirections() const;
+ void reset();
+
+private:
+ QPoint lastPoint;
+ DirectionList directions;
+};
+
+class QDirectionDiagonalRecognizer
+{
+public:
+ QDirectionDiagonalRecognizer();
+ Direction addPosition(const QPoint &pos);
+ DirectionList getDirections() const;
+ void reset();
+
+private:
+ QPoint lastPoint;
+ DirectionList directions;
+};
+
+QT_END_NAMESPACE
+
+#endif // QDIRECTIONRECOGNIZER_P_H
diff --git a/src/gui/kernel/qdirectionsimplificator_p.h b/src/gui/kernel/qdirectionsimplificator_p.h
new file mode 100644
index 0000000..7b71ca0
--- /dev/null
+++ b/src/gui/kernel/qdirectionsimplificator_p.h
@@ -0,0 +1,172 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial Usage
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QDIRECTIONSIMPLIFICATOR_P_H
+#define QDIRECTIONSIMPLIFICATOR_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "private/qdirectionrecognizer_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QDirectionSimplificator
+{
+public:
+ QDirectionSimplificator(const DirectionList &dir);
+
+ bool simplify(DirectionList *result);
+
+private:
+ DirectionList directions;
+ DirectionList lastResult;
+ enum State {
+ None,
+ Trim, // remove first and last element
+ AccidentalMoves, // 66866 => 6666
+ ComplexAccidentalMoves, // 778788 => 777888 (swapping elements without changing direction)
+ ShortMoves, // (moves of length 1)
+ } state;
+
+ struct SimplifyTrim
+ {
+ SimplifyTrim() : state(0) { }
+ bool operator()(DirectionList &directions)
+ {
+ if (state == 0) {
+ directions.removeFirst();
+ state = 1;
+ } else if (state == 1) {
+ directions.removeLast();
+ state = 2;
+ } else if (state == 2 && directions.size() >= 2) {
+ directions.removeFirst();
+ directions.removeLast();
+ state = 3;
+ } else {
+ return false;
+ }
+ return true;
+ }
+ int state;
+ };
+ struct SimplifyAccidentalMoves
+ {
+ SimplifyAccidentalMoves() : state(0) { }
+ bool operator()(DirectionList &directions)
+ {
+ return false;
+ }
+ int state;
+ };
+ struct SimplifyComplexAccidentalMoves
+ {
+ SimplifyComplexAccidentalMoves() : state(0) { }
+ bool operator()(DirectionList &directions)
+ {
+ return false;
+ }
+ int state;
+ };
+
+ SimplifyTrim trim;
+ SimplifyAccidentalMoves accidentalMoves;
+ SimplifyComplexAccidentalMoves complexAccidentalMoves;
+ //SimplifyShortMoves shortMoves;
+};
+
+QDirectionSimplificator::QDirectionSimplificator(const DirectionList &dir)
+ : directions(dir), state(None)
+{
+}
+
+bool QDirectionSimplificator::simplify(DirectionList *result)
+{
+ if (directions.isEmpty() || !result)
+ return false;
+ *result = directions;
+ switch(state) {
+ case None:
+ state = Trim;
+ trim = SimplifyTrim();
+ case Trim:
+ if (trim(*result))
+ break;
+ *result = lastResult;
+ state = AccidentalMoves;
+ accidentalMoves = SimplifyAccidentalMoves();
+ case AccidentalMoves:
+ if (accidentalMoves(*result))
+ break;
+ *result = lastResult;
+ state = ComplexAccidentalMoves;
+ complexAccidentalMoves = SimplifyComplexAccidentalMoves();
+ case ComplexAccidentalMoves:
+ if (complexAccidentalMoves(*result))
+ break;
+ *result = lastResult;
+ // state = ShortMoves;
+ // shortMoves = SimplifyShortMoves();
+ // case ShortMoves:
+ // if (shortMoves(*result))
+ // break;
+ // state = None;
+ default:
+ return false;
+ }
+ lastResult = *result;
+ if (lastResult.isEmpty())
+ return false;
+ return true;
+}
+
+QT_END_NAMESPACE
+
+#endif // QDIRECTIONSIMPLIFICATOR_P_H
diff --git a/src/gui/kernel/qevent.cpp b/src/gui/kernel/qevent.cpp
index 0ab4423..d616e5e 100644
--- a/src/gui/kernel/qevent.cpp
+++ b/src/gui/kernel/qevent.cpp
@@ -52,6 +52,8 @@
QT_BEGIN_NAMESPACE
+QString qt_getStandardGestureTypeName(Qt::GestureType type);
+
/*!
\class QInputEvent
\ingroup events
@@ -3322,6 +3324,9 @@ QDebug operator<<(QDebug dbg, const QEvent *e) {
case QEvent::ChildRemoved: n = n ? n : "ChildRemoved";
dbg.nospace() << "QChildEvent(" << n << ", " << (static_cast<const QChildEvent*>(e))->child();
return dbg.space();
+ case QEvent::Gesture:
+ n = "Gesture";
+ break;
default:
dbg.nospace() << "QEvent(" << (const void *)e << ", type = " << e->type() << ')';
return dbg.space();
@@ -3518,4 +3523,373 @@ QMenubarUpdatedEvent::QMenubarUpdatedEvent(QMenuBar * const menuBar)
#endif
+/*!
+ \class QGestureEvent
+ \since 4.6
+ \ingroup events
+
+ \brief The QGestureEvent class provides the parameters used for
+ gesture recognition.
+
+ The QGestureEvent class contains a list of gestures that are being
+ executed right now (\l{QGestureEvent::}{gestureTypes()}) and a
+ list of gestures that are cancelled (the gesture might be
+ cancelled because the window lost focus, or because of timeout,
+ etc).
+
+ \sa QGesture
+*/
+
+/*!
+ Creates new QGestureEvent containing a list of \a gestures that
+ are being executed and a list of gesture that were cancelled (\a
+ cancelledGestures).
+*/
+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);
+}
+
+/*!
+ Destroys the QGestureEvent object.
+*/
+QGestureEvent::~QGestureEvent()
+{
+}
+
+/*!
+ Returns true if the gesture event contains gesture of specific \a
+ type; returns false otherwise.
+*/
+bool QGestureEvent::contains(Qt::GestureType type) const
+{
+ return contains(qt_getStandardGestureTypeName(type));
+}
+
+/*!
+ Returns true if the gesture event contains gesture of specific \a
+ type; returns false otherwise.
+*/
+bool QGestureEvent::contains(const QString &type) const
+{
+ return gesture(type) != 0;
+}
+
+/*!
+ Returns a list of gesture names that this event contains.
+*/
+QList<QString> QGestureEvent::gestureTypes() const
+{
+ return m_gestures.keys();
+}
+
+/*!
+ Returns extended information about a gesture of specific \a type.
+*/
+const QGesture* QGestureEvent::gesture(Qt::GestureType type) const
+{
+ return gesture(qt_getStandardGestureTypeName(type));
+}
+
+/*!
+ Returns extended information about a gesture of specific \a type.
+*/
+const QGesture* QGestureEvent::gesture(const QString &type) const
+{
+ return m_gestures.value(type, 0);
+}
+
+/*!
+ Returns extended information about all gestures in the event.
+*/
+QList<QGesture*> QGestureEvent::gestures() const
+{
+ return m_gestures.values();
+}
+
+/*!
+ Returns a set of gesture names that used to be executed, but were
+ cancelled (i.e. they were not finished properly).
+*/
+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
+.
+ \since 4.6
+ \ingroup events
+
+ Touch events occur when pressing, releasing, or moving one or more
+ touch points on a touch device (such as a touch-screen or
+ track-pad), and if the widget has the Qt::WA_AcceptTouchEvents
+ attribute.
+
+ Like QMouseEvent, Qt automatically grabs the touch device on the
+ first press inside a widget; the widget will receive all touch
+ events until the last touch point is released.
+
+ A touch event contains a special accept flag that indicates
+ whether the receiver wants the event. By default, the event is
+ ignored. You should call accept() if the touch event is handled by
+ your widget. A touch event is propagated up the parent widget
+ chain until a widget accepts it with accept(), or an event filter
+ consumes it. If the touch event is neither accepted nor consumed,
+ then mouse events are simulated from the state of the first touch
+ point.
+
+ All touch events are of type QEvent::Touch. The touchPoints()
+ function returns a list of all touch points contained in the
+ event. Information about each touch point can be retreived using
+ the QTouchEvent::TouchPoint class.
+
+ The Qt::TouchPointState enum describes the different states that a
+ touch point may have.
+
+ QTouchEvent::TouchPoint Qt::TouchPointState Qt::WA_AcceptTouchEvents
+*/
+
+/*! \enum Qt::TouchPointState
+ \since 4.6
+
+ This enum represents the state of a touch point at the time the
+ QTouchEvent occurred.
+
+ \value TouchPointPressed The touch point is now pressed.
+ \value TouchPointMoved The touch point moved.
+ \value TouchPointStationary The touch point did not move.
+ \value TouchPointReleased The touch point was released.
+*/
+
+/*! \class QTouchEvent::TouchPoint
+ \brief The QTouchEvent::TouchPoint class provide information about a touch point in a QTouchEvent.
+ \since 4.6
+*/
+
+/*!
+ Constructs a QTouchEvent with the given \a type and \a
+ touchPoints. The \a modifiers are the current keyboard modifiers
+ at the time of the event.
+*/
+QTouchEvent::QTouchEvent(QEvent::Type type,
+ Qt::KeyboardModifiers modifiers,
+ const QList<QTouchEvent::TouchPoint *> &touchPoints)
+ : QInputEvent(type, modifiers), _touchPoints(touchPoints)
+{ }
+
+/*!
+ Destroys the QTouchEvent.
+*/
+QTouchEvent::~QTouchEvent()
+{ }
+
+/*! \fn const QList<QTouchEvent::TouchPoint *> &QTouchEvent::TouchPoints() const
+
+ Returns the list of touch points contained in the touch event.
+*/
+
+/*! \internal
+
+ Constructs a QTouchEvent::TouchPoint for use in a QTouchEvent.
+*/
+QTouchEvent::TouchPoint::TouchPoint(int id)
+ : d(new QTouchEventTouchPointPrivate(id))
+{ }
+
+/*! \internal
+
+ Destroys the QTouchEvent::TouchPoint.
+*/
+QTouchEvent::TouchPoint::~TouchPoint()
+{
+ delete d;
+}
+
+/*!
+ Returns the id number of this touch point. Id numbers are
+ sequential, starting at zero, meaning the first touch point has id
+ 0, the second has id 1, and so on...
+*/
+int QTouchEvent::TouchPoint::id() const
+{
+ return d->id;
+}
+
+/*! \internal */
+void QTouchEvent::TouchPoint::setId(int id)
+{
+ d->id = id;
+}
+
+/*!
+ Returns the current state of this touch point.
+*/
+Qt::TouchPointState QTouchEvent::TouchPoint::state() const
+{
+ return d->state;
+}
+
+/*! \internal */
+void QTouchEvent::TouchPoint::setState(Qt::TouchPointState state)
+{
+ d->state = state;
+}
+
+/*!
+ Returns the position of this touch point, relative to the widget
+ or item that received the event.
+*/
+QPointF QTouchEvent::TouchPoint::pos() const
+{
+ return d->pos;
+}
+
+/*! \internal */
+void QTouchEvent::TouchPoint::setPos(const QPointF &pos)
+{
+ d->pos = pos;
+}
+
+/*!
+ Returns the starting position of this touch point, relative to the
+ widget that received the event.
+*/
+QPointF QTouchEvent::TouchPoint::startPos() const
+{
+ return d->startPos;
+}
+
+/*! \internal */
+void QTouchEvent::TouchPoint::setStartPos(const QPointF &startPos)
+{
+ d->startPos = startPos;
+}
+
+/*!
+ Returns the position of this touch point from the previous touch
+ event, relative to the widget that received the event.
+*/
+QPointF QTouchEvent::TouchPoint::lastPos() const
+{
+ return d->lastPos;
+}
+
+/*! \internal */
+void QTouchEvent::TouchPoint::setLastPos(const QPointF &lastPos)
+{
+ d->lastPos = lastPos;
+}
+
+/*!
+ Returns the screen position of this touch point.
+*/
+QPointF QTouchEvent::TouchPoint::screenPos() const
+{
+ return d->screenPos;
+}
+
+/*! \internal */
+void QTouchEvent::TouchPoint::setScreenPos(const QPointF &screenPos)
+{
+ d->screenPos = screenPos;
+}
+
+/*!
+ Returns the starting screen position of this touch point.
+*/
+QPointF QTouchEvent::TouchPoint::startScreenPos() const
+{
+ return d->startScreenPos;
+}
+
+/*! \internal */
+void QTouchEvent::TouchPoint::setStartScreenPos(const QPointF &startScreenPos)
+{
+ d->startScreenPos = startScreenPos;
+}
+
+/*!
+ Returns the screen position of this touch point from the previous
+ touch event.
+*/
+QPointF QTouchEvent::TouchPoint::lastScreenPos() const
+{
+ return d->lastScreenPos;
+}
+
+/*! \internal */
+void QTouchEvent::TouchPoint::setLastScreenPos(const QPointF &lastScreenPos)
+{
+ d->lastScreenPos = lastScreenPos;
+}
+
+/*!
+ Returns the pressure of this touch point. The return value is in
+ the range 0.0 to 1.0.
+*/
+qreal QTouchEvent::TouchPoint::pressure() const
+{
+ return d->pressure;
+}
+
+/*! \internal */
+void QTouchEvent::TouchPoint::setPressure(qreal pressure)
+{
+ d->pressure = pressure;
+}
+
QT_END_NAMESPACE
diff --git a/src/gui/kernel/qevent.h b/src/gui/kernel/qevent.h
index 449730d..ed4129c 100644
--- a/src/gui/kernel/qevent.h
+++ b/src/gui/kernel/qevent.h
@@ -52,6 +52,9 @@
#include <QtGui/qmime.h>
#include <QtGui/qdrag.h>
#include <QtCore/qvariant.h>
+#include <QtCore/qmap.h>
+#include <QtCore/qset.h>
+#include <QtGui/qgesture.h>
QT_BEGIN_HEADER
@@ -710,6 +713,41 @@ private:
};
#endif
+class Q_GUI_EXPORT QGestureEvent : public QEvent
+{
+public:
+ QGestureEvent(const QSet<QGesture*> &gestures,
+ const QSet<QString> &cancelledGestures = QSet<QString>());
+ ~QGestureEvent();
+
+ bool contains(Qt::GestureType type) const;
+ bool contains(const QString &type) const;
+
+ QList<QString> gestureTypes() const;
+
+ const QGesture* gesture(Qt::GestureType type) const;
+ const QGesture* gesture(const QString &type) const;
+ QList<QGesture*> gestures() const;
+
+ 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;
+
+ friend class QApplication;
+ friend class QGestureManager;
+};
+
#ifndef QT_NO_DEBUG_STREAM
Q_GUI_EXPORT QDebug operator<<(QDebug, const QEvent *);
#endif
@@ -719,6 +757,64 @@ inline bool operator==(QKeyEvent *e, QKeySequence::StandardKey key){return (e ?
inline bool operator==(QKeySequence::StandardKey key, QKeyEvent *e){return (e ? e->matches(key) : false);}
#endif // QT_NO_SHORTCUT
+class QTouchEventTouchPointPrivate;
+class Q_GUI_EXPORT QTouchEvent : public QInputEvent
+{
+public:
+ class Q_GUI_EXPORT TouchPoint
+ {
+ public:
+ TouchPoint(int id = -1);
+ ~TouchPoint();
+
+ int id() const;
+ void setId(int id);
+
+ Qt::TouchPointState state() const;
+ void setState(Qt::TouchPointState state);
+
+ QPointF pos() const;
+ void setPos(const QPointF &pos);
+
+ QPointF startPos() const;
+ void setStartPos(const QPointF &startPos);
+
+ QPointF lastPos() const;
+ void setLastPos(const QPointF &lastPos);
+
+ QPointF screenPos() const;
+ void setScreenPos(const QPointF &screenPos);
+
+ QPointF startScreenPos() const;
+ void setStartScreenPos(const QPointF &startScreenPos);
+
+ QPointF lastScreenPos() const;
+ void setLastScreenPos(const QPointF &lastScreenPos);
+
+ qreal pressure() const; // 0.0 -> 1.0
+ void setPressure(qreal pressure);
+
+ protected:
+ QTouchEventTouchPointPrivate *d;
+
+ friend class QApplication;
+ friend class QApplicationPrivate;
+ };
+
+ QTouchEvent(QEvent::Type type,
+ Qt::KeyboardModifiers modifiers,
+ const QList<QTouchEvent::TouchPoint *> &touchPoints);
+ ~QTouchEvent();
+
+ inline const QList<QTouchEvent::TouchPoint *> &touchPoints() const { return _touchPoints; }
+
+protected:
+ QList<QTouchEvent::TouchPoint *> _touchPoints;
+
+ friend class QApplication;
+ friend class QApplicationPrivate;
+};
+
QT_END_NAMESPACE
QT_END_HEADER
diff --git a/src/gui/kernel/qevent_p.h b/src/gui/kernel/qevent_p.h
index 8e762d6..dd78c3e 100644
--- a/src/gui/kernel/qevent_p.h
+++ b/src/gui/kernel/qevent_p.h
@@ -89,6 +89,23 @@ protected:
friend class QMouseEvent;
};
+class QTouchEventTouchPointPrivate
+{
+public:
+ inline QTouchEventTouchPointPrivate(int id)
+ : id(id),
+ state(Qt::TouchPointReleased),
+ pressure(qreal(-1.))
+ { }
+
+ int id;
+ Qt::TouchPointState state;
+ QPointF pos, startPos, lastPos;
+ QPointF scenePos, startScenePos, lastScenePos;
+ QPointF screenPos, startScreenPos, lastScreenPos;
+ qreal pressure;
+};
+
QT_END_NAMESPACE
#endif // QEVENT_P_H
diff --git a/src/gui/kernel/qgesture.cpp b/src/gui/kernel/qgesture.cpp
new file mode 100644
index 0000000..ac55521
--- /dev/null
+++ b/src/gui/kernel/qgesture.cpp
@@ -0,0 +1,290 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial Usage
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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 "qgesture.h"
+#include <private/qgesture_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QString qt_getStandardGestureTypeName(Qt::GestureType type);
+
+/*!
+ \class QGesture
+ \since 4.6
+
+ \brief The QGesture class represents a gesture, containing all
+ properties that describe a gesture.
+
+ The widget receives a QGestureEvent with a list of QGesture
+ objects that represent gestures that are occuring on it. The class
+ has a list of properties that can be queried by the user to get
+ some gesture-specific arguments (i.e. position of the tap in the
+ DoubleTap gesture).
+
+ When creating custom gesture recognizers, they might add new
+ properties to the gesture object, or custom gesture developers
+ might subclass the QGesture objects to provide some extended
+ information. However, if the gesture developer wants to add a new
+ property to the gesture object that describe coordinate (like a
+ QPoint or QRect), it is required to subclass the QGesture and
+ re-implement the \l{QGesture::}{translate()} function to make sure
+ the coordinates are translated properly when the gesture event is
+ propagated to parent widgets.
+
+ \sa QGestureEvent, QGestureRecognizer
+*/
+
+/*!
+ Creates a new gesture object of type \a type in a \a state and
+ marks it as a child of \a parent.
+
+ Usually QGesture objects should only be contructed by the
+ QGestureRecognizer classes.
+*/
+QGesture::QGesture(QObject *parent, const QString &type, Qt::GestureState state)
+ : QObject(*new QGesturePrivate, parent), m_accept(0)
+{
+ Q_D(QGesture);
+ d->type = type;
+ d->state = state;
+}
+
+/*!
+ Creates a new gesture object of type \a type in a \a state and
+ marks it as a child of \a parent.
+
+ This constructor also fills some basic information about the
+ gesture like a \a startPos which describes the start point of the
+ gesture, \a lastPos - last point where the gesture happened, \a
+ pos - a current point, \a rect - a bounding rect of the gesture,
+ \a hotSpot - a center point of the gesture, \a startTime - a time
+ when the gesture has started, \a duration - how long the gesture
+ is going on.
+
+ Usually QGesture objects should only be contructed by the
+ QGestureRecognizer classes.
+*/
+QGesture::QGesture(QObject *parent, const QString &type, const QPoint &startPos,
+ const QPoint &lastPos, const QPoint &pos, const QRect &rect,
+ const QPoint &hotSpot, const QDateTime &startTime,
+ uint duration, Qt::GestureState state)
+ : QObject(*new QGesturePrivate, parent)
+{
+ Q_D(QGesture);
+ d->type = type;
+ d->state = state;
+ d->init(startPos, lastPos, pos, rect, hotSpot, startTime, duration);
+}
+
+/*! \internal
+*/
+QGesture::QGesture(QGesturePrivate &dd, QObject *parent, const QString &type,
+ Qt::GestureState state)
+ : QObject(dd, parent)
+{
+ Q_D(QGesture);
+ d->type = type;
+ d->state = state;
+}
+
+/*!
+ Destroys the gesture object.
+*/
+QGesture::~QGesture()
+{
+}
+
+/*!
+ \property QGesture::type
+
+ \brief The type of the gesture.
+*/
+QString QGesture::type() const
+{
+ return d_func()->type;
+}
+
+
+/*!
+ \property QGesture::state
+
+ \brief The current state of the gesture.
+*/
+Qt::GestureState QGesture::state() const
+{
+ return d_func()->state;
+}
+
+/*!
+ Translates the internal gesture properties that represent
+ coordinates by \a offset.
+
+ Custom gesture recognizer developer have to re-implement this
+ function if they want to store custom properties that represent
+ coordinates.
+*/
+void QGesture::translate(const QPoint &offset)
+{
+ Q_D(QGesture);
+ d->rect.translate(offset);
+ d->hotSpot += offset;
+ d->startPos += offset;
+ d->lastPos += offset;
+ d->pos += offset;
+}
+
+/*!
+ \property QGesture::rect
+
+ \brief The bounding rect of a gesture.
+*/
+QRect QGesture::rect() const
+{
+ return d_func()->rect;
+}
+
+/*!
+ \property QGesture::hotSpot
+
+ \brief The center point of a gesture.
+*/
+QPoint QGesture::hotSpot() const
+{
+ return d_func()->hotSpot;
+}
+
+/*!
+ \property QGesture::startTime
+
+ \brief The time when the gesture has started.
+*/
+QDateTime QGesture::startTime() const
+{
+ return d_func()->startTime;
+}
+
+/*!
+ \property QGesture::duration
+
+ \brief The duration time of a gesture.
+*/
+uint QGesture::duration() const
+{
+ return d_func()->duration;
+}
+
+/*!
+ \property QGesture::startPos
+
+ \brief The start position of the pointer.
+*/
+QPoint QGesture::startPos() const
+{
+ return d_func()->startPos;
+}
+
+/*!
+ \property QGesture::lastPos
+
+ \brief The last recorded position of the pointer.
+*/
+QPoint QGesture::lastPos() const
+{
+ return d_func()->lastPos;
+}
+
+/*!
+ \property QGesture::pos
+
+ \brief The current position of the pointer.
+*/
+QPoint QGesture::pos() const
+{
+ return d_func()->pos;
+}
+
+/*!
+ \class QPanningGesture
+ \since 4.6
+
+ \brief The QPanningGesture class represents a Pan gesture,
+ providing additional information related to panning.
+
+ This class is provided for convenience, panning direction
+ information is also contained in the QGesture object in it's
+ properties.
+*/
+
+/*! \internal
+*/
+QPanningGesture::QPanningGesture(QObject *parent)
+ : QGesture(*new QPanningGesturePrivate, parent,
+ qt_getStandardGestureTypeName(Qt::PanGesture))
+{
+}
+
+/*! \internal
+*/
+QPanningGesture::~QPanningGesture()
+{
+}
+
+/*!
+ \property QPanningGesture::lastDirection
+
+ \brief The last recorded direction of panning.
+*/
+Qt::DirectionType QPanningGesture::lastDirection() const
+{
+ return d_func()->lastDirection;
+}
+
+/*!
+ \property QPanningGesture::direction
+
+ \brief The current direction of panning.
+*/
+Qt::DirectionType QPanningGesture::direction() const
+{
+ return d_func()->direction;
+}
+
+QT_END_NAMESPACE
diff --git a/src/gui/kernel/qgesture.h b/src/gui/kernel/qgesture.h
new file mode 100644
index 0000000..d220232
--- /dev/null
+++ b/src/gui/kernel/qgesture.h
@@ -0,0 +1,145 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial Usage
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QGESTURE_H
+#define QGESTURE_H
+
+#include "qobject.h"
+#include "qlist.h"
+#include "qdatetime.h"
+#include "qpoint.h"
+#include "qrect.h"
+#include "qmetatype.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+class QGesturePrivate;
+class Q_GUI_EXPORT QGesture : public QObject
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QGesture)
+
+ Q_PROPERTY(QString type READ type)
+ Q_PROPERTY(Qt::GestureState state READ state)
+
+ Q_PROPERTY(QRect rect READ rect)
+ Q_PROPERTY(QPoint hotSpot READ hotSpot)
+ Q_PROPERTY(QDateTime startTime READ startTime)
+ Q_PROPERTY(uint duration READ duration)
+ Q_PROPERTY(QPoint startPos READ startPos)
+ Q_PROPERTY(QPoint lastPos READ lastPos)
+ 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, const QPoint &startPos,
+ const QPoint &lastPos, const QPoint &pos, const QRect &rect,
+ const QPoint &hotSpot, const QDateTime &startTime,
+ 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;
+
+ QRect rect() const;
+ QPoint hotSpot() const;
+ QDateTime startTime() const;
+ uint duration() const;
+
+ QPoint startPos() const;
+ QPoint lastPos() const;
+ QPoint pos() const;
+
+protected:
+ QGesture(QGesturePrivate &dd, QObject *parent, const QString &type,
+ Qt::GestureState state = Qt::GestureStarted);
+ virtual void translate(const QPoint &offset);
+
+private:
+ ushort m_accept : 1;
+
+ friend class QGestureManager;
+ friend class QApplication;
+ friend class QGestureRecognizerPan;
+ friend class QDoubleTapGestureRecognizer;
+ friend class QTapAndHoldGestureRecognizer;
+};
+
+class QPanningGesturePrivate;
+class Q_GUI_EXPORT QPanningGesture : public QGesture
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QPanningGesture)
+
+ Q_PROPERTY(Qt::DirectionType lastDirection READ lastDirection)
+ Q_PROPERTY(Qt::DirectionType direction READ direction)
+
+public:
+ Qt::DirectionType lastDirection() const;
+ Qt::DirectionType direction() const;
+
+private:
+ QPanningGesture(QObject *parent = 0);
+ ~QPanningGesture();
+
+ friend class QGestureRecognizerPan;
+};
+
+Q_DECLARE_METATYPE(Qt::DirectionType)
+Q_DECLARE_METATYPE(Qt::GestureState)
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QGESTURE_H
diff --git a/src/gui/kernel/qgesture_p.h b/src/gui/kernel/qgesture_p.h
new file mode 100644
index 0000000..d2d77cc
--- /dev/null
+++ b/src/gui/kernel/qgesture_p.h
@@ -0,0 +1,111 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial Usage
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QGESTURE_P_H
+#define QGESTURE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qrect.h"
+#include "qpoint.h"
+#include "qdatetime.h"
+#include "private/qobject_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QGesturePrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QGesture)
+
+public:
+ QGesturePrivate()
+ : state(Qt::NoGesture), singleshot(0), duration(0) { }
+
+ void init(const QPoint &startPos, const QPoint &lastPos,
+ const QPoint &pos, const QRect &rect,
+ const QPoint &hotSpot, const QDateTime &startTime,
+ uint duration)
+ {
+ this->rect = rect;
+ this->hotSpot = hotSpot;
+ this->startTime = startTime;
+ this->duration = duration;
+ this->startPos = startPos;
+ this->lastPos = lastPos;
+ this->pos = pos;
+ }
+
+ QString type;
+ Qt::GestureState state;
+
+ QPointer<QWidget> widget;
+ uint singleshot:1;
+
+ QRect rect;
+ QPoint hotSpot;
+ QDateTime startTime;
+ uint duration;
+ QPoint startPos;
+ QPoint lastPos;
+ QPoint pos;
+};
+
+class QPanningGesturePrivate : public QGesturePrivate
+{
+ Q_DECLARE_PUBLIC(QPanningGesture)
+
+public:
+ Qt::DirectionType lastDirection;
+ Qt::DirectionType direction;
+};
+
+QT_END_NAMESPACE
+
+#endif // QGESTURE_P_H
diff --git a/src/gui/kernel/qgesturemanager.cpp b/src/gui/kernel/qgesturemanager.cpp
new file mode 100644
index 0000000..c7341f2
--- /dev/null
+++ b/src/gui/kernel/qgesturemanager.cpp
@@ -0,0 +1,630 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial Usage
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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 "qgesturemanager_p.h"
+#include "qgesture.h"
+#include "qgesture_p.h"
+#include "qevent.h"
+
+#include "qapplication.h"
+#include "qapplication_p.h"
+#include "qwidget.h"
+#include "qwidget_p.h"
+
+#include "qgesturestandardrecognizers_p.h"
+
+#include "qdebug.h"
+
+// #define GESTURE_DEBUG
+#ifndef GESTURE_DEBUG
+# define DEBUG if (0) qDebug
+#else
+# define DEBUG qDebug
+#endif
+
+QT_BEGIN_NAMESPACE
+
+bool qt_sendSpontaneousEvent(QObject *receiver, QEvent *event);
+
+static const unsigned int MaximumGestureRecognitionTimeout = 2000;
+
+QGestureManager::QGestureManager(QObject *parent)
+ : QObject(parent), eventDeliveryDelayTimeout(300),
+ delayedPressTimer(0), lastMousePressReceiver(0), lastMousePressEvent(QEvent::None, QPoint(), Qt::NoButton, 0, 0),
+ lastGestureId(0), state(NotGesture)
+{
+ qRegisterMetaType<Qt::DirectionType>();
+ qRegisterMetaType<Qt::GestureState>();
+
+ recognizers << new QDoubleTapGestureRecognizer(this);
+ recognizers << new QTapAndHoldGestureRecognizer(this);
+ recognizers << new QGestureRecognizerPan(this);
+
+ foreach(QGestureRecognizer *r, recognizers)
+ connect(r, SIGNAL(stateChanged(QGestureRecognizer::Result)),
+ this, SLOT(recognizerStateChanged(QGestureRecognizer::Result)));
+}
+
+void QGestureManager::addRecognizer(QGestureRecognizer *recognizer)
+{
+ recognizer->setParent(this);
+ recognizers << recognizer;
+}
+
+void QGestureManager::removeRecognizer(QGestureRecognizer *recognizer)
+{
+ recognizers.remove(recognizer);
+}
+
+bool QGestureManager::filterEvent(QWidget *receiver, QEvent *event)
+{
+ QPoint currentPos;
+ switch (event->type()) {
+ case QEvent::MouseButtonPress:
+ case QEvent::MouseButtonRelease:
+ case QEvent::MouseButtonDblClick:
+ case QEvent::MouseMove:
+ currentPos = static_cast<QMouseEvent*>(event)->pos(); break;
+ default: break;
+ }
+
+ const QMap<QString, int> &grabbedGestures = qApp->d_func()->grabbedGestures;
+
+ bool ret = false;
+ QSet<QGestureRecognizer*> startedGestures;
+ QSet<QGestureRecognizer*> finishedGestures;
+ QSet<QGestureRecognizer*> newMaybeGestures;
+ QSet<QGestureRecognizer*> cancelledGestures;
+ QSet<QGestureRecognizer*> notGestures;
+ if (state == NotGesture || state == MaybeGesture) {
+ DEBUG() << "QGestureManager: current event processing state: "
+ << (state == NotGesture ? "NotGesture" : "MaybeGesture");
+
+ QSet<QGestureRecognizer*> stillMaybeGestures;
+ // try other recognizers.
+ foreach(QGestureRecognizer *r, recognizers) {
+ if (grabbedGestures.value(r->gestureType(), 0) <= 0)
+ continue;
+ QGestureRecognizer::Result result = r->filterEvent(event);
+ if (result == QGestureRecognizer::GestureStarted) {
+ DEBUG() << "QGestureManager: gesture started: " << r;
+ startedGestures << r;
+ } else if (result == QGestureRecognizer::GestureFinished) {
+ DEBUG() << "QGestureManager: gesture finished: " << r;
+ finishedGestures << r;
+ } else if (result == QGestureRecognizer::MaybeGesture) {
+ DEBUG() << "QGestureManager: maybe gesture: " << r;
+ newMaybeGestures << r;
+ } else if (result == QGestureRecognizer::NotGesture) {
+ // if it was maybe gesture, but isn't a gesture anymore.
+ DEBUG() << "QGestureManager: not gesture: " << r;
+ notGestures << r;
+ }
+ }
+ activeGestures -= newMaybeGestures;
+ activeGestures += startedGestures;
+ 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());
+ it = maybeGestures.erase(it);
+ } else {
+ ++it;
+ }
+ }
+ foreach(QGestureRecognizer *r, newMaybeGestures) {
+ if (!maybeGestures.contains(r)) {
+ int timerId = startTimer(MaximumGestureRecognitionTimeout);
+ if (!timerId)
+ qWarning("QGestureManager: couldn't start timer!");
+ maybeGestures.insert(r, timerId);
+ }
+ }
+ if (!finishedGestures.isEmpty() || !activeGestures.isEmpty()) {
+ // gesture found!
+ ret = true;
+ DEBUG() << "QGestureManager: sending gesture event for: "
+ << activeGestures << " and " << finishedGestures;
+
+ QSet<QGesture*> gestures;
+ foreach(QGestureRecognizer *r, finishedGestures) {
+ if (QGesture *gesture = r->getGesture()) {
+ gestures << gesture;
+ gesture->d_func()->singleshot = true;
+ }
+ }
+ foreach(QGestureRecognizer *r, activeGestures) {
+ if (QGesture *gesture = r->getGesture()) {
+ gestures << gesture;
+ gesture->d_func()->singleshot = false;
+ }
+ }
+ Q_ASSERT(!gestures.isEmpty());
+ ret = sendGestureEvent(receiver, gestures);
+
+ if (!activeGestures.isEmpty()) {
+ DEBUG() << "QGestureManager: new state = Gesture";
+ state = Gesture;
+ } else if (!maybeGestures.isEmpty()) {
+ DEBUG() << "QGestureManager: new state = Maybe";
+ state = MaybeGesture;
+ } else {
+ DEBUG() << "QGestureManager: new state = NotGesture";
+ state = NotGesture;
+ }
+ } else if (!maybeGestures.isEmpty()) {
+ if (state != MaybeGesture) {
+ // We got a new set of events that look like a start
+ // of some gesture, so we switch to state MaybeGesture
+ // and wait for more events.
+ DEBUG() << "QGestureManager: new state = Maybe. Waiting for events";
+ state = MaybeGesture;
+ // start gesture timer
+ } else {
+ // we still not sure if it is a gesture or not.
+ }
+ } else if (state == MaybeGesture) {
+ // last time we thought it looks like gesture, but now we
+ // know for sure that it isn't.
+ DEBUG() << "QGestureManager: new state = NotGesture";
+ state = NotGesture;
+ }
+ foreach(QGestureRecognizer *r, finishedGestures)
+ r->reset();
+ foreach(QGestureRecognizer *r, cancelledGestures)
+ r->reset();
+ foreach(QGestureRecognizer *r, notGestures)
+ r->reset();
+ } else if (state == Gesture) {
+ DEBUG() << "QGestureManager: current event processing state: Gesture";
+ Q_ASSERT(!activeGestures.isEmpty());
+
+ foreach(QGestureRecognizer *r, recognizers) {
+ if (grabbedGestures.value(r->gestureType(), 0) <= 0)
+ continue;
+ QGestureRecognizer::Result result = r->filterEvent(event);
+ if (result == QGestureRecognizer::GestureStarted) {
+ DEBUG() << "QGestureManager: gesture started: " << r;
+ startedGestures << r;
+ } else if (result == QGestureRecognizer::GestureFinished) {
+ DEBUG() << "QGestureManager: gesture finished: " << r;
+ finishedGestures << r;
+ } else if (result == QGestureRecognizer::MaybeGesture) {
+ DEBUG() << "QGestureManager: maybe gesture: " << r;
+ newMaybeGestures << r;
+ } else if (result == QGestureRecognizer::NotGesture) {
+ // if it was an active gesture, but isn't a gesture anymore.
+ if (activeGestures.contains(r)) {
+ DEBUG() << "QGestureManager: cancelled gesture: " << r;
+ cancelledGestures << r;
+ } else {
+ DEBUG() << "QGestureManager: not gesture: " << r;
+ notGestures << r;
+ }
+ }
+ }
+ // 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()) {
+ killTimer(it.value());
+ maybeGestures.erase(it);
+ }
+ }
+ foreach(QGestureRecognizer *r, newMaybeGestures) {
+ if (!maybeGestures.contains(r)) {
+ int timerId = startTimer(MaximumGestureRecognitionTimeout);
+ if (!timerId)
+ qWarning("QGestureManager: couldn't start timer!");
+ maybeGestures.insert(r, timerId);
+ }
+ }
+ QSet<QGesture*> gestures;
+ if (!finishedGestures.isEmpty() || !activeGestures.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);
+ }
+ }
+ activeGestures -= finishedGestures;
+ foreach(QGestureRecognizer *r, activeGestures) {
+ if (QGesture *gesture = r->getGesture()) {
+ gestures << gesture;
+ gesture->d_func()->singleshot = false;
+ }
+ }
+ }
+ QSet<QString> cancelledGestureNames;
+ foreach(QGestureRecognizer *r, cancelledGestures)
+ cancelledGestureNames << r->gestureType();
+ if(!gestures.isEmpty()) {
+ ret = sendGestureEvent(receiver, gestures, cancelledGestureNames);
+ }
+
+ foreach(QGestureRecognizer *r, finishedGestures)
+ r->reset();
+ foreach(QGestureRecognizer *r, cancelledGestures)
+ r->reset();
+ foreach(QGestureRecognizer *r, notGestures)
+ r->reset();
+ if (!activeGestures.isEmpty()) {
+ // nothing changed, we are still handling a gesture
+ } else if (!maybeGestures.isEmpty()) {
+ DEBUG() << "QGestureManager: new state = Maybe. Waiting for events: " << maybeGestures;
+ state = MaybeGesture;
+ } else {
+ DEBUG() << "QGestureManager: new state = NotGesture";
+ state = NotGesture;
+ }
+ }
+
+ if (delayedPressTimer && state == Gesture) {
+ DEBUG() << "QGestureManager: gesture started. Forgetting about postponed mouse press event";
+ killTimer(delayedPressTimer);
+ delayedPressTimer = 0;
+ lastMousePressReceiver = 0;
+ } else if (delayedPressTimer && (state == NotGesture ||
+ event->type() == QEvent::MouseButtonRelease)) {
+ // not a gesture or released button too fast, so replay press
+ // event back.
+ DEBUG() << "QGestureManager: replaying mouse press event";
+ QMap<QGestureRecognizer*, int>::const_iterator it = maybeGestures.begin(),
+ e = maybeGestures.end();;
+ for (; it != e; ++it) {
+ it.key()->reset();
+ killTimer(it.value());
+ }
+ maybeGestures.clear();
+ state = NotGesture;
+
+ if (lastMousePressReceiver) {
+ QApplication::sendEvent(lastMousePressReceiver, &lastMousePressEvent);
+ if (event->type() == QEvent::MouseButtonRelease) {
+ QMouseEvent *me = static_cast<QMouseEvent*>(event);
+ QMouseEvent move(QEvent::MouseMove, me->pos(), me->globalPos(), me->button(),
+ me->buttons(), me->modifiers());
+ QApplication::sendEvent(lastMousePressReceiver, &move);
+ ret = false;
+ }
+ lastMousePressReceiver = 0;
+ }
+ lastMousePressReceiver = 0;
+ killTimer(delayedPressTimer);
+ delayedPressTimer = 0;
+ } else if (state == MaybeGesture && event->type() == QEvent::MouseButtonPress
+ && eventDeliveryDelayTimeout) {
+ // postpone the press event delivery until we know for
+ // sure whether it is a gesture.
+ DEBUG() << "QGestureManager: postponing mouse press event";
+ QMouseEvent *me = static_cast<QMouseEvent*>(event);
+ lastMousePressReceiver = receiver;
+ lastMousePressEvent = QMouseEvent(QEvent::MouseButtonPress, me->pos(),
+ me->globalPos(), me->button(),
+ me->buttons(), me->modifiers());
+ Q_ASSERT(delayedPressTimer == 0);
+ delayedPressTimer = startTimer(eventDeliveryDelayTimeout);
+ if (!delayedPressTimer)
+ qWarning("QGestureManager: couldn't start delayed press timer!");
+ ret = true;
+ }
+ if (delayedPressTimer && event->type() == QEvent::MouseMove) {
+ // if we have postponed a mouse press event, postpone all
+ // subsequent mouse move events as well.
+ ret = true;
+ }
+
+ lastPos = currentPos;
+ return ret;
+}
+
+void QGestureManager::timerEvent(QTimerEvent *event)
+{
+ if (event->timerId() == delayedPressTimer) {
+ DEBUG() << "QGestureManager: replaying mouse press event due to timeout";
+ // sanity checks
+ Q_ASSERT(state != Gesture);
+
+ QMap<QGestureRecognizer*, int>::const_iterator it = maybeGestures.begin(),
+ e = maybeGestures.end();;
+ for (; it != e; ++it) {
+ it.key()->reset();
+ killTimer(it.value());
+ }
+ maybeGestures.clear();
+ state = NotGesture;
+
+ if (lastMousePressReceiver) {
+ // we neither received a mouse release event nor gesture
+ // started, so we replay stored mouse press event.
+ QApplication::sendEvent(lastMousePressReceiver, &lastMousePressEvent);
+ lastMousePressReceiver = 0;
+ }
+
+ lastMousePressReceiver = 0;
+ killTimer(delayedPressTimer);
+ delayedPressTimer = 0;
+ } else {
+ // sanity checks, remove later
+ Q_ASSERT((state == Gesture && !activeGestures.isEmpty()) || (state != Gesture && activeGestures.isEmpty()));
+
+ typedef QMap<QGestureRecognizer*, int> MaybeGestureMap;
+ for (MaybeGestureMap::iterator it = maybeGestures.begin(), e = maybeGestures.end();
+ it != e; ++it) {
+ if (it.value() == event->timerId()) {
+ DEBUG() << "QGestureManager: gesture timeout.";
+ QGestureRecognizer *r = it.key();
+ r->reset();
+ maybeGestures.erase(it);
+ killTimer(event->timerId());
+ break;
+ }
+ }
+
+ if (state == MaybeGesture && maybeGestures.isEmpty()) {
+ DEBUG() << "QGestureManager: new state = NotGesture because of timeout";
+ state = NotGesture;
+ }
+ }
+}
+
+bool QGestureManager::inGestureMode()
+{
+ return state == Gesture;
+}
+
+void QGestureManager::recognizerStateChanged(QGestureRecognizer::Result result)
+{
+ QGestureRecognizer *recognizer = qobject_cast<QGestureRecognizer*>(sender());
+ if (!recognizer)
+ return;
+ if (qApp->d_func()->grabbedGestures.value(recognizer->gestureType(), 0) <= 0) {
+ recognizer->reset();
+ return;
+ }
+
+ switch (result) {
+ case QGestureRecognizer::GestureStarted:
+ case QGestureRecognizer::GestureFinished: {
+ if (result == QGestureRecognizer::GestureStarted) {
+ DEBUG() << "QGestureManager: gesture started: " << recognizer;
+ activeGestures << recognizer;
+ DEBUG() << "QGestureManager: new state = Gesture";
+ state = Gesture;
+ } else {
+ DEBUG() << "QGestureManager: gesture finished: " << recognizer;
+ }
+ if (maybeGestures.contains(recognizer)) {
+ killTimer(maybeGestures.value(recognizer));
+ maybeGestures.remove(recognizer);
+ }
+ QSet<QGesture*> gestures;
+ if (QGesture *gesture = recognizer->getGesture())
+ gestures << gesture;
+ if(!gestures.isEmpty()) {
+ //FIXME: sendGestureEvent(targetWidget, gestures);
+ }
+ if (result == QGestureRecognizer::GestureFinished)
+ recognizer->reset();
+ }
+ break;
+ case QGestureRecognizer::MaybeGesture: {
+ DEBUG() << "QGestureManager: maybe gesture: " << recognizer;
+ if (activeGestures.contains(recognizer)) {
+ //FIXME: sendGestureEvent(targetWidget, QSet<QGesture*>(), QSet<QString>() << recognizer->gestureType());
+ }
+ if (!maybeGestures.contains(recognizer)) {
+ int timerId = startTimer(MaximumGestureRecognitionTimeout);
+ if (!timerId)
+ qWarning("QGestureManager: couldn't start timer!");
+ maybeGestures.insert(recognizer, timerId);
+ }
+ }
+ break;
+ case QGestureRecognizer::NotGesture:
+ DEBUG() << "QGestureManager: not gesture: " << recognizer;
+ if (maybeGestures.contains(recognizer)) {
+ killTimer(maybeGestures.value(recognizer));
+ maybeGestures.remove(recognizer);
+ }
+ recognizer->reset();
+ break;
+ default:
+ Q_ASSERT(false);
+ }
+
+ if (delayedPressTimer && state == Gesture) {
+ killTimer(delayedPressTimer);
+ delayedPressTimer = 0;
+ }
+}
+
+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)
+{
+ 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(QSet<QGesture*>::const_iterator it = gestures.begin(), e = gestures.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);
+ // find the target widget
+ QWidget *w = receiver;
+ QPoint offset;
+ while (w) {
+ 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].insert(g);
+ }
+
+ QSet<QGesture*> ignoredGestures;
+ 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);
+ 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);
+ }
+ }
+ }
+ }
+ // try to send all gestures that were ignored to the next parent
+ return sendGestureEvent(0, ignoredGestures, cancelled) || ret;
+}
+
+int QGestureManager::eventDeliveryDelay() const
+{
+ return eventDeliveryDelayTimeout;
+}
+
+void QGestureManager::setEventDeliveryDelay(int ms)
+{
+ eventDeliveryDelayTimeout = ms;
+}
+
+int QGestureManager::makeGestureId(const QString &name)
+{
+ gestureIdMap[++lastGestureId] = name;
+ return lastGestureId;
+}
+
+void QGestureManager::releaseGestureId(int gestureId)
+{
+ gestureIdMap.remove(gestureId);
+}
+
+QString QGestureManager::gestureNameFromId(int gestureId) const
+{
+ return gestureIdMap.value(gestureId);
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qgesturemanager_p.cpp"
+
diff --git a/src/gui/kernel/qgesturemanager_p.h b/src/gui/kernel/qgesturemanager_p.h
new file mode 100644
index 0000000..963edf9
--- /dev/null
+++ b/src/gui/kernel/qgesturemanager_p.h
@@ -0,0 +1,125 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial Usage
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QGESTUREMANAGER_P_H
+#define QGESTUREMANAGER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qlist.h"
+#include "qset.h"
+#include "qevent.h"
+#include "qbasictimer.h"
+#include "qpointer.h"
+
+#include "qgesturerecognizer.h"
+
+QT_BEGIN_NAMESPACE
+
+class QWidget;
+class Q_GUI_EXPORT QGestureManager : public QObject
+{
+ Q_OBJECT
+public:
+ QGestureManager(QObject *parent);
+
+ int eventDeliveryDelay() const;
+ void setEventDeliveryDelay(int ms);
+
+ void addRecognizer(QGestureRecognizer *recognizer);
+ void removeRecognizer(QGestureRecognizer *recognizer);
+
+ bool filterEvent(QWidget *receiver, QEvent *event);
+ bool inGestureMode();
+
+ int makeGestureId(const QString &name);
+ void releaseGestureId(int gestureId);
+ QString gestureNameFromId(int gestureId) const;
+
+ // declared in qapplication.cpp
+ static QGestureManager* instance();
+
+protected:
+ void timerEvent(QTimerEvent *event);
+
+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;
+
+ QPoint lastPos;
+
+ int eventDeliveryDelayTimeout;
+ int delayedPressTimer;
+ QPointer<QWidget> lastMousePressReceiver;
+ QMouseEvent lastMousePressEvent;
+
+ QMap<int, QString> gestureIdMap;
+ int lastGestureId;
+
+ enum State {
+ Gesture,
+ NotGesture,
+ MaybeGesture // that mean timers are up and waiting for some
+ // more events, and input events are handled by
+ // gesture recognizer explicitely
+ } state;
+};
+
+QT_END_NAMESPACE
+
+#endif // QGESTUREMANAGER_P_H
diff --git a/src/gui/kernel/qgesturerecognizer.cpp b/src/gui/kernel/qgesturerecognizer.cpp
new file mode 100644
index 0000000..41160cd
--- /dev/null
+++ b/src/gui/kernel/qgesturerecognizer.cpp
@@ -0,0 +1,156 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial Usage
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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 "qgesturerecognizer.h"
+#include "qgesture.h"
+
+#include <private/qobject_p.h>
+#include <private/qgesturerecognizer_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QString qt_getStandardGestureTypeName(Qt::GestureType gestureType);
+
+/*!
+ \class QGestureRecognizer
+ \since 4.6
+
+ \brief The QGestureRecognizer class is the base class for
+ implementing custom gestures.
+
+ This is a base class, to create a custom gesture type, you should
+ subclass it and implement its pure virtual functions.
+
+ Usually gesture recognizer implements state machine, storing its
+ state internally in the recognizer object. The recognizer receives
+ input events through the \l{QGestureRecognizer::}{filterEvent()}
+ virtual function and decides whether the parsed event should
+ change the state of the recognizer - i.e. if the event starts or
+ ends a gesture or if it isn't related to gesture at all.
+*/
+
+/*!
+ \enum QGestureRecognizer::Result
+ \since 4.6
+
+ This enum type defines the state of the gesture recognizer.
+
+ \value Ignore Gesture recognizer ignores the event.
+
+ \value NotGesture Not a gesture.
+
+ \value GestureStarted The continuous gesture has started. When the
+ recognizer is in this state, a \l{QGestureEvent}{gesture event}
+ containing QGesture objects returned by the
+ \l{QGestureRecognizer::}{getGesture()} will be sent to a widget.
+
+ \value GestureFinished The gesture has ended. A
+ \l{QGestureEvent}{gesture event} will be sent to a widget.
+
+ \value MaybeGesture Gesture recognizer hasn't decided yet if a
+ gesture has started, but it might start soon after the following
+ events are received by the recognizer. This means that gesture
+ manager shouldn't reset() the internal state of the gesture
+ recognizer.
+*/
+
+/*! \fn QGestureRecognizer::Result QGestureRecognizer::filterEvent(const QEvent *event)
+
+ This is a pure virtual function that needs to be implemented in
+ subclasses.
+
+ Parses input \a event and returns the result, which specifies if
+ the event sequence is a gesture or not.
+*/
+
+/*! \fn QGesture* QGestureRecognizer::getGesture()
+
+ Returns a gesture object that will be send to the widget. This
+ function is called when the gesture recognizer changed its state
+ to QGestureRecognizer::GestureStarted or
+ QGestureRecognizer::GestureFinished.
+
+ The gesture object is owned by the recognizer itself.
+*/
+
+/*! \fn void QGestureRecognizer::reset()
+
+ Resets the internal state of the gesture recognizer.
+*/
+
+/*! \fn void QGestureRecognizer::stateChanged(QGestureRecognizer::Result result)
+
+ The gesture recognizer might emit the stateChanged() signal when
+ the gesture state changes asynchronously, i.e. without any event
+ being filtered through filterEvent().
+*/
+
+QGestureRecognizerPrivate::QGestureRecognizerPrivate()
+ : gestureType(Qt::UnknownGesture)
+{
+}
+
+/*!
+ Creates a new gesture recognizer object that handles gestures of
+ the specific \a gestureType as a child of \a parent.
+
+ \sa QApplication::addGestureRecognizer(),
+ QApplication::removeGestureRecognizer(),
+*/
+QGestureRecognizer::QGestureRecognizer(const QString &gestureType, QObject *parent)
+ : QObject(*new QGestureRecognizerPrivate, parent)
+{
+ Q_D(QGestureRecognizer);
+ d->customGestureType = gestureType;
+}
+
+/*!
+ Returns the name of the gesture that is handled by the recognizer.
+*/
+QString QGestureRecognizer::gestureType() const
+{
+ Q_D(const QGestureRecognizer);
+ if (d->gestureType == Qt::UnknownGesture)
+ return d->customGestureType;
+ return qt_getStandardGestureTypeName(d->gestureType);
+}
+
+QT_END_NAMESPACE
diff --git a/src/gui/kernel/qgesturerecognizer.h b/src/gui/kernel/qgesturerecognizer.h
new file mode 100644
index 0000000..8bc8b97
--- /dev/null
+++ b/src/gui/kernel/qgesturerecognizer.h
@@ -0,0 +1,87 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial Usage
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QGESTURERECOGNIZER_H
+#define QGESTURERECOGNIZER_H
+
+#include "qevent.h"
+#include "qlist.h"
+#include "qset.h"
+
+QT_BEGIN_NAMESPACE
+
+class QGesture;
+class QGestureRecognizerPrivate;
+class Q_GUI_EXPORT QGestureRecognizer : public QObject
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QGestureRecognizer)
+
+public:
+ enum Result
+ {
+ Ignore,
+ NotGesture,
+ GestureStarted,
+ GestureFinished,
+ MaybeGesture
+ };
+
+ explicit QGestureRecognizer(const QString &gestureType, QObject *parent = 0);
+
+ QString gestureType() const;
+
+ virtual QGestureRecognizer::Result filterEvent(const QEvent* event) = 0;
+ virtual QGesture* getGesture() = 0;
+ virtual void reset() = 0;
+
+signals:
+ void stateChanged(QGestureRecognizer::Result result);
+
+private:
+ friend class QDoubleTapGestureRecognizer;
+ friend class QTapAndHoldGestureRecognizer;
+ friend class QGestureRecognizerPan;
+};
+
+QT_END_NAMESPACE
+
+#endif // QGESTURERECOGNIZER_P_H
diff --git a/src/gui/kernel/qgesturerecognizer_p.h b/src/gui/kernel/qgesturerecognizer_p.h
new file mode 100644
index 0000000..4d80b99
--- /dev/null
+++ b/src/gui/kernel/qgesturerecognizer_p.h
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial Usage
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QGESTURERECOGNIZER_P_H
+#define QGESTURERECOGNIZER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qobject_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QGestureRecognizerPrivate : public QObjectPrivate
+{
+public:
+ QGestureRecognizerPrivate();
+
+public:
+ Qt::GestureType gestureType;
+ QString customGestureType;
+};
+
+QT_END_NAMESPACE
+
+#endif // QGESTURERECOGNIZER_P_H
diff --git a/src/gui/kernel/qgesturestandardrecognizers.cpp b/src/gui/kernel/qgesturestandardrecognizers.cpp
new file mode 100644
index 0000000..f6b8b90
--- /dev/null
+++ b/src/gui/kernel/qgesturestandardrecognizers.cpp
@@ -0,0 +1,306 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial Usage
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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 "qgesturestandardrecognizers_p.h"
+#include "qgesture_p.h"
+#include "qgesturerecognizer_p.h"
+
+// #define GESTURE_RECOGNIZER_DEBUG
+#ifndef GESTURE_RECOGNIZER_DEBUG
+# define DEBUG if (0) qDebug
+#else
+# define DEBUG qDebug
+#endif
+
+QT_BEGIN_NAMESPACE
+
+QString qt_getStandardGestureTypeName(Qt::GestureType gestureType)
+{
+ switch (gestureType) {
+ case Qt::TapGesture:
+ return QLatin1String("__QTapGesture");
+ case Qt::DoubleTapGesture:
+ return QLatin1String("__QDoubleTapGesture");
+ case Qt::TrippleTapGesture:
+ return QLatin1String("__QTrippleTapGesture");
+ case Qt::TapAndHoldGesture:
+ return QLatin1String("__QTapAndHoldGesture");
+ case Qt::PanGesture:
+ return QLatin1String("__QPanGesture");
+ case Qt::PinchGesture:
+ return QLatin1String("__QPinchGesture");
+ case Qt::UnknownGesture:
+ break;
+ }
+ qFatal("QGestureRecognizer::gestureType: got an unhandled gesture type.");
+ return QLatin1String("__unknown_gesture");
+}
+
+//
+// QGestureRecognizerPan
+//
+
+QGestureRecognizerPan::QGestureRecognizerPan(QObject *parent)
+ : QGestureRecognizer(QString(), parent),
+ mousePressed(false), gestureState(Qt::NoGesture),
+ lastDirection(Qt::NoDirection), currentDirection(Qt::NoDirection)
+{
+ Q_D(QGestureRecognizer);
+ d->gestureType = Qt::PanGesture;
+}
+
+QGestureRecognizer::Result QGestureRecognizerPan::filterEvent(const QEvent *event)
+{
+ if (event->type() == QEvent::MouseButtonPress) {
+ const QMouseEvent *ev = static_cast<const QMouseEvent*>(event);
+ if (currentDirection != Qt::NoDirection) {
+ DEBUG() << "Pan: MouseButtonPress: fail. another press during pan";
+ reset();
+ return QGestureRecognizer::NotGesture;
+ }
+ if (ev->button() != Qt::LeftButton) {
+ return QGestureRecognizer::NotGesture;
+ }
+ DEBUG() << "Pan: MouseButtonPress: maybe gesture started";
+ mousePressed = true;
+ pressedPos = lastPos = currentPos = ev->pos();
+ return QGestureRecognizer::MaybeGesture;
+ } else if (event->type() == QEvent::MouseButtonRelease) {
+ const QMouseEvent *ev = static_cast<const QMouseEvent*>(event);
+ if (mousePressed && currentDirection != Qt::NoDirection
+ && ev->button() == Qt::LeftButton) {
+ DEBUG() << "Pan: MouseButtonRelease: pan detected";
+ gestureState = Qt::GestureFinished;
+ currentPos = ev->pos();
+ internalReset();
+ return QGestureRecognizer::GestureFinished;
+ }
+ DEBUG() << "Pan: MouseButtonRelease: some weird release detected, ignoring";
+ reset();
+ return QGestureRecognizer::NotGesture;
+ } else if (event->type() == QEvent::MouseMove) {
+ if (!mousePressed)
+ return QGestureRecognizer::NotGesture;
+ const QMouseEvent *ev = static_cast<const QMouseEvent*>(event);
+ lastPos = currentPos;
+ currentPos = ev->pos();
+ Qt::DirectionType newDirection =
+ simpleRecognizer.addPosition(ev->pos()).direction;
+ DEBUG() << "Pan: MouseMove: simplerecognizer result = " << newDirection;
+ QGestureRecognizer::Result result = QGestureRecognizer::NotGesture;
+ if (currentDirection == Qt::NoDirection) {
+ if (newDirection == Qt::NoDirection) {
+ result = QGestureRecognizer::MaybeGesture;
+ } else {
+ result = QGestureRecognizer::GestureStarted;
+ gestureState = Qt::GestureStarted;
+ }
+ } else {
+ result = QGestureRecognizer::GestureStarted;
+ gestureState = Qt::GestureUpdated;
+ }
+ if (newDirection != Qt::NoDirection) {
+ if (currentDirection != newDirection)
+ lastDirection = currentDirection;
+ currentDirection = newDirection;
+ }
+ return result;
+ }
+ return QGestureRecognizer::Ignore;
+}
+
+QGesture* QGestureRecognizerPan::getGesture()
+{
+ if (currentDirection == Qt::NoDirection)
+ return 0;
+ QPanningGesturePrivate *d = gesture.d_func();
+ d->startPos = pressedPos;
+ d->lastPos = lastPos;
+ d->pos = currentPos;
+ d->hotSpot = pressedPos;
+ d->state = gestureState;
+ d->lastDirection = lastDirection;
+ d->direction = currentDirection;
+
+ return &gesture;
+}
+
+void QGestureRecognizerPan::reset()
+{
+ mousePressed = false;
+ lastDirection = Qt::NoDirection;
+ currentDirection = Qt::NoDirection;
+ gestureState = Qt::NoGesture;
+ diagonalRecognizer.reset();
+ simpleRecognizer.reset();
+}
+
+void QGestureRecognizerPan::internalReset()
+{
+ mousePressed = false;
+ diagonalRecognizer.reset();
+ simpleRecognizer.reset();
+}
+
+
+//
+// QDoubleTapGestureRecognizer
+//
+QDoubleTapGestureRecognizer::QDoubleTapGestureRecognizer(QObject *parent)
+ : QGestureRecognizer(QString(), parent),
+ gesture(0, qt_getStandardGestureTypeName(Qt::DoubleTapGesture))
+{
+ Q_D(QGestureRecognizer);
+ d->gestureType = Qt::DoubleTapGesture;
+}
+
+QGestureRecognizer::Result QDoubleTapGestureRecognizer::filterEvent(const QEvent *event)
+{
+ if (event->type() == QEvent::MouseButtonPress) {
+ const QMouseEvent *ev = static_cast<const QMouseEvent*>(event);
+ if (pressedPosition.isNull()) {
+ pressedPosition = ev->pos();
+ return QGestureRecognizer::MaybeGesture;
+ } else if ((pressedPosition - ev->pos()).manhattanLength() < 10) {
+ return QGestureRecognizer::GestureFinished;
+ }
+ return QGestureRecognizer::NotGesture;
+ } else if (event->type() == QEvent::MouseButtonRelease) {
+ const QMouseEvent *ev = static_cast<const QMouseEvent*>(event);
+ if (!pressedPosition.isNull() && (pressedPosition - ev->pos()).manhattanLength() < 10)
+ return QGestureRecognizer::MaybeGesture;
+ return QGestureRecognizer::NotGesture;
+ } else if (event->type() == QEvent::MouseButtonDblClick) {
+ const QMouseEvent *ev = static_cast<const QMouseEvent*>(event);
+ pressedPosition = ev->pos();
+ return QGestureRecognizer::GestureFinished;
+ }
+ return QGestureRecognizer::NotGesture;
+}
+
+QGesture* QDoubleTapGestureRecognizer::getGesture()
+{
+ QGesturePrivate *d = gesture.d_func();
+ d->startPos = pressedPosition;
+ d->lastPos = pressedPosition;
+ d->pos = pressedPosition;
+ d->hotSpot = pressedPosition;
+ d->state = Qt::GestureFinished;
+ return &gesture;
+}
+
+void QDoubleTapGestureRecognizer::reset()
+{
+ pressedPosition = QPoint();
+}
+
+//
+// QTapAndHoldGestureRecognizer
+//
+const int QTapAndHoldGestureRecognizer::iterationCount = 40;
+const int QTapAndHoldGestureRecognizer::iterationTimeout = 50;
+
+QTapAndHoldGestureRecognizer::QTapAndHoldGestureRecognizer(QObject *parent)
+ : QGestureRecognizer(QString(), parent),
+ gesture(0, qt_getStandardGestureTypeName(Qt::TapAndHoldGesture)),
+ iteration(0)
+{
+ Q_D(QGestureRecognizer);
+ d->gestureType = Qt::TapAndHoldGesture;
+}
+
+QGestureRecognizer::Result QTapAndHoldGestureRecognizer::filterEvent(const QEvent *event)
+{
+ if (event->type() == QEvent::MouseButtonPress) {
+ const QMouseEvent *ev = static_cast<const QMouseEvent*>(event);
+ if (timer.isActive())
+ timer.stop();
+ timer.start(QTapAndHoldGestureRecognizer::iterationTimeout, this);
+ pressedPosition = ev->pos();
+ return QGestureRecognizer::MaybeGesture;
+ } else if (event->type() == QEvent::MouseMove) {
+ const QMouseEvent *ev = static_cast<const QMouseEvent*>(event);
+ if ((pressedPosition - ev->pos()).manhattanLength() < 15)
+ return QGestureRecognizer::GestureStarted;
+ else
+ return QGestureRecognizer::NotGesture;
+ } else if (event->type() == QEvent::MouseButtonRelease) {
+ timer.stop();
+ return QGestureRecognizer::NotGesture;
+ }
+ return QGestureRecognizer::Ignore;
+}
+
+void QTapAndHoldGestureRecognizer::timerEvent(QTimerEvent *event)
+{
+ if (event->timerId() != timer.timerId())
+ return;
+ if (iteration == QTapAndHoldGestureRecognizer::iterationCount) {
+ timer.stop();
+ emit stateChanged(QGestureRecognizer::GestureFinished);
+ } else {
+ emit stateChanged(QGestureRecognizer::GestureStarted);
+ }
+ ++iteration;
+}
+
+QGesture* QTapAndHoldGestureRecognizer::getGesture()
+{
+ QGesturePrivate *d = gesture.d_func();
+ d->startPos = pressedPosition;
+ d->lastPos = pressedPosition;
+ d->pos = pressedPosition;
+ d->hotSpot = pressedPosition;
+ if (iteration >= QTapAndHoldGestureRecognizer::iterationCount)
+ d->state = Qt::GestureFinished;
+ else
+ d->state = iteration == 0 ? Qt::GestureStarted : Qt::GestureUpdated;
+ return &gesture;
+}
+
+void QTapAndHoldGestureRecognizer::reset()
+{
+ pressedPosition = QPoint();
+ timer.stop();
+ iteration = 0;
+}
+
+QT_END_NAMESPACE
diff --git a/src/gui/kernel/qgesturestandardrecognizers_p.h b/src/gui/kernel/qgesturestandardrecognizers_p.h
new file mode 100644
index 0000000..81db3e6
--- /dev/null
+++ b/src/gui/kernel/qgesturestandardrecognizers_p.h
@@ -0,0 +1,130 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial Usage
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QGESTURESTANDARDRECOGNIZERS_P_H
+#define QGESTURESTANDARDRECOGNIZERS_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qevent.h"
+#include "qbasictimer.h"
+#include "qdebug.h"
+
+#include "qgesturerecognizer.h"
+#include "private/qdirectionrecognizer_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QGestureRecognizerPan : public QGestureRecognizer
+{
+ Q_OBJECT
+public:
+ QGestureRecognizerPan(QObject *parent);
+
+ QGestureRecognizer::Result filterEvent(const QEvent *event);
+ QGesture* getGesture();
+ void reset();
+
+private:
+ void internalReset();
+
+ QPanningGesture gesture;
+
+ QPoint pressedPos;
+ QPoint lastPos;
+ QPoint currentPos;
+ bool mousePressed;
+ Qt::GestureState gestureState;
+ Qt::DirectionType lastDirection;
+ Qt::DirectionType currentDirection;
+ QDirectionDiagonalRecognizer diagonalRecognizer;
+ QDirectionSimpleRecognizer simpleRecognizer;
+};
+
+class QDoubleTapGestureRecognizer : public QGestureRecognizer
+{
+ Q_OBJECT
+public:
+ QDoubleTapGestureRecognizer(QObject *parent);
+
+ QGestureRecognizer::Result filterEvent(const QEvent *event);
+ QGesture* getGesture();
+ void reset();
+
+private:
+ QGesture gesture;
+ QPoint pressedPosition;
+};
+
+class QTapAndHoldGestureRecognizer : public QGestureRecognizer
+{
+ Q_OBJECT
+public:
+ QTapAndHoldGestureRecognizer(QObject *parent);
+
+ QGestureRecognizer::Result filterEvent(const QEvent *event);
+ QGesture* getGesture();
+ void reset();
+
+protected:
+ void timerEvent(QTimerEvent *event);
+
+private:
+ QGesture gesture;
+ QPoint pressedPosition;
+ QBasicTimer timer;
+ int iteration;
+ static const int iterationCount;
+ static const int iterationTimeout;
+};
+
+QT_END_NAMESPACE
+
+#endif // QGESTURESTANDARDRECOGNIZERS_P_H
diff --git a/src/gui/kernel/qwidget.cpp b/src/gui/kernel/qwidget.cpp
index ab529fe..3a146e5 100644
--- a/src/gui/kernel/qwidget.cpp
+++ b/src/gui/kernel/qwidget.cpp
@@ -109,6 +109,7 @@
#include "private/qabstractscrollarea_p.h"
#include "private/qgraphicssystem_p.h"
+#include "private/qgesturemanager_p.h"
// widget/widget data creation count
//#define QWIDGET_EXTRA_DEBUG
@@ -127,6 +128,8 @@ Q_GUI_EXPORT void qt_x11_set_global_double_buffer(bool enable)
}
#endif
+QString qt_getStandardGestureTypeName(Qt::GestureType);
+
static inline bool qRectIntersects(const QRect &r1, const QRect &r2)
{
return (qMax(r1.left(), r2.left()) <= qMin(r1.right(), r2.right()) &&
@@ -7460,10 +7463,14 @@ bool QWidget::event(QEvent *event)
case QEvent::MouseButtonRelease:
case QEvent::MouseButtonDblClick:
case QEvent::MouseMove:
+ case QEvent::TouchBegin:
+ case QEvent::TouchUpdate:
+ case QEvent::TouchEnd:
case QEvent::ContextMenu:
#ifndef QT_NO_WHEELEVENT
case QEvent::Wheel:
#endif
+ case QEvent::Gesture:
return false;
default:
break;
@@ -7859,6 +7866,9 @@ bool QWidget::event(QEvent *event)
d->needWindowChange = false;
break;
#endif
+ case QEvent::Gesture:
+ event->ignore();
+ break;
#ifndef QT_NO_PROPERTIES
case QEvent::DynamicPropertyChange: {
const QByteArray &propName = static_cast<QDynamicPropertyChangeEvent *>(event)->propertyName();
@@ -10948,6 +10958,85 @@ QWindowSurface *QWidget::windowSurface() const
return bs ? bs->windowSurface : 0;
}
+/*!
+ \since 4.6
+
+ Subscribes the widget to the specified \a gesture type.
+
+ Returns the id of the gesture.
+
+ \sa releaseGesture(), setGestureEnabled()
+*/
+int QWidget::grabGesture(const QString &gesture)
+{
+ Q_D(QWidget);
+ return d->grabGesture(QGestureManager::instance()->makeGestureId(gesture));
+}
+
+int QWidgetPrivate::grabGesture(int gestureId)
+{
+ gestures << gestureId;
+ ++qApp->d_func()->grabbedGestures[QGestureManager::instance()->gestureNameFromId(gestureId)];
+ return gestureId;
+}
+
+bool QWidgetPrivate::releaseGesture(int gestureId)
+{
+ QApplicationPrivate *qAppPriv = qApp->d_func();
+ if (gestures.contains(gestureId)) {
+ QString name = QGestureManager::instance()->gestureNameFromId(gestureId);
+ Q_ASSERT(qAppPriv->grabbedGestures[name] > 0);
+ --qAppPriv->grabbedGestures[name];
+ gestures.remove(gestureId);
+ return true;
+ }
+ return false;
+}
+
+/*!
+ \since 4.6
+
+ Subscribes the widget to the specified \a gesture type.
+
+ Returns the id of the gesture.
+
+ \sa releaseGesture(), setGestureEnabled()
+*/
+int QWidget::grabGesture(Qt::GestureType gesture)
+{
+ return grabGesture(qt_getStandardGestureTypeName(gesture));
+}
+
+/*!
+ \since 4.6
+
+ Unsubscribes the widget from a gesture, which is specified by the
+ \a gestureId.
+
+ \sa grabGesture(), setGestureEnabled()
+*/
+void QWidget::releaseGesture(int gestureId)
+{
+ Q_D(QWidget);
+ if (d->releaseGesture(gestureId))
+ QGestureManager::instance()->releaseGestureId(gestureId);
+}
+
+/*!
+ \since 4.6
+
+ If \a enable is true, the gesture with the given \a gestureId is
+ enabled; otherwise the gesture is disabled.
+
+ The id of the gesture is returned by the grabGesture().
+
+ \sa grabGesture(), releaseGesture()
+*/
+void QWidget::setGestureEnabled(int gestureId, bool enable)
+{
+ //###
+}
+
void QWidgetPrivate::getLayoutItemMargins(int *left, int *top, int *right, int *bottom) const
{
if (left)
diff --git a/src/gui/kernel/qwidget.h b/src/gui/kernel/qwidget.h
index 6703d26..80d4f3e 100644
--- a/src/gui/kernel/qwidget.h
+++ b/src/gui/kernel/qwidget.h
@@ -59,6 +59,8 @@
#include <QtGui/qevent.h>
#endif
+#include <QtGui/qgesture.h>
+
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
@@ -90,6 +92,7 @@ class QDragLeaveEvent;
class QDropEvent;
class QShowEvent;
class QHideEvent;
+class QGestureEvent;
class QInputContext;
class QIcon;
class QWindowSurface;
@@ -610,6 +613,11 @@ public:
void setWindowSurface(QWindowSurface *surface);
QWindowSurface *windowSurface() const;
+ int grabGesture(const QString &gesture);
+ int grabGesture(Qt::GestureType gesture);
+ void releaseGesture(int gestureId);
+ void setGestureEnabled(int gestureId, bool enable = true);
+
Q_SIGNALS:
void customContextMenuRequested(const QPoint &pos);
@@ -745,6 +753,7 @@ private:
friend bool isWidgetOpaque(const QWidget *);
friend class QGLWidgetPrivate;
#endif
+ friend class QGestureManager;
#ifdef Q_WS_X11
friend void qt_net_update_user_time(QWidget *tlw, unsigned long timestamp);
friend void qt_net_remove_user_time(QWidget *tlw);
diff --git a/src/gui/kernel/qwidget_p.h b/src/gui/kernel/qwidget_p.h
index bf4f091..a603b44 100644
--- a/src/gui/kernel/qwidget_p.h
+++ b/src/gui/kernel/qwidget_p.h
@@ -57,9 +57,11 @@
#include "private/qobject_p.h"
#include "QtCore/qrect.h"
#include "QtCore/qlocale.h"
+#include "QtCore/qset.h"
#include "QtGui/qregion.h"
#include "QtGui/qsizepolicy.h"
#include "QtGui/qstyle.h"
+#include "QtGui/qevent.h"
#ifdef Q_WS_WIN
#include "QtCore/qt_windows.h"
@@ -516,6 +518,10 @@ public:
QList<QAction*> actions;
#endif
+ QSet<int> gestures;
+ int grabGesture(int gestureId);
+ bool releaseGesture(int gestureId);
+
// Bit fields.
uint high_attributes[3]; // the low ones are in QWidget::widget_attributes
QPalette::ColorRole fg_role : 8;
diff --git a/src/gui/kernel/qwidget_win.cpp b/src/gui/kernel/qwidget_win.cpp
index 0f341fd..d381cb2 100644
--- a/src/gui/kernel/qwidget_win.cpp
+++ b/src/gui/kernel/qwidget_win.cpp
@@ -497,6 +497,10 @@ void QWidgetPrivate::create_sys(WId window, bool initializeWindow, bool destroyO
}
}
+ // ### don't always register for touch events
+ if (id && QApplicationPrivate::RegisterTouchWindow && !desktop)
+ QApplicationPrivate::RegisterTouchWindow(id, 0);
+
q->setAttribute(Qt::WA_WState_Created); // accept move/resize events
hd = 0; // no display context
diff --git a/src/gui/widgets/qabstractscrollarea.cpp b/src/gui/widgets/qabstractscrollarea.cpp
index 9886969..190dbb5 100644
--- a/src/gui/widgets/qabstractscrollarea.cpp
+++ b/src/gui/widgets/qabstractscrollarea.cpp
@@ -908,6 +908,7 @@ bool QAbstractScrollArea::event(QEvent *e)
case QEvent::DragMove:
case QEvent::DragLeave:
#endif
+ case QEvent::Gesture:
return false;
case QEvent::StyleChange:
case QEvent::LayoutDirectionChange:
diff --git a/src/network/kernel/qauthenticator.cpp b/src/network/kernel/qauthenticator.cpp
index 33795aa..a66672d 100644
--- a/src/network/kernel/qauthenticator.cpp
+++ b/src/network/kernel/qauthenticator.cpp
@@ -52,7 +52,7 @@
QT_BEGIN_NAMESPACE
-#include "../../3rdparty/des/des.cpp"
+#include <../../3rdparty/des/des.cpp>
static QByteArray qNtlmPhase1();
static QByteArray qNtlmPhase3(QAuthenticatorPrivate *ctx, const QByteArray& phase2data);