summaryrefslogtreecommitdiffstats
path: root/src/gui
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui')
-rw-r--r--src/gui/graphicsview/qgraphicsitem.cpp147
-rw-r--r--src/gui/graphicsview/qgraphicsitem.h7
-rw-r--r--src/gui/graphicsview/qgraphicsitem_p.h52
-rw-r--r--src/gui/graphicsview/qgraphicsproxywidget.cpp16
-rw-r--r--src/gui/graphicsview/qgraphicsscene.cpp353
-rw-r--r--src/gui/graphicsview/qgraphicsscene.h2
-rw-r--r--src/gui/graphicsview/qgraphicsscene_p.h25
-rw-r--r--src/gui/graphicsview/qgraphicssceneevent.cpp270
-rw-r--r--src/gui/graphicsview/qgraphicssceneevent.h47
-rw-r--r--src/gui/graphicsview/qgraphicsview.cpp106
-rw-r--r--src/gui/graphicsview/qgraphicsview_p.h11
-rw-r--r--src/gui/kernel/kernel.pri17
-rw-r--r--src/gui/kernel/qapplication.cpp369
-rw-r--r--src/gui/kernel/qapplication.h12
-rw-r--r--src/gui/kernel/qapplication_mac.mm5
-rw-r--r--src/gui/kernel/qapplication_p.h64
-rw-r--r--src/gui/kernel/qapplication_qws.cpp5
-rw-r--r--src/gui/kernel/qapplication_win.cpp109
-rw-r--r--src/gui/kernel/qapplication_x11.cpp230
-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.cpp571
-rw-r--r--src/gui/kernel/qevent.h118
-rw-r--r--src/gui/kernel/qevent_p.h28
-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.cpp644
-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.cpp150
-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/styles/qproxystyle.cpp4
-rw-r--r--src/gui/widgets/qabstractscrollarea.cpp1
41 files changed, 5233 insertions, 75 deletions
diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp
index 555f7b0..1c062cc 100644
--- a/src/gui/graphicsview/qgraphicsitem.cpp
+++ b/src/gui/graphicsview/qgraphicsitem.cpp
@@ -574,6 +574,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>
@@ -614,6 +615,8 @@ public:
};
Q_GLOBAL_STATIC(QGraphicsItemCustomDataStore, qt_dataStore)
+QString qt_getStandardGestureTypeName(Qt::GestureType type);
+
/*!
\internal
@@ -1127,6 +1130,7 @@ QGraphicsItem::~QGraphicsItem()
{
d_ptr->inDestructor = 1;
d_ptr->removeExtraItemCache();
+ d_ptr->removeExtraGestures();
clearFocus();
if (!d_ptr->children.isEmpty()) {
@@ -2281,6 +2285,36 @@ void QGraphicsItem::setAcceptsHoverEvents(bool enabled)
setAcceptHoverEvents(enabled);
}
+/*! \since 4.6
+
+ Returns true if an item accepts touch events (QTouchEvent); 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)
+{
+ if (d_ptr->acceptTouchEvents == quint32(enabled))
+ return;
+ d_ptr->acceptTouchEvents = quint32(enabled);
+ if (d_ptr->acceptTouchEvents && d_ptr->scene && d_ptr->scene->d_func()->allItemsIgnoreTouchEvents) {
+ d_ptr->scene->d_func()->allItemsIgnoreTouchEvents = false;
+ d_ptr->scene->d_func()->enableTouchEventsOnViews();
+ }
+}
+
/*!
Returns true if this item handles child events (i.e., all events
intended for any of its children are instead sent to this item);
@@ -6219,6 +6253,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
@@ -6242,6 +6372,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 aeb4691..3a3d1a1 100644
--- a/src/gui/graphicsview/qgraphicsitem.h
+++ b/src/gui/graphicsview/qgraphicsitem.h
@@ -212,6 +212,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);
@@ -377,6 +379,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 b9e7041..a0d061b 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 "qgraphicsview_p.h"
@@ -92,6 +93,12 @@ public:
void purge();
};
+class QGestureExtraData
+{
+public:
+ QSet<int> gestures;
+};
+
class Q_AUTOTEST_EXPORT QGraphicsItemPrivate
{
Q_DECLARE_PUBLIC(QGraphicsItem)
@@ -101,7 +108,8 @@ public:
ExtraCursor,
ExtraCacheData,
ExtraMaxDeviceCoordCacheSize,
- ExtraBoundingRegionGranularity
+ ExtraBoundingRegionGranularity,
+ ExtraGestures
};
enum AncestorFlag {
@@ -153,6 +161,8 @@ public:
isObject(0),
ignoreVisible(0),
ignoreOpacity(0),
+ acceptTouchEvents(0),
+ acceptedTouchBeginEvent(0),
globalStackingOrder(-1),
q_ptr(0)
{
@@ -174,7 +184,7 @@ public:
void combineTransformToParent(QTransform *x, const QTransform *viewTransform = 0) const;
void combineTransformFromParent(QTransform *x, const QTransform *viewTransform = 0) const;
-
+
// ### Qt 5: Remove. Workaround for reimplementation added after Qt 4.4.
virtual QVariant inputMethodQueryHelper(Qt::InputMethodQuery query) const;
static bool movableAncestorIsSelected(const QGraphicsItem *item);
@@ -243,7 +253,7 @@ public:
}
}
}
-
+
struct ExtraStruct {
ExtraStruct(Extra type, QVariant value)
: type(type), value(value)
@@ -255,7 +265,7 @@ public:
bool operator<(Extra extra) const
{ return type < extra; }
};
-
+
QList<ExtraStruct> extras;
QGraphicsItemCache *maybeExtraItemCache() const;
@@ -384,7 +394,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;
@@ -401,8 +435,8 @@ public:
quint32 cacheMode : 2;
quint32 hasBoundingRegionGranularity : 1;
quint32 isWidget : 1;
- quint32 dirty : 1;
- quint32 dirtyChildren : 1;
+ quint32 dirty : 1;
+ quint32 dirtyChildren : 1;
quint32 localCollisionHack : 1;
quint32 dirtyClipPath : 1;
quint32 emptyClipPath : 1;
@@ -421,7 +455,9 @@ public:
quint32 isObject : 1;
quint32 ignoreVisible : 1;
quint32 ignoreOpacity : 1;
- quint32 unused : 12; // feel free to use
+ quint32 acceptTouchEvents : 1;
+ quint32 acceptedTouchBeginEvent : 1;
+ quint32 unused : 10; // feel free to use
// Optional stacking order
int globalStackingOrder;
diff --git a/src/gui/graphicsview/qgraphicsproxywidget.cpp b/src/gui/graphicsview/qgraphicsproxywidget.cpp
index 57269ce..1f3637d 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 d9d31ef..7428d79 100644
--- a/src/gui/graphicsview/qgraphicsscene.cpp
+++ b/src/gui/graphicsview/qgraphicsscene.cpp
@@ -246,6 +246,8 @@
#ifdef Q_WS_X11
#include <private/qt_x11_p.h>
#endif
+#include <private/qgesturemanager_p.h>
+#include <private/qgesture_p.h>
QT_BEGIN_NAMESPACE
@@ -358,7 +360,8 @@ QGraphicsScenePrivate::QGraphicsScenePrivate()
painterStateProtection(true),
sortCacheEnabled(false),
updatingSortCache(false),
- style(0)
+ style(0),
+ allItemsIgnoreTouchEvents(true)
{
}
@@ -1357,6 +1360,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());
@@ -2885,6 +2889,7 @@ void QGraphicsScene::clear()
d->largestUntransformableItem = QRectF();
d->allItemsIgnoreHoverEvents = true;
d->allItemsUseDefaultCursor = true;
+ d->allItemsIgnoreTouchEvents = true;
}
/*!
@@ -3062,6 +3067,12 @@ void QGraphicsScene::addItem(QGraphicsItem *item)
}
#endif //QT_NO_CURSOR
+ // Enable touch events if the item accepts touch events.
+ if (d->allItemsIgnoreTouchEvents && item->acceptTouchEvents()) {
+ d->allItemsIgnoreTouchEvents = false;
+ d->enableTouchEventsOnViews();
+ }
+
// Update selection lists
if (item->isSelected())
d->selectedItems << item;
@@ -3793,6 +3804,9 @@ bool QGraphicsScene::event(QEvent *event)
case QEvent::GraphicsSceneHoverEnter:
case QEvent::GraphicsSceneHoverLeave:
case QEvent::GraphicsSceneHoverMove:
+ case QEvent::TouchBegin:
+ case QEvent::TouchUpdate:
+ case QEvent::TouchEnd:
// 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
@@ -3946,6 +3960,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::TouchBegin:
+ case QEvent::TouchUpdate:
+ case QEvent::TouchEnd:
+ d->touchEventHandler(static_cast<QTouchEvent *>(event));
+ break;
case QEvent::Timer:
if (d->indexTimerId && static_cast<QTimerEvent *>(event)->timerId() == d->indexTimerId) {
if (d->restartIndexTimer) {
@@ -3962,6 +4022,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
@@ -5166,7 +5290,7 @@ void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter *
painter->setWorldTransform(transform);
painter->setClipPath(item->shape(), Qt::IntersectClip);
}
-
+
if (!dontDrawChildren) {
if (item && item->d_ptr->needSortChildren) {
item->d_ptr->needSortChildren = 0;
@@ -5856,6 +5980,231 @@ 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, QTouchEvent *touchEvent)
+{
+ QList<QTouchEvent::TouchPoint> touchPoints = touchEvent->touchPoints();
+ for (int i = 0; i < touchPoints.count(); ++i) {
+ QTouchEvent::TouchPoint &touchPoint = touchPoints[i];
+ touchPoint.setRect(item->mapFromScene(touchPoint.sceneRect()).boundingRect());
+ touchPoint.setStartPos(item->d_ptr->genericMapFromScene(touchPoint.startScenePos(), touchEvent->widget()));
+ touchPoint.setLastPos(item->d_ptr->genericMapFromScene(touchPoint.lastScenePos(), touchEvent->widget()));
+ }
+ touchEvent->setTouchPoints(touchPoints);
+}
+
+int QGraphicsScenePrivate::findClosestTouchPointId(const QPointF &scenePos)
+{
+ int closestTouchPointId = -1;
+ qreal closestDistance = qreal(0.);
+ foreach (const QTouchEvent::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(QTouchEvent *sceneTouchEvent)
+{
+ typedef QPair<Qt::TouchPointStates, QList<QTouchEvent::TouchPoint> > StatesAndTouchPoints;
+ QHash<QGraphicsItem *, StatesAndTouchPoints> itemsNeedingEvents;
+
+ for (int i = 0; i < sceneTouchEvent->touchPoints().count(); ++i) {
+ const QTouchEvent::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::TouchBegin;
+ break;
+ case Qt::TouchPointReleased:
+ // all touch points have released state
+ eventType = QEvent::TouchEnd;
+ break;
+ case Qt::TouchPointStationary:
+ // don't send the event if nothing changed
+ continue;
+ default:
+ // all other combinations
+ eventType = QEvent::TouchUpdate;
+ break;
+ }
+
+ QTouchEvent 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::TouchBegin:
+ {
+ // 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, QTouchEvent *touchEvent)
+{
+ Q_Q(QGraphicsScene);
+
+ if (cachedItemsUnderMouse.isEmpty() || cachedItemsUnderMouse.first() != origin) {
+ const QTouchEvent::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 QTouchEvent::TouchPoint &touchPoint = touchEvent->touchPoints().at(i);
+ itemForTouchPointId[touchPoint.id()] = item;
+ }
+ break;
+ }
+ }
+
+ touchEvent->setAccepted(eventAccepted);
+ return res;
+}
+
+void QGraphicsScenePrivate::enableTouchEventsOnViews()
+{
+ foreach (QGraphicsView *view, views)
+ view->viewport()->setAttribute(Qt::WA_AcceptTouchEvents, true);
+}
+
+
QT_END_NAMESPACE
#include "moc_qgraphicsscene.cpp"
diff --git a/src/gui/graphicsview/qgraphicsscene.h b/src/gui/graphicsview/qgraphicsscene.h
index 1d4a617..aa9fd5d 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 a8f6699..983486f 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 "qgraphicsview.h"
#include "qgraphicsscene_bsp_p.h"
#include "qgraphicsitem_p.h"
@@ -77,6 +78,7 @@ QT_BEGIN_NAMESPACE
class QGraphicsView;
class QGraphicsWidget;
+class QGesture;
class QGraphicsScenePrivate : public QObjectPrivate
{
@@ -165,7 +167,7 @@ public:
void grabKeyboard(QGraphicsItem *item);
void ungrabKeyboard(QGraphicsItem *item, bool itemIsDying = false);
void clearKeyboardGrabber();
-
+
QGraphicsItem *dragDropItem;
QGraphicsWidget *enterWidget;
Qt::DropAction lastDropAction;
@@ -184,6 +186,9 @@ public:
void storeMouseButtonsForMouseGrabber(QGraphicsSceneMouseEvent *event);
QList<QGraphicsView *> views;
+ void addView(QGraphicsView *view);
+ void removeView(QGraphicsView *view);
+
bool painterStateProtection;
QMultiMap<QGraphicsItem *, QGraphicsItem *> sceneEventFilters;
@@ -246,7 +251,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)
@@ -294,6 +299,22 @@ public:
void updatePalette(const QPalette &palette);
QStyleOptionGraphicsItem styleOptionTmp;
+
+ // 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);
+
+ QMap<int, QTouchEvent::TouchPoint> sceneCurrentTouchPoints;
+ QHash<int, QGraphicsItem *> itemForTouchPointId;
+ static void updateTouchPointsForItem(QGraphicsItem *item, QTouchEvent *touchEvent);
+ int findClosestTouchPointId(const QPointF &scenePos);
+ void touchEventHandler(QTouchEvent *touchEvent);
+ bool sendTouchBeginEvent(QGraphicsItem *item, QTouchEvent *touchEvent);
+ bool allItemsIgnoreTouchEvents;
+ void enableTouchEventsOnViews();
};
QT_END_NAMESPACE
diff --git a/src/gui/graphicsview/qgraphicssceneevent.cpp b/src/gui/graphicsview/qgraphicssceneevent.cpp
index 283010d..ec4f5f8 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
@@ -268,9 +268,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 +527,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 +550,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 +1280,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 +1378,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 +1433,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 +1678,249 @@ 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();
+}
+
QT_END_NAMESPACE
#endif // QT_NO_GRAPHICSVIEW
diff --git a/src/gui/graphicsview/qgraphicssceneevent.h b/src/gui/graphicsview/qgraphicssceneevent.h
index d493de3..8a30bb8 100644
--- a/src/gui/graphicsview/qgraphicssceneevent.h
+++ b/src/gui/graphicsview/qgraphicssceneevent.h
@@ -44,6 +44,10 @@
#include <QtCore/qcoreevent.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,49 @@ 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;
+};
+
#endif // QT_NO_GRAPHICSVIEW
QT_END_NAMESPACE
diff --git a/src/gui/graphicsview/qgraphicsview.cpp b/src/gui/graphicsview/qgraphicsview.cpp
index fb1a822..6ac2914 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,23 @@ 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::translateTouchEvent(QGraphicsViewPrivate *d, QTouchEvent *touchEvent)
+{
+ QList<QTouchEvent::TouchPoint> touchPoints = touchEvent->touchPoints();
+ for (int i = 0; i < touchPoints.count(); ++i) {
+ QTouchEvent::TouchPoint &touchPoint = touchPoints[i];
+ // the scene will set the item local pos, startPos, lastPos, and rect before delivering to
+ // an item, but for now those functions are returning the view's local coordinates
+ touchPoint.setSceneRect(d->mapToScene(touchPoint.rect()));
+ touchPoint.setStartScenePos(d->mapToScene(touchPoint.startPos()));
+ touchPoint.setLastScenePos(d->mapToScene(touchPoint.lastPos()));
+
+ // screenPos, startScreenPos, lastScreenPos, and screenRect are already set
+ }
+
+ touchEvent->setTouchPoints(touchPoints);
+}
+
/*!
\internal
*/
@@ -591,7 +612,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());
@@ -1488,7 +1509,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;
}
@@ -1497,7 +1518,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;
@@ -1507,6 +1528,10 @@ void QGraphicsView::setScene(QGraphicsScene *scene)
|| !d->scene->d_func()->allItemsUseDefaultCursor) {
d->viewport->setMouseTracking(true);
}
+
+ // enable touch events if any items is interested in them
+ if (!d->scene->d_func()->allItemsIgnoreTouchEvents)
+ d->viewport->setAttribute(Qt::WA_AcceptTouchEvents);
} else {
d->recalculateContentSize();
}
@@ -2590,6 +2615,11 @@ void QGraphicsView::setupViewport(QWidget *widget)
|| !d->scene->d_func()->allItemsUseDefaultCursor)) {
widget->setMouseTracking(true);
}
+
+ // enable touch events if any items is interested in them
+ if (d->scene && !d->scene->d_func()->allItemsIgnoreTouchEvents)
+ widget->setAttribute(Qt::WA_AcceptTouchEvents);
+
widget->setAcceptDrops(acceptDrops());
}
@@ -2626,6 +2656,9 @@ bool QGraphicsView::event(QEvent *event)
}
}
break;
+ case QEvent::Gesture:
+ viewportEvent(event);
+ return true;
default:
break;
}
@@ -2707,6 +2740,34 @@ 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.
+ QTouchEvent *touchEvent = static_cast<QTouchEvent *>(event);
+ touchEvent->setWidget(viewport());
+ QGraphicsViewPrivate::translateTouchEvent(d, touchEvent);
+ (void) QApplication::sendEvent(d->scene, touchEvent);
+ }
+
+ return true;
+ }
default:
break;
}
@@ -2965,7 +3026,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);
}
/*!
@@ -3004,7 +3065,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();
@@ -3174,7 +3235,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());
@@ -3634,6 +3695,39 @@ 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);
+}
+
+QRectF QGraphicsViewPrivate::mapToScene(const QRectF &rect) const
+{
+ QPointF scrollOffset(horizontalScroll(), verticalScroll());
+ QPointF tl = scrollOffset + rect.topLeft();
+ QPointF tr = scrollOffset + rect.topRight();
+ QPointF br = scrollOffset + rect.bottomRight();
+ QPointF bl = scrollOffset + rect.bottomLeft();
+
+ QPolygonF poly;
+ poly.resize(4);
+ if (!identityMatrix) {
+ QTransform x = matrix.inverted();
+ poly[0] = x.map(tl);
+ poly[1] = x.map(tr);
+ poly[2] = x.map(br);
+ poly[3] = x.map(bl);
+ } else {
+ poly[0] = tl;
+ poly[1] = tr;
+ poly[2] = br;
+ poly[3] = bl;
+ }
+ return poly.boundingRect();
+}
+
QT_END_NAMESPACE
#include "moc_qgraphicsview.cpp"
diff --git a/src/gui/graphicsview/qgraphicsview_p.h b/src/gui/graphicsview/qgraphicsview_p.h
index 9551ff6..5682138 100644
--- a/src/gui/graphicsview/qgraphicsview_p.h
+++ b/src/gui/graphicsview/qgraphicsview_p.h
@@ -177,6 +177,17 @@ public:
QRegion exposedRegion;
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;
+ QRectF mapToScene(const QRectF &rect) const;
+ static void translateTouchEvent(QGraphicsViewPrivate *d, QTouchEvent *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 7219fed..5ef453d 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;
}
@@ -884,6 +899,8 @@ void QApplicationPrivate::initialize()
QApplicationPrivate::wheel_scroll_lines = 3;
#endif
#endif
+
+ initializeMultitouch();
}
/*!
@@ -1034,6 +1051,8 @@ QApplication::~QApplication()
delete QDragManager::self();
#endif
+ d->cleanupMultitouch();
+
qt_cleanup();
if (QApplicationPrivate::widgetCount)
@@ -1381,7 +1400,7 @@ void QApplication::setStyle(QStyle *style)
#endif // QT_NO_STYLE_STYLESHEET
QApplicationPrivate::app_style = style;
QApplicationPrivate::app_style->setParent(qApp); // take ownership
-
+
// take care of possible palette requirements of certain gui
// styles. Do it before polishing the application since the style
// might call QApplication::setPalette() itself
@@ -2868,7 +2887,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);
@@ -2921,7 +2941,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) {
@@ -3562,26 +3586,32 @@ 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
-# else
- false
+ || 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::Gesture && t != QEvent::GraphicsSceneGesture) {
+ 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:
@@ -3709,19 +3739,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) {
@@ -3803,17 +3824,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) {
@@ -4018,7 +4031,45 @@ 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->setWidget(widget);
+ touchEvent->setAccepted(acceptTouchEvents);
+ res = acceptTouchEvents && d->notify_helper(widget, touchEvent);
+ eventAccepted = touchEvent->isAccepted();
+ widget->setAttribute(Qt::WA_WState_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;
@@ -4985,6 +5036,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;
@@ -4998,6 +5066,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.
@@ -5129,6 +5248,186 @@ 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
+ QRectF rect = touchPoint.screenRect();
+ const QPointF screenPos = rect.center();
+ const QPointF delta = screenPos - screenPos.toPoint();
+
+ rect.moveCenter(widget->mapFromGlobal(screenPos.toPoint()) + delta);
+ touchPoint.setRect(rect);
+
+ touchPoint.setStartPos(widget->mapFromGlobal(touchPoint.startScreenPos().toPoint()) + delta);
+ touchPoint.setLastPos(widget->mapFromGlobal(touchPoint.lastScreenPos().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 &screenPos)
+{
+ int closestTouchPointId = -1;
+ qreal closestDistance = qreal(0.);
+ foreach (const QTouchEvent::TouchPoint &touchPoint, appCurrentTouchPoints) {
+ qreal distance = QLineF(screenPos, touchPoint.screenPos()).length();
+ if (closestTouchPointId == -1 || distance < closestDistance) {
+ closestTouchPointId = touchPoint.id();
+ closestDistance = distance;
+ }
+ }
+ return closestTouchPointId;
+}
+
+void 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.screenPos().toPoint());
+ if (!window)
+ continue;
+ widget = window->childAt(window->mapFromGlobal(touchPoint.screenPos().toPoint()));
+ if (!widget)
+ widget = window;
+
+ int closestTouchPointId = d->findClosestTouchPointId(touchPoint.screenPos());
+ QWidget *closestWidget = d->widgetForTouchPointId.value(closestTouchPointId);
+ if (closestWidget
+ && (widget->isAncestorOf(closestWidget) || closestWidget->isAncestorOf(widget))) {
+ widget = closestWidget;
+ }
+ d->widgetForTouchPointId[touchPoint.id()] = widget;
+ touchPoint.setStartScreenPos(touchPoint.screenPos());
+ touchPoint.setLastScreenPos(touchPoint.screenPos());
+ 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.setStartScreenPos(previousTouchPoint.startScreenPos());
+ touchPoint.setLastScreenPos(previousTouchPoint.screenPos());
+ 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.setStartScreenPos(previousTouchPoint.startScreenPos());
+ touchPoint.setLastScreenPos(previousTouchPoint.screenPos());
+ d->appCurrentTouchPoints[touchPoint.id()] = touchPoint;
+ break;
+ }
+ Q_ASSERT(widget != 0);
+
+ // make the *scene* functions return the same as the *screen* functions
+ touchPoint.setSceneRect(touchPoint.screenRect());
+ touchPoint.setStartScenePos(touchPoint.startScreenPos());
+ touchPoint.setLastScenePos(touchPoint.lastScreenPos());
+
+ StatesAndTouchPoints &maskAndPoints = widgetsNeedingEvents[widget];
+ maskAndPoints.first |= touchPoint.state();
+ if (touchPoint.isPrimary())
+ maskAndPoints.first |= Qt::TouchPointPrimary;
+ maskAndPoints.second.append(touchPoint);
+ }
+
+ if (widgetsNeedingEvents.isEmpty())
+ return;
+
+ 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 & Qt::TouchPointStateMask) {
+ 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);
+
+ 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_WState_AcceptedTouchBeginEvent);
+ (void ) QApplication::sendSpontaneousEvent(widget, &touchEvent);
+ break;
+ }
+ default:
+ if (widget->testAttribute(Qt::WA_WState_AcceptedTouchBeginEvent)) {
+ if (touchEvent.type() == QEvent::TouchEnd)
+ widget->setAttribute(Qt::WA_WState_AcceptedTouchBeginEvent, false);
+ (void) QApplication::sendSpontaneousEvent(widget, &touchEvent);
+ }
+ break;
+ }
+ }
+}
+
+Q_GUI_EXPORT void qt_translateRawTouchEvent(const QList<QTouchEvent::TouchPoint> &touchPoints,
+ QWidget *window)
+{
+ 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 b3bb1cd..954f824 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();
@@ -382,6 +391,9 @@ private:
#if defined(Q_WS_MAC) || defined(Q_WS_X11)
Q_PRIVATE_SLOT(d_func(), void _q_alertTimeOut())
#endif
+#if defined(QT_RX71_MULTITOUCH)
+ Q_PRIVATE_SLOT(d_func(), void _q_readRX71MultiTouchEvents())
+#endif
};
QT_END_NAMESPACE
diff --git a/src/gui/kernel/qapplication_mac.mm b/src/gui/kernel/qapplication_mac.mm
index ace5d1d..479b1fe 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 a9e5d60..f2226ce 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,10 @@ class QClipboard;
class QGraphicsScene;
class QGraphicsSystem;
class QInputContext;
-class QKeyEvent;
-class QMouseEvent;
class QObject;
-class QWheelEvent;
class QWidget;
+class QGestureManager;
+class QSocketNotifier;
extern bool qt_is_gui_used;
#ifndef QT_NO_CLIPBOARD
@@ -189,6 +189,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;
@@ -421,17 +427,67 @@ 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 void 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
+
+#ifdef QT_RX71_MULTITOUCH
+ bool hasRX71MultiTouch;
+
+ struct RX71TouchPointState {
+ QSocketNotifier *socketNotifier;
+ QTouchEvent::TouchPoint touchPoint;
+
+ int minX, maxX, scaleX;
+ int minY, maxY, scaleY;
+ int minZ, maxZ;
+ };
+ QList<RX71TouchPointState> allRX71TouchPoints;
+
+ bool readRX71MultiTouchEvents(int deviceNumber);
+ void fakeMouseEventFromRX71TouchEvent();
+ void _q_readRX71MultiTouchEvents();
+#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 0567a1d..f568438 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 0c74cfa..66dfee2 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,78 @@ 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 screenPos(qreal(touchInput.x) / qreal(100.), qreal(touchInput.y) / qreal(100.));
+ QRectF screenRect;
+ if (touchInput.dwMask & TOUCHINPUTMASKF_CONTACTAREA)
+ screenRect.setSize(QSizeF(qreal(touchInput.cxContact) / qreal(100.),
+ qreal(touchInput.cyContact) / qreal(100.)));
+ screenRect.moveCenter(screenPos);
+
+ Qt::TouchPointStates state;
+ if (touchInput.dwFlags & TOUCHEVENTF_DOWN) {
+ state = Qt::TouchPointPressed;
+ } else if (touchInput.dwFlags & TOUCHEVENTF_UP) {
+ state = Qt::TouchPointReleased;
+ } else {
+ state = (screenPos == touchPoint.screenPos()
+ ? Qt::TouchPointStationary
+ : Qt::TouchPointMoved);
+ }
+ if (touchInput.dwFlags & TOUCHEVENTF_PRIMARY)
+ state |= Qt::TouchPointPrimary;
+ touchPoint.setState(state);
+ touchPoint.setScreenRect(screenRect);
+
+ touchPoints.append(touchPoint);
+ }
+ QApplicationPrivate::CloseTouchInputHandle((HANDLE) msg.lParam);
+
+ translateRawTouchEvent(widgetForHwnd, touchPoints);
+ return true;
+}
+
QT_END_NAMESPACE
diff --git a/src/gui/kernel/qapplication_x11.cpp b/src/gui/kernel/qapplication_x11.cpp
index 942836a..19c5928 100644
--- a/src/gui/kernel/qapplication_x11.cpp
+++ b/src/gui/kernel/qapplication_x11.cpp
@@ -128,6 +128,12 @@ extern "C" {
#include <private/qbackingstore_p.h>
+#ifdef QT_RX71_MULTITOUCH
+# include <qsocketnotifier.h>
+# include <linux/input.h>
+# include <errno.h>
+#endif
+
#if _POSIX_VERSION+0 < 200112L && !defined(Q_OS_BSD4)
# define QT_NO_UNSETENV
#endif
@@ -3214,6 +3220,7 @@ int QApplication::x11ProcessEvent(XEvent* event)
{
Q_D(QApplication);
QScopedLoopLevelCounter loopLevelCounter(d->threadData);
+
#ifdef ALIEN_DEBUG
//qDebug() << "QApplication::x11ProcessEvent:" << event->type;
#endif
@@ -4484,7 +4491,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)) {
@@ -5098,6 +5104,7 @@ bool QETWidget::translatePropertyEvent(const XEvent *event)
return true;
}
+
//
// Paint event translation
//
@@ -5999,4 +6006,225 @@ void QSessionManager::requestPhase2()
#endif // QT_NO_SESSIONMANAGER
+#if defined(QT_RX71_MULTITOUCH)
+
+static inline int testBit(const char *array, int bit)
+{
+ return (array[bit/8] & (1<<(bit%8)));
+}
+
+static int openRX71Device(const QByteArray &deviceName)
+{
+ int fd = open(deviceName, O_RDONLY | O_NONBLOCK);
+ if (fd == -1) {
+ fd = -errno;
+ return fd;
+ }
+
+ // fetch the event type mask and check that the device reports absolute coordinates
+ char eventTypeMask[(EV_MAX + sizeof(char) - 1) * sizeof(char) + 1];
+ memset(eventTypeMask, 0, sizeof(eventTypeMask));
+ if (ioctl(fd, EVIOCGBIT(0, sizeof(eventTypeMask)), eventTypeMask) < 0) {
+ close(fd);
+ return -1;
+ }
+ if (!testBit(eventTypeMask, EV_ABS)) {
+ close(fd);
+ return -1;
+ }
+
+ // make sure that we can get the absolute X and Y positions from the device
+ char absMask[(ABS_MAX + sizeof(char) - 1) * sizeof(char) + 1];
+ memset(absMask, 0, sizeof(absMask));
+ if (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absMask)), absMask) < 0) {
+ close(fd);
+ return -1;
+ }
+ if (!testBit(absMask, ABS_X) || !testBit(absMask, ABS_Y)) {
+ close(fd);
+ return -1;
+ }
+
+ return fd;
+}
+
+void QApplicationPrivate::initializeMultitouch_sys()
+{
+ Q_Q(QApplication);
+
+ QByteArray deviceName = QByteArray("/dev/input/event");
+ int currentDeviceNumber = 0;
+ for (;;) {
+ int fd = openRX71Device(QByteArray(deviceName + QByteArray::number(currentDeviceNumber++)));
+ if (fd == -ENOENT) {
+ // no more devices
+ break;
+ }
+ if (fd < 0) {
+ // not a touch device
+ continue;
+ }
+
+ struct input_absinfo abs_x, abs_y, abs_z;
+ ioctl(fd, EVIOCGABS(ABS_X), &abs_x);
+ ioctl(fd, EVIOCGABS(ABS_Y), &abs_y);
+ ioctl(fd, EVIOCGABS(ABS_Z), &abs_z);
+
+ int deviceNumber = allRX71TouchPoints.count();
+
+ QSocketNotifier *socketNotifier = new QSocketNotifier(fd, QSocketNotifier::Read, q);
+ QObject::connect(socketNotifier, SIGNAL(activated(int)), q, SLOT(_q_readRX71MultiTouchEvents()));
+
+ RX71TouchPointState touchPointState = {
+ socketNotifier,
+ QTouchEvent::TouchPoint(deviceNumber),
+
+ abs_x.minimum, abs_x.maximum, q->desktop()->screenGeometry().width(),
+ abs_y.minimum, abs_y.maximum, q->desktop()->screenGeometry().height(),
+ abs_z.minimum, abs_z.maximum
+ };
+ allRX71TouchPoints.append(touchPointState);
+ }
+
+ hasRX71MultiTouch = allRX71TouchPoints.count() > 1;
+ if (!hasRX71MultiTouch) {
+ for (int i = 0; i < allRX71TouchPoints.count(); ++i) {
+ QSocketNotifier *socketNotifier = allRX71TouchPoints.at(i).socketNotifier;
+ close(socketNotifier->socket());
+ delete socketNotifier;
+ }
+ allRX71TouchPoints.clear();
+ }
+}
+
+void QApplicationPrivate::cleanupMultitouch_sys()
+{
+ hasRX71MultiTouch = false;
+ for (int i = 0; i < allRX71TouchPoints.count(); ++i) {
+ QSocketNotifier *socketNotifier = allRX71TouchPoints.at(i).socketNotifier;
+ close(socketNotifier->socket());
+ delete socketNotifier;
+ }
+ allRX71TouchPoints.clear();
+}
+
+bool QApplicationPrivate::readRX71MultiTouchEvents(int deviceNumber)
+{
+ RX71TouchPointState &touchPointState = allRX71TouchPoints[deviceNumber];
+ QSocketNotifier *socketNotifier = touchPointState.socketNotifier;
+ int fd = socketNotifier->socket();
+
+ QTouchEvent::TouchPoint &touchPoint = touchPointState.touchPoint;
+
+ bool down = touchPoint.state() != Qt::TouchPointReleased;
+ if (down)
+ touchPoint.setState(Qt::TouchPointStationary);
+
+ bool changed = false;
+ for (;;) {
+ struct input_event inputEvent;
+ int bytesRead = read(fd, &inputEvent, sizeof(inputEvent));
+ if (bytesRead <= 0)
+ break;
+ if (bytesRead != sizeof(inputEvent)) {
+ qWarning("Qt: INTERNAL ERROR: short read in readRX71MultiTouchEvents()");
+ return false;
+ }
+
+ switch (inputEvent.type) {
+ case EV_SYN:
+ changed = true;
+ switch (touchPoint.state()) {
+ case Qt::TouchPointPressed:
+ case Qt::TouchPointReleased:
+ // make sure we don't compress pressed and releases with any other events
+ return changed;
+ default:
+ break;
+ }
+ continue;
+ case EV_KEY:
+ case EV_ABS:
+ break;
+ default:
+ qWarning("Qt: WARNING: unknown event type %d on multitouch device", inputEvent.type);
+ continue;
+ }
+
+ QPointF screenPos = touchPoint.screenPos();
+ switch (inputEvent.code) {
+ case BTN_TOUCH:
+ if (!down && inputEvent.value != 0)
+ touchPoint.setState(Qt::TouchPointPressed);
+ else if (down && inputEvent.value == 0)
+ touchPoint.setState(Qt::TouchPointReleased);
+ break;
+ case ABS_TOOL_WIDTH:
+ case ABS_VOLUME:
+ case ABS_PRESSURE:
+ // ignore for now
+ break;
+ case ABS_X:
+ {
+ qreal newValue = ((qreal(inputEvent.value - touchPointState.minX)
+ / qreal(touchPointState.maxX - touchPointState.minX))
+ * touchPointState.scaleX);
+ screenPos.rx() = newValue;
+ touchPoint.setScreenPos(screenPos);
+ break;
+ }
+ case ABS_Y:
+ {
+ qreal newValue = ((qreal(inputEvent.value - touchPointState.minY)
+ / qreal(touchPointState.maxY - touchPointState.minY))
+ * touchPointState.scaleY);
+ screenPos.ry() = newValue;
+ touchPoint.setScreenPos(screenPos);
+ break;
+ }
+ case ABS_Z:
+ {
+ // map Z (signal strength) to pressure for now
+ qreal newValue = (qreal(inputEvent.value - touchPointState.minZ)
+ / qreal(touchPointState.maxZ - touchPointState.minZ));
+ touchPoint.setPressure(newValue);
+ break;
+ }
+ default:
+ qWarning("Qt: WARNING: unknown event code %d on multitouch device", inputEvent.code);
+ continue;
+ }
+ }
+
+ if (down && touchPoint.state() != Qt::TouchPointReleased)
+ touchPoint.setState(changed ? Qt::TouchPointMoved : Qt::TouchPointStationary);
+
+ return changed;
+}
+
+void QApplicationPrivate::_q_readRX71MultiTouchEvents()
+{
+ // read touch events from all devices
+ bool changed = false;
+ for (int i = 0; i < allRX71TouchPoints.count(); ++i)
+ changed = readRX71MultiTouchEvents(i) || changed;
+ if (!changed)
+ return;
+
+ QList<QTouchEvent::TouchPoint> touchPoints;
+ for (int i = 0; i < allRX71TouchPoints.count(); ++i)
+ touchPoints.append(allRX71TouchPoints.at(i).touchPoint);
+
+ translateRawTouchEvent(0, touchPoints);
+}
+
+#else // !QT_RX71_MULTITOUCH
+
+void QApplicationPrivate::initializeMultitouch_sys()
+{ }
+void QApplicationPrivate::cleanupMultitouch_sys()
+{ }
+
+#endif // QT_RX71_MULTITOUCH
+
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 12bbc7d..c9b9bc8 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
@@ -83,6 +85,13 @@ QInputEvent::~QInputEvent()
\sa QApplication::keyboardModifiers()
*/
+/*! \fn void QInputEvent::setModifiers(Qt::KeyboardModifiers modifiers)
+
+ \internal
+
+ Sets the keyboard modifiers flags for this event.
+*/
+
/*!
\class QMouseEvent
\ingroup events
@@ -3322,6 +3331,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 +3530,563 @@ 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.
+
+ \omitvalue TouchPointStateMask
+ \omitvalue TouchPointPrimary
+*/
+
+/*! \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 QWidget *QTouchEvent::widget() const
+
+ Returns the widget on which the event occurred.
+*/
+
+
+/*! \fn Qt::TouchPointStates QTouchEvent::touchPointStates() const
+
+ Returns 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::setWidget(QWidget *widget)
+
+ \internal
+
+ Sets the widget 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 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;
+}
+
+/*!
+ Returns the current state of this touch point.
+*/
+Qt::TouchPointState QTouchEvent::TouchPoint::state() const
+{
+ return Qt::TouchPointState(int(d->state) & Qt::TouchPointStateMask);
+}
+
+/*!
+ Returns true if this touch point is the primary touch point. The primary touch point is the
+ point for which the windowing system generates mouse events.
+*/
+bool QTouchEvent::TouchPoint::isPrimary() const
+{
+ return (d->state & Qt::TouchPointPrimary) != 0;
+}
+
+/*!
+ Returns the position of this touch point, relative to the widget
+ or item that received the event.
+*/
+QPointF QTouchEvent::TouchPoint::pos() const
+{
+ return d->rect.center();
+}
+
+/*!
+ Returns the scene position of this touch point.
+*/
+QPointF QTouchEvent::TouchPoint::scenePos() const
+{
+ return d->sceneRect.center();
+}
+
+/*!
+ Returns the screen position of this touch point.
+*/
+QPointF QTouchEvent::TouchPoint::screenPos() const
+{
+ return d->screenRect.center();
+}
+
+/*!
+ Returns the starting position of this touch point, relative to the
+ widget that received the event.
+*/
+QPointF QTouchEvent::TouchPoint::startPos() const
+{
+ return d->startPos;
+}
+
+/*!
+ Returns the starting scene position of this touch point.
+*/
+QPointF QTouchEvent::TouchPoint::startScenePos() const
+{
+ return d->startScenePos;
+}
+
+/*!
+ Returns the starting screen position of this touch point.
+*/
+QPointF QTouchEvent::TouchPoint::startScreenPos() const
+{
+ return d->startScreenPos;
+}
+
+/*!
+ 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;
+}
+
+/*!
+ Returns the scene position of this touch point from the previous
+ touch event.
+*/
+QPointF QTouchEvent::TouchPoint::lastScenePos() const
+{
+ return d->lastScenePos;
+}
+
+/*!
+ Returns the screen position of this touch point from the previous
+ touch event.
+*/
+QPointF QTouchEvent::TouchPoint::lastScreenPos() const
+{
+ return d->lastScreenPos;
+}
+
+/*!
+ Returns the rect for this touch point. The rect is centered around the point returned by pos().
+ Note this function returns an empty rect if the device does not report touch point sizes.
+*/
+QRectF QTouchEvent::TouchPoint::rect() const
+{
+ return d->screenRect;
+}
+
+/*!
+ Returns the rect for this touch point in scene coordinates.
+*/
+QRectF QTouchEvent::TouchPoint::sceneRect() const
+{
+ return d->sceneRect;
+}
+
+/*!
+ Returns the rect for this touch point in screen coordinates.
+*/
+QRectF QTouchEvent::TouchPoint::screenRect() const
+{
+ return d->screenRect;
+}
+
+/*!
+ 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::setId(int id)
+{
+ if (d->ref != 1)
+ d = d->detach();
+ d->id = id;
+}
+
+/*! \internal */
+void QTouchEvent::TouchPoint::setState(Qt::TouchPointStates state)
+{
+ if (d->ref != 1)
+ d = d->detach();
+ d->state = state;
+}
+
+/*! \internal */
+void QTouchEvent::TouchPoint::setPos(const QPointF &pos)
+{
+ if (d->ref != 1)
+ d = d->detach();
+ d->rect.moveCenter(pos);
+}
+
+/*! \internal */
+void QTouchEvent::TouchPoint::setScenePos(const QPointF &scenePos)
+{
+ if (d->ref != 1)
+ d = d->detach();
+ d->sceneRect.moveCenter(scenePos);
+}
+
+/*! \internal */
+void QTouchEvent::TouchPoint::setScreenPos(const QPointF &screenPos)
+{
+ if (d->ref != 1)
+ d = d->detach();
+ d->screenRect.moveCenter(screenPos);
+}
+
+/*! \internal */
+void QTouchEvent::TouchPoint::setStartPos(const QPointF &startPos)
+{
+ if (d->ref != 1)
+ d = d->detach();
+ d->startPos = startPos;
+}
+
+/*! \internal */
+void QTouchEvent::TouchPoint::setStartScenePos(const QPointF &startScenePos)
+{
+ if (d->ref != 1)
+ d = d->detach();
+ d->startScenePos = startScenePos;
+}
+
+/*! \internal */
+void QTouchEvent::TouchPoint::setStartScreenPos(const QPointF &startScreenPos)
+{
+ if (d->ref != 1)
+ d = d->detach();
+ d->startScreenPos = startScreenPos;
+}
+
+/*! \internal */
+void QTouchEvent::TouchPoint::setLastPos(const QPointF &lastPos)
+{
+ if (d->ref != 1)
+ d = d->detach();
+ d->lastPos = lastPos;
+}
+
+/*! \internal */
+void QTouchEvent::TouchPoint::setLastScenePos(const QPointF &lastScenePos)
+{
+ if (d->ref != 1)
+ d = d->detach();
+ d->lastScenePos = lastScenePos;
+}
+
+/*! \internal */
+void QTouchEvent::TouchPoint::setLastScreenPos(const QPointF &lastScreenPos)
+{
+ if (d->ref != 1)
+ d = d->detach();
+ d->lastScreenPos = lastScreenPos;
+}
+
+/*! \internal */
+void QTouchEvent::TouchPoint::setRect(const QRectF &rect)
+{
+ if (d->ref != 1)
+ d = d->detach();
+ d->rect = rect;
+}
+
+/*! \internal */
+void QTouchEvent::TouchPoint::setSceneRect(const QRectF &sceneRect)
+{
+ if (d->ref != 1)
+ d = d->detach();
+ d->sceneRect = sceneRect;
+}
+
+/*! \internal */
+void QTouchEvent::TouchPoint::setScreenRect(const QRectF &screenRect)
+{
+ if (d->ref != 1)
+ d = d->detach();
+ d->screenRect = screenRect;
+}
+
+/*! \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;
+}
+
QT_END_NAMESPACE
diff --git a/src/gui/kernel/qevent.h b/src/gui/kernel/qevent.h
index c2cb05f..ee81e78 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
@@ -67,6 +70,7 @@ public:
QInputEvent(Type type, Qt::KeyboardModifiers modifiers = Qt::NoModifier);
~QInputEvent();
inline Qt::KeyboardModifiers modifiers() const { return modState; }
+ inline void setModifiers(Qt::KeyboardModifiers modifiers) { modState = modifiers; }
protected:
Qt::KeyboardModifiers modState;
};
@@ -710,6 +714,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 +758,85 @@ 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;
+
+ Qt::TouchPointState state() const;
+ bool isPrimary() const;
+
+ QPointF pos() const;
+ QPointF startPos() const;
+ QPointF lastPos() const;
+
+ QPointF scenePos() const;
+ QPointF startScenePos() const;
+ QPointF lastScenePos() const;
+
+ QPointF screenPos() const;
+ QPointF startScreenPos() const;
+ QPointF lastScreenPos() const;
+
+ QRectF rect() const;
+ QRectF sceneRect() const;
+ QRectF screenRect() const;
+
+ qreal pressure() const;
+
+ // internal
+ void setId(int id);
+ void setState(Qt::TouchPointStates state);
+ void setPos(const QPointF &pos);
+ void setScenePos(const QPointF &scenePos);
+ void setScreenPos(const QPointF &screenPos);
+ void setStartPos(const QPointF &startPos);
+ void setStartScenePos(const QPointF &startScenePos);
+ void setStartScreenPos(const QPointF &startScreenPos);
+ void setLastPos(const QPointF &lastPos);
+ void setLastScenePos(const QPointF &lastScenePos);
+ void setLastScreenPos(const QPointF &lastScreenPos);
+ void setRect(const QRectF &rect);
+ void setSceneRect(const QRectF &sceneRect);
+ void setScreenRect(const QRectF &screenRect);
+ void setPressure(qreal pressure);
+ TouchPoint &operator=(const TouchPoint &other);
+
+ private:
+ QTouchEventTouchPointPrivate *d;
+ };
+
+ QTouchEvent(QEvent::Type type,
+ Qt::KeyboardModifiers modifiers = Qt::NoModifier,
+ Qt::TouchPointStates touchPointStates = 0,
+ const QList<QTouchEvent::TouchPoint> &touchPoints = QList<QTouchEvent::TouchPoint>());
+ ~QTouchEvent();
+
+ inline QWidget *widget() const { return _widget; }
+ inline Qt::TouchPointStates touchPointStates() const { return _touchPointStates; }
+ inline const QList<QTouchEvent::TouchPoint> &touchPoints() const { return _touchPoints; }
+
+ // internal
+ inline void setWidget(QWidget *widget) { _widget = widget; }
+ inline void setTouchPointStates(Qt::TouchPointStates touchPointStates) { _touchPointStates = touchPointStates; }
+ inline void setTouchPoints(const QList<QTouchEvent::TouchPoint> &touchPoints) { _touchPoints = touchPoints; }
+
+protected:
+ QWidget *_widget;
+ 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 9cc1e81..53d7a23 100644
--- a/src/gui/kernel/qevent_p.h
+++ b/src/gui/kernel/qevent_p.h
@@ -89,6 +89,34 @@ 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;
+ if (!this->ref.deref())
+ delete this;
+ return d;
+ }
+
+ QAtomicInt ref;
+ int id;
+ Qt::TouchPointStates state;
+ QRectF rect, sceneRect, screenRect;
+ QPointF startPos, startScenePos, startScreenPos;
+ QPointF lastPos, lastScenePos, lastScreenPos;
+ qreal pressure;
+};
+
QT_END_NAMESPACE
#endif // QEVENT_P_H
diff --git a/src/gui/kernel/qgesture.cpp b/src/gui/kernel/qgesture.cpp
new file mode 100644
index 0000000..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..a1d55fa
--- /dev/null
+++ b/src/gui/kernel/qgesturemanager.cpp
@@ -0,0 +1,644 @@
+/****************************************************************************
+**
+** 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;
+ }
+ }
+
+ 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;
+ }
+
+ Q_ASSERT(!started.isEmpty());
+ ret = sendGestureEvent(receiver, started, QSet<QGesture*>());
+ } 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 8c6e0a7..8dd32f5 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,46 @@ bool QWidget::event(QEvent *event)
d->needWindowChange = false;
break;
#endif
+ case QEvent::Gesture:
+ event->ignore();
+ break;
+ case QEvent::TouchBegin:
+ case QEvent::TouchUpdate:
+ case QEvent::TouchEnd:
+ {
+ QTouchEvent *touchEvent = static_cast<QTouchEvent *>(event);
+ const QTouchEvent::TouchPoint &touchPoint = touchEvent->touchPoints().first();
+ if (touchPoint.isPrimary())
+ break;
+
+ // fake a mouse event!
+ QEvent::Type eventType = QEvent::None;
+ switch (touchEvent->type()) {
+ case QEvent::TouchBegin:
+ eventType = QEvent::MouseButtonPress;
+ break;
+ case QEvent::TouchUpdate:
+ eventType = QEvent::MouseMove;
+ break;
+ case QEvent::TouchEnd:
+ eventType = QEvent::MouseButtonRelease;
+ break;
+ default:
+ Q_ASSERT(!true);
+ break;
+ }
+ if (eventType == QEvent::None)
+ break;
+
+ QMouseEvent mouseEvent(eventType,
+ touchPoint.pos().toPoint(),
+ touchPoint.screenPos().toPoint(),
+ Qt::LeftButton,
+ Qt::LeftButton,
+ touchEvent->modifiers());
+ (void) QApplication::sendEvent(this, &mouseEvent);
+ break;
+ }
#ifndef QT_NO_PROPERTIES
case QEvent::DynamicPropertyChange: {
const QByteArray &propName = static_cast<QDynamicPropertyChangeEvent *>(event)->propertyName();
@@ -9881,6 +9928,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 +11016,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 975da5a..82e9f36 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 c285866..cf065d3 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"
@@ -522,6 +524,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;
@@ -556,6 +563,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 988ddf2..e39ca77 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/styles/qproxystyle.cpp b/src/gui/styles/qproxystyle.cpp
index 589ca9c..7177bed 100644
--- a/src/gui/styles/qproxystyle.cpp
+++ b/src/gui/styles/qproxystyle.cpp
@@ -93,7 +93,7 @@ void QProxyStylePrivate::ensureBaseStyle() const
baseStyle = 0;
}
}
- }
+ }
if (!baseStyle) // Use application desktop style
baseStyle = QStyleFactory::create(QApplicationPrivate::desktopStyleKey());
@@ -368,7 +368,7 @@ bool QProxyStyle::event(QEvent *e)
return d->baseStyle->event(e);
}
-/*!
+/*!
Returns an icon for the given \a standardIcon.
Reimplement this slot to provide your own icons in a QStyle
diff --git a/src/gui/widgets/qabstractscrollarea.cpp b/src/gui/widgets/qabstractscrollarea.cpp
index 00be29b..e1beb98 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: