diff options
Diffstat (limited to 'src/gui/graphicsview')
-rw-r--r-- | src/gui/graphicsview/qgraphicsitem.cpp | 142 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicsitem.h | 7 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicsitem_p.h | 42 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicsproxywidget.cpp | 16 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicsscene.cpp | 392 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicsscene.h | 2 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicsscene_p.h | 25 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicssceneevent.cpp | 411 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicssceneevent.h | 82 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicsview.cpp | 86 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicsview_p.h | 9 |
11 files changed, 1192 insertions, 22 deletions
diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index 72b832a..fb95875 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -530,6 +530,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> @@ -570,6 +571,8 @@ public: }; Q_GLOBAL_STATIC(QGraphicsItemCustomDataStore, qt_dataStore) +QString qt_getStandardGestureTypeName(Qt::GestureType type); + /*! \internal @@ -1052,6 +1055,7 @@ QGraphicsItem::~QGraphicsItem() clearFocus(); d_ptr->removeExtraItemCache(); + d_ptr->removeExtraGestures(); QList<QGraphicsItem *> oldChildren = d_ptr->children; qDeleteAll(oldChildren); Q_ASSERT(d_ptr->children.isEmpty()); @@ -2157,6 +2161,31 @@ void QGraphicsItem::setAcceptsHoverEvents(bool enabled) setAcceptHoverEvents(enabled); } +/*! \since 4.6 + + Returns true if an item accepts touch events + (QGraphicsSceneTouchEvent); otherwise, returns false. By default, + items do not accept touch events. + + \sa setAcceptTouchEvents() +*/ +bool QGraphicsItem::acceptTouchEvents() const +{ + return d_ptr->acceptTouchEvents; +} + +/*! + \since 4.6 + + If \a enabled is true, this item will accept touch events; + otherwise, it will ignore them. By default, items do not accept + touch events. +*/ +void QGraphicsItem::setAcceptTouchEvents(bool enabled) +{ + d_ptr->acceptTouchEvents = quint32(enabled); +} + /*! Returns true if this item handles child events (i.e., all events intended for any of its children are instead sent to this item); @@ -5819,6 +5848,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 @@ -5842,6 +5967,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 0a0179e..e5779f7 100644 --- a/src/gui/graphicsview/qgraphicsitem.h +++ b/src/gui/graphicsview/qgraphicsitem.h @@ -205,6 +205,8 @@ public: void setAcceptsHoverEvents(bool enabled); // obsolete bool acceptHoverEvents() const; void setAcceptHoverEvents(bool enabled); + bool acceptTouchEvents() const; + void setAcceptTouchEvents(bool enabled); bool handlesChildEvents() const; void setHandlesChildEvents(bool enabled); @@ -338,6 +340,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 820ef04..7642b98 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" #if !defined(QT_NO_GRAPHICSVIEW) || (QT_EDITION & QT_MODULE_GRAPHICSVIEW) != QT_MODULE_GRAPHICSVIEW @@ -89,6 +90,12 @@ public: void purge(); }; +class QGestureExtraData +{ +public: + QSet<int> gestures; +}; + class Q_AUTOTEST_EXPORT QGraphicsItemPrivate { Q_DECLARE_PUBLIC(QGraphicsItem) @@ -101,7 +108,8 @@ public: ExtraMaxDeviceCoordCacheSize, ExtraBoundingRegionGranularity, ExtraOpacity, - ExtraEffectiveOpacity + ExtraEffectiveOpacity, + ExtraGestures }; enum AncestorFlag { @@ -145,6 +153,8 @@ public: inSetPosHelper(0), flags(0), allChildrenCombineOpacity(1), + acceptTouchEvents(0), + acceptedTouchBeginEvent(0), globalStackingOrder(-1), sceneTransformIndex(-1), q_ptr(0) @@ -301,7 +311,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; @@ -331,7 +365,9 @@ public: // New 32 bits quint32 flags : 10; quint32 allChildrenCombineOpacity : 1; - quint32 padding : 21; // feel free to use + quint32 acceptTouchEvents : 1; + quint32 acceptedTouchBeginEvent : 1; + quint32 padding : 19; // feel free to use // Optional stacking order int globalStackingOrder; diff --git a/src/gui/graphicsview/qgraphicsproxywidget.cpp b/src/gui/graphicsview/qgraphicsproxywidget.cpp index 01b7593..5641068 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 1fbda85..7638907 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -247,6 +247,8 @@ static const int QGRAPHICSSCENE_INDEXTIMER_TIMEOUT = 2000; #ifdef Q_WS_X11 #include <private/qt_x11_p.h> #endif +#include <private/qgesturemanager_p.h> +#include <private/qgesture_p.h> QT_BEGIN_NAMESPACE @@ -1336,6 +1338,7 @@ void QGraphicsScenePrivate::mousePressEventHandler(QGraphicsSceneMouseEvent *mou // event is converted to a press. Known limitation: // Triple-clicking will not generate a doubleclick, though. QGraphicsSceneMouseEvent mousePress(QEvent::GraphicsSceneMousePress); + mousePress.spont = mouseEvent->spont; mousePress.accept(); mousePress.setButton(mouseEvent->button()); mousePress.setButtons(mouseEvent->buttons()); @@ -3762,6 +3765,9 @@ bool QGraphicsScene::event(QEvent *event) case QEvent::GraphicsSceneHoverEnter: case QEvent::GraphicsSceneHoverLeave: case QEvent::GraphicsSceneHoverMove: + case QEvent::GraphicsSceneTouchBegin: + case QEvent::GraphicsSceneTouchUpdate: + case QEvent::GraphicsSceneTouchEnd: // Reset the under-mouse list to ensure that this event gets fresh // item-under-mouse data. Be careful about this list; if people delete // items from inside event handlers, this list can quickly end up @@ -3913,6 +3919,52 @@ bool QGraphicsScene::event(QEvent *event) // geometries that do not have an explicit style set. update(); break; + case QEvent::GraphicsSceneGesture: { + QGraphicsSceneGestureEvent *ev = static_cast<QGraphicsSceneGestureEvent*>(event); + QGraphicsView *view = qobject_cast<QGraphicsView*>(ev->widget()); + if (!view) { + qWarning("QGraphicsScene::event: gesture event was received without a view"); + break; + } + + // get a list of gestures that just started. + QSet<QGesture*> startedGestures; + QList<QGesture*> gestures = ev->gestures(); + for(QList<QGesture*>::const_iterator it = gestures.begin(), e = gestures.end(); + it != e; ++it) { + QGesture *g = *it; + QGesturePrivate *gd = g->d_func(); + if (g->state() == Qt::GestureStarted || gd->singleshot) { + startedGestures.insert(g); + } + } + if (!startedGestures.isEmpty()) { + // find a target for each started gesture. + for(QSet<QGesture*>::const_iterator it = startedGestures.begin(), e = startedGestures.end(); + it != e; ++it) { + QGesture *g = *it; + QGesturePrivate *gd = g->d_func(); + gd->graphicsItem = 0; + QList<QGraphicsItem*> itemsInGestureArea = items(g->hotSpot()); + const QString gestureName = g->type(); + foreach(QGraphicsItem *item, itemsInGestureArea) { + if (item->d_func()->hasGesture(gestureName)) { + Q_ASSERT(gd->graphicsItem == 0); + gd->graphicsItem = item; + d->itemsWithGestures[item].insert(g); + break; + } + } + } + } + d->sendGestureEvent(ev->gestures().toSet(), ev->cancelledGestures()); + } + break; + case QEvent::GraphicsSceneTouchBegin: + case QEvent::GraphicsSceneTouchUpdate: + case QEvent::GraphicsSceneTouchEnd: + d->touchEventHandler(static_cast<QGraphicsSceneTouchEvent *>(event)); + break; case QEvent::Timer: if (d->indexTimerId && static_cast<QTimerEvent *>(event)->timerId() == d->indexTimerId) { if (d->restartIndexTimer) { @@ -3929,6 +3981,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 @@ -5539,6 +5655,282 @@ void QGraphicsScene::setActiveWindow(QGraphicsWidget *widget) } } +void QGraphicsScenePrivate::addView(QGraphicsView *view) +{ + views << view; + foreach(int gestureId, grabbedGestures) + view->d_func()->grabGesture(gestureId); +} + +void QGraphicsScenePrivate::removeView(QGraphicsView *view) +{ + views.removeAll(view); + foreach(int gestureId, grabbedGestures) + view->releaseGesture(gestureId); +} + +void QGraphicsScenePrivate::grabGesture(QGraphicsItem *item, int gestureId) +{ + if (!grabbedGestures.contains(gestureId)) { + foreach(QGraphicsView *view, views) + view->d_func()->grabGesture(gestureId); + } + (void)itemsWithGestures[item]; + grabbedGestures << gestureId; +} + +void QGraphicsScenePrivate::releaseGesture(QGraphicsItem *item, int gestureId) +{ + itemsWithGestures.remove(item); + //### +} + +void QGraphicsScenePrivate::updateTouchPointsForItem(QGraphicsItem *item, + QGraphicsSceneTouchEvent *touchEvent) +{ + QList<QGraphicsSceneTouchEvent::TouchPoint *> touchPoints = touchEvent->touchPoints(); + for (int i = 0; i < touchPoints.count(); ++i) { + QGraphicsSceneTouchEvent::TouchPoint *touchPoint = touchPoints.at(i); + touchPoint->setPos(item->d_ptr->genericMapFromScene(touchPoint->scenePos(), touchEvent->widget())); + touchPoint->setStartPos(item->d_ptr->genericMapFromScene(touchPoint->startScenePos(), touchEvent->widget())); + touchPoint->setLastPos(item->d_ptr->genericMapFromScene(touchPoint->lastScenePos(), touchEvent->widget())); + } +} + +QGraphicsSceneTouchEvent::TouchPoint *QGraphicsScenePrivate::findClosestTouchPoint(const QList<QGraphicsSceneTouchEvent::TouchPoint *> &sceneActiveTouchPoints, + const QPointF &scenePos) +{ + QGraphicsSceneTouchEvent::TouchPoint *closestTouchPoint = 0; + qreal closestDistance; + for (int i = 0; i < sceneActiveTouchPoints.count(); ++i) { + QGraphicsSceneTouchEvent::TouchPoint *touchPoint = sceneActiveTouchPoints.at(i); + qreal distance = QLineF(scenePos, touchPoint->scenePos()).length(); + if (!closestTouchPoint || distance < closestDistance) { + closestTouchPoint = touchPoint; + closestDistance = distance; + } + } + return closestTouchPoint; +} + +QEvent::Type QGraphicsScenePrivate::appendTouchPoint(QGraphicsSceneTouchEvent::TouchPoint *touchPoint, + QList<QGraphicsSceneTouchEvent::TouchPoint *> *currentTouchPoints) +{ + QEvent::Type eventType = currentTouchPoints->isEmpty() + ? QEvent::GraphicsSceneTouchBegin + : QEvent::GraphicsSceneTouchUpdate; + + // insort touch point (for the app) + int at = 0; + for (; at < sceneCurrentTouchPoints.count(); ++at) { + if (sceneCurrentTouchPoints.at(at)->id() > touchPoint->id()) + break; + } + sceneCurrentTouchPoints.insert(at, touchPoint); + // again, for the items's currentTouchPoints + for (at = 0; at < currentTouchPoints->count(); ++at) { + if (currentTouchPoints->at(at)->id() > touchPoint->id()) + break; + } + currentTouchPoints->insert(at, touchPoint); + + return eventType; +} + +QEvent::Type QGraphicsScenePrivate::removeTouchPoint(QGraphicsSceneTouchEvent::TouchPoint *touchPoint, + QList<QGraphicsSceneTouchEvent::TouchPoint *> *currentTouchPoints) +{ + // remove touch point from all known touch points + for (int i = qMin(sceneCurrentTouchPoints.count() - 1, touchPoint->id()); i >= 0; --i) { + if (sceneCurrentTouchPoints.at(i) == touchPoint) { + sceneCurrentTouchPoints.removeAt(i); + break; + } + } + // again, for the items's currentTouchPoints + for (int i = qMin(currentTouchPoints->count() - 1, touchPoint->id()); i >= 0; --i) { + if (currentTouchPoints->at(i) == touchPoint) { + currentTouchPoints->removeAt(i); + break; + } + } + + return currentTouchPoints->isEmpty() ? QEvent::GraphicsSceneTouchEnd : QEvent::GraphicsSceneTouchUpdate; +} + +void QGraphicsScenePrivate::touchEventHandler(QGraphicsSceneTouchEvent *sceneTouchEvent) +{ + QList<QGraphicsSceneTouchEvent::TouchPoint *> sceneActiveTouchPoints = sceneCurrentTouchPoints; + + QHash<QGraphicsItem *, QGraphicsSceneTouchEvent *> itemsNeedingEvents; + for (int i = 0; i < sceneTouchEvent->touchPoints().count(); ++i) { + QGraphicsSceneTouchEvent::TouchPoint *touchPoint = sceneTouchEvent->touchPoints().at(i); + + // update state + QGraphicsItem *item = 0; + QEvent::Type eventType = QEvent::None; + QList<QGraphicsSceneTouchEvent::TouchPoint *> activeTouchPoints; + if (touchPoint->state() == Qt::TouchPointPressed) { + // determine which item this event will go to + cachedItemsUnderMouse = itemsAtPosition(touchPoint->screenPos().toPoint(), + touchPoint->scenePos(), + sceneTouchEvent->widget()); + item = cachedItemsUnderMouse.isEmpty() ? 0 : cachedItemsUnderMouse.first(); + QGraphicsSceneTouchEvent::TouchPoint *closestTouchPoint = findClosestTouchPoint(sceneActiveTouchPoints, touchPoint->scenePos()); + if (closestTouchPoint) { + QGraphicsItem *closestItem = itemForTouchPointId.value(closestTouchPoint->id()); + if (!item + || (closestItem + && (item->isAncestorOf(closestItem) + || closestItem->isAncestorOf(item)))) { + item = closestItem; + } + } + if (!item) + continue; + + itemForTouchPointId.insert(touchPoint->id(), item); + + QList<QGraphicsSceneTouchEvent::TouchPoint *> ¤tTouchPoints = itemCurrentTouchPoints[item]; + eventType = appendTouchPoint(touchPoint, ¤tTouchPoints); + // make sure new points are added to activeTouchPoints as well + sceneActiveTouchPoints = sceneCurrentTouchPoints; + activeTouchPoints = currentTouchPoints; + } else if (touchPoint->state() == Qt::TouchPointReleased) { + item = itemForTouchPointId.take(touchPoint->id()); + if (!item) + continue; + + QList<QGraphicsSceneTouchEvent::TouchPoint *> ¤tTouchPoints = itemCurrentTouchPoints[item]; + sceneActiveTouchPoints = sceneCurrentTouchPoints; + activeTouchPoints = currentTouchPoints; + eventType = removeTouchPoint(touchPoint, ¤tTouchPoints); + } else { + item = itemForTouchPointId.value(touchPoint->id()); + if (!item) + continue; + + sceneActiveTouchPoints = sceneCurrentTouchPoints; + activeTouchPoints = itemCurrentTouchPoints.value(item); + eventType = QEvent::GraphicsSceneTouchUpdate; + } + Q_ASSERT(eventType != QEvent::None); + + if (touchPoint->state() != Qt::TouchPointStationary) { + QGraphicsSceneTouchEvent *&touchEvent = itemsNeedingEvents[item]; + if (!touchEvent) { + touchEvent = new QGraphicsSceneTouchEvent(eventType); + touchEvent->setWidget(sceneTouchEvent->widget()); + touchEvent->setModifiers(sceneTouchEvent->modifiers()); + } + Q_ASSERT(touchEvent->type() == eventType); + touchEvent->setTouchPoints(activeTouchPoints); + } + } + + if (itemsNeedingEvents.isEmpty()) { + sceneTouchEvent->ignore(); + return; + } + + bool acceptSceneTouchEvent = false; + QHash<QGraphicsItem *, QGraphicsSceneTouchEvent *>::ConstIterator it = itemsNeedingEvents.constBegin(); + const QHash<QGraphicsItem *, QGraphicsSceneTouchEvent *>::ConstIterator end = itemsNeedingEvents.constEnd(); + for (; it != end; ++it) { + QGraphicsItem *item = it.key(); + + QGraphicsSceneTouchEvent *touchEvent = it.value(); + + switch (touchEvent->type()) { + case QEvent::GraphicsSceneTouchBegin: + { + // if the TouchBegin handler recurses, we assume that means the event + // has been implicitly accepted and continue to send touch events + item->d_ptr->acceptedTouchBeginEvent = true; + bool res = sendTouchBeginEvent(item, touchEvent) + && touchEvent->isAccepted(); + acceptSceneTouchEvent = acceptSceneTouchEvent || res; + break; + } + case QEvent::GraphicsSceneTouchEnd: + { + QList<QGraphicsSceneTouchEvent::TouchPoint *> currentTouchPoints = itemCurrentTouchPoints.take(item); + if (!currentTouchPoints.isEmpty()) { + qFatal("Qt: INTERNAL ERROR, the widget's currentTouchPoints should be empty!"); + } + // fall-through intended + } + default: + if (item->d_ptr->acceptedTouchBeginEvent) { + updateTouchPointsForItem(item, touchEvent); + (void) sendEvent(item, touchEvent); + acceptSceneTouchEvent = true; + } + break; + } + + delete touchEvent; + } + sceneTouchEvent->setAccepted(acceptSceneTouchEvent); +} + +bool QGraphicsScenePrivate::sendTouchBeginEvent(QGraphicsItem *origin, QGraphicsSceneTouchEvent *touchEvent) +{ + Q_Q(QGraphicsScene); + + if (cachedItemsUnderMouse.isEmpty() || cachedItemsUnderMouse.first() != origin) { + QGraphicsSceneTouchEvent::TouchPoint *firstTouchPoint = touchEvent->touchPoints().first(); + cachedItemsUnderMouse = itemsAtPosition(firstTouchPoint->screenPos().toPoint(), + firstTouchPoint->scenePos(), + touchEvent->widget()); + } + Q_ASSERT(cachedItemsUnderMouse.first() == origin); + + // Set focus on the topmost enabled item that can take focus. + bool setFocus = false; + foreach (QGraphicsItem *item, cachedItemsUnderMouse) { + if (item->isEnabled() && (item->flags() & QGraphicsItem::ItemIsFocusable)) { + if (!item->isWidget() || ((QGraphicsWidget *)item)->focusPolicy() & Qt::ClickFocus) { + setFocus = true; + if (item != q->focusItem()) + q->setFocusItem(item, Qt::MouseFocusReason); + break; + } + } + } + + // If nobody could take focus, clear it. + if (!stickyFocus && !setFocus) + q->setFocusItem(0, Qt::MouseFocusReason); + + bool res = false; + bool eventAccepted = touchEvent->isAccepted(); + foreach (QGraphicsItem *item, cachedItemsUnderMouse) { + // first, try to deliver the touch event + updateTouchPointsForItem(item, touchEvent); + touchEvent->ignore(); + res = item->acceptTouchEvents() + && sendEvent(item, touchEvent); + eventAccepted = touchEvent->isAccepted(); + item->d_ptr->acceptedTouchBeginEvent = (res && eventAccepted); + touchEvent->spont = false; + if (res && eventAccepted) { + // the first item to accept the TouchBegin gets an implicit grab. + for (int i = 0; i < touchEvent->touchPoints().count(); ++i) { + QGraphicsSceneTouchEvent::TouchPoint *touchPoint = touchEvent->touchPoints().at(i); + itemForTouchPointId[touchPoint->id()] = item; + } + if (origin != item) + itemCurrentTouchPoints.remove(origin); + itemCurrentTouchPoints[item] = touchEvent->touchPoints(); + break; + } + } + + touchEvent->setAccepted(eventAccepted); + return res; +} + QT_END_NAMESPACE #include "moc_qgraphicsscene.cpp" diff --git a/src/gui/graphicsview/qgraphicsscene.h b/src/gui/graphicsview/qgraphicsscene.h index 9802f87..a76b348 100644 --- a/src/gui/graphicsview/qgraphicsscene.h +++ b/src/gui/graphicsview/qgraphicsscene.h @@ -50,6 +50,7 @@ #include <QtGui/qtransform.h> #include <QtGui/qmatrix.h> #include <QtGui/qpen.h> +#include <QtGui/qevent.h> QT_BEGIN_HEADER @@ -79,6 +80,7 @@ class QGraphicsSceneHelpEvent; class QGraphicsSceneHoverEvent; class QGraphicsSceneMouseEvent; class QGraphicsSceneWheelEvent; +class QGraphicsSceneGestureEvent; class QGraphicsSimpleTextItem; class QGraphicsTextItem; class QGraphicsView; diff --git a/src/gui/graphicsview/qgraphicsscene_p.h b/src/gui/graphicsview/qgraphicsscene_p.h index 9ace725..160ba49 100644 --- a/src/gui/graphicsview/qgraphicsscene_p.h +++ b/src/gui/graphicsview/qgraphicsscene_p.h @@ -57,6 +57,7 @@ #if !defined(QT_NO_GRAPHICSVIEW) || (QT_EDITION & QT_MODULE_GRAPHICSVIEW) != QT_MODULE_GRAPHICSVIEW +#include "qgraphicssceneevent.h" #include "qgraphicsscene_bsp_p.h" #include "qgraphicsitem_p.h" @@ -73,6 +74,7 @@ QT_BEGIN_NAMESPACE class QGraphicsView; class QGraphicsWidget; +class QGesture; class QGraphicsScenePrivate : public QObjectPrivate { @@ -181,6 +183,9 @@ public: void storeMouseButtonsForMouseGrabber(QGraphicsSceneMouseEvent *event); QList<QGraphicsView *> views; + void addView(QGraphicsView *view); + void removeView(QGraphicsView *view); + bool painterStateProtection; QMultiMap<QGraphicsItem *, QGraphicsItem *> sceneEventFilters; @@ -263,9 +268,29 @@ public: void resolvePalette(); void updatePalette(const QPalette &palette); + // items with gestures -> list of started gestures. + QMap<QGraphicsItem*, QSet<QGesture*> > itemsWithGestures; + QSet<int> grabbedGestures; + void grabGesture(QGraphicsItem *item, int gestureId); + void releaseGesture(QGraphicsItem *item, int gestureId); + void sendGestureEvent(const QSet<QGesture*> &gestures, const QSet<QString> &cancelled); + mutable QVector<QTransform> sceneTransformCache; mutable QBitArray validTransforms; mutable QVector<int> freeSceneTransformSlots; + + QList<QGraphicsSceneTouchEvent::TouchPoint *> sceneCurrentTouchPoints; + QHash<QGraphicsItem *, QList<QGraphicsSceneTouchEvent::TouchPoint *> > itemCurrentTouchPoints; + QHash<int, QGraphicsItem *> itemForTouchPointId; + static void updateTouchPointsForItem(QGraphicsItem *item, QGraphicsSceneTouchEvent *touchEvent); + static QGraphicsSceneTouchEvent::TouchPoint *findClosestTouchPoint(const QList<QGraphicsSceneTouchEvent::TouchPoint *> &activeTouchPoints, + const QPointF &scenePos); + QEvent::Type appendTouchPoint(QGraphicsSceneTouchEvent::TouchPoint *touchPoint, + QList<QGraphicsSceneTouchEvent::TouchPoint *> *currentTouchPoints); + QEvent::Type removeTouchPoint(QGraphicsSceneTouchEvent::TouchPoint *touchPoint, + QList<QGraphicsSceneTouchEvent::TouchPoint *> *currentTouchPoints); + void touchEventHandler(QGraphicsSceneTouchEvent *touchEvent); + bool sendTouchBeginEvent(QGraphicsItem *item, QGraphicsSceneTouchEvent *touchEvent); }; QT_END_NAMESPACE diff --git a/src/gui/graphicsview/qgraphicssceneevent.cpp b/src/gui/graphicsview/qgraphicssceneevent.cpp index 0ffd2b1..bb13bd8 100644 --- a/src/gui/graphicsview/qgraphicssceneevent.cpp +++ b/src/gui/graphicsview/qgraphicssceneevent.cpp @@ -76,14 +76,14 @@ received by the view (see \l{QGraphicsSceneMouseEvent::}{lastScreenPos()}, \l{QGraphicsSceneMouseEvent::}{lastScenePos()}, and - \l{QGraphicsSceneMouseEvent::}{lastPos()}). + \l{QGraphicsSceneMouseEvent::}{lastPos()}). \sa QEvent */ /*! \class QGraphicsSceneMouseEvent - \brief The QGraphicsSceneMouseEvent class provides mouse events + \brief The QGraphicsSceneMouseEvent class provides mouse events in the graphics view framework. \since 4.2 \ingroup multimedia @@ -106,7 +106,7 @@ /*! \class QGraphicsSceneWheelEvent - \brief The QGraphicsSceneWheelEvent class provides wheel events + \brief The QGraphicsSceneWheelEvent class provides wheel events in the graphics view framework. \brief The QGraphicsSceneWheelEvent class provides wheel events in the graphics view framework. @@ -157,7 +157,7 @@ /*! \class QGraphicsSceneHoverEvent - \brief The QGraphicsSceneHoverEvent class provides hover events + \brief The QGraphicsSceneHoverEvent class provides hover events in the graphics view framework. \since 4.2 \ingroup multimedia @@ -173,7 +173,7 @@ /*! \class QGraphicsSceneHelpEvent - \brief The QGraphicsSceneHelpEvent class provides events when a + \brief The QGraphicsSceneHelpEvent class provides events when a tooltip is requested. \since 4.2 \ingroup multimedia @@ -199,7 +199,7 @@ /*! \class QGraphicsSceneDragDropEvent \brief The QGraphicsSceneDragDropEvent class provides events for - drag and drop in the graphics view framework. + drag and drop in the graphics view framework. \since 4.2 \ingroup multimedia \ingroup graphicsview-api @@ -257,6 +257,37 @@ QGraphicsItem::ItemPositionHasChanged */ +/*! + \class QGraphicsSceneTouchEvent + \brief The QGraphicsSceneTouchEvent class provides touch events in the graphics view framework. + \since 4.6 + \ingroup multimedia + \ingroup graphicsview-api + + When a QGraphicsView receives a QTouchEvent, it translates it to a + QGraphicsSceneTouchEvent. The event is then forwarded to the + QGraphicsScene associated with the view. + + The touchPoints() function returns a list of touch points for the + event. In addition to containing the item, scene, and screen + coordinates, each touch point also contains its starting and + previous coordinates. + + \sa QTouchEvent +*/ + +/*! + \class QGraphicsSceneTouchEvent::TouchPoint + \brief The QGraphicsSceneTouchEvent::TouchPoint class represents a single touch point in a QGraphicsSceneTouchEvent. + \since 4.6 + \ingroup multimedia + \ingroup graphicsview-api + + Each touch point in a QGraphicsSceneTouchEvent has an id() and + state() in addition to current, starting, and previous coordinates + for the touch point in item, scene, and screen coordinates. +*/ + #include "qgraphicssceneevent.h" #ifndef QT_NO_GRAPHICSVIEW @@ -268,9 +299,14 @@ #include <QtCore/qpoint.h> #include <QtCore/qsize.h> #include <QtCore/qstring.h> +#include "qgraphicsview.h" +#include "qgraphicsitem.h" +#include <private/qevent_p.h> QT_BEGIN_NAMESPACE +QString qt_getStandardGestureTypeName(Qt::GestureType type); + class QGraphicsSceneEventPrivate { public: @@ -522,7 +558,7 @@ void QGraphicsSceneMouseEvent::setLastPos(const QPointF &pos) } /*! - Returns the last recorded mouse cursor position in scene + Returns the last recorded mouse cursor position in scene coordinates. The last recorded position is the position of the previous mouse event received by the view that created the event. @@ -545,7 +581,7 @@ void QGraphicsSceneMouseEvent::setLastScenePos(const QPointF &pos) } /*! - Returns the last recorded mouse cursor position in screen + Returns the last recorded mouse cursor position in screen coordinates. The last recorded position is the position of the previous mouse event received by the view that created the event. @@ -1275,7 +1311,7 @@ QGraphicsSceneDragDropEvent::~QGraphicsSceneDragDropEvent() /*! Returns the mouse position of the event relative to the view that sent the event. - + \sa QGraphicsView, screenPos(), scenePos() */ QPointF QGraphicsSceneDragDropEvent::pos() const @@ -1373,7 +1409,7 @@ void QGraphicsSceneDragDropEvent::setButtons(Qt::MouseButtons buttons) /*! Returns the keyboard modifiers that were pressed when the drag - and drop event was created. + and drop event was created. \sa Qt::KeyboardModifiers */ @@ -1428,7 +1464,7 @@ void QGraphicsSceneDragDropEvent::setPossibleActions(Qt::DropActions actions) The action must be one of the possible actions as defined by \c possibleActions(). - \sa Qt::DropAction, possibleActions() + \sa Qt::DropAction, possibleActions() */ Qt::DropAction QGraphicsSceneDragDropEvent::proposedAction() const @@ -1673,6 +1709,359 @@ void QGraphicsSceneMoveEvent::setNewPos(const QPointF &pos) d->newPos = pos; } +/*! + \class QGraphicsSceneGestureEvent + \brief The QGraphicsSceneGestureEvent class provides gesture events for + the graphics view framework. + \since 4.6 + \ingroup multimedia + \ingroup graphicsview-api + + QGraphicsSceneGestureEvent extends information provided by + QGestureEvent by adding some convenience functions like + \l{QGraphicsSceneEvent::}{widget()} to get a widget that received + original gesture event, and convenience functions mapToScene(), + mapToItem() for converting positions of the gesture into + QGraphicsScene and QGraphicsItem coordinate system respectively. + + The scene sends the event to the first QGraphicsItem under the + mouse cursor that accepts gestures; a graphics item is set to accept + gestures with \l{QGraphicsItem::}{grabGesture()}. + + \sa QGestureEvent +*/ + +/*! + Constructs a QGraphicsSceneGestureEvent. +*/ +QGraphicsSceneGestureEvent::QGraphicsSceneGestureEvent() + : QGraphicsSceneEvent(QEvent::GraphicsSceneGesture) +{ + setAccepted(false); +} + +/*! + Destroys a QGraphicsSceneGestureEvent. +*/ +QGraphicsSceneGestureEvent::~QGraphicsSceneGestureEvent() +{ +} + +/*! + Returns true if the gesture event contains gesture of specific \a + type; returns false otherwise. +*/ +bool QGraphicsSceneGestureEvent::contains(const QString &type) const +{ + return gesture(type) != 0; +} + +/*! + Returns true if the gesture event contains gesture of specific \a + type; returns false otherwise. +*/ +bool QGraphicsSceneGestureEvent::contains(Qt::GestureType type) const +{ + return contains(qt_getStandardGestureTypeName(type)); +} + +/*! + Returns a list of gesture names that this event contains. +*/ +QList<QString> QGraphicsSceneGestureEvent::gestureTypes() const +{ + return m_gestures.keys(); +} + +/*! + Returns extended information about a gesture of specific \a type. +*/ +const QGesture* QGraphicsSceneGestureEvent::gesture(const QString &type) const +{ + return m_gestures.value(type, 0); +} + +/*! + Returns extended information about a gesture of specific \a type. +*/ +const QGesture* QGraphicsSceneGestureEvent::gesture(Qt::GestureType type) const +{ + return gesture(qt_getStandardGestureTypeName(type)); +} + +/*! + Returns extended information about all gestures in the event. +*/ +QList<QGesture*> QGraphicsSceneGestureEvent::gestures() const +{ + return m_gestures.values(); +} + +/*! + Returns a set of gesture names that used to be executed, but were + cancelled (i.e. they were not finished properly). +*/ +QSet<QString> QGraphicsSceneGestureEvent::cancelledGestures() const +{ + return m_cancelledGestures; +} + +/*! + Sets a list of gesture names \a cancelledGestures that used to be + executed, but were cancelled (i.e. they were not finished + properly). +*/ +void QGraphicsSceneGestureEvent::setCancelledGestures(const QSet<QString> &cancelledGestures) +{ + m_cancelledGestures = cancelledGestures; +} + +/*! + Maps the point \a point, which is in a view coordinate system, to + scene coordinate system, and returns the mapped coordinate. + + A \a point is in coordinate system of the widget that received + gesture event. + + \sa mapToItem(), {The Graphics View Coordinate System} +*/ +QPointF QGraphicsSceneGestureEvent::mapToScene(const QPoint &point) const +{ + if (QGraphicsView *view = qobject_cast<QGraphicsView*>(widget())) + return view->mapToScene(point); + return QPointF(); +} + +/*! + Maps the rectangular \a rect, which is in a view coordinate system, to + scene coordinate system, and returns the mapped coordinate. + + A \a rect is in coordinate system of the widget that received + gesture event. + + \sa mapToItem(), {The Graphics View Coordinate System} +*/ +QPolygonF QGraphicsSceneGestureEvent::mapToScene(const QRect &rect) const +{ + if (QGraphicsView *view = qobject_cast<QGraphicsView*>(widget())) + return view->mapToScene(rect); + return QPolygonF(); +} + +/*! + Maps the point \a point, which is in a view coordinate system, to + item's \a item coordinate system, and returns the mapped coordinate. + + If \a item is 0, this function returns the same as mapToScene(). + + \sa mapToScene(), {The Graphics View Coordinate System} +*/ +QPointF QGraphicsSceneGestureEvent::mapToItem(const QPoint &point, QGraphicsItem *item) const +{ + if (item) { + if (QGraphicsView *view = qobject_cast<QGraphicsView*>(widget())) + return item->mapFromScene(view->mapToScene(point)); + } else { + return mapToScene(point); + } + return QPointF(); +} + +/*! + Maps the rectangualar \a rect, which is in a view coordinate system, to + item's \a item coordinate system, and returns the mapped coordinate. + + If \a item is 0, this function returns the same as mapToScene(). + + \sa mapToScene(), {The Graphics View Coordinate System} +*/ +QPolygonF QGraphicsSceneGestureEvent::mapToItem(const QRect &rect, QGraphicsItem *item) const +{ + if (item) { + if (QGraphicsView *view = qobject_cast<QGraphicsView*>(widget())) + return item->mapFromScene(view->mapToScene(rect)); + } else { + return mapToScene(rect); + } + return QPolygonF(); +} + +/*! + Set a list of gesture objects containing extended information about \a gestures. +*/ +void QGraphicsSceneGestureEvent::setGestures(const QList<QGesture*> &gestures) +{ + foreach(QGesture *g, gestures) + m_gestures.insert(g->type(), g); +} + +/*! + Set a list of gesture objects containing extended information about \a gestures. +*/ +void QGraphicsSceneGestureEvent::setGestures(const QSet<QGesture*> &gestures) +{ + foreach(QGesture *g, gestures) + m_gestures.insert(g->type(), g); +} + +/*! + Sets the accept flag of the all gestures inside the event object, + the equivalent of calling \l{QEvent::accept()}{accept()} or + \l{QEvent::setAccepted()}{setAccepted(true)}. + + Setting the accept parameter indicates that the event receiver + wants the gesture. Unwanted gestures might be propagated to the parent + widget. +*/ +void QGraphicsSceneGestureEvent::acceptAll() +{ + QHash<QString, QGesture*>::iterator it = m_gestures.begin(), + e = m_gestures.end(); + for(; it != e; ++it) + it.value()->accept(); + setAccepted(true); +} + +/*! + Sets the accept flag of the specified gesture inside the event + object, the equivalent of calling + \l{QGestureEvent::gesture()}{gesture(type)}->\l{QGesture::accept()}{accept()} + + Setting the accept parameter indicates that the event receiver + wants the gesture. Unwanted gestures might be propagated to the parent + widget. +*/ +void QGraphicsSceneGestureEvent::accept(Qt::GestureType type) +{ + if (QGesture *g = m_gestures.value(qt_getStandardGestureTypeName(type), 0)) + g->accept(); +} + +/*! + Sets the accept flag of the specified gesture inside the event + object, the equivalent of calling + \l{QGestureEvent::gesture()}{gesture(type)}->\l{QGesture::accept()}{accept()} + + Setting the accept parameter indicates that the event receiver + wants the gesture. Unwanted gestures might be propagated to the parent + widget. +*/ +void QGraphicsSceneGestureEvent::accept(const QString &type) +{ + if (QGesture *g = m_gestures.value(type, 0)) + g->accept(); +} + +class QGraphicsSceneTouchEventPrivate : public QGraphicsSceneEventPrivate +{ + Q_DECLARE_PUBLIC(QGraphicsSceneTouchEvent) +public: + inline QGraphicsSceneTouchEventPrivate() + : modifiers(Qt::NoModifier) + { } + + QList<QGraphicsSceneTouchEvent::TouchPoint *> touchPoints; + Qt::KeyboardModifiers modifiers; +}; + +/*! + \internal + + Constructs a generic QGraphicsSceneTouchEvent of type \a type. +*/ +QGraphicsSceneTouchEvent::QGraphicsSceneTouchEvent(Type type) + : QGraphicsSceneEvent(*new QGraphicsSceneTouchEventPrivate, type) +{ } + +/*! + Destroys the QGraphicsSceneTouchEvent. +*/ +QGraphicsSceneTouchEvent::~QGraphicsSceneTouchEvent() +{ } + +/*! + Returns the list of touch points for this event. + + \sa QGraphicsSceneTouchEvent::TouchPoint +*/ +const QList<QGraphicsSceneTouchEvent::TouchPoint *> &QGraphicsSceneTouchEvent::touchPoints() const +{ + Q_D(const QGraphicsSceneTouchEvent); + return d->touchPoints; +} + +/*! \internal */ +void QGraphicsSceneTouchEvent::setTouchPoints(const QList<QGraphicsSceneTouchEvent::TouchPoint *> &touchPoints) +{ + Q_D(QGraphicsSceneTouchEvent); + d->touchPoints = touchPoints; +} + +/*! + Returns the keyboard modifiers in use at the time the event was + sent. +*/ +Qt::KeyboardModifiers QGraphicsSceneTouchEvent::modifiers() const +{ + Q_D(const QGraphicsSceneTouchEvent); + return d->modifiers; +} + +/*! \internal */ +void QGraphicsSceneTouchEvent::setModifiers(Qt::KeyboardModifiers modifiers) +{ + Q_D(QGraphicsSceneTouchEvent); + d->modifiers = modifiers; +} + +/*! + Returns the current position of this touch point in scene coordinates. + + \sa pos(), screenPos() +*/ +QPointF QGraphicsSceneTouchEvent::TouchPoint::scenePos() const +{ + return d->scenePos; +} + +/*! \internal */ +void QGraphicsSceneTouchEvent::TouchPoint::setScenePos(const QPointF &scenePos) +{ + d->scenePos = scenePos; +} + +/*! + Returns the starting position of this touch point in scene coordinates. + + \sa startPos(), startScreenPos() +*/ +QPointF QGraphicsSceneTouchEvent::TouchPoint::startScenePos() const +{ + return d->startScenePos; +} + +/*! \internal */ +void QGraphicsSceneTouchEvent::TouchPoint::setStartScenePos(const QPointF &startScenePos) +{ + d->startScenePos = startScenePos; +} + +/*! + Returns the previous position of this touch point in scene coordinates. + + \sa lastPos(), lastScreenPos() +*/ +QPointF QGraphicsSceneTouchEvent::TouchPoint::lastScenePos() const +{ + return d->lastScenePos; +} + +/*! \internal */ +void QGraphicsSceneTouchEvent::TouchPoint::setLastScenePos(const QPointF &lastScenePos) +{ + d->lastScenePos = lastScenePos; +} + QT_END_NAMESPACE #endif // QT_NO_GRAPHICSVIEW diff --git a/src/gui/graphicsview/qgraphicssceneevent.h b/src/gui/graphicsview/qgraphicssceneevent.h index be50e96..8b24d33 100644 --- a/src/gui/graphicsview/qgraphicssceneevent.h +++ b/src/gui/graphicsview/qgraphicssceneevent.h @@ -42,8 +42,12 @@ #ifndef QGRAPHICSSCENEEVENT_H #define QGRAPHICSSCENEEVENT_H -#include <QtCore/qcoreevent.h> +#include <QtGui/qevent.h> #include <QtCore/qpoint.h> +#include <QtCore/qrect.h> +#include <QtGui/qpolygon.h> +#include <QtCore/qset.h> +#include <QtCore/qhash.h> QT_BEGIN_HEADER @@ -302,6 +306,82 @@ public: void setNewPos(const QPointF &pos); }; +class QGesture; +class QGraphicsItem; +class QGraphicsSceneGestureEventPrivate; +class Q_GUI_EXPORT QGraphicsSceneGestureEvent : public QGraphicsSceneEvent +{ + Q_DECLARE_PRIVATE(QGraphicsSceneGestureEvent) +public: + QGraphicsSceneGestureEvent(); + ~QGraphicsSceneGestureEvent(); + + bool contains(const QString &type) const; + bool contains(Qt::GestureType type) const; + + QList<QString> gestureTypes() const; + + const QGesture* gesture(Qt::GestureType type) const; + const QGesture* gesture(const QString &type) const; + QList<QGesture*> gestures() const; + void setGestures(const QList<QGesture*> &gestures); + void setGestures(const QSet<QGesture*> &gestures); + + QSet<QString> cancelledGestures() const; + void setCancelledGestures(const QSet<QString> &cancelledGestures); + + void acceptAll(); +#ifndef Q_NO_USING_KEYWORD + using QEvent::accept; +#else + inline void accept() { QEvent::accept(); } +#endif + void accept(Qt::GestureType type); + void accept(const QString &type); + + QPointF mapToScene(const QPoint &point) const; + QPolygonF mapToScene(const QRect &rect) const; + QPointF mapToItem(const QPoint &point, QGraphicsItem *item) const; + QPolygonF mapToItem(const QRect &rect, QGraphicsItem *item) const; + +protected: + QHash<QString, QGesture*> m_gestures; + QSet<QString> m_cancelledGestures; +}; + +class QGraphicsSceneTouchEventPrivate; +class Q_GUI_EXPORT QGraphicsSceneTouchEvent : public QGraphicsSceneEvent +{ +public: + class Q_GUI_EXPORT TouchPoint : public QTouchEvent::TouchPoint + { + public: + QPointF scenePos() const; + void setScenePos(const QPointF &scenePos); + + QPointF startScenePos() const; + void setStartScenePos(const QPointF &startScenePos); + + QPointF lastScenePos() const; + void setLastScenePos(const QPointF &lastScenePos); + + qreal pressure() const; // 0.0 -> 1.0 + void setPressure(qreal pressure); + }; + + QGraphicsSceneTouchEvent(Type type = None); + ~QGraphicsSceneTouchEvent(); + + const QList<QGraphicsSceneTouchEvent::TouchPoint *> &touchPoints() const; + void setTouchPoints(const QList<QGraphicsSceneTouchEvent::TouchPoint *> &touchPoints); + + Qt::KeyboardModifiers modifiers() const; + void setModifiers(Qt::KeyboardModifiers modifiers); + +private: + Q_DECLARE_PRIVATE(QGraphicsSceneTouchEvent); +}; + #endif // QT_NO_GRAPHICSVIEW QT_END_NAMESPACE diff --git a/src/gui/graphicsview/qgraphicsview.cpp b/src/gui/graphicsview/qgraphicsview.cpp index 396618c..f3feb15 100644 --- a/src/gui/graphicsview/qgraphicsview.cpp +++ b/src/gui/graphicsview/qgraphicsview.cpp @@ -295,6 +295,8 @@ static const int QGRAPHICSVIEW_PREALLOC_STYLE_OPTIONS = 503; // largest prime < QT_BEGIN_NAMESPACE +bool qt_sendSpontaneousEvent(QObject *receiver, QEvent *event); + inline int q_round_bound(qreal d) //### (int)(qreal) INT_MAX != INT_MAX for single precision { if (d <= (qreal) INT_MIN) @@ -304,6 +306,30 @@ inline int q_round_bound(qreal d) //### (int)(qreal) INT_MAX != INT_MAX for sing return d >= 0.0 ? int(d + 0.5) : int(d - int(d-1) + 0.5) + int(d-1); } +static void qt_convertTouchEventToGraphicsSceneTouchEvent(QGraphicsViewPrivate *d, + QTouchEvent *originalEvent, + QGraphicsSceneTouchEvent *touchEvent) +{ + QList<QTouchEvent::TouchPoint *> originalTouchPoints = originalEvent->touchPoints(); + QList<QGraphicsSceneTouchEvent::TouchPoint *> touchPoints; + for (int i = 0; i < originalTouchPoints.count(); ++i) { + QGraphicsSceneTouchEvent::TouchPoint *touchPoint = + static_cast<QGraphicsSceneTouchEvent::TouchPoint *>(originalTouchPoints.at(i)); + // the scene will set the pos before delivering to an item + touchPoint->setScenePos(d->mapToScene(touchPoint->pos())); + // the scene will set the startPos before delivering to an item + touchPoint->setStartScenePos(d->mapToScene(touchPoint->startPos())); + // the scene will set the lastPos before delivering to an item + touchPoint->setLastScenePos(d->mapToScene(touchPoint->lastScreenPos())); + // lastScreenPos is already set in the originalTouchPoint + + touchPoints.append(touchPoint); + } + + touchEvent->setTouchPoints(touchPoints); + touchEvent->setModifiers(originalEvent->modifiers()); +} + /*! \internal */ @@ -602,7 +628,7 @@ void QGraphicsViewPrivate::mouseMoveEventHandler(QMouseEvent *event) lastMouseMoveScenePoint = mouseEvent.scenePos(); lastMouseMoveScreenPoint = mouseEvent.screenPos(); mouseEvent.setAccepted(false); - QApplication::sendEvent(scene, &mouseEvent); + qt_sendSpontaneousEvent(scene, &mouseEvent); // Remember whether the last event was accepted or not. lastMouseEvent.setAccepted(mouseEvent.isAccepted()); @@ -1623,7 +1649,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; } @@ -1632,7 +1658,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; @@ -2759,6 +2785,9 @@ bool QGraphicsView::event(QEvent *event) } } break; + case QEvent::Gesture: + viewportEvent(event); + return true; default: break; } @@ -2839,6 +2868,43 @@ bool QGraphicsView::viewportEvent(QEvent *event) d->scene->d_func()->updateAll = false; } break; + case QEvent::Gesture: { + QGraphicsSceneGestureEvent gestureEvent; + gestureEvent.setWidget(this); + QGestureEvent *ev = static_cast<QGestureEvent*>(event); + gestureEvent.setGestures(ev->gestures()); + gestureEvent.setCancelledGestures(ev->cancelledGestures()); + QApplication::sendEvent(d->scene, &gestureEvent); + event->setAccepted(gestureEvent.isAccepted()); + return true; + } + break; + case QEvent::TouchBegin: + case QEvent::TouchUpdate: + case QEvent::TouchEnd: + { + if (!isEnabled()) + return false; + + if (d->scene && d->sceneInteractionAllowed) { + // Convert and deliver the touch event to the scene. + QEvent::Type eventType = event->type() == QEvent::TouchBegin + ? QEvent::GraphicsSceneTouchBegin + : event->type() == QEvent::TouchEnd + ? QEvent::GraphicsSceneTouchEnd + : QEvent::GraphicsSceneTouchUpdate; + QGraphicsSceneTouchEvent touchEvent(eventType); + touchEvent.setWidget(viewport()); + qt_convertTouchEventToGraphicsSceneTouchEvent(d, + static_cast<QTouchEvent *>(event), + &touchEvent); + touchEvent.setAccepted(false); + QApplication::sendEvent(d->scene, &touchEvent); + event->setAccepted(touchEvent.isAccepted()); + } + + return true; + } default: break; } @@ -3097,7 +3163,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); } /*! @@ -3136,7 +3202,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(); @@ -3306,7 +3372,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()); @@ -3776,6 +3842,14 @@ void QGraphicsView::resetTransform() setTransform(QTransform()); } +QPointF QGraphicsViewPrivate::mapToScene(const QPointF &point) const +{ + QPointF p = point; + p.rx() += horizontalScroll(); + p.ry() += verticalScroll(); + return identityMatrix ? p : matrix.inverted().map(p); +} + QT_END_NAMESPACE #include "moc_qgraphicsview.cpp" diff --git a/src/gui/graphicsview/qgraphicsview_p.h b/src/gui/graphicsview/qgraphicsview_p.h index c18f85d..779b638 100644 --- a/src/gui/graphicsview/qgraphicsview_p.h +++ b/src/gui/graphicsview/qgraphicsview_p.h @@ -174,6 +174,15 @@ public: bool updateSceneSlotReimplementedChecked; QList<QGraphicsItem *> findItems(const QRegion &exposedRegion, bool *allItems) const; + + void generateStyleOptions(const QList<QGraphicsItem *> &itemList, + QGraphicsItem **itemArray, + QStyleOptionGraphicsItem *styleOptionArray, + const QTransform &worldTransform, + bool allItems, + const QRegion &exposedRegion) const; + + QPointF mapToScene(const QPointF &point) const; }; QT_END_NAMESPACE |