summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/corelib/global/qnamespace.h50
-rw-r--r--src/corelib/kernel/qcoreevent.cpp9
-rw-r--r--src/corelib/kernel/qcoreevent.h15
-rw-r--r--src/gui/graphicsview/qgraphicsitem.cpp142
-rw-r--r--src/gui/graphicsview/qgraphicsitem.h7
-rw-r--r--src/gui/graphicsview/qgraphicsitem_p.h42
-rw-r--r--src/gui/graphicsview/qgraphicsproxywidget.cpp16
-rw-r--r--src/gui/graphicsview/qgraphicsscene.cpp339
-rw-r--r--src/gui/graphicsview/qgraphicsscene.h2
-rw-r--r--src/gui/graphicsview/qgraphicsscene_p.h25
-rw-r--r--src/gui/graphicsview/qgraphicssceneevent.cpp672
-rw-r--r--src/gui/graphicsview/qgraphicssceneevent.h129
-rw-r--r--src/gui/graphicsview/qgraphicsview.cpp98
-rw-r--r--src/gui/graphicsview/qgraphicsview_p.h12
-rw-r--r--src/gui/kernel/kernel.pri17
-rw-r--r--src/gui/kernel/qapplication.cpp362
-rw-r--r--src/gui/kernel/qapplication.h9
-rw-r--r--src/gui/kernel/qapplication_mac.mm5
-rw-r--r--src/gui/kernel/qapplication_p.h45
-rw-r--r--src/gui/kernel/qapplication_qws.cpp5
-rw-r--r--src/gui/kernel/qapplication_win.cpp110
-rw-r--r--src/gui/kernel/qapplication_x11.cpp7
-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.cpp462
-rw-r--r--src/gui/kernel/qevent.h118
-rw-r--r--src/gui/kernel/qevent_p.h29
-rw-r--r--src/gui/kernel/qgesture.cpp315
-rw-r--r--src/gui/kernel/qgesture.h154
-rw-r--r--src/gui/kernel/qgesture_p.h113
-rw-r--r--src/gui/kernel/qgesturemanager.cpp643
-rw-r--r--src/gui/kernel/qgesturemanager_p.h126
-rw-r--r--src/gui/kernel/qgesturerecognizer.cpp159
-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.cpp113
-rw-r--r--src/gui/kernel/qwidget.h9
-rw-r--r--src/gui/kernel/qwidget_p.h8
-rw-r--r--src/gui/kernel/qwidget_win.cpp13
-rw-r--r--src/gui/widgets/qabstractscrollarea.cpp1
-rw-r--r--src/network/kernel/qauthenticator.cpp2
-rw-r--r--src/testlib/qtest_gui.h1
-rw-r--r--src/testlib/qtesttouch.h149
-rw-r--r--src/testlib/testlib.pro3
47 files changed, 5516 insertions, 68 deletions
diff --git a/src/corelib/global/qnamespace.h b/src/corelib/global/qnamespace.h
index 9e53d89..78e2b08 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
};
@@ -1542,6 +1545,52 @@ public:
BottomLeftSection,
TitleBarArea // For move
};
+
+ enum TouchPointState {
+ TouchPointPressed = 0x01,
+ TouchPointMoved = 0x02,
+ TouchPointStationary = 0x04,
+ TouchPointReleased = 0x08
+ };
+ Q_DECLARE_FLAGS(TouchPointStates, TouchPointState)
+
+ 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
;
@@ -1561,6 +1610,7 @@ Q_DECLARE_OPERATORS_FOR_FLAGS(Qt::DropActions)
Q_DECLARE_OPERATORS_FOR_FLAGS(Qt::ItemFlags)
Q_DECLARE_OPERATORS_FOR_FLAGS(Qt::MatchFlags)
Q_DECLARE_OPERATORS_FOR_FLAGS(Qt::TextInteractionFlags)
+Q_DECLARE_OPERATORS_FOR_FLAGS(Qt::TouchPointStates)
typedef bool (*qInternalCallback)(void **);
diff --git a/src/corelib/kernel/qcoreevent.cpp b/src/corelib/kernel/qcoreevent.cpp
index d6b0174..d28d34e 100644
--- a/src/corelib/kernel/qcoreevent.cpp
+++ b/src/corelib/kernel/qcoreevent.cpp
@@ -222,6 +222,15 @@ 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 RawTouch A raw event from a touch-screen or track-pad device (QTouchEvent)
+ \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 18188a8..feefd08 100644
--- a/src/corelib/kernel/qcoreevent.h
+++ b/src/corelib/kernel/qcoreevent.h
@@ -272,7 +272,17 @@ public:
Signal = 192,
Wrapped = 193,
- // 512 reserved for Qt Jambi's MetaCall event
+ TouchBegin = 194,
+ TouchUpdate = 195,
+ TouchEnd = 196,
+ GraphicsSceneTouchBegin = 197,
+ GraphicsSceneTouchUpdate = 198,
+ GraphicsSceneTouchEnd = 199,
+
+ Gesture = 200,
+ GraphicsSceneGesture = 201,
+
+ // 512 reserved for Qt Jambi's MetaCall event
// 513 reserved for Qt Jambi's DeleteOnMainThread event
User = 1000, // first user event id
@@ -310,6 +320,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 b9e462b..00f1aed 100644
--- a/src/gui/graphicsview/qgraphicsitem.cpp
+++ b/src/gui/graphicsview/qgraphicsitem.cpp
@@ -557,6 +557,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>
@@ -597,6 +598,8 @@ public:
};
Q_GLOBAL_STATIC(QGraphicsItemCustomDataStore, qt_dataStore)
+QString qt_getStandardGestureTypeName(Qt::GestureType type);
+
/*!
\internal
@@ -1079,6 +1082,7 @@ QGraphicsItem::~QGraphicsItem()
clearFocus();
d_ptr->removeExtraItemCache();
+ d_ptr->removeExtraGestures();
QList<QGraphicsItem *> oldChildren = d_ptr->children;
qDeleteAll(oldChildren);
Q_ASSERT(d_ptr->children.isEmpty());
@@ -2188,6 +2192,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);
@@ -6281,6 +6310,102 @@ 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)
+{
+ /// TODO: if we are QGraphicsProxyWidget we should subscribe the widget to gesture as well.
+ 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->grabGesture(id);
+ return id;
+}
+
+void QGraphicsItemPrivate::grabGesture(int id)
+{
+ Q_Q(QGraphicsItem);
+ extraGestures()->gestures << id;
+ if (scene)
+ scene->d_func()->grabGesture(q, id);
+}
+
+bool QGraphicsItemPrivate::releaseGesture(int id)
+{
+ Q_Q(QGraphicsItem);
+ QGestureExtraData *extra = maybeExtraGestures();
+ if (extra && extra->gestures.contains(id)) {
+ if (scene)
+ scene->d_func()->releaseGesture(q, id);
+ extra->gestures.remove(id);
+ return true;
+ }
+ return false;
+}
+
+/*!
+ \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)
+{
+ /// TODO: if we are QGraphicsProxyWidget we should unsubscribe the widget from gesture as well.
+ if (d_ptr->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 QGraphicsItem::setGestureEnabled(int gestureId, bool enable)
+{
+ //###
+}
+
+bool QGraphicsItemPrivate::hasGesture(const QString &name) const
+{
+ if (QGestureExtraData *extra = maybeExtraGestures()) {
+ QGestureManager *gm = QGestureManager::instance();
+ QSet<int>::const_iterator it = extra->gestures.begin(),
+ e = extra->gestures.end();
+ for (; it != e; ++it) {
+ if (gm->gestureNameFromId(*it) == name)
+ return true;
+ }
+ }
+ return false;
+}
+
+/*!
This virtual function is called by QGraphicsItem to notify custom items
that some part of the item's state changes. By reimplementing this
function, your can react to a change, and in some cases, (depending on \a
@@ -6304,6 +6429,23 @@ QVariant QGraphicsItem::inputMethodQuery(Qt::InputMethodQuery query) const
QVariant QGraphicsItem::itemChange(GraphicsItemChange change, const QVariant &value)
{
Q_UNUSED(change);
+ if (change == QGraphicsItem::ItemSceneChange) {
+ QGestureExtraData *extra = d_ptr->maybeExtraGestures();
+ if (!qVariantValue<QGraphicsScene*>(value) && extra) {
+ // the item has been removed from a scene, unsubscribe gestures.
+ Q_ASSERT(d_ptr->scene);
+ foreach(int id, extra->gestures)
+ d_ptr->scene->d_func()->releaseGesture(this, id);
+ }
+ } else if (change == QGraphicsItem::ItemSceneHasChanged) {
+ QGraphicsScene *scene = qVariantValue<QGraphicsScene*>(value);
+ QGestureExtraData *extra = d_ptr->maybeExtraGestures();
+ if (scene && extra) {
+ // item has been added to the scene
+ foreach(int id, extra->gestures)
+ scene->d_func()->grabGesture(this, id);
+ }
+ }
return value;
}
diff --git a/src/gui/graphicsview/qgraphicsitem.h b/src/gui/graphicsview/qgraphicsitem.h
index f6ee197..11e05d0 100644
--- a/src/gui/graphicsview/qgraphicsitem.h
+++ b/src/gui/graphicsview/qgraphicsitem.h
@@ -205,6 +205,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);
@@ -368,6 +370,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 bd81fe5..bedcf20 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"
#include "qpixmapcache.h"
#include <QtCore/qpoint.h>
@@ -91,6 +92,12 @@ public:
void purge();
};
+class QGestureExtraData
+{
+public:
+ QSet<int> gestures;
+};
+
class Q_AUTOTEST_EXPORT QGraphicsItemPrivate
{
Q_DECLARE_PUBLIC(QGraphicsItem)
@@ -113,7 +120,8 @@ public:
ExtraBoundingRegionGranularity,
ExtraOpacity,
ExtraEffectiveOpacity,
- ExtraDecomposedTransform
+ ExtraDecomposedTransform,
+ ExtraGestures
};
enum AncestorFlag {
@@ -160,6 +168,8 @@ public:
hasDecomposedTransform(0),
dirtyTransform(0),
dirtyTransformComponents(0),
+ acceptTouchEvents(0),
+ acceptedTouchBeginEvent(0),
globalStackingOrder(-1),
sceneTransformIndex(-1),
q_ptr(0)
@@ -317,7 +327,31 @@ public:
int index;
int depth;
- // Packed 32 bits
+ inline QGestureExtraData* extraGestures() const
+ {
+ QGestureExtraData *c = (QGestureExtraData *)qVariantValue<void *>(extra(ExtraGestures));
+ if (!c) {
+ QGraphicsItemPrivate *that = const_cast<QGraphicsItemPrivate *>(this);
+ c = new QGestureExtraData;
+ that->setExtra(ExtraGestures, qVariantFromValue<void *>(c));
+ }
+ return c;
+ }
+ QGestureExtraData* maybeExtraGestures() const
+ {
+ return (QGestureExtraData *)qVariantValue<void *>(extra(ExtraGestures));
+ }
+ inline void removeExtraGestures()
+ {
+ QGestureExtraData *c = (QGestureExtraData *)qVariantValue<void *>(extra(ExtraGestures));
+ delete c;
+ unsetExtra(ExtraGestures);
+ }
+ bool hasGesture(const QString &gesture) const;
+ void grabGesture(int id);
+ bool releaseGesture(int id);
+
+ // Packed 32 bytes
quint32 acceptedMouseButtons : 5;
quint32 visible : 1;
quint32 explicitlyHidden : 1;
@@ -350,7 +384,9 @@ public:
quint32 hasDecomposedTransform : 1;
quint32 dirtyTransform : 1;
quint32 dirtyTransformComponents : 1;
- quint32 padding : 18; // feel free to use
+ quint32 acceptTouchEvents : 1;
+ quint32 acceptedTouchBeginEvent : 1;
+ quint32 padding : 16; // feel free to use
// Optional stacking order
int globalStackingOrder;
diff --git a/src/gui/graphicsview/qgraphicsproxywidget.cpp b/src/gui/graphicsview/qgraphicsproxywidget.cpp
index a5b11ff..8f11d6f 100644
--- a/src/gui/graphicsview/qgraphicsproxywidget.cpp
+++ b/src/gui/graphicsview/qgraphicsproxywidget.cpp
@@ -48,6 +48,7 @@
#include "private/qgraphicsproxywidget_p.h"
#include "private/qwidget_p.h"
#include "private/qapplication_p.h"
+#include "private/qgesturemanager_p.h"
#include <QtCore/qdebug.h>
#include <QtGui/qevent.h>
@@ -275,7 +276,7 @@ void QGraphicsProxyWidgetPrivate::sendWidgetMouseEvent(QGraphicsSceneMouseEvent
QWidget *embeddedMouseGrabberPtr = (QWidget *)embeddedMouseGrabber;
QApplicationPrivate::sendMouseEvent(receiver, mouseEvent, alienWidget, widget,
- &embeddedMouseGrabberPtr, lastWidgetUnderMouse);
+ &embeddedMouseGrabberPtr, lastWidgetUnderMouse, event->spontaneous());
embeddedMouseGrabber = embeddedMouseGrabberPtr;
// Handle enter/leave events when last button is released from mouse
@@ -648,6 +649,9 @@ void QGraphicsProxyWidgetPrivate::setWidget_helper(QWidget *newWidget, bool auto
q->setAttribute(Qt::WA_OpaquePaintEvent);
widget = newWidget;
+ foreach(int gestureId, widget->d_func()->gestures) {
+ grabGesture(gestureId);
+ }
// Changes only go from the widget to the proxy.
enabledChangeMode = QGraphicsProxyWidgetPrivate::WidgetToProxyMode;
@@ -871,6 +875,16 @@ bool QGraphicsProxyWidget::event(QEvent *event)
}
break;
}
+ case QEvent::GraphicsSceneGesture: {
+ qDebug() << "QGraphicsProxyWidget: graphicsscenegesture";
+ if (d->widget && d->widget->isVisible()) {
+ QGraphicsSceneGestureEvent *ge = static_cast<QGraphicsSceneGestureEvent*>(event);
+ //### TODO: widget->childAt(): decompose gesture event and find widget under hotspots.
+ //QGestureManager::instance()->sendGestureEvent(d->widget, ge->gestures().toSet(), ge->cancelledGestures());
+ return true;
+ }
+ break;
+ }
default:
break;
}
diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp
index 49c2329..cffaa40 100644
--- a/src/gui/graphicsview/qgraphicsscene.cpp
+++ b/src/gui/graphicsview/qgraphicsscene.cpp
@@ -247,6 +247,8 @@ static const int QGRAPHICSSCENE_INDEXTIMER_TIMEOUT = 2000;
#ifdef Q_WS_X11
#include <private/qt_x11_p.h>
#endif
+#include <private/qgesturemanager_p.h>
+#include <private/qgesture_p.h>
QT_BEGIN_NAMESPACE
@@ -1336,6 +1338,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());
@@ -3764,6 +3767,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
@@ -3915,6 +3921,52 @@ 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);
+ QGraphicsView *view = qobject_cast<QGraphicsView*>(ev->widget());
+ if (!view) {
+ qWarning("QGraphicsScene::event: gesture event was received without a view");
+ break;
+ }
+
+ // get a list of gestures that just started.
+ QSet<QGesture*> startedGestures;
+ QList<QGesture*> gestures = ev->gestures();
+ for(QList<QGesture*>::const_iterator it = gestures.begin(), e = gestures.end();
+ it != e; ++it) {
+ QGesture *g = *it;
+ QGesturePrivate *gd = g->d_func();
+ if (g->state() == Qt::GestureStarted || gd->singleshot) {
+ startedGestures.insert(g);
+ }
+ }
+ if (!startedGestures.isEmpty()) {
+ // find a target for each started gesture.
+ for(QSet<QGesture*>::const_iterator it = startedGestures.begin(), e = startedGestures.end();
+ it != e; ++it) {
+ QGesture *g = *it;
+ QGesturePrivate *gd = g->d_func();
+ gd->graphicsItem = 0;
+ QList<QGraphicsItem*> itemsInGestureArea = items(g->hotSpot());
+ const QString gestureName = g->type();
+ foreach(QGraphicsItem *item, itemsInGestureArea) {
+ if (item->d_func()->hasGesture(gestureName)) {
+ Q_ASSERT(gd->graphicsItem == 0);
+ gd->graphicsItem = item;
+ d->itemsWithGestures[item].insert(g);
+ break;
+ }
+ }
+ }
+ }
+ d->sendGestureEvent(ev->gestures().toSet(), ev->cancelledGestures());
+ }
+ break;
+ case QEvent::GraphicsSceneTouchBegin:
+ 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) {
@@ -3931,6 +3983,70 @@ bool QGraphicsScene::event(QEvent *event)
return true;
}
+void QGraphicsScenePrivate::sendGestureEvent(const QSet<QGesture*> &gestures, const QSet<QString> &cancelled)
+{
+ Q_Q(QGraphicsScene);
+ typedef QMap<QGraphicsItem*, QSet<QGesture*> > ItemGesturesMap;
+ ItemGesturesMap itemGestures;
+ QSet<QGesture*> startedGestures;
+ for(QSet<QGesture*>::const_iterator it = gestures.begin(), e = gestures.end();
+ it != e; ++it) {
+ QGesture *g = *it;
+ Q_ASSERT(g != 0);
+ QGesturePrivate *gd = g->d_func();
+ if (gd->graphicsItem != 0) {
+ itemGestures[gd->graphicsItem].insert(g);
+ if (g->state() == Qt::GestureStarted || gd->singleshot)
+ startedGestures.insert(g);
+ }
+ }
+
+ QSet<QGesture*> ignoredGestures;
+ for(ItemGesturesMap::const_iterator it = itemGestures.begin(), e = itemGestures.end();
+ it != e; ++it) {
+ QGraphicsItem *receiver = it.key();
+ Q_ASSERT(receiver != 0);
+ QGraphicsSceneGestureEvent event;
+ event.setGestures(it.value());
+ event.setCancelledGestures(cancelled);
+ bool processed = sendEvent(receiver, &event);
+ QSet<QGesture*> started = startedGestures.intersect(it.value());
+ if (event.isAccepted())
+ foreach(QGesture *g, started)
+ g->accept();
+ if (!started.isEmpty() && !(processed && event.isAccepted())) {
+ // there are started gestures event that weren't
+ // accepted, so propagating each gesture independently.
+ QSet<QGesture*>::const_iterator it = started.begin(),
+ e = started.end();
+ for(; it != e; ++it) {
+ QGesture *g = *it;
+ if (processed && g->isAccepted()) {
+ continue;
+ }
+ QGesturePrivate *gd = g->d_func();
+ QGraphicsItem *item = gd->graphicsItem;
+ gd->graphicsItem = 0;
+
+ //### THIS IS BS, DONT FORGET TO REWRITE THIS CODE
+ // need to make sure we try to deliver event just once to each widget
+ const QString gestureType = g->type();
+ QList<QGraphicsItem*> itemsUnderGesture = q->items(g->hotSpot());
+ for (int i = 0; i < itemsUnderGesture.size(); ++i) {
+ QGraphicsItem *item = itemsUnderGesture.at(i);
+ if (item != receiver && item->d_func()->hasGesture(gestureType)) {
+ ignoredGestures.insert(g);
+ gd->graphicsItem = item;
+ break;
+ }
+ }
+ }
+ }
+ }
+ if (!ignoredGestures.isEmpty())
+ sendGestureEvent(ignoredGestures, cancelled);
+}
+
/*!
\reimp
@@ -5540,6 +5656,229 @@ 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);
+ }
+ (void)itemsWithGestures[item];
+ grabbedGestures << gestureId;
+}
+
+void QGraphicsScenePrivate::releaseGesture(QGraphicsItem *item, int gestureId)
+{
+ itemsWithGestures.remove(item);
+ //###
+}
+
+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[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()));
+#ifdef Q_CC_GNU
+# warning FIXME
+#endif
+ // ### touchPoint.setSize(item->d_ptr->genericMapFromScene(touchPoint.sceneSize(), touchEvent->widget()));
+ }
+ touchEvent->setTouchPoints(touchPoints);
+}
+
+int QGraphicsScenePrivate::findClosestTouchPointId(const QPointF &scenePos)
+{
+ int closestTouchPointId = -1;
+ qreal closestDistance = qreal(0.);
+ foreach (const QGraphicsSceneTouchEvent::TouchPoint &touchPoint, sceneCurrentTouchPoints) {
+ qreal distance = QLineF(scenePos, touchPoint.scenePos()).length();
+ if (closestTouchPointId == -1|| distance < closestDistance) {
+ closestTouchPointId = touchPoint.id();
+ closestDistance = distance;
+ }
+ }
+ return closestTouchPointId;
+}
+
+void QGraphicsScenePrivate::touchEventHandler(QGraphicsSceneTouchEvent *sceneTouchEvent)
+{
+ typedef QPair<Qt::TouchPointStates, QList<QGraphicsSceneTouchEvent::TouchPoint> > StatesAndTouchPoints;
+ QHash<QGraphicsItem *, StatesAndTouchPoints> itemsNeedingEvents;
+
+ for (int i = 0; i < sceneTouchEvent->touchPoints().count(); ++i) {
+ const QGraphicsSceneTouchEvent::TouchPoint &touchPoint = sceneTouchEvent->touchPoints().at(i);
+
+ // update state
+ QGraphicsItem *item = 0;
+ 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();
+ int closestTouchPointId = findClosestTouchPointId(touchPoint.scenePos());
+ QGraphicsItem *closestItem = itemForTouchPointId.value(closestTouchPointId);
+ if (!item
+ || (closestItem
+ && (item->isAncestorOf(closestItem)
+ || closestItem->isAncestorOf(item)))) {
+ item = closestItem;
+ }
+ if (!item)
+ continue;
+
+ itemForTouchPointId.insert(touchPoint.id(), item);
+ sceneCurrentTouchPoints.insert(touchPoint.id(), touchPoint);
+ } else if (touchPoint.state() == Qt::TouchPointReleased) {
+ item = itemForTouchPointId.take(touchPoint.id());
+ if (!item)
+ continue;
+
+ sceneCurrentTouchPoints.remove(touchPoint.id());
+ } else {
+ item = itemForTouchPointId.value(touchPoint.id());
+ if (!item)
+ continue;
+ Q_ASSERT(sceneCurrentTouchPoints.contains(touchPoint.id()));
+ sceneCurrentTouchPoints[touchPoint.id()] = touchPoint;
+ }
+
+ StatesAndTouchPoints &statesAndTouchPoints = itemsNeedingEvents[item];
+ statesAndTouchPoints.first |= touchPoint.state();
+ statesAndTouchPoints.second.append(touchPoint);
+ }
+
+ if (itemsNeedingEvents.isEmpty()) {
+ sceneTouchEvent->ignore();
+ return;
+ }
+
+ bool acceptSceneTouchEvent = false;
+ QHash<QGraphicsItem *, StatesAndTouchPoints>::ConstIterator it = itemsNeedingEvents.constBegin();
+ const QHash<QGraphicsItem *, StatesAndTouchPoints>::ConstIterator end = itemsNeedingEvents.constEnd();
+ for (; it != end; ++it) {
+ QGraphicsItem *item = it.key();
+
+ // determine event type from the state mask
+ QEvent::Type eventType;
+ switch (it.value().first) {
+ case Qt::TouchPointPressed:
+ // all touch points have pressed state
+ eventType = QEvent::GraphicsSceneTouchBegin;
+ break;
+ case Qt::TouchPointReleased:
+ // all touch points have released state
+ eventType = QEvent::GraphicsSceneTouchEnd;
+ break;
+ case Qt::TouchPointStationary:
+ // don't send the event if nothing changed
+ continue;
+ default:
+ // all other combinations
+ eventType = QEvent::GraphicsSceneTouchUpdate;
+ break;
+ }
+
+ QGraphicsSceneTouchEvent touchEvent(eventType);
+ touchEvent.setWidget(sceneTouchEvent->widget());
+ touchEvent.setModifiers(sceneTouchEvent->modifiers());
+ touchEvent.setTouchPointStates(it.value().first);
+ touchEvent.setTouchPoints(it.value().second);
+
+ 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;
+ }
+ default:
+ if (item->d_ptr->acceptedTouchBeginEvent) {
+ updateTouchPointsForItem(item, &touchEvent);
+ (void) sendEvent(item, &touchEvent);
+ acceptSceneTouchEvent = true;
+ }
+ break;
+ }
+ }
+ sceneTouchEvent->setAccepted(acceptSceneTouchEvent);
+}
+
+bool QGraphicsScenePrivate::sendTouchBeginEvent(QGraphicsItem *origin, QGraphicsSceneTouchEvent *touchEvent)
+{
+ Q_Q(QGraphicsScene);
+
+ if (cachedItemsUnderMouse.isEmpty() || cachedItemsUnderMouse.first() != origin) {
+ const 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);
+ bool acceptTouchEvents = item->acceptTouchEvents();
+ touchEvent->setAccepted(acceptTouchEvents);
+ res = 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) {
+ const QGraphicsSceneTouchEvent::TouchPoint &touchPoint = touchEvent->touchPoints().at(i);
+ itemForTouchPointId[touchPoint.id()] = item;
+ }
+ 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..f90bb8f 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"
@@ -73,6 +74,7 @@ QT_BEGIN_NAMESPACE
class QGraphicsView;
class QGraphicsWidget;
+class QGesture;
class QGraphicsScenePrivate : public QObjectPrivate
{
@@ -162,7 +164,7 @@ public:
void grabKeyboard(QGraphicsItem *item);
void ungrabKeyboard(QGraphicsItem *item, bool itemIsDying = false);
void clearKeyboardGrabber();
-
+
QGraphicsItem *dragDropItem;
QGraphicsWidget *enterWidget;
Qt::DropAction lastDropAction;
@@ -181,6 +183,9 @@ public:
void storeMouseButtonsForMouseGrabber(QGraphicsSceneMouseEvent *event);
QList<QGraphicsView *> views;
+ void addView(QGraphicsView *view);
+ void removeView(QGraphicsView *view);
+
bool painterStateProtection;
QMultiMap<QGraphicsItem *, QGraphicsItem *> sceneEventFilters;
@@ -239,7 +244,7 @@ public:
static bool closestItemLast_withoutCache(const QGraphicsItem *item1, const QGraphicsItem *item2);
static inline bool closestItemFirst_withCache(const QGraphicsItem *item1, const QGraphicsItem *item2)
- {
+ {
return item1->d_ptr->globalStackingOrder < item2->d_ptr->globalStackingOrder;
}
static inline bool closestItemLast_withCache(const QGraphicsItem *item1, const QGraphicsItem *item2)
@@ -252,7 +257,7 @@ public:
void drawItemHelper(QGraphicsItem *item, QPainter *painter,
const QStyleOptionGraphicsItem *option, QWidget *widget,
bool painterStateProtection);
-
+
QStyle *style;
QFont font;
void setFont_helper(const QFont &font);
@@ -263,9 +268,23 @@ public:
void resolvePalette();
void updatePalette(const QPalette &palette);
+ // items with gestures -> list of started gestures.
+ QMap<QGraphicsItem*, QSet<QGesture*> > itemsWithGestures;
+ QSet<int> grabbedGestures;
+ void grabGesture(QGraphicsItem *item, int gestureId);
+ void releaseGesture(QGraphicsItem *item, int gestureId);
+ void sendGestureEvent(const QSet<QGesture*> &gestures, const QSet<QString> &cancelled);
+
mutable QVector<QTransform> sceneTransformCache;
mutable QBitArray validTransforms;
mutable QVector<int> freeSceneTransformSlots;
+
+ QMap<int, QGraphicsSceneTouchEvent::TouchPoint> sceneCurrentTouchPoints;
+ QHash<int, QGraphicsItem *> itemForTouchPointId;
+ static void updateTouchPointsForItem(QGraphicsItem *item, QGraphicsSceneTouchEvent *touchEvent);
+ int findClosestTouchPointId(const QPointF &scenePos);
+ 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 0ffd2b1..c1052e3 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,620 @@ 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)
+{
+ setAccepted(false);
+}
+
+/*!
+ 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);
+}
+
+/*!
+ Set a list of gesture objects containing extended information about \a gestures.
+*/
+void QGraphicsSceneGestureEvent::setGestures(const QSet<QGesture*> &gestures)
+{
+ foreach(QGesture *g, gestures)
+ m_gestures.insert(g->type(), g);
+}
+
+/*!
+ Sets the accept flag of the all gestures inside the event object,
+ the equivalent of calling \l{QEvent::accept()}{accept()} or
+ \l{QEvent::setAccepted()}{setAccepted(true)}.
+
+ 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), touchPointStates()
+ { }
+
+ Qt::KeyboardModifiers modifiers;
+ Qt::TouchPointStates touchPointStates;
+ QList<QGraphicsSceneTouchEvent::TouchPoint> touchPoints;
+};
+
+/*!
+ \internal
+
+ Constructs a generic QGraphicsSceneTouchEvent of type \a type.
+*/
+QGraphicsSceneTouchEvent::QGraphicsSceneTouchEvent(Type type)
+ : QGraphicsSceneEvent(*new QGraphicsSceneTouchEventPrivate, type)
+{ }
+
+/*!
+ Destroys the QGraphicsSceneTouchEvent.
+*/
+QGraphicsSceneTouchEvent::~QGraphicsSceneTouchEvent()
+{ }
+
+/*!
+ 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 a bitwise OR of all of the touch point states at the time
+ the event was sent.
+*/
+Qt::TouchPointStates QGraphicsSceneTouchEvent::touchPointStates() const
+{
+ Q_D(const QGraphicsSceneTouchEvent);
+ return d->touchPointStates;
+}
+
+/*! \internal */
+void QGraphicsSceneTouchEvent::setTouchPointStates(Qt::TouchPointStates touchPointStates)
+{
+ Q_D(QGraphicsSceneTouchEvent);
+ d->touchPointStates = touchPointStates;
+}
+
+/*!
+ 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;
+}
+
+/*! \internal */
+QGraphicsSceneTouchEvent::TouchPoint::TouchPoint(int id)
+ : d(new QTouchEventTouchPointPrivate(id))
+{ }
+
+/*! \internal */
+QGraphicsSceneTouchEvent::TouchPoint::TouchPoint(const QGraphicsSceneTouchEvent::TouchPoint &other)
+ : d(other.d)
+{
+ d->ref.ref();
+}
+
+/*! \internal */
+QGraphicsSceneTouchEvent::TouchPoint::TouchPoint(QTouchEventTouchPointPrivate *dd)
+ : d(dd)
+{
+ d->ref.ref();
+}
+
+/*! \internal */
+QGraphicsSceneTouchEvent::TouchPoint::~TouchPoint()
+{
+ if (!d->ref.deref())
+ delete d;
+}
+
+/*!
+ Returns the id number of this touch point.
+
+ Id numbers are globally sequential, starting at zero, meaning the
+ first touch point in the application has id 0, the second has id 1,
+ and so on.
+*/
+int QGraphicsSceneTouchEvent::TouchPoint::id() const
+{
+ return d->id;
+}
+
+/*! \internal */
+void QGraphicsSceneTouchEvent::TouchPoint::setId(int id)
+{
+ if (!d->ref == 1)
+ d = d->detach();
+ d->id = id;
+}
+
+/*!
+ Returns the current state of this touch point.
+*/
+Qt::TouchPointState QGraphicsSceneTouchEvent::TouchPoint::state() const
+{
+ return d->state;
+}
+
+/*! \internal */
+void QGraphicsSceneTouchEvent::TouchPoint::setState(Qt::TouchPointState state)
+{
+ if (d->ref != 1)
+ d = d->detach();
+ d->state = state;
+}
+
+/*!
+ Returns the position of this touch point, relative to the widget
+ or item that received the event.
+*/
+QPointF QGraphicsSceneTouchEvent::TouchPoint::pos() const
+{
+ return d->pos;
+}
+
+/*! \internal */
+void QGraphicsSceneTouchEvent::TouchPoint::setPos(const QPointF &pos)
+{
+ if (d->ref != 1)
+ d = d->detach();
+ d->pos = pos;
+}
+
+/*!
+ Returns the starting position of this touch point, relative to the
+ widget that received the event.
+*/
+QPointF QGraphicsSceneTouchEvent::TouchPoint::startPos() const
+{
+ return d->startPos;
+}
+
+/*! \internal */
+void QGraphicsSceneTouchEvent::TouchPoint::setStartPos(const QPointF &startPos)
+{
+ if (d->ref != 1)
+ d = d->detach();
+ d->startPos = startPos;
+}
+
+/*!
+ Returns the position of this touch point from the previous touch
+ event, relative to the widget that received the event.
+*/
+QPointF QGraphicsSceneTouchEvent::TouchPoint::lastPos() const
+{
+ return d->lastPos;
+}
+
+/*! \internal */
+void QGraphicsSceneTouchEvent::TouchPoint::setLastPos(const QPointF &lastPos)
+{
+ if (d->ref != 1)
+ d = d->detach();
+ d->lastPos = lastPos;
+}
+
+/*!
+ 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)
+{
+ if (d->ref != 1)
+ d = d->detach();
+ 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)
+{
+ if (d->ref != 1)
+ d = d->detach();
+ 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)
+{
+ if (d->ref != 1)
+ d = d->detach();
+ d->lastScenePos = lastScenePos;
+}
+
+/*!
+ Returns the screen position of this touch point.
+*/
+QPointF QGraphicsSceneTouchEvent::TouchPoint::screenPos() const
+{
+ return d->screenPos;
+}
+
+/*! \internal */
+void QGraphicsSceneTouchEvent::TouchPoint::setScreenPos(const QPointF &screenPos)
+{
+ if (d->ref != 1)
+ d = d->detach();
+ d->screenPos = screenPos;
+}
+
+/*!
+ Returns the starting screen position of this touch point.
+*/
+QPointF QGraphicsSceneTouchEvent::TouchPoint::startScreenPos() const
+{
+ return d->startScreenPos;
+}
+
+/*! \internal */
+void QGraphicsSceneTouchEvent::TouchPoint::setStartScreenPos(const QPointF &startScreenPos)
+{
+ if (d->ref != 1)
+ d = d->detach();
+ d->startScreenPos = startScreenPos;
+}
+
+/*!
+ Returns the screen position of this touch point from the previous
+ touch event.
+*/
+QPointF QGraphicsSceneTouchEvent::TouchPoint::lastScreenPos() const
+{
+ return d->lastScreenPos;
+}
+
+/*! \internal */
+void QGraphicsSceneTouchEvent::TouchPoint::setLastScreenPos(const QPointF &lastScreenPos)
+{
+ if (d->ref != 1)
+ d = d->detach();
+ d->lastScreenPos = lastScreenPos;
+}
+
+/*!
+ Returns the size of this touch point.
+*/
+QSizeF QGraphicsSceneTouchEvent::TouchPoint::size() const
+{
+ return d->size;
+}
+
+/*! \internal */
+void QGraphicsSceneTouchEvent::TouchPoint::setSize(const QSizeF &size)
+{
+ if (d->ref != 1)
+ d = d->detach();
+ d->size = size;
+}
+
+/*!
+ Returns the size of this touch point in scene coordinates.
+*/
+QSizeF QGraphicsSceneTouchEvent::TouchPoint::sceneSize() const
+{
+ return d->sceneSize;
+}
+
+/*! \internal */
+void QGraphicsSceneTouchEvent::TouchPoint::setSceneSize(const QSizeF &sceneSize)
+{
+ if (d->ref != 1)
+ d = d->detach();
+ d->sceneSize = sceneSize;
+}
+
+/*!
+ Returns the size of this touch point in screen coordinates.
+*/
+QSizeF QGraphicsSceneTouchEvent::TouchPoint::screenSize() const
+{
+ return d->screenSize;
+}
+
+/*! \internal */
+void QGraphicsSceneTouchEvent::TouchPoint::setScreenSize(const QSizeF &screenSize)
+{
+ if (d->ref != 1)
+ d = d->detach();
+ d->screenSize = screenSize;
+}
+
+/*!
+ Returns the pressure of this touch point. The return value is in
+ the range 0.0 to 1.0.
+*/
+qreal QGraphicsSceneTouchEvent::TouchPoint::pressure() const
+{
+ return d->pressure;
+}
+
+/*! \internal */
+void QGraphicsSceneTouchEvent::TouchPoint::setPressure(qreal pressure)
+{
+ if (d->ref != 1)
+ d = d->detach();
+ d->pressure = pressure;
+}
+
+/*! \internal */
+QGraphicsSceneTouchEvent::TouchPoint &QGraphicsSceneTouchEvent::TouchPoint::operator=(const QGraphicsSceneTouchEvent::TouchPoint &other)
+{
+ other.d->ref.ref();
+ if (!d->ref.deref())
+ delete d;
+ d = other.d;
+ return *this;
+}
+
QT_END_NAMESPACE
#endif // QT_NO_GRAPHICSVIEW
diff --git a/src/gui/graphicsview/qgraphicssceneevent.h b/src/gui/graphicsview/qgraphicssceneevent.h
index be50e96..3c53f36 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,129 @@ 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);
+ void setGestures(const QSet<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:
+ TouchPoint(int id = -1);
+ TouchPoint(const TouchPoint &other);
+ ~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 scenePos() const;
+ void setScenePos(const QPointF &scenePos);
+
+ QPointF startScenePos() const;
+ void setStartScenePos(const QPointF &startScenePos);
+
+ QPointF lastScenePos() const;
+ void setLastScenePos(const QPointF &lastScenePos);
+
+ QPointF screenPos() const;
+ void setScreenPos(const QPointF &screenPos);
+
+ QPointF startScreenPos() const;
+ void setStartScreenPos(const QPointF &startScreenPos);
+
+ QPointF lastScreenPos() const;
+ void setLastScreenPos(const QPointF &lastScreenPos);
+
+ QSizeF size() const;
+ void setSize(const QSizeF &size);
+
+ QSizeF sceneSize() const;
+ void setSceneSize(const QSizeF &sceneSize);
+
+ QSizeF screenSize() const;
+ void setScreenSize(const QSizeF &screenSize);
+
+ qreal pressure() const;
+ void setPressure(qreal pressure);
+
+ TouchPoint &operator=(const TouchPoint &other);
+
+ private:
+ TouchPoint(QTouchEventTouchPointPrivate *dd);
+ QTouchEventTouchPointPrivate *d;
+ friend class QGraphicsViewPrivate;
+ };
+
+ QGraphicsSceneTouchEvent(Type type = None);
+ ~QGraphicsSceneTouchEvent();
+
+ Qt::KeyboardModifiers modifiers() const;
+ void setModifiers(Qt::KeyboardModifiers modifiers);
+
+ Qt::TouchPointStates touchPointStates() const;
+ void setTouchPointStates(Qt::TouchPointStates touchPointStates);
+
+ const QList<QGraphicsSceneTouchEvent::TouchPoint> &touchPoints() const;
+ void setTouchPoints(const QList<QGraphicsSceneTouchEvent::TouchPoint> &touchPoints);
+
+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 10b837a..e874071 100644
--- a/src/gui/graphicsview/qgraphicsview.cpp
+++ b/src/gui/graphicsview/qgraphicsview.cpp
@@ -284,8 +284,12 @@ static const int QGRAPHICSVIEW_PREALLOC_STYLE_OPTIONS = 503; // largest prime <
#include <private/qt_x11_p.h>
#endif
+#include <private/qevent_p.h>
+
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)
@@ -295,6 +299,36 @@ 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);
}
+void QGraphicsViewPrivate::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 =
+ QTouchEventTouchPointPrivate::get(originalTouchPoints.at(i));
+ // the scene will set the item local pos, startPos, lastPos, and size before delivering to
+ // an item, but for now those functions are returning the view's local coordinates (since
+ // we're reusing the d-pointer from the orignalTouchPoint)
+ touchPoint.setScenePos(d->mapToScene(touchPoint.pos()));
+ touchPoint.setStartScenePos(d->mapToScene(touchPoint.startPos()));
+ touchPoint.setLastScenePos(d->mapToScene(touchPoint.lastPos()));
+#ifdef Q_CC_GNU
+# warning FIXME
+#endif
+ // ### touchPoint.setSceneSize(d->mapToScene(touchPoint.screenSize()));
+
+ // screenPos, startScreenPos, lastScreenPos, and screenSize are already set from the
+ // originalTouchPoint
+
+ touchPoints.append(touchPoint);
+ }
+
+ touchEvent->setTouchPoints(touchPoints);
+ touchEvent->setModifiers(originalEvent->modifiers());
+}
+
/*!
\internal
*/
@@ -593,7 +627,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());
@@ -1614,7 +1648,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;
}
@@ -1623,7 +1657,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;
@@ -2750,6 +2784,9 @@ bool QGraphicsView::event(QEvent *event)
}
}
break;
+ case QEvent::Gesture:
+ viewportEvent(event);
+ return true;
default:
break;
}
@@ -2830,6 +2867,47 @@ 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);
+ event->setAccepted(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;
+ switch(event->type()) {
+ case QEvent::TouchUpdate:
+ eventType = QEvent::GraphicsSceneTouchUpdate;
+ break;
+ case QEvent::TouchBegin:
+ eventType = QEvent::GraphicsSceneTouchBegin;
+ break;
+ default:
+ eventType = QEvent::GraphicsSceneTouchEnd;
+ }
+ QGraphicsSceneTouchEvent touchEvent(eventType);
+ touchEvent.setWidget(viewport());
+ QGraphicsViewPrivate::convertTouchEventToGraphicsSceneTouchEvent(d, static_cast<QTouchEvent *>(event), &touchEvent);
+ touchEvent.setAccepted(false);
+ QApplication::sendEvent(d->scene, &touchEvent);
+ event->setAccepted(touchEvent.isAccepted());
+ }
+
+ return true;
+ }
default:
break;
}
@@ -3088,7 +3166,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);
}
/*!
@@ -3127,7 +3205,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();
@@ -3297,7 +3375,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());
@@ -3767,6 +3845,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 c18f85d..da1ca14 100644
--- a/src/gui/graphicsview/qgraphicsview_p.h
+++ b/src/gui/graphicsview/qgraphicsview_p.h
@@ -174,6 +174,18 @@ public:
bool updateSceneSlotReimplementedChecked;
QList<QGraphicsItem *> findItems(const QRegion &exposedRegion, bool *allItems) const;
+
+ void generateStyleOptions(const QList<QGraphicsItem *> &itemList,
+ QGraphicsItem **itemArray,
+ QStyleOptionGraphicsItem *styleOptionArray,
+ const QTransform &worldTransform,
+ bool allItems,
+ const QRegion &exposedRegion) const;
+
+ QPointF mapToScene(const QPointF &point) const;
+ static void convertTouchEventToGraphicsSceneTouchEvent(QGraphicsViewPrivate *d,
+ QTouchEvent *originalEvent,
+ QGraphicsSceneTouchEvent *touchEvent);
};
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 4923d23..e5cf0b5 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;
}
@@ -888,6 +903,8 @@ void QApplicationPrivate::initialize()
QApplicationPrivate::wheel_scroll_lines = 3;
#endif
#endif
+
+ initializeMultitouch();
}
/*!
@@ -1038,6 +1055,8 @@ QApplication::~QApplication()
delete QDragManager::self();
#endif
+ d->cleanupMultitouch();
+
qt_cleanup();
if (QApplicationPrivate::widgetCount)
@@ -2869,7 +2888,8 @@ QWidget *QApplicationPrivate::pickMouseReceiver(QWidget *candidate, const QPoint
*/
bool QApplicationPrivate::sendMouseEvent(QWidget *receiver, QMouseEvent *event,
QWidget *alienWidget, QWidget *nativeWidget,
- QWidget **buttonDown, QPointer<QWidget> &lastMouseReceiver)
+ QWidget **buttonDown, QPointer<QWidget> &lastMouseReceiver,
+ bool spontaneous)
{
Q_ASSERT(receiver);
Q_ASSERT(event);
@@ -2922,7 +2942,11 @@ bool QApplicationPrivate::sendMouseEvent(QWidget *receiver, QMouseEvent *event,
// We need this quard in case someone opens a modal dialog / popup. If that's the case
// leaveAfterRelease is set to null, but we shall not update lastMouseReceiver.
const bool wasLeaveAfterRelease = leaveAfterRelease != 0;
- bool result = QApplication::sendSpontaneousEvent(receiver, event);
+ bool result;
+ if (spontaneous)
+ result = QApplication::sendSpontaneousEvent(receiver, event);
+ else
+ result = QApplication::sendEvent(receiver, event);
if (!graphicsWidget && leaveAfterRelease && event->type() == QEvent::MouseButtonRelease
&& !event->buttons() && QWidget::mouseGrabber() != leaveAfterRelease) {
@@ -3563,24 +3587,36 @@ bool QApplication::notify(QObject *receiver, QEvent *e)
QApplicationPrivate::mouse_buttons |= me->button();
else
QApplicationPrivate::mouse_buttons &= ~me->button();
- }
+ }
#if !defined(QT_NO_WHEELEVENT) || !defined(QT_NO_TABLETEVENT)
- else if (
+ else if (false
# ifndef QT_NO_WHEELEVENT
- e->type() == QEvent::Wheel ||
+ || e->type() == QEvent::Wheel
# endif
# ifndef QT_NO_TABLETEVENT
- e->type() == QEvent::TabletMove
- || e->type() == QEvent::TabletPress
- || e->type() == QEvent::TabletRelease
+ || e->type() == QEvent::TabletMove
+ || e->type() == QEvent::TabletPress
+ || e->type() == QEvent::TabletRelease
# endif
- ) {
+ ) {
QInputEvent *ie = static_cast<QInputEvent*>(e);
QApplicationPrivate::modifier_buttons = ie->modifiers();
}
#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:
@@ -3708,19 +3744,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) {
@@ -3802,17 +3829,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) {
@@ -4017,7 +4036,44 @@ bool QApplication::notify(QObject *receiver, QEvent *e)
}
break;
#endif
+ case QEvent::TouchBegin:
+ // Note: TouchUpdate and TouchEnd events are never propagated
+ {
+ QWidget *widget = static_cast<QWidget *>(receiver);
+ 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
+ bool acceptTouchEvents = widget->testAttribute(Qt::WA_AcceptTouchEvents);
+ touchEvent->setAccepted(acceptTouchEvents);
+ res = 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) {
+ const QTouchEvent::TouchPoint &touchPoint = touchEvent->touchPoints().at(i);
+ d->widgetForTouchPointId[touchPoint.id()] = widget;
+ }
+ 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;
@@ -4984,6 +5040,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;
@@ -4997,6 +5070,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.
@@ -5128,6 +5252,180 @@ 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[i];
+
+ // preserve the sub-pixel resolution
+ const QPointF delta = touchPoint.globalPos() - touchPoint.globalPos().toPoint();
+ touchPoint.setPos(widget->mapFromGlobal(touchPoint.globalPos().toPoint()) + delta);
+ touchPoint.setStartPos(widget->mapFromGlobal(touchPoint.startGlobalPos().toPoint()) + delta);
+ touchPoint.setLastPos(widget->mapFromGlobal(touchPoint.lastGlobalPos().toPoint()) + delta);
+ }
+}
+
+void QApplicationPrivate::initializeMultitouch()
+{
+ widgetForTouchPointId.clear();
+ appCurrentTouchPoints.clear();
+
+ initializeMultitouch_sys();
+}
+
+void QApplicationPrivate::cleanupMultitouch()
+{
+ cleanupMultitouch_sys();
+
+ widgetForTouchPointId.clear();
+ appCurrentTouchPoints.clear();
+}
+
+int QApplicationPrivate::findClosestTouchPointId(const QPointF &globalPos)
+{
+ int closestTouchPointId = -1;
+ qreal closestDistance = qreal(0.);
+ foreach (const QTouchEvent::TouchPoint &touchPoint, appCurrentTouchPoints) {
+ qreal distance = QLineF(globalPos, touchPoint.globalPos()).length();
+ if (closestTouchPointId == -1 || distance < closestDistance) {
+ closestTouchPointId = touchPoint.id();
+ closestDistance = distance;
+ }
+ }
+ return closestTouchPointId;
+}
+
+bool QApplicationPrivate::translateRawTouchEvent(QWidget *window,
+ const QList<QTouchEvent::TouchPoint> &touchPoints)
+{
+ QApplicationPrivate *d = self;
+ QApplication *q = self->q_func();
+
+ typedef QPair<Qt::TouchPointStates, QList<QTouchEvent::TouchPoint> > StatesAndTouchPoints;
+ QHash<QWidget *, StatesAndTouchPoints> widgetsNeedingEvents;
+
+ for (int i = 0; i < touchPoints.count(); ++i) {
+ QTouchEvent::TouchPoint touchPoint = touchPoints.at(i);
+
+ // update state
+ QWidget *widget = 0;
+ switch (touchPoint.state()) {
+ case Qt::TouchPointPressed:
+ {
+ // determine which widget this event will go to
+ if (!window)
+ window = q->topLevelAt(touchPoint.globalPos().toPoint());
+ if (!window)
+ continue;
+ widget = window->childAt(window->mapFromGlobal(touchPoint.globalPos().toPoint()));
+ if (!widget)
+ widget = window;
+
+ int closestTouchPointId = d->findClosestTouchPointId(touchPoint.globalPos());
+ QWidget *closestWidget = d->widgetForTouchPointId.value(closestTouchPointId);
+ if (closestWidget
+ && (widget->isAncestorOf(closestWidget) || closestWidget->isAncestorOf(widget))) {
+ widget = closestWidget;
+ }
+ d->widgetForTouchPointId[touchPoint.id()] = widget;
+ touchPoint.setStartGlobalPos(touchPoint.globalPos());
+ touchPoint.setLastGlobalPos(touchPoint.globalPos());
+ d->appCurrentTouchPoints.insert(touchPoint.id(), touchPoint);
+ break;
+ }
+ case Qt::TouchPointReleased:
+ {
+ widget = d->widgetForTouchPointId.take(touchPoint.id());
+ if (!widget)
+ continue;
+
+ QTouchEvent::TouchPoint previousTouchPoint = d->appCurrentTouchPoints.take(touchPoint.id());
+ touchPoint.setStartGlobalPos(previousTouchPoint.startGlobalPos());
+ touchPoint.setLastGlobalPos(previousTouchPoint.globalPos());
+ break;
+ }
+ default:
+ widget = d->widgetForTouchPointId.value(touchPoint.id());
+ if (!widget)
+ continue;
+ Q_ASSERT(d->appCurrentTouchPoints.contains(touchPoint.id()));
+ QTouchEvent::TouchPoint previousTouchPoint = d->appCurrentTouchPoints.value(touchPoint.id());
+ touchPoint.setStartGlobalPos(previousTouchPoint.startGlobalPos());
+ touchPoint.setLastGlobalPos(previousTouchPoint.globalPos());
+ d->appCurrentTouchPoints[touchPoint.id()] = touchPoint;
+ break;
+ }
+ Q_ASSERT(widget != 0);
+
+ StatesAndTouchPoints &maskAndPoints = widgetsNeedingEvents[widget];
+ maskAndPoints.first |= touchPoint.state();
+ maskAndPoints.second.append(touchPoint);
+ }
+
+ if (widgetsNeedingEvents.isEmpty())
+ return false;
+
+ bool returnValue = false;
+
+ QHash<QWidget *, StatesAndTouchPoints>::ConstIterator it = widgetsNeedingEvents.constBegin();
+ const QHash<QWidget *, StatesAndTouchPoints>::ConstIterator end = widgetsNeedingEvents.constEnd();
+ for (; it != end; ++it) {
+ QWidget *widget = it.key();
+ if (!QApplicationPrivate::tryModalHelper(widget, 0))
+ continue;
+
+ QEvent::Type eventType;
+ switch(it.value().first) {
+ case Qt::TouchPointPressed:
+ eventType = QEvent::TouchBegin;
+ break;
+ case Qt::TouchPointReleased:
+ eventType = QEvent::TouchEnd;
+ break;
+ case Qt::TouchPointStationary:
+ // don't send the event if nothing changed
+ continue;
+ default:
+ eventType = QEvent::TouchUpdate;
+ break;
+ }
+
+ QTouchEvent touchEvent(eventType,
+ q->keyboardModifiers(),
+ it.value().first,
+ it.value().second);
+ updateTouchPointsForWidget(widget, &touchEvent);
+
+ bool res = false;
+ 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);
+ res = QApplication::sendSpontaneousEvent(widget, &touchEvent)
+ && touchEvent.isAccepted();
+ break;
+ }
+ default:
+ if (widget->testAttribute(Qt::WA_AcceptedTouchBeginEvent)) {
+ (void) QApplication::sendSpontaneousEvent(widget, &touchEvent);
+ res = true;
+ }
+ break;
+ }
+ returnValue = returnValue || res;
+ }
+
+ return returnValue;
+}
+
+Q_GUI_EXPORT bool qt_translateRawTouchEvent(const QList<QTouchEvent::TouchPoint> &touchPoints,
+ QWidget *window)
+{
+ return QApplicationPrivate::translateRawTouchEvent(window, touchPoints);
+}
+
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_mac.mm b/src/gui/kernel/qapplication_mac.mm
index 6a592e4..a28d2e8 100644
--- a/src/gui/kernel/qapplication_mac.mm
+++ b/src/gui/kernel/qapplication_mac.mm
@@ -2998,4 +2998,9 @@ void onApplicationChangedActivation( bool activated )
#endif
}
+void QApplicationPrivate::initializeMultitouch_sys()
+{ }
+void QApplicationPrivate::cleanupMultitouch_sys()
+{ }
+
QT_END_NAMESPACE
diff --git a/src/gui/kernel/qapplication_p.h b/src/gui/kernel/qapplication_p.h
index 7e97418..60796fc 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;
@@ -419,17 +424,49 @@ public:
QEvent::Type type, Qt::MouseButtons buttons,
QWidget *buttonDown, QWidget *alienWidget);
static bool sendMouseEvent(QWidget *receiver, QMouseEvent *event, QWidget *alienWidget,
- QWidget *native, QWidget **buttonDown, QPointer<QWidget> &lastMouseReceiver);
+ QWidget *native, QWidget **buttonDown, QPointer<QWidget> &lastMouseReceiver,
+ bool spontaneous = true);
#if defined(Q_WS_WIN) || defined(Q_WS_X11)
void sendSyntheticEnterLeave(QWidget *widget);
#endif
+ QGestureManager *gestureManager;
+ // map<gesture name -> number of widget subscribed to it>
+ QMap<QString, int> grabbedGestures;
+
+ QHash<int, QWidget *> widgetForTouchPointId;
+ QMap<int, QTouchEvent::TouchPoint> appCurrentTouchPoints;
+ static void updateTouchPointsForWidget(QWidget *widget, QTouchEvent *touchEvent);
+ void initializeMultitouch();
+ void initializeMultitouch_sys();
+ void cleanupMultitouch();
+ void cleanupMultitouch_sys();
+ int findClosestTouchPointId(const QPointF &screenPos);
+ void appendTouchPoint(const QTouchEvent::TouchPoint &touchPoint);
+ void removeTouchPoint(int touchPointId);
+ static bool translateRawTouchEvent(QWidget *widget,
+ const QList<QTouchEvent::TouchPoint> &touchPoints);
+
+#if defined(Q_WS_WIN)
+ static qt_RegisterTouchWindowPtr RegisterTouchWindow;
+ static qt_GetTouchInputInfoPtr GetTouchInputInfo;
+ static qt_CloseTouchInputHandlePtr CloseTouchInputHandle;
+
+ QHash<DWORD, int> touchInputIDToTouchPointID;
+ QList<QTouchEvent::TouchPoint> appAllTouchPoints;
+ 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_qws.cpp b/src/gui/kernel/qapplication_qws.cpp
index ea52e11..e89011f 100644
--- a/src/gui/kernel/qapplication_qws.cpp
+++ b/src/gui/kernel/qapplication_qws.cpp
@@ -3746,4 +3746,9 @@ void QApplication::setArgs(int c, char **v)
d->argv = v;
}
+void QApplicationPrivate::initializeMultitouch_sys()
+{ }
+void QApplicationPrivate::cleanupMultitouch_sys()
+{ }
+
QT_END_NAMESPACE
diff --git a/src/gui/kernel/qapplication_win.cpp b/src/gui/kernel/qapplication_win.cpp
index b21eb36..ae6cadf 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,37 @@ extern void qt_wince_hide_taskbar(HWND hwnd); //defined in qguifunctions_wince.c
# include <winable.h>
#endif
+#ifndef WM_TOUCH
+# define WM_TOUCH 0x0240
+
+# 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 TOUCHEVENTF_PALM 0x0080
+
+# 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 {
@@ -1708,6 +1740,9 @@ LRESULT CALLBACK QtWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam
result = widget->translateWheelEvent(msg);
} else {
switch (message) {
+ case WM_TOUCH:
+ result = getQApplicationPrivateInternal()->translateTouchEvent(msg);
+ break;
case WM_KEYDOWN: // keyboard event
case WM_SYSKEYDOWN:
qt_keymapper_private()->updateKeyMap(msg);
@@ -3961,4 +3996,79 @@ 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_sys()
+{
+ 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"));
+
+ touchInputIDToTouchPointID.clear();
+}
+
+void QApplicationPrivate::cleanupMultitouch_sys()
+{
+ touchInputIDToTouchPointID.clear();
+}
+
+bool QApplicationPrivate::translateTouchEvent(const MSG &msg)
+{
+ Q_Q(QApplication);
+
+ QWidget *widgetForHwnd = QWidget::find(msg.hwnd);
+ if (!widgetForHwnd)
+ return false;
+
+ QList<QTouchEvent::TouchPoint> touchPoints;
+
+ 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);
+ }
+
+ QTouchEvent::TouchPoint touchPoint(touchPointID);
+
+ // update state
+ QPointF globalPos(qreal(touchInput.x) / qreal(100.), qreal(touchInput.y) / qreal(100.));
+ QSizeF contactArea = (touchInput.dwMask & TOUCHINPUTMASKF_CONTACTAREA)
+ ? QSizeF(qreal(touchInput.cxContact) / qreal(100.),
+ qreal(touchInput.cyContact) / qreal(100.))
+ : QSizeF();
+
+ if (touchInput.dwFlags & TOUCHEVENTF_DOWN) {
+ touchPoint.setState(Qt::TouchPointPressed);
+ touchPoint.setGlobalPos(globalPos);
+ touchPoint.setSize(contactArea);
+ } else if (touchInput.dwFlags & TOUCHEVENTF_UP) {
+ touchPoint.setState(Qt::TouchPointReleased);
+ touchPoint.setGlobalPos(globalPos);
+ touchPoint.setSize(QSizeF());
+ } else {
+ touchPoint.setState(globalPos == touchPoint.globalPos()
+ ? Qt::TouchPointStationary
+ : Qt::TouchPointMoved);
+ touchPoint.setGlobalPos(globalPos);
+ touchPoint.setSize(contactArea);
+ }
+
+ touchPoints.append(touchPoint);
+ }
+ QApplicationPrivate::CloseTouchInputHandle((HANDLE) msg.lParam);
+
+ extern bool qt_translateRawTouchEvent(const QList<QTouchEvent::TouchPoint> &, QWidget *);
+ qt_tabletChokeMouse = qt_translateRawTouchEvent(touchPoints, widgetForHwnd);
+ return qt_tabletChokeMouse;
+}
+
QT_END_NAMESPACE
diff --git a/src/gui/kernel/qapplication_x11.cpp b/src/gui/kernel/qapplication_x11.cpp
index 8ebea19..d55aa2d 100644
--- a/src/gui/kernel/qapplication_x11.cpp
+++ b/src/gui/kernel/qapplication_x11.cpp
@@ -4477,7 +4477,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)) {
@@ -5085,6 +5084,7 @@ bool QETWidget::translatePropertyEvent(const XEvent *event)
return true;
}
+
//
// Paint event translation
//
@@ -5986,4 +5986,9 @@ void QSessionManager::requestPhase2()
#endif // QT_NO_SESSIONMANAGER
+void QApplicationPrivate::initializeMultitouch_sys()
+{ }
+void QApplicationPrivate::cleanupMultitouch_sys()
+{ }
+
QT_END_NAMESPACE
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 a59e870..5b3c0fe 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,461 @@ 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.
+
+ All touch events are of type QEvent::TouchBegin,
+ QEvent::TouchUpdate, or QEvent::TouchEnd. 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.
+
+ Similar to QMouseEvent, Qt automatically grabs each touch point on
+ the first press inside a widget; the widget will receive all
+ updates for the touch point until it is released. Note that it is
+ possible for a widget to receive events for multiple touch points,
+ and that multiple widgets may be receiving touch events at the same
+ time.
+
+ A touch event contains a special accept flag that indicates
+ whether the receiver wants the event. By default, the event is
+ accepted. You should call ignore() if the touch event is not handled by
+ your widget. A QEvent::TouchBegin event is propagated up the parent widget
+ chain until a widget accepts it with accept(), or an event filter
+ consumes it. If the QEvent::TouchBegin event is neither accepted nor consumed,
+ then mouse events are simulated from the state of the first touch
+ point.
+
+ 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,
+ Qt::TouchPointStates touchPointStates,
+ const QList<QTouchEvent::TouchPoint> &touchPoints)
+ : QInputEvent(type, modifiers),
+ _touchPointStates(touchPointStates),
+ _touchPoints(touchPoints)
+{ }
+
+/*!
+ Destroys the QTouchEvent.
+*/
+QTouchEvent::~QTouchEvent()
+{ }
+
+/*! \fn Qt::TouchPointStates QTouchEvent::touchPointStates() const
+
+ Returns a bitwise OR of all the touch point states for this event.
+*/
+
+/*! \fn void QTouchEvent::setTouchPointStates(Qt::TouchPointStates touchPointStates)
+
+ \internal
+
+ Sets a bitwise OR of all the touch point states for this event.
+*/
+
+/*! \fn const QList<QTouchEvent::TouchPoint> &QTouchEvent::TouchPoints() const
+
+ Returns the list of touch points contained in the touch event.
+*/
+
+/*! \fn void QTouchEvent::setTouchPoints(QList<QTouchEvent::TouchPoint> &touchPoints)
+
+ \internal
+
+ Sets the list of touch points for this event.
+*/
+
+/*! \internal
+
+ Constructs a QTouchEvent::TouchPoint for use in a QTouchEvent.
+*/
+QTouchEvent::TouchPoint::TouchPoint(int id)
+ : d(new QTouchEventTouchPointPrivate(id))
+{ }
+
+/*! \internal
+
+ Constructs a copy of \a other.
+*/
+QTouchEvent::TouchPoint::TouchPoint(const QTouchEvent::TouchPoint &other)
+ : d(other.d)
+{
+ d->ref.ref();
+}
+
+/*! \internal
+
+ Destroys the QTouchEvent::TouchPoint.
+*/
+QTouchEvent::TouchPoint::~TouchPoint()
+{
+ if (!d->ref.deref())
+ delete d;
+}
+
+/*!
+ Returns the id number of this touch point.
+
+ Id numbers are globally sequential, starting at zero, meaning the
+ first touch point in the application 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)
+{
+ if (d->ref != 1)
+ d = d->detach();
+ 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)
+{
+ if (d->ref != 1)
+ d = d->detach();
+ 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)
+{
+ if (d->ref != 1)
+ d = d->detach();
+ 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)
+{
+ if (d->ref != 1)
+ d = d->detach();
+ 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)
+{
+ if (d->ref != 1)
+ d = d->detach();
+ d->lastPos = lastPos;
+}
+
+/*!
+ Returns the screen position of this touch point.
+*/
+QPointF QTouchEvent::TouchPoint::globalPos() const
+{
+ return d->screenPos;
+}
+
+/*! \internal */
+void QTouchEvent::TouchPoint::setGlobalPos(const QPointF &globalPos)
+{
+ if (d->ref != 1)
+ d = d->detach();
+ d->screenPos = globalPos;
+}
+
+/*!
+ Returns the starting screen position of this touch point.
+*/
+QPointF QTouchEvent::TouchPoint::startGlobalPos() const
+{
+ return d->startScreenPos;
+}
+
+/*! \internal */
+void QTouchEvent::TouchPoint::setStartGlobalPos(const QPointF &startGlobalPos)
+{
+ if (d->ref != 1)
+ d = d->detach();
+ d->startScreenPos = startGlobalPos;
+}
+
+/*!
+ Returns the screen position of this touch point from the previous
+ touch event.
+*/
+QPointF QTouchEvent::TouchPoint::lastGlobalPos() const
+{
+ return d->lastScreenPos;
+}
+
+/*! \internal */
+void QTouchEvent::TouchPoint::setLastGlobalPos(const QPointF &lastGlobalPos)
+{
+ if (d->ref != 1)
+ d = d->detach();
+ d->lastScreenPos = lastGlobalPos;
+}
+
+/*!
+ Returns the size of this touch point.
+*/
+QSizeF QTouchEvent::TouchPoint::size() const
+{
+ return d->screenSize;
+}
+
+/*! \internal */
+void QTouchEvent::TouchPoint::setSize(const QSizeF &size)
+{
+ if (d->ref != 1)
+ d = d->detach();
+ d->screenSize = size;
+}
+
+/*!
+ 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)
+{
+ if (d->ref != 1)
+ d = d->detach();
+ d->pressure = pressure;
+}
+
+/*! \internal */
+QTouchEvent::TouchPoint &QTouchEvent::TouchPoint::operator=(const QTouchEvent::TouchPoint &other)
+{
+ other.d->ref.ref();
+ if (!d->ref.deref())
+ delete d;
+ d = other.d;
+ return *this;
+}
+
+QTouchEventTouchPointPrivate *QTouchEventTouchPointPrivate::get(const QTouchEvent::TouchPoint &tp)
+{
+ return tp.d;
+}
+
QT_END_NAMESPACE
diff --git a/src/gui/kernel/qevent.h b/src/gui/kernel/qevent.h
index 449730d..0c4bbb7 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,86 @@ 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(const TouchPoint &other);
+ ~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 globalPos() const;
+ void setGlobalPos(const QPointF &globalPos);
+
+ QPointF startGlobalPos() const;
+ void setStartGlobalPos(const QPointF &startGlobalPos);
+
+ QPointF lastGlobalPos() const;
+ void setLastGlobalPos(const QPointF &lastGlobalPos);
+
+ QSizeF size() const;
+ void setSize(const QSizeF &size);
+
+ qreal pressure() const;
+ void setPressure(qreal pressure);
+
+ TouchPoint &operator=(const TouchPoint &other);
+
+ private:
+ QTouchEventTouchPointPrivate *d;
+
+ friend class QTouchEventTouchPointPrivate;
+ };
+
+ QTouchEvent(QEvent::Type type,
+ Qt::KeyboardModifiers modifiers,
+ Qt::TouchPointStates touchPointStates,
+ const QList<QTouchEvent::TouchPoint> &touchPoints);
+ ~QTouchEvent();
+
+ inline Qt::TouchPointStates touchPointStates() const
+ {
+ return _touchPointStates;
+ }
+ inline void setTouchPointStates(Qt::TouchPointStates touchPointStates)
+ {
+ _touchPointStates = touchPointStates;
+ }
+
+ inline const QList<QTouchEvent::TouchPoint> &touchPoints() const
+ {
+ return _touchPoints;
+ }
+ inline void setTouchPoints(const QList<QTouchEvent::TouchPoint> &touchPoints)
+ {
+ _touchPoints = touchPoints;
+ }
+
+protected:
+ Qt::TouchPointStates _touchPointStates;
+ QList<QTouchEvent::TouchPoint> _touchPoints;
+
+ 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..573fdc8 100644
--- a/src/gui/kernel/qevent_p.h
+++ b/src/gui/kernel/qevent_p.h
@@ -89,6 +89,35 @@ protected:
friend class QMouseEvent;
};
+class QTouchEventTouchPointPrivate
+{
+public:
+ inline QTouchEventTouchPointPrivate(int id)
+ : ref(1),
+ id(id),
+ state(Qt::TouchPointReleased),
+ pressure(qreal(-1.))
+ { }
+
+ inline QTouchEventTouchPointPrivate *detach()
+ {
+ QTouchEventTouchPointPrivate *d = new QTouchEventTouchPointPrivate(*this);
+ d->ref = 1;
+ return d;
+ }
+
+ QAtomicInt ref;
+ int id;
+ Qt::TouchPointState state;
+ QPointF pos, startPos, lastPos;
+ QPointF scenePos, startScenePos, lastScenePos;
+ QPointF screenPos, startScreenPos, lastScreenPos;
+ QSizeF size, sceneSize, screenSize;
+ qreal pressure;
+
+ static QTouchEventTouchPointPrivate *get(const QTouchEvent::TouchPoint &tp);
+};
+
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..2bb7de7
--- /dev/null
+++ b/src/gui/kernel/qgesture.cpp
@@ -0,0 +1,315 @@
+/****************************************************************************
+**
+** 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;
+}
+
+void QGesture::setRect(const QRect &rect)
+{
+ d_func()->rect = rect;
+}
+
+/*!
+ \property QGesture::hotSpot
+
+ \brief The center point of a gesture.
+*/
+QPoint QGesture::hotSpot() const
+{
+ return d_func()->hotSpot;
+}
+
+void QGesture::setHotSpot(const QPoint &point)
+{
+ d_func()->hotSpot = point;
+}
+
+/*!
+ \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;
+}
+
+void QGesture::setStartPos(const QPoint &point)
+{
+ d_func()->startPos = point;
+}
+
+/*!
+ \property QGesture::lastPos
+
+ \brief The last recorded position of the pointer.
+*/
+QPoint QGesture::lastPos() const
+{
+ return d_func()->lastPos;
+}
+
+void QGesture::setLastPos(const QPoint &point)
+{
+ d_func()->lastPos = point;
+}
+
+/*!
+ \property QGesture::pos
+
+ \brief The current position of the pointer.
+*/
+QPoint QGesture::pos() const
+{
+ return d_func()->pos;
+}
+
+void QGesture::setPos(const QPoint &point)
+{
+ d_func()->pos = point;
+}
+
+/*!
+ \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..95486bf
--- /dev/null
+++ b/src/gui/kernel/qgesture.h
@@ -0,0 +1,154 @@
+/****************************************************************************
+**
+** 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(QDateTime startTime READ startTime)
+ Q_PROPERTY(uint duration READ duration)
+
+ Q_PROPERTY(QRect rect READ rect WRITE setRect)
+ Q_PROPERTY(QPoint hotSpot READ hotSpot WRITE setHotSpot)
+ Q_PROPERTY(QPoint startPos READ startPos WRITE setStartPos)
+ Q_PROPERTY(QPoint lastPos READ lastPos WRITE setLastPos)
+ Q_PROPERTY(QPoint pos READ pos WRITE setPos)
+
+public:
+ 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;
+
+ QDateTime startTime() const;
+ uint duration() const;
+
+ QRect rect() const;
+ void setRect(const QRect &rect);
+ QPoint hotSpot() const;
+ void setHotSpot(const QPoint &point);
+
+ QPoint startPos() const;
+ void setStartPos(const QPoint &point);
+ QPoint lastPos() const;
+ void setLastPos(const QPoint &point);
+ QPoint pos() const;
+ void setPos(const QPoint &point);
+
+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 QGraphicsScene;
+ friend class QGraphicsScenePrivate;
+ 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..0f2e791
--- /dev/null
+++ b/src/gui/kernel/qgesture_p.h
@@ -0,0 +1,113 @@
+/****************************************************************************
+**
+** 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 QGraphicsItem;
+class QGesturePrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QGesture)
+
+public:
+ QGesturePrivate()
+ : state(Qt::NoGesture), graphicsItem(0), 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;
+ QGraphicsItem *graphicsItem;
+ 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..799bcfd
--- /dev/null
+++ b/src/gui/kernel/qgesturemanager.cpp
@@ -0,0 +1,643 @@
+/****************************************************************************
+**
+** 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;
+ }
+ }
+ Q_ASSERT(activeGestures.isEmpty());
+ 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() || !startedGestures.isEmpty()) {
+ // gesture found!
+ ret = true;
+ QSet<QGesture*> started;
+ foreach(QGestureRecognizer *r, finishedGestures) {
+ if (QGesture *gesture = r->getGesture()) {
+ started << gesture;
+ gesture->d_func()->singleshot = true;
+ }
+ }
+ foreach(QGestureRecognizer *r, startedGestures) {
+ if (QGesture *gesture = r->getGesture()) {
+ started << gesture;
+ gesture->d_func()->singleshot = false;
+ }
+ }
+ Q_ASSERT(!started.isEmpty());
+ ret = sendGestureEvent(receiver, started, QSet<QGesture*>());
+
+ 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;
+ }
+ }
+ }
+
+ 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);
+ }
+ }
+ QSet<QGesture*> started, updated;
+ if (!finishedGestures.isEmpty() || !startedGestures.isEmpty()) {
+ // another gesture found!
+ ret = true;
+ foreach(QGestureRecognizer *r, finishedGestures) {
+ if (QGesture *gesture = r->getGesture()) {
+ gesture->d_func()->singleshot = !activeGestures.contains(r);
+ if (gesture->d_func()->singleshot)
+ started << gesture;
+ else
+ updated << gesture;
+ }
+ }
+ foreach(QGestureRecognizer *r, startedGestures) {
+ if (QGesture *gesture = r->getGesture()) {
+ gesture->d_func()->singleshot = !activeGestures.contains(r);
+ if (gesture->d_func()->singleshot)
+ started << gesture;
+ else
+ updated << gesture;
+ }
+ }
+ }
+ activeGestures -= newMaybeGestures;
+ activeGestures -= cancelledGestures;
+ activeGestures += startedGestures;
+ activeGestures -= finishedGestures;
+ QSet<QString> cancelledGestureNames;
+ foreach(QGestureRecognizer *r, cancelledGestures)
+ cancelledGestureNames << r->gestureType();
+ ret = sendGestureEvent(receiver, started, updated, 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::sendGestureEvent(QWidget *receiver,
+ const QSet<QGesture*> &startedGestures,
+ const QSet<QGesture*> &updatedGestures,
+ const QSet<QString> &cancelled)
+{
+ DEBUG() << "QGestureManager::sendGestureEvent: sending to" << receiver
+ << "gestures:" << startedGestures << "," << updatedGestures
+ << "cancelled:" << cancelled;
+ // grouping gesture objects by receiver widgets.
+ typedef QMap<QWidget*, QSet<QGesture*> > WidgetGesturesMap;
+ WidgetGesturesMap widgetGestures;
+ for(QSet<QGesture*>::const_iterator it = startedGestures.begin(), e = startedGestures.end();
+ it != e; ++it) {
+ QGesture *g = *it;
+ QGesturePrivate *gd = g->d_func();
+ if (receiver) {
+ // find the target widget
+ gd->widget = 0;
+ gd->graphicsItem = 0;
+ QWidget *w = receiver;
+ QPoint offset;
+ const QString gestureType = g->type();
+ while (w) {
+ if (w->d_func()->hasGesture(gestureType))
+ break;
+ if (w->isWindow()) {
+ w = 0;
+ break;
+ }
+ offset += w->pos();
+ w = w->parentWidget();
+ }
+ if (w && w != gd->widget) {
+ DEBUG() << "QGestureManager::sendGestureEvent:" << g << "propagating to widget" << w << "offset" << offset;
+ g->translate(offset);
+ }
+ gd->widget = w;
+ }
+ 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*/);
+ QSet<QGesture*> gestures = it.value();
+ // mark all gestures as ignored by default
+ for(QSet<QGesture*>::iterator it = gestures.begin(), e = gestures.end(); it != e; ++it)
+ (*it)->ignore();
+ // TODO: send cancelled gesture event to the widget that received the original gesture!
+ QGestureEvent event(gestures, cancelled);
+ DEBUG() << "QGestureManager::sendGestureEvent: sending now to" << receiver
+ << "gestures" << gestures;
+ bool processed = qt_sendSpontaneousEvent(receiver, &event);
+ QSet<QGesture*> started = startedGestures & gestures;
+ DEBUG() << "QGestureManager::sendGestureEvent:" <<
+ (event.isAccepted() ? "" : "not") << "all gestures were accepted";
+ if (!started.isEmpty() && !(processed && event.isAccepted())) {
+ // there are started gestures events that weren't
+ // accepted, so propagating each gesture independently.
+ if (event.isAccepted()) {
+ foreach(QGesture *g, started)
+ g->accept();
+ }
+ QSet<QGesture*>::const_iterator it = started.begin(),
+ e = started.end();
+ for(; it != e; ++it) {
+ 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 && !w->isWindow()) {
+ g->translate(w->pos());
+ w = w->parentWidget();
+ QPoint offset;
+ const QString gestureType = g->type();
+ while (w) {
+ if (w->d_func()->hasGesture(gestureType)) {
+ DEBUG() << "QGestureManager::sendGestureEvent:" << receiver
+ << "didn't accept gesture" << g << "propagating to" << w;
+ ignoredGestures.insert(g);
+ gd->widget = w;
+ break;
+ }
+ if (w->isWindow()) {
+ w = 0;
+ break;
+ }
+ offset += w->pos();
+ w = w->parentWidget();
+ }
+ if (w) {
+ g->translate(offset);
+ } else {
+ DEBUG() << "QGestureManager::sendGestureEvent:" << receiver
+ << "didn't accept gesture" << g << "and nobody wants it";
+ }
+ }
+ }
+ }
+ }
+ if (ignoredGestures.isEmpty())
+ return ret;
+ // try to send all gestures that were ignored to the next parent
+ return sendGestureEvent(0, ignoredGestures, QSet<QGesture*>(), 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..745feb3
--- /dev/null
+++ b/src/gui/kernel/qgesturemanager_p.h
@@ -0,0 +1,126 @@
+/****************************************************************************
+**
+** 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_AUTOTEST_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();
+
+ bool sendGestureEvent(QWidget *receiver,
+ const QSet<QGesture*> &startedGestures,
+ const QSet<QGesture*> &updatedGestures,
+ const QSet<QString> &cancelled = QSet<QString>());
+
+protected:
+ void timerEvent(QTimerEvent *event);
+
+private slots:
+ void recognizerStateChanged(QGestureRecognizer::Result);
+
+private:
+ 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..879f557
--- /dev/null
+++ b/src/gui/kernel/qgesturerecognizer.cpp
@@ -0,0 +1,159 @@
+/****************************************************************************
+**
+** 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 returned QGesture object must point to the same object in a
+ single gesture sequence.
+
+ 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..67d7949
--- /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, //TODO: rename to just Gesture?
+ 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 6026821..dfbd647 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()) &&
@@ -7474,10 +7477,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;
@@ -7873,6 +7880,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();
@@ -9881,6 +9891,12 @@ void QWidget::setAttribute(Qt::WidgetAttribute attribute, bool on)
}
break;
+#if defined(Q_WS_WIN)
+ case Qt::WA_AcceptTouchEvents:
+ if (on)
+ d->registerTouchWindow();
+ break;
+#endif
default:
break;
}
@@ -10963,6 +10979,103 @@ 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);
+ int id = d->grabGesture(QGestureManager::instance()->makeGestureId(gesture));
+ if (d->extra && d->extra->proxyWidget)
+ d->extra->proxyWidget->QGraphicsItem::d_ptr->grabGesture(id);
+ return id;
+}
+
+int QWidgetPrivate::grabGesture(int gestureId)
+{
+ 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;
+}
+
+bool QWidgetPrivate::hasGesture(const QString &name) const
+{
+ QGestureManager *gm = QGestureManager::instance();
+ QSet<int>::const_iterator it = gestures.begin(),
+ e = gestures.end();
+ for (; it != e; ++it) {
+ if (gm->gestureNameFromId(*it) == name)
+ return true;
+ }
+ return false;
+}
+
+/*!
+ \since 4.6
+
+ 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)) {
+ if (d->extra && d->extra->proxyWidget)
+ d->extra->proxyWidget->QGraphicsItem::d_ptr->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 ff194f7..bd671c8 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"
@@ -524,6 +526,11 @@ public:
QList<QAction*> actions;
#endif
+ QSet<int> gestures;
+ int grabGesture(int gestureId);
+ bool releaseGesture(int gestureId);
+ bool hasGesture(const QString &type) const;
+
// Bit fields.
uint high_attributes[3]; // the low ones are in QWidget::widget_attributes
QPalette::ColorRole fg_role : 8;
@@ -558,6 +565,7 @@ public:
void unregisterOleDnd(QWidget *widget, QOleDropTarget *target);
#endif
void grabMouseWhileInWindow();
+ void registerTouchWindow();
#elif defined(Q_WS_MAC) // <--------------------------------------------------------- MAC
// This is new stuff
uint needWindowChange : 1;
diff --git a/src/gui/kernel/qwidget_win.cpp b/src/gui/kernel/qwidget_win.cpp
index ea79329..1b3cfed 100644
--- a/src/gui/kernel/qwidget_win.cpp
+++ b/src/gui/kernel/qwidget_win.cpp
@@ -500,6 +500,9 @@ void QWidgetPrivate::create_sys(WId window, bool initializeWindow, bool destroyO
q->setAttribute(Qt::WA_WState_Created); // accept move/resize events
hd = 0; // no display context
+ if (q->testAttribute(Qt::WA_AcceptTouchEvents))
+ registerTouchWindow();
+
if (window) { // got window from outside
if (IsWindowVisible(window))
q->setAttribute(Qt::WA_WState_Visible);
@@ -2069,8 +2072,16 @@ void QWidgetPrivate::setModal_sys()
{
}
+void QWidgetPrivate::registerTouchWindow()
+{
+ Q_Q(QWidget);
-
+ // enable WM_TOUCH* messages on our window
+ if (q->testAttribute(Qt::WA_WState_Created)
+ && QApplicationPrivate::RegisterTouchWindow
+ && q->windowType() != Qt::Desktop)
+ QApplicationPrivate::RegisterTouchWindow(q->effectiveWinId(), 0);
+}
QT_END_NAMESPACE
diff --git a/src/gui/widgets/qabstractscrollarea.cpp b/src/gui/widgets/qabstractscrollarea.cpp
index 5eed745..79ca11d 100644
--- a/src/gui/widgets/qabstractscrollarea.cpp
+++ b/src/gui/widgets/qabstractscrollarea.cpp
@@ -909,6 +909,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 cae3024..c6e5e55 100644
--- a/src/network/kernel/qauthenticator.cpp
+++ b/src/network/kernel/qauthenticator.cpp
@@ -53,7 +53,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);
diff --git a/src/testlib/qtest_gui.h b/src/testlib/qtest_gui.h
index d389f1c..d317e85 100644
--- a/src/testlib/qtest_gui.h
+++ b/src/testlib/qtest_gui.h
@@ -46,6 +46,7 @@
#include <QtTest/qtest.h>
#include <QtTest/qtestevent.h>
#include <QtTest/qtestmouse.h>
+#include <QtTest/qtesttouch.h>
#include <QtTest/qtestkeyboard.h>
#include <QtGui/qicon.h>
diff --git a/src/testlib/qtesttouch.h b/src/testlib/qtesttouch.h
new file mode 100644
index 0000000..2db015a
--- /dev/null
+++ b/src/testlib/qtesttouch.h
@@ -0,0 +1,149 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the QtTest module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QTESTTOUCH_H
+#define QTESTTOUCH_H
+
+#if 0
+// inform syncqt
+#pragma qt_no_master_include
+#endif
+
+#include <QtTest/qtest_global.h>
+#include <QtTest/qtestassert.h>
+#include <QtTest/qtestsystem.h>
+#include <QtTest/qtestspontaneevent.h>
+
+#include <QtCore/qmap.h>
+#include <QtGui/qevent.h>
+#include <QtGui/qwidget.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Test)
+
+extern Q_GUI_EXPORT bool qt_translateRawTouchEvent(const QList<QTouchEvent::TouchPoint> &touchPoints, QWidget *window);
+
+namespace QTest
+{
+
+ class QTouchEventSequence
+ {
+ public:
+ ~QTouchEventSequence()
+ {
+ commit();
+ points.clear();
+ }
+ QTouchEventSequence& press(int touchId, const QPoint &pt, QWidget *widget = 0)
+ {
+ QTouchEvent::TouchPoint &p = point(touchId);
+ p.setGlobalPos(mapToScreen(widget, pt));
+ p.setState(Qt::TouchPointPressed);
+ return *this;
+ }
+ QTouchEventSequence& move(int touchId, const QPoint &pt, QWidget *widget = 0)
+ {
+ QTouchEvent::TouchPoint &p = point(touchId);
+ p.setGlobalPos(mapToScreen(widget, pt));
+ p.setState(Qt::TouchPointMoved);
+ return *this;
+ }
+ QTouchEventSequence& release(int touchId, const QPoint &pt, QWidget *widget = 0)
+ {
+ QTouchEvent::TouchPoint &p = point(touchId);
+ p.setGlobalPos(mapToScreen(widget, pt));
+ p.setState(Qt::TouchPointReleased);
+ return *this;
+ }
+ QTouchEventSequence& stationary(int touchId)
+ {
+ QTouchEvent::TouchPoint &p = point(touchId);
+ p.setState(Qt::TouchPointStationary);
+ return *this;
+ }
+
+ private:
+ QTouchEventSequence(QWidget *widget)
+ : targetWidget(widget)
+ {
+ }
+ QTouchEventSequence(const QTouchEventSequence &v);
+ void operator=(const QTouchEventSequence&);
+
+ QTouchEvent::TouchPoint &point(int touchId)
+ {
+ if (!points.contains(touchId))
+ points[touchId] = QTouchEvent::TouchPoint(touchId);
+ return points[touchId];
+ }
+ QPoint mapToScreen(QWidget *widget, const QPoint &pt)
+ {
+ if (widget)
+ return widget->mapToGlobal(pt);
+ return targetWidget ? targetWidget->mapToGlobal(pt) : pt;
+ }
+ void commit()
+ {
+ if (!qt_translateRawTouchEvent(points.values(), targetWidget))
+ QTest::qWarn("Touch event not accepted by receiving widget");
+ targetWidget = 0;
+ }
+
+ QMap<int, QTouchEvent::TouchPoint> points;
+ QWidget *targetWidget;
+ friend QTouchEventSequence touchEvent(QWidget*);
+ };
+
+ QTouchEventSequence touchEvent(QWidget *widget = 0)
+ {
+ return QTouchEventSequence(widget);
+ }
+
+}
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QTESTTOUCH_H
diff --git a/src/testlib/testlib.pro b/src/testlib/testlib.pro
index ae4f182..9740c21 100644
--- a/src/testlib/testlib.pro
+++ b/src/testlib/testlib.pro
@@ -20,7 +20,8 @@ HEADERS = qtest_global.h \
qtestxunitstreamer.h \
qtestxmlstreamer.h \
qtestlightxmlstreamer.h \
- qtestfilelogger.h
+ qtestfilelogger.h \
+ qtesttouch.h
SOURCES = qtestcase.cpp \
qtestlog.cpp \
qtesttable.cpp \