summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/gui/graphicsview/qgraphicsscene.cpp166
-rw-r--r--src/gui/graphicsview/qgraphicsscene_p.h6
-rw-r--r--src/gui/graphicsview/qgraphicsview.cpp106
-rw-r--r--src/gui/graphicsview/qgraphicsview_p.h5
4 files changed, 283 insertions, 0 deletions
diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp
index 553967c..b47ed5e 100644
--- a/src/gui/graphicsview/qgraphicsscene.cpp
+++ b/src/gui/graphicsview/qgraphicsscene.cpp
@@ -3609,6 +3609,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
@@ -3760,6 +3763,15 @@ bool QGraphicsScene::event(QEvent *event)
// geometries that do not have an explicit style set.
update();
break;
+ case QEvent::GraphicsSceneTouchBegin:
+ d->touchBeginEvent(static_cast<QGraphicsSceneTouchEvent *>(event));
+ break;
+ case QEvent::GraphicsSceneTouchUpdate:
+ d->touchUpdateEvent(static_cast<QGraphicsSceneTouchEvent *>(event));
+ break;
+ case QEvent::GraphicsSceneTouchEnd:
+ d->touchEndEvent(static_cast<QGraphicsSceneTouchEvent *>(event));
+ break;
case QEvent::Timer:
if (d->indexTimerId && static_cast<QTimerEvent *>(event)->timerId() == d->indexTimerId) {
if (d->restartIndexTimer) {
@@ -5370,6 +5382,160 @@ void QGraphicsScene::setActiveWindow(QGraphicsWidget *widget)
}
}
+// ### FIXME: the code for touch event support is mosly copied from
+// ### QGraphicsScenePrivate::mousePressEventHandler() and friends, need to
+// ### refactor to reduce code duplication
+
+void QGraphicsScenePrivate::sendTouchEvent(QGraphicsSceneTouchEvent *touchEvent)
+{
+ if (touchEvent->type() == QEvent::GraphicsSceneTouchEnd && lastMouseGrabberItemHasImplicitMouseGrab) {
+ clearMouseGrabber();
+ return;
+ }
+
+ QGraphicsItem *item = mouseGrabberItems.last();
+ 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()));
+ }
+ sendEvent(item, touchEvent);
+}
+
+void QGraphicsScenePrivate::touchBeginEvent(QGraphicsSceneTouchEvent *touchEvent)
+{
+ Q_Q(QGraphicsScene);
+
+ // Ignore by default, unless we find a mouse grabber that accepts it.
+ touchEvent->ignore();
+
+ // Deliver to any existing mouse grabber.
+ if (!mouseGrabberItems.isEmpty()) {
+ // The event is ignored by default, but we disregard the event's
+ // accepted state after delivery; the mouse is grabbed, after all.
+ sendTouchEvent(touchEvent);
+ return;
+ }
+
+ // Start by determining the number of items at the current position.
+ // Reuse value from earlier calculations if possible.
+ if (cachedItemsUnderMouse.isEmpty()) {
+ QGraphicsSceneTouchEvent::TouchPoint *touchPoint = touchEvent->touchPoints().first();
+ // ### FIXME: should the itemsAtPosition() function support sub-pixel screenPos?
+ cachedItemsUnderMouse = itemsAtPosition(touchPoint->screenPos().toPoint(),
+ touchPoint->scenePos(),
+ touchEvent->widget());
+ }
+
+ // Update window activation.
+ QGraphicsWidget *newActiveWindow = windowForItem(cachedItemsUnderMouse.value(0));
+ if (newActiveWindow != activeWindow)
+ q->setActiveWindow(newActiveWindow);
+
+ // 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);
+
+ // Find a mouse grabber by sending touch events to all mouse grabber
+ // candidates one at a time, until the event is accepted. It's accepted by
+ // default, so the receiver has to explicitly ignore it for it to pass
+ // through.
+ foreach (QGraphicsItem *item, cachedItemsUnderMouse) {
+ if (!item->acceptTouchEvents()) {
+ // Skip items that don't accept the touch events
+ continue;
+ }
+
+ grabMouse(item, /* implicit = */ true);
+ touchEvent->accept();
+
+ // check if the item we are sending to are disabled (before we send the event)
+ bool disabled = !item->isEnabled();
+ bool isWindow = item->isWindow();
+ sendTouchEvent(touchEvent);
+
+ bool dontSendUngrabEvents = mouseGrabberItems.isEmpty() || mouseGrabberItems.last() != item;
+ if (disabled) {
+ ungrabMouse(item, /* itemIsDying = */ dontSendUngrabEvents);
+ break;
+ }
+ if (touchEvent->isAccepted()) {
+ lastMouseGrabberItem = item;
+ return;
+ }
+ ungrabMouse(item, /* itemIsDying = */ dontSendUngrabEvents);
+
+ // Don't propagate through windows.
+ if (isWindow)
+ break;
+ }
+
+ // Is the event still ignored? Then the mouse press goes to the scene.
+ // Reset the mouse grabber, clear the selection, clear focus, and leave
+ // the event ignored so that it can propagate through the originating
+ // view.
+ if (!touchEvent->isAccepted()) {
+ clearMouseGrabber();
+
+ QGraphicsView *view = touchEvent->widget() ? qobject_cast<QGraphicsView *>(touchEvent->widget()->parentWidget()) : 0;
+ bool dontClearSelection = view && view->dragMode() == QGraphicsView::ScrollHandDrag;
+ if (!dontClearSelection) {
+ // Clear the selection if the originating view isn't in scroll
+ // hand drag mode. The view will clear the selection if no drag
+ // happened.
+ q->clearSelection();
+ }
+ }
+}
+
+void QGraphicsScenePrivate::touchUpdateEvent(QGraphicsSceneTouchEvent *touchEvent)
+{
+ if (mouseGrabberItems.isEmpty()) {
+ touchEvent->ignore();
+ return;
+ }
+
+ // Forward the event to the mouse grabber
+ sendTouchEvent(touchEvent);
+ touchEvent->accept();
+}
+
+void QGraphicsScenePrivate::touchEndEvent(QGraphicsSceneTouchEvent *touchEvent)
+{
+ if (mouseGrabberItems.isEmpty()) {
+ touchEvent->ignore();
+ return;
+ }
+
+ // Forward the event to the mouse grabber
+ sendTouchEvent(touchEvent);
+ touchEvent->accept();
+
+ // Reset the mouse grabber
+ if (!mouseGrabberItems.isEmpty()) {
+ lastMouseGrabberItem = mouseGrabberItems.last();
+ if (lastMouseGrabberItemHasImplicitMouseGrab)
+ mouseGrabberItems.last()->ungrabMouse();
+ } else {
+ lastMouseGrabberItem = 0;
+ }
+}
+
QT_END_NAMESPACE
#include "moc_qgraphicsscene.cpp"
diff --git a/src/gui/graphicsview/qgraphicsscene_p.h b/src/gui/graphicsview/qgraphicsscene_p.h
index 7f441da..d5e539b 100644
--- a/src/gui/graphicsview/qgraphicsscene_p.h
+++ b/src/gui/graphicsview/qgraphicsscene_p.h
@@ -73,6 +73,7 @@ QT_BEGIN_NAMESPACE
class QGraphicsView;
class QGraphicsWidget;
+class QGraphicsSceneTouchEvent;
class QGraphicsScenePrivate : public QObjectPrivate
{
@@ -259,6 +260,11 @@ public:
mutable QVector<QTransform> sceneTransformCache;
mutable QBitArray validTransforms;
mutable QVector<int> freeSceneTransformSlots;
+
+ void sendTouchEvent(QGraphicsSceneTouchEvent *touchEvent);
+ void touchBeginEvent(QGraphicsSceneTouchEvent *touchEvent);
+ void touchUpdateEvent(QGraphicsSceneTouchEvent *touchEvent);
+ void touchEndEvent(QGraphicsSceneTouchEvent *touchEvent);
};
QT_END_NAMESPACE
diff --git a/src/gui/graphicsview/qgraphicsview.cpp b/src/gui/graphicsview/qgraphicsview.cpp
index a661441..f95d328 100644
--- a/src/gui/graphicsview/qgraphicsview.cpp
+++ b/src/gui/graphicsview/qgraphicsview.cpp
@@ -2926,6 +2926,28 @@ bool QGraphicsView::viewportEvent(QEvent *event)
d->scene->d_func()->updateAll = false;
}
break;
+ case QEvent::TouchBegin:
+ case QEvent::TouchUpdate:
+ case QEvent::TouchEnd:
+ {
+ if (!isEnabled())
+ return false;
+ QTouchEvent *touchEvent = static_cast<QTouchEvent *>(event);
+ switch (touchEvent->type()) {
+ case QEvent::TouchBegin:
+ d->touchBeginEvent(touchEvent);
+ break;
+ case QEvent::TouchUpdate:
+ d->touchUpdateEvent(touchEvent);
+ break;
+ case QEvent::TouchEnd:
+ d->touchEndEvent(touchEvent);
+ break;
+ default:
+ break;
+ }
+ return true;
+ }
default:
break;
}
@@ -3864,6 +3886,90 @@ void QGraphicsView::resetTransform()
setTransform(QTransform());
}
+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) {
+ QTouchEvent::TouchPoint *originalTouchPoint = originalTouchPoints.at(i);
+
+ QGraphicsSceneTouchEvent::TouchPoint *touchPoint = new QGraphicsSceneTouchEvent::TouchPoint();
+ touchPoint->setId(originalTouchPoint->id());
+ touchPoint->setState(originalTouchPoint->state());
+ // the scene will set the pos before delivering to an item
+ touchPoint->setScenePos(d->mapToScene(originalTouchPoint->pos()));
+ touchPoint->setScreenPos(originalTouchPoint->globalPos());
+ // the scene will set the startPos before delivering to an item
+ touchPoint->setStartScenePos(d->mapToScene(originalTouchPoint->startPos()));
+ touchPoint->setStartScreenPos(originalTouchPoint->startGlobalPos());
+ // the scene will set the lastPos before delivering to an item
+ touchPoint->setLastScenePos(d->mapToScene(originalTouchPoint->lastPos()));
+ touchPoint->setLastScreenPos(originalTouchPoint->lastGlobalPos());
+ touchPoint->setPressure(originalTouchPoint->pressure());
+
+ touchPoints.append(touchPoint);
+ }
+
+ touchEvent->setTouchPoints(touchPoints);
+ touchEvent->setModifiers(originalEvent->modifiers());
+}
+
+QPointF QGraphicsViewPrivate::mapToScene(const QPointF &point) const
+{
+ QPointF p = point;
+ p.rx() += horizontalScroll();
+ p.ry() += verticalScroll();
+ return identityMatrix ? p : matrix.inverted().map(p);
+}
+
+void QGraphicsViewPrivate::touchBeginEvent(QTouchEvent *event)
+{
+ Q_Q(QGraphicsView);
+
+ if (!scene || !sceneInteractionAllowed)
+ return;
+
+ // Convert and deliver the touch event to the scene.
+ QGraphicsSceneTouchEvent touchEvent(QEvent::GraphicsSceneTouchBegin);
+ touchEvent.setWidget(q->viewport());
+ qt_convertTouchEventToGraphicsSceneTouchEvent(this, event, &touchEvent);
+ touchEvent.setAccepted(false);
+ QApplication::sendEvent(scene, &touchEvent);
+ event->setAccepted(touchEvent.isAccepted());
+}
+
+void QGraphicsViewPrivate::touchUpdateEvent(QTouchEvent *event)
+{
+ Q_Q(QGraphicsView);
+
+ if (!scene || !sceneInteractionAllowed)
+ return;
+
+ // Convert and deliver the touch event to the scene.
+ QGraphicsSceneTouchEvent touchEvent(QEvent::GraphicsSceneTouchUpdate);
+ touchEvent.setWidget(q->viewport());
+ qt_convertTouchEventToGraphicsSceneTouchEvent(this, event, &touchEvent);
+ touchEvent.setAccepted(false);
+ QApplication::sendEvent(scene, &touchEvent);
+ event->setAccepted(touchEvent.isAccepted());
+}
+
+void QGraphicsViewPrivate::touchEndEvent(QTouchEvent *event)
+{
+ Q_Q(QGraphicsView);
+
+ if (!scene || !sceneInteractionAllowed)
+ return;
+
+ // Convert and deliver the touch event to the scene.
+ QGraphicsSceneTouchEvent touchEvent(QEvent::GraphicsSceneTouchEnd);
+ touchEvent.setWidget(q->viewport());
+ qt_convertTouchEventToGraphicsSceneTouchEvent(this, event, &touchEvent);
+ touchEvent.setAccepted(false);
+ QApplication::sendEvent(scene, &touchEvent);
+ event->setAccepted(touchEvent.isAccepted());
+}
+
QT_END_NAMESPACE
#include "moc_qgraphicsview.cpp"
diff --git a/src/gui/graphicsview/qgraphicsview_p.h b/src/gui/graphicsview/qgraphicsview_p.h
index 2109673..e9479f3 100644
--- a/src/gui/graphicsview/qgraphicsview_p.h
+++ b/src/gui/graphicsview/qgraphicsview_p.h
@@ -182,6 +182,11 @@ public:
const QTransform &worldTransform,
bool allItems,
const QRegion &exposedRegion) const;
+
+ QPointF mapToScene(const QPointF &point) const;
+ void touchBeginEvent(QTouchEvent *event);
+ void touchUpdateEvent(QTouchEvent *event);
+ void touchEndEvent(QTouchEvent *event);
};
QT_END_NAMESPACE