diff options
author | Bjørn Erik Nilsen <bjorn.nilsen@nokia.com> | 2009-07-01 09:25:57 (GMT) |
---|---|---|
committer | Bjørn Erik Nilsen <bjorn.nilsen@nokia.com> | 2009-07-01 09:25:57 (GMT) |
commit | 574fdf0b7e61c1c9994739035d9adb51af2629d0 (patch) | |
tree | 6cf91585a63b26dce56f18a1ccd924cf7ec38cb9 /src/gui/graphicsview | |
parent | a1d5b33bd33ecf1d809346a39d2386cafaf50cef (diff) | |
parent | 9cb231d773db6deb8fb145eb40aa949a2758d002 (diff) | |
download | Qt-574fdf0b7e61c1c9994739035d9adb51af2629d0.zip Qt-574fdf0b7e61c1c9994739035d9adb51af2629d0.tar.gz Qt-574fdf0b7e61c1c9994739035d9adb51af2629d0.tar.bz2 |
Merge commit 'qt/master' into graphicssceneindex
Conflicts:
src/gui/graphicsview/qgraphicsscene.cpp
src/gui/graphicsview/qgraphicsscene_p.h
src/gui/graphicsview/qgraphicsview.cpp
src/gui/graphicsview/qgraphicsview_p.h
Diffstat (limited to 'src/gui/graphicsview')
-rw-r--r-- | src/gui/graphicsview/qgraphicsitem.cpp | 147 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicsitem.h | 7 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicsitem_p.h | 52 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicslayout_p.cpp | 4 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicslinearlayout.cpp | 14 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicsproxywidget.cpp | 16 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicsscene.cpp | 368 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicsscene.h | 3 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicsscene_p.h | 23 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicssceneevent.cpp | 271 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicssceneevent.h | 47 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicsview.cpp | 119 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicsview_p.h | 4 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicswidget.cpp | 16 |
14 files changed, 1050 insertions, 41 deletions
diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index e9d1076..6850b5f 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -575,6 +575,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> @@ -604,6 +605,8 @@ public: }; Q_GLOBAL_STATIC(QGraphicsItemCustomDataStore, qt_dataStore) +QString qt_getStandardGestureTypeName(Qt::GestureType type); + /*! \internal @@ -1117,6 +1120,7 @@ QGraphicsItem::~QGraphicsItem() { d_ptr->inDestructor = 1; d_ptr->removeExtraItemCache(); + d_ptr->removeExtraGestures(); clearFocus(); if (!d_ptr->children.isEmpty()) { @@ -2273,6 +2277,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); @@ -6210,6 +6244,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 @@ -6233,6 +6363,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 48fb5c3..cd59fae 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 243582a..a4b2c25 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) { @@ -183,7 +193,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); @@ -252,7 +262,7 @@ public: } } } - + struct ExtraStruct { ExtraStruct(Extra type, QVariant value) : type(type), value(value) @@ -264,7 +274,7 @@ public: bool operator<(Extra extra) const { return type < extra; } }; - + QList<ExtraStruct> extras; QGraphicsItemCache *maybeExtraItemCache() const; @@ -393,7 +403,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; @@ -410,8 +444,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; @@ -430,7 +464,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/qgraphicslayout_p.cpp b/src/gui/graphicsview/qgraphicslayout_p.cpp index 6296207..83bf14b 100644 --- a/src/gui/graphicsview/qgraphicslayout_p.cpp +++ b/src/gui/graphicsview/qgraphicslayout_p.cpp @@ -120,8 +120,8 @@ static bool removeLayoutItemFromLayout(QGraphicsLayout *lay, QGraphicsLayoutItem if (!lay) return false; - QGraphicsLayoutItem *child; - for (int i = 0; (child = lay->itemAt(i)); ++i) { + for (int i = lay->count() - 1; i >= 0; --i) { + QGraphicsLayoutItem *child = lay->itemAt(i); if (child && child->isLayout()) { if (removeLayoutItemFromLayout(static_cast<QGraphicsLayout*>(child), layoutItem)) return true; diff --git a/src/gui/graphicsview/qgraphicslinearlayout.cpp b/src/gui/graphicsview/qgraphicslinearlayout.cpp index 2e78fc0..3b037cf 100644 --- a/src/gui/graphicsview/qgraphicslinearlayout.cpp +++ b/src/gui/graphicsview/qgraphicslinearlayout.cpp @@ -323,7 +323,11 @@ void QGraphicsLinearLayout::removeItem(QGraphicsLayoutItem *item) void QGraphicsLinearLayout::removeAt(int index) { Q_D(QGraphicsLinearLayout); - if (QGridLayoutItem *gridItem = d->engine.itemAt(d->gridRow(index), d->gridColumn(index))) { + if (index < 0 || index >= d->engine.itemCount()) { + qWarning("QGraphicsLinearLayout::removeAt: invalid index %d", index); + return; + } + if (QGridLayoutItem *gridItem = d->engine.itemAt(index)) { if (QGraphicsLayoutItem *layoutItem = gridItem->layoutItem()) layoutItem->setParentLayoutItem(0); d->removeGridItem(gridItem); @@ -463,7 +467,7 @@ QSizePolicy::ControlTypes QGraphicsLinearLayout::controlTypes(LayoutSide side) c int QGraphicsLinearLayout::count() const { Q_D(const QGraphicsLinearLayout); - return d->engine.rowCount(d->orientation); + return d->engine.itemCount(); } /*! @@ -472,8 +476,12 @@ int QGraphicsLinearLayout::count() const QGraphicsLayoutItem *QGraphicsLinearLayout::itemAt(int index) const { Q_D(const QGraphicsLinearLayout); + if (index < 0 || index >= d->engine.itemCount()) { + qWarning("QGraphicsLinearLayout::itemAt: invalid index %d", index); + return 0; + } QGraphicsLayoutItem *item = 0; - if (QGridLayoutItem *gridItem = d->engine.itemAt(d->gridRow(index), d->gridColumn(index))) + if (QGridLayoutItem *gridItem = d->engine.itemAt(index)) item = gridItem->layoutItem(); return item; } diff --git a/src/gui/graphicsview/qgraphicsproxywidget.cpp b/src/gui/graphicsview/qgraphicsproxywidget.cpp index 07ebb8c..ab94679 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 ed1d2f3..1263c3a 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -243,11 +243,14 @@ #include <QtGui/qstyleoption.h> #include <QtGui/qtooltip.h> #include <QtGui/qtransform.h> +#include <QtGui/qgesture.h> #include <private/qapplication_p.h> #include <private/qobject_p.h> #ifdef Q_WS_X11 #include <private/qt_x11_p.h> #endif +#include <private/qgesturemanager_p.h> +#include <private/qgesture_p.h> QT_BEGIN_NAMESPACE @@ -294,7 +297,9 @@ QGraphicsScenePrivate::QGraphicsScenePrivate() allItemsIgnoreHoverEvents(true), allItemsUseDefaultCursor(true), painterStateProtection(true), - style(0) + style(0), + sortCacheEnabled(false), + allItemsIgnoreTouchEvents(true) { } @@ -1007,6 +1012,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()); @@ -1957,6 +1963,7 @@ void QGraphicsScene::clear() d->lastItemCount = 0; d->allItemsIgnoreHoverEvents = true; d->allItemsUseDefaultCursor = true; + d->allItemsIgnoreTouchEvents = true; } /*! @@ -2115,6 +2122,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; @@ -2846,6 +2859,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 @@ -2999,12 +3015,122 @@ 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; default: return QObject::event(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 @@ -4849,6 +4975,246 @@ 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) { + if (sceneTouchEvent->deviceType() == QTouchEvent::TouchPad) { + // on touch-pad devices, send all touch points to the same item + item = itemForTouchPointId.isEmpty() + ? 0 + : itemForTouchPointId.constBegin().value(); + } + + if (!item) { + // determine which item this touch point will go to + cachedItemsUnderMouse = itemsAtPosition(touchPoint.screenPos().toPoint(), + touchPoint.scenePos(), + sceneTouchEvent->widget()); + item = cachedItemsUnderMouse.isEmpty() ? 0 : cachedItemsUnderMouse.first(); + } + + if (sceneTouchEvent->deviceType() == QTouchEvent::TouchScreen) { + // on touch-screens, combine this touch point with the closest one we find if it + // is a a direct descendent or ancestor ( + 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.setDeviceType(sceneTouchEvent->deviceType()); + 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 560671a..8329942 100644 --- a/src/gui/graphicsview/qgraphicsscene.h +++ b/src/gui/graphicsview/qgraphicsscene.h @@ -79,6 +79,7 @@ class QGraphicsSceneHelpEvent; class QGraphicsSceneHoverEvent; class QGraphicsSceneMouseEvent; class QGraphicsSceneWheelEvent; +class QGraphicsSceneGestureEvent; class QGraphicsSimpleTextItem; class QGraphicsTextItem; class QGraphicsView; @@ -206,7 +207,7 @@ public: inline QGraphicsRectItem *addRect(qreal x, qreal y, qreal w, qreal h, const QPen &pen = QPen(), const QBrush &brush = QBrush()) { return addRect(QRectF(x, y, w, h), pen, brush); } void removeItem(QGraphicsItem *item); - + QGraphicsItem *focusItem() const; void setFocusItem(QGraphicsItem *item, Qt::FocusReason focusReason = Qt::OtherFocusReason); bool hasFocus() const; diff --git a/src/gui/graphicsview/qgraphicsscene_p.h b/src/gui/graphicsview/qgraphicsscene_p.h index b3d7535..4842e72 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 "qgraphicsitem_p.h" @@ -75,6 +76,7 @@ QT_BEGIN_NAMESPACE class QGraphicsSceneIndex; class QGraphicsView; class QGraphicsWidget; +class QGesture; class QGraphicsScenePrivate : public QObjectPrivate { @@ -145,7 +147,7 @@ public: void grabKeyboard(QGraphicsItem *item); void ungrabKeyboard(QGraphicsItem *item, bool itemIsDying = false); void clearKeyboardGrabber(); - + QGraphicsItem *dragDropItem; QGraphicsWidget *enterWidget; Qt::DropAction lastDropAction; @@ -163,6 +165,9 @@ public: void storeMouseButtonsForMouseGrabber(QGraphicsSceneMouseEvent *event); QList<QGraphicsView *> views; + void addView(QGraphicsView *view); + void removeView(QGraphicsView *view); + bool painterStateProtection; QMultiMap<QGraphicsItem *, QGraphicsItem *> sceneEventFilters; @@ -240,6 +245,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; + QMap<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(); }; // QRectF::intersects() returns false always if either the source or target diff --git a/src/gui/graphicsview/qgraphicssceneevent.cpp b/src/gui/graphicsview/qgraphicssceneevent.cpp index 283010d..7906fb8 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,15 @@ #include <QtCore/qpoint.h> #include <QtCore/qsize.h> #include <QtCore/qstring.h> +#include "qgraphicsview.h" +#include "qgraphicsitem.h" +#include <QtGui/qgesture.h> +#include <private/qevent_p.h> QT_BEGIN_NAMESPACE +QString qt_getStandardGestureTypeName(Qt::GestureType type); + class QGraphicsSceneEventPrivate { public: @@ -522,7 +528,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 +551,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 +1281,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 +1379,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 +1434,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 +1679,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 e4decf9..995f3f3 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,10 @@ void QGraphicsViewPrivate::mouseMoveEventHandler(QMouseEvent *event) lastMouseMoveScenePoint = mouseEvent.scenePos(); lastMouseMoveScreenPoint = mouseEvent.screenPos(); mouseEvent.setAccepted(false); - QApplication::sendEvent(scene, &mouseEvent); + if (event->spontaneous()) + qt_sendSpontaneousEvent(scene, &mouseEvent); + else + QApplication::sendEvent(scene, &mouseEvent); // Remember whether the last event was accepted or not. lastMouseEvent.setAccepted(mouseEvent.isAccepted()); @@ -1456,7 +1480,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; } @@ -1465,7 +1489,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; @@ -1475,6 +1499,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(); } @@ -2488,6 +2516,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()); } @@ -2524,6 +2557,9 @@ bool QGraphicsView::event(QEvent *event) } } break; + case QEvent::Gesture: + viewportEvent(event); + return true; default: break; } @@ -2605,6 +2641,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; } @@ -2863,7 +2927,10 @@ void QGraphicsView::mouseDoubleClickEvent(QMouseEvent *event) mouseEvent.setAccepted(false); mouseEvent.setButton(event->button()); mouseEvent.setModifiers(event->modifiers()); - QApplication::sendEvent(d->scene, &mouseEvent); + if (event->spontaneous()) + qt_sendSpontaneousEvent(d->scene, &mouseEvent); + else + QApplication::sendEvent(d->scene, &mouseEvent); } /*! @@ -2902,7 +2969,10 @@ void QGraphicsView::mousePressEvent(QMouseEvent *event) mouseEvent.setButton(event->button()); mouseEvent.setModifiers(event->modifiers()); mouseEvent.setAccepted(false); - QApplication::sendEvent(d->scene, &mouseEvent); + if (event->spontaneous()) + qt_sendSpontaneousEvent(d->scene, &mouseEvent); + else + QApplication::sendEvent(d->scene, &mouseEvent); // Update the original mouse event accepted state. bool isAccepted = mouseEvent.isAccepted(); @@ -3073,7 +3143,10 @@ void QGraphicsView::mouseReleaseEvent(QMouseEvent *event) mouseEvent.setButton(event->button()); mouseEvent.setModifiers(event->modifiers()); mouseEvent.setAccepted(false); - QApplication::sendEvent(d->scene, &mouseEvent); + if (event->spontaneous()) + qt_sendSpontaneousEvent(d->scene, &mouseEvent); + else + QApplication::sendEvent(d->scene, &mouseEvent); // Update the last mouse event selected state. d->lastMouseEvent.setAccepted(mouseEvent.isAccepted()); @@ -3204,7 +3277,6 @@ void QGraphicsView::paintEvent(QPaintEvent *event) // Find all exposed items bool allItems = false; QList<QGraphicsItem *> itemList = d->findItems(d->exposedRegion, &allItems, viewTransform); - if (!itemList.isEmpty()) { // Generate the style options. const int numItems = itemList.size(); @@ -3532,6 +3604,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 d0c5e6e..7b9fd5e 100644 --- a/src/gui/graphicsview/qgraphicsview_p.h +++ b/src/gui/graphicsview/qgraphicsview_p.h @@ -174,6 +174,10 @@ public: QList<QGraphicsItem *> findItems(const QRegion &exposedRegion, bool *allItems, const QTransform &viewTransform) 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/graphicsview/qgraphicswidget.cpp b/src/gui/graphicsview/qgraphicswidget.cpp index 0644ce9..86c0b48 100644 --- a/src/gui/graphicsview/qgraphicswidget.cpp +++ b/src/gui/graphicsview/qgraphicswidget.cpp @@ -971,15 +971,18 @@ void QGraphicsWidget::updateGeometry() deliver events related to state changes in the item. Because of this, it is very important that subclasses call the base implementation. - For example, QGraphicsWidget uses ItemVisibleChange to deliver \l Show and - \l Hide events, ItemPositionHasChanged to deliver \l Move events, and - ItemParentChange both to deliver \l ParentChange events, and for managing - the focus chain. + \a change specifies the type of change, and \a value is the new value. + + For example, QGraphicsWidget uses ItemVisibleChange to deliver + \l{QEvent::Show} {Show} and \l{QEvent::Hide}{Hide} events, + ItemPositionHasChanged to deliver \l{QEvent::Move}{Move} events, + and ItemParentChange both to deliver \l{QEvent::ParentChange} + {ParentChange} events, and for managing the focus chain. QGraphicsWidget enables the ItemSendsGeometryChanges flag by default in order to track position changes. - \sa propertyChange() + \sa QGraphicsItem::itemChange() */ QVariant QGraphicsWidget::itemChange(GraphicsItemChange change, const QVariant &value) { @@ -1211,7 +1214,8 @@ Qt::WindowFrameSection QGraphicsWidget::windowFrameSectionAt(const QPointF &pos) /*! \reimp - QGraphicsWidget handles the following events: + Handles the \a event. QGraphicsWidget handles the following + events: \table \o Event \o Usage \row \o Polish |