diff options
Diffstat (limited to 'src/gui')
-rw-r--r-- | src/gui/graphicsview/qgraphicsitem.cpp | 25 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicsitem.h | 2 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicsitem_p.h | 2 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicsscene.cpp | 166 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicsscene_p.h | 6 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicssceneevent.cpp | 338 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicssceneevent.h | 64 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicsview.cpp | 106 | ||||
-rw-r--r-- | src/gui/graphicsview/qgraphicsview_p.h | 5 | ||||
-rw-r--r-- | src/gui/kernel/qapplication.cpp | 94 | ||||
-rw-r--r-- | src/gui/kernel/qapplication_p.h | 32 | ||||
-rw-r--r-- | src/gui/kernel/qapplication_win.cpp | 188 | ||||
-rw-r--r-- | src/gui/kernel/qevent.cpp | 164 | ||||
-rw-r--r-- | src/gui/kernel/qevent.h | 43 | ||||
-rw-r--r-- | src/gui/kernel/qevent_p.h | 16 | ||||
-rw-r--r-- | src/gui/kernel/qwidget_win.cpp | 4 |
16 files changed, 1218 insertions, 37 deletions
diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index 3aa74f3..21ffe7d 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -2074,6 +2074,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); diff --git a/src/gui/graphicsview/qgraphicsitem.h b/src/gui/graphicsview/qgraphicsitem.h index b98882d..ec3373a 100644 --- a/src/gui/graphicsview/qgraphicsitem.h +++ b/src/gui/graphicsview/qgraphicsitem.h @@ -203,6 +203,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); diff --git a/src/gui/graphicsview/qgraphicsitem_p.h b/src/gui/graphicsview/qgraphicsitem_p.h index 078c543..b1184fb 100644 --- a/src/gui/graphicsview/qgraphicsitem_p.h +++ b/src/gui/graphicsview/qgraphicsitem_p.h @@ -143,6 +143,7 @@ public: emptyClipPath(0), inSetPosHelper(0), allChildrenCombineOpacity(1), + acceptTouchEvents(0), globalStackingOrder(-1), sceneTransformIndex(-1), q_ptr(0) @@ -327,6 +328,7 @@ public: quint32 emptyClipPath : 1; quint32 inSetPosHelper : 1; quint32 allChildrenCombineOpacity : 1; + quint32 acceptTouchEvents : 1; // Optional stacking order int globalStackingOrder; diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index d9e0eec..f90998f 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -3796,6 +3796,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 @@ -3947,6 +3950,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) { @@ -5572,6 +5584,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 9ace725..de39205 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 { @@ -266,6 +267,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/qgraphicssceneevent.cpp b/src/gui/graphicsview/qgraphicssceneevent.cpp index b819c2c..3c9799b 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 @@ -522,7 +553,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 +576,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 +1306,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 +1404,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 +1459,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 +1704,291 @@ void QGraphicsSceneMoveEvent::setNewPos(const QPointF &pos) d->newPos = pos; } +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() +{ + Q_D(QGraphicsSceneTouchEvent); + qDeleteAll(d->touchPoints); +} + +/*! + 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; +} + +class QGraphicsSceneTouchEventTouchPointPrivate +{ +public: + inline QGraphicsSceneTouchEventTouchPointPrivate() + : id(-1), state(Qt::TouchPointReleased), pressure(qreal(0.)) + { } + + int id; + Qt::TouchPointState state; + QPointF pos, startPos, lastPos; + QPointF scenePos, startScenePos, lastScenePos; + QPointF screenPos, startScreenPos, lastScreenPos; + qreal pressure; +}; + +/*! \internal + + Constructs a new touch point for use in a QGraphicsSceneTouchEvent. +*/ +QGraphicsSceneTouchEvent::TouchPoint::TouchPoint() + : d(new QGraphicsSceneTouchEventTouchPointPrivate) +{ +} + +/*! \internal + + Destroys the QGraphicsSceneTouchEvent::TouchPoint. +*/ +QGraphicsSceneTouchEvent::TouchPoint::~TouchPoint() +{ + delete d; +} + +/*! + Returns the identifier for this touch point. +*/ +int QGraphicsSceneTouchEvent::TouchPoint::id() const +{ + return d->id; +} + +/*! \internal */ +void QGraphicsSceneTouchEvent::TouchPoint::setId(int id) +{ + d->id = id; +} + +/*! + Returns the state of this touch point at the time the + QGraphicsSceneTouchEvent occurred. +*/ +Qt::TouchPointState QGraphicsSceneTouchEvent::TouchPoint::state() const +{ + return d->state; +} + +/*! \internal */ +void QGraphicsSceneTouchEvent::TouchPoint::setState(Qt::TouchPointState state) +{ + d->state = state; +} + +/*! + Returns the current position of this touch point in item coordinates. + + \sa scenePos(), screenPos() +*/ +QPointF QGraphicsSceneTouchEvent::TouchPoint::pos() const +{ + return d->pos; +} + +/*! \internal */ +void QGraphicsSceneTouchEvent::TouchPoint::setPos(const QPointF &pos) +{ + d->pos = pos; +} + +/*! + Returns the starting position of this touch point in item coordinates. + + \sa startScenePos(), startScreenPos() +*/ +QPointF QGraphicsSceneTouchEvent::TouchPoint::startPos() const +{ + return d->startPos; +} + +/*! \internal */ +void QGraphicsSceneTouchEvent::TouchPoint::setStartPos(const QPointF &startPos) +{ + d->startPos = startPos; +} + +/*! + Returns the previous position of this touch point in item coordinates. + + \sa lastScenePos(), lastScreenPos() +*/ +QPointF QGraphicsSceneTouchEvent::TouchPoint::lastPos() const +{ + return d->lastPos; +} + +/*! \internal */ +void QGraphicsSceneTouchEvent::TouchPoint::setLastPos(const QPointF &lastPos) +{ + d->lastPos = lastPos; +} + +/*! + Returns the current position of this touch point in scene coordinates. + + \sa pos(), screenPos() +*/ +QPointF QGraphicsSceneTouchEvent::TouchPoint::scenePos() const +{ + return d->scenePos; +} + +/*! \internal */ +void QGraphicsSceneTouchEvent::TouchPoint::setScenePos(const QPointF &scenePos) +{ + 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; +} + +/*! + Returns the current position of this touch point in screen coordinates. + + \sa pos(), scenePos() +*/ +QPointF QGraphicsSceneTouchEvent::TouchPoint::screenPos() const +{ + return d->screenPos; +} + +/*! \internal */ +void QGraphicsSceneTouchEvent::TouchPoint::setScreenPos(const QPointF &screenPos) +{ + d->screenPos = screenPos; +} + +/*! + Returns the starting position of this touch point in screen coordinates. + + \sa startPos(), startScenePos() +*/ +QPointF QGraphicsSceneTouchEvent::TouchPoint::startScreenPos() const +{ + return d->startScreenPos; +} + +/*! \internal */ +void QGraphicsSceneTouchEvent::TouchPoint::setStartScreenPos(const QPointF &startScreenPos) +{ + d->startScreenPos = startScreenPos; +} + +/*! + Returns the previous position of this touch point in screen coordinates. + + \sa lastPos(), lastScenePos() +*/ +QPointF QGraphicsSceneTouchEvent::TouchPoint::lastScreenPos() const +{ + return d->lastScreenPos; +} + +/*! \internal */ +void QGraphicsSceneTouchEvent::TouchPoint::setLastScreenPos(const QPointF &lastScreenPos) +{ + d->lastScreenPos = lastScreenPos; +} + +/*! + Returns the pressure of this touch point. +*/ +qreal QGraphicsSceneTouchEvent::TouchPoint::pressure() const +{ + return d->pressure; +} + +/*! \internal */ +void QGraphicsSceneTouchEvent::TouchPoint::setPressure(qreal pressure) +{ + d->pressure = pressure; +} + QT_END_NAMESPACE #endif // QT_NO_GRAPHICSVIEW diff --git a/src/gui/graphicsview/qgraphicssceneevent.h b/src/gui/graphicsview/qgraphicssceneevent.h index be50e96..8ae3a99 100644 --- a/src/gui/graphicsview/qgraphicssceneevent.h +++ b/src/gui/graphicsview/qgraphicssceneevent.h @@ -302,6 +302,70 @@ public: void setNewPos(const QPointF &pos); }; +class QGraphicsSceneTouchEventPrivate; +class QGraphicsSceneTouchEventTouchPointPrivate; +class Q_GUI_EXPORT QGraphicsSceneTouchEvent : public QGraphicsSceneEvent +{ +public: + QGraphicsSceneTouchEvent(Type type = None); + ~QGraphicsSceneTouchEvent(); + + class Q_GUI_EXPORT TouchPoint + { + public: + TouchPoint(); + ~TouchPoint(); + + int id() const; + void setId(int id); + + Qt::TouchPointState state() const; + void setState(Qt::TouchPointState state); + + QPointF pos() const; + void setPos(const QPointF &pos); + + QPointF startPos() const; + void setStartPos(const QPointF &startPos); + + QPointF lastPos() const; + void setLastPos(const QPointF &lastPos); + + QPointF scenePos() const; + void setScenePos(const QPointF &scenePos); + + QPointF startScenePos() const; + void setStartScenePos(const QPointF &startScenePos); + + QPointF lastScenePos() const; + void setLastScenePos(const QPointF &lastScenePos); + + QPointF screenPos() const; + void setScreenPos(const QPointF &screenPos); + + QPointF startScreenPos() const; + void setStartScreenPos(const QPointF &startScreenPos); + + QPointF lastScreenPos() const; + void setLastScreenPos(const QPointF &lastScreenPos); + + qreal pressure() const; // 0.0 -> 1.0 + void setPressure(qreal pressure); + + private: + QGraphicsSceneTouchEventTouchPointPrivate *d; + }; + + const QList<TouchPoint *> &touchPoints() const; + void setTouchPoints(const QList<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 a9d585c..9e4647b 100644 --- a/src/gui/graphicsview/qgraphicsview.cpp +++ b/src/gui/graphicsview/qgraphicsview.cpp @@ -2942,6 +2942,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; } @@ -3880,6 +3902,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 a76279e..abab921 100644 --- a/src/gui/graphicsview/qgraphicsview_p.h +++ b/src/gui/graphicsview/qgraphicsview_p.h @@ -181,6 +181,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 diff --git a/src/gui/kernel/qapplication.cpp b/src/gui/kernel/qapplication.cpp index d5a96bd..52d6a70 100644 --- a/src/gui/kernel/qapplication.cpp +++ b/src/gui/kernel/qapplication.cpp @@ -85,6 +85,7 @@ #include <stdlib.h> #include "qapplication_p.h" +#include "qevent_p.h" #include "qwidget_p.h" #include "qapplication.h" @@ -3709,19 +3710,10 @@ bool QApplication::notify(QObject *receiver, QEvent *e) QPoint relpos = mouse->pos(); if (e->spontaneous()) { - if (e->type() == QEvent::MouseButtonPress) { - QWidget *fw = w; - while (fw) { - if (fw->isEnabled() - && QApplicationPrivate::shouldSetFocus(fw, Qt::ClickFocus)) { - fw->setFocus(Qt::MouseFocusReason); - break; - } - if (fw->isWindow()) - break; - fw = fw->parentWidget(); - } + QApplicationPrivate::giveFocusAccordingToFocusPolicy(w, + Qt::ClickFocus, + Qt::MouseFocusReason); } if (e->type() == QEvent::MouseMove && mouse->buttons() == 0) { @@ -3803,17 +3795,9 @@ bool QApplication::notify(QObject *receiver, QEvent *e) bool eventAccepted = wheel->isAccepted(); if (e->spontaneous()) { - QWidget *fw = w; - while (fw) { - if (fw->isEnabled() - && QApplicationPrivate::shouldSetFocus(fw, Qt::WheelFocus)) { - fw->setFocus(Qt::MouseFocusReason); - break; - } - if (fw->isWindow()) - break; - fw = fw->parentWidget(); - } + QApplicationPrivate::giveFocusAccordingToFocusPolicy(w, + Qt::WheelFocus, + Qt::MouseFocusReason); } while (w) { @@ -4018,7 +4002,41 @@ bool QApplication::notify(QObject *receiver, QEvent *e) } break; #endif + case QEvent::TouchBegin: + // Note: TouchUpdate and TouchEnd events are sent to d->currentMultitouchWidget and never propagated + { + QWidget *widget = static_cast<QWidget *>(receiver); + QTouchEvent *touchEvent = static_cast<QTouchEvent *>(e); + bool eventAccepted = touchEvent->isAccepted(); + + if (widget->testAttribute(Qt::WA_AcceptTouchEvents) && e->spontaneous()) { + // give the widget focus if the focus policy allows it + QApplicationPrivate::giveFocusAccordingToFocusPolicy(widget, + Qt::ClickFocus, + Qt::MouseFocusReason); + } + + while (widget) { + // first, try to deliver the touch event + touchEvent->ignore(); + res = widget->testAttribute(Qt::WA_AcceptTouchEvents) + && d->notify_helper(widget, touchEvent); + eventAccepted = touchEvent->isAccepted(); + touchEvent->spont = false; + if (res && eventAccepted) { + // the first widget to accept the TouchBegin gets an implicit grab. + d->currentMultitouchWidget = widget; + break; + } else if (widget->isWindow() || widget->testAttribute(Qt::WA_NoMousePropagation)) { + break; + } + widget = widget->parentWidget(); + d->updateTouchPointsForWidget(widget, touchEvent); + } + touchEvent->setAccepted(eventAccepted); + break; + } default: res = d->notify_helper(receiver, e); break; @@ -4985,6 +5003,23 @@ Qt::LayoutDirection QApplication::keyboardInputDirection() return qt_keymapper_private()->keyboardInputDirection; } +void QApplicationPrivate::giveFocusAccordingToFocusPolicy(QWidget *widget, + Qt::FocusPolicy focusPolicy, + Qt::FocusReason focusReason) +{ + QWidget *focusWidget = widget; + while (focusWidget) { + if (focusWidget->isEnabled() + && QApplicationPrivate::shouldSetFocus(focusWidget, focusPolicy)) { + focusWidget->setFocus(focusReason); + break; + } + if (focusWidget->isWindow()) + break; + focusWidget = focusWidget->parentWidget(); + } +} + bool QApplicationPrivate::shouldSetFocus(QWidget *w, Qt::FocusPolicy policy) { QWidget *f = w; @@ -4998,6 +5033,19 @@ bool QApplicationPrivate::shouldSetFocus(QWidget *w, Qt::FocusPolicy policy) return true; } +void QApplicationPrivate::updateTouchPointsForWidget(QWidget *widget, QTouchEvent *touchEvent) +{ + for (int i = 0; i < touchEvent->_touchPoints.count(); ++i) { + QTouchEvent::TouchPoint *touchPoint = touchEvent->_touchPoints.at(i); + + // preserve the sub-pixel resolution + const QPointF delta = touchPoint->d->globalPos - touchPoint->d->globalPos.toPoint(); + touchPoint->d->pos = widget->mapFromGlobal(touchPoint->d->globalPos.toPoint()) + delta; + touchPoint->d->startPos = widget->mapFromGlobal(touchPoint->d->startGlobalPos.toPoint()) + delta; + touchPoint->d->lastPos = widget->mapFromGlobal(touchPoint->d->lastGlobalPos.toPoint()) + delta; + } +} + QT_END_NAMESPACE #include "moc_qapplication.cpp" diff --git a/src/gui/kernel/qapplication_p.h b/src/gui/kernel/qapplication_p.h index 7487f0a..ce7110d 100644 --- a/src/gui/kernel/qapplication_p.h +++ b/src/gui/kernel/qapplication_p.h @@ -55,6 +55,7 @@ // #include "QtGui/qapplication.h" +#include "QtGui/qevent.h" #include "QtGui/qfont.h" #include "QtGui/qcursor.h" #include "QtGui/qregion.h" @@ -77,10 +78,7 @@ class QClipboard; class QGraphicsScene; class QGraphicsSystem; class QInputContext; -class QKeyEvent; -class QMouseEvent; class QObject; -class QWheelEvent; class QWidget; extern bool qt_is_gui_used; @@ -189,6 +187,12 @@ extern "C" { } #endif +#if defined(Q_WS_WIN) +typedef BOOL (WINAPI *qt_RegisterTouchWindowPtr)(HWND, ULONG); +typedef BOOL (WINAPI *qt_GetTouchInputInfoPtr)(HANDLE, UINT, PVOID, int); +typedef BOOL (WINAPI *qt_CloseTouchInputHandlePtr)(HANDLE); +#endif + class QScopedLoopLevelCounter { QThreadData *threadData; @@ -424,12 +428,34 @@ public: void sendSyntheticEnterLeave(QWidget *widget); #endif + QPointer<QWidget> currentMultitouchWidget; + static void updateTouchPointsForWidget(QWidget *widget, QTouchEvent *touchEvent); + +#if defined(Q_WS_WIN) + static qt_RegisterTouchWindowPtr RegisterTouchWindow; + static qt_GetTouchInputInfoPtr GetTouchInputInfo; + static qt_CloseTouchInputHandlePtr CloseTouchInputHandle; + + QMap<DWORD, int> touchInputIDToTouchPointID; + QVector<QTouchEvent::TouchPoint *> allTouchPoints; + QList<QTouchEvent::TouchPoint *> currentTouchPoints, activeTouchPoints; + + void initializeMultitouch(); + void insertActiveTouch(QTouchEvent::TouchPoint *touchPoint); + void removeActiveTouch(QTouchEvent::TouchPoint *touchPoint); + bool translateTouchEvent(const MSG &msg); +#endif + private: #ifdef Q_WS_QWS QMap<const QScreen*, QRect> maxWindowRects; #endif static QApplicationPrivate *self; + + static void giveFocusAccordingToFocusPolicy(QWidget *w, + Qt::FocusPolicy focusPolicy, + Qt::FocusReason focusReason); static bool shouldSetFocus(QWidget *w, Qt::FocusPolicy policy); }; diff --git a/src/gui/kernel/qapplication_win.cpp b/src/gui/kernel/qapplication_win.cpp index 2f2fc2c..4878ea7 100644 --- a/src/gui/kernel/qapplication_win.cpp +++ b/src/gui/kernel/qapplication_win.cpp @@ -88,6 +88,7 @@ extern void qt_wince_hide_taskbar(HWND hwnd); //defined in qguifunctions_wince.c #include "qdebug.h" #include <private/qkeymapper_p.h> #include <private/qlocale_p.h> +#include "qevent_p.h" //#define ALIEN_DEBUG @@ -112,6 +113,39 @@ extern void qt_wince_hide_taskbar(HWND hwnd); //defined in qguifunctions_wince.c # include <winable.h> #endif +#ifndef WM_TOUCHMOVE + +# define WM_TOUCHMOVE 0x0240 +# define WM_TOUCHDOWN 0x0241 +# define WM_TOUCHUP 0x0242 + +# define TOUCHEVENTF_MOVE 0x0001 +# define TOUCHEVENTF_DOWN 0x0002 +# define TOUCHEVENTF_UP 0x0004 +# define TOUCHEVENTF_INRANGE 0x0008 +# define TOUCHEVENTF_PRIMARY 0x0010 +# define TOUCHEVENTF_NOCOALESCE 0x0020 +# define TOUCHEVENTF_PEN 0x0040 + +# define TOUCHINPUTMASKF_TIMEFROMSYSTEM 0x0001 +# define TOUCHINPUTMASKF_EXTRAINFO 0x0002 +# define TOUCHINPUTMASKF_CONTACTAREA 0x0004 + +typedef struct tagTOUCHINPUT +{ + LONG x; + LONG y; + HANDLE hSource; + DWORD dwID; + DWORD dwFlags; + DWORD dwMask; + DWORD dwTime; + ULONG_PTR dwExtraInfo; + DWORD cxContact; + DWORD cyContact; +} TOUCHINPUT, *PTOUCHINPUT; + +#endif #ifndef FLASHW_STOP typedef struct { @@ -856,6 +890,8 @@ void qt_init(QApplicationPrivate *priv, int) if (ptrUpdateLayeredWindow && !ptrUpdateLayeredWindowIndirect) ptrUpdateLayeredWindowIndirect = qt_updateLayeredWindowIndirect; #endif + + priv->initializeMultitouch(); } /***************************************************************************** @@ -1726,6 +1762,11 @@ LRESULT CALLBACK QtWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam result = widget->translateWheelEvent(msg); } else { switch (message) { + case WM_TOUCHMOVE: + case WM_TOUCHDOWN: + case WM_TOUCHUP: + result = getQApplicationPrivateInternal()->translateTouchEvent(msg); + break; case WM_KEYDOWN: // keyboard event case WM_SYSKEYDOWN: qt_keymapper_private()->updateKeyMap(msg); @@ -3950,4 +3991,151 @@ void QSessionManager::cancel() #endif //QT_NO_SESSIONMANAGER +qt_RegisterTouchWindowPtr QApplicationPrivate::RegisterTouchWindow = 0; +qt_GetTouchInputInfoPtr QApplicationPrivate::GetTouchInputInfo = 0; +qt_CloseTouchInputHandlePtr QApplicationPrivate::CloseTouchInputHandle = 0; + +void QApplicationPrivate::initializeMultitouch() +{ + QLibrary library(QLatin1String("user32")); + RegisterTouchWindow = static_cast<qt_RegisterTouchWindowPtr>(library.resolve("RegisterTouchWindow")); + GetTouchInputInfo = static_cast<qt_GetTouchInputInfoPtr>(library.resolve("GetTouchInputInfo")); + CloseTouchInputHandle = static_cast<qt_CloseTouchInputHandlePtr>(library.resolve("CloseTouchInputHandle")); + + currentMultitouchWidget = 0; + touchInputIDToTouchPointID.clear(); + allTouchPoints.clear(); + currentTouchPoints.clear(); + activeTouchPoints.clear(); +} + +void QApplicationPrivate::insertActiveTouch(QTouchEvent::TouchPoint *touchPoint) +{ + // insort deviceNumber + int at = 0; + for (; at < currentTouchPoints.count(); ++at) { + if (currentTouchPoints.at(at)->id() > touchPoint->id()) + break; + } + currentTouchPoints.insert(at, touchPoint); + activeTouchPoints = currentTouchPoints; + + if (currentTouchPoints.count() > allTouchPoints.count()) { + qFatal("Qt: INTERNAL ERROR: currentTouchPoints.count() (%d) > allTouchPoints.count() (%d)", + currentTouchPoints.count(), + allTouchPoints.count()); + } +} + +void QApplicationPrivate::removeActiveTouch(QTouchEvent::TouchPoint *touchPoint) +{ + for (int i = qMin(currentTouchPoints.count() - 1, touchPoint->id()); i >= 0; --i) { + if (currentTouchPoints.at(i) == touchPoint) { + currentTouchPoints.removeAt(i); + break; + } + } + + // leave activeTouchPoints unchanged, since we need to make sure + // that the Release for deviceNumber is sent +} + +bool QApplicationPrivate::translateTouchEvent(const MSG &msg) +{ + Q_Q(QApplication); + + bool sendTouchBegin = currentTouchPoints.isEmpty(); + activeTouchPoints = currentTouchPoints; + + QVector<TOUCHINPUT> winTouchInputs(msg.wParam); + memset(winTouchInputs.data(), 0, sizeof(TOUCHINPUT) * winTouchInputs.count()); + QApplicationPrivate::GetTouchInputInfo((HANDLE) msg.lParam, msg.wParam, winTouchInputs.data(), sizeof(TOUCHINPUT)); + for (int i = 0; i < winTouchInputs.count(); ++i) { + const TOUCHINPUT &touchInput = winTouchInputs.at(i); + + int touchPointID = touchInputIDToTouchPointID.value(touchInput.dwID, -1); + if (touchPointID == -1) { + touchPointID = touchInputIDToTouchPointID.count(); + touchInputIDToTouchPointID.insert(touchInput.dwID, touchPointID); + } + + if (allTouchPoints.count() <= touchPointID) + allTouchPoints.resize(touchPointID + 1); + + QTouchEvent::TouchPoint *touchPoint = allTouchPoints.at(touchPointID); + if (!touchPoint) + touchPoint = allTouchPoints[touchPointID] = new QTouchEvent::TouchPoint(touchPointID); + + // update state + bool down = touchPoint->d->state != Qt::TouchPointReleased; + QPointF globalPos(qreal(touchInput.x) / qreal(100.), qreal(touchInput.y) / qreal(100.)); + if (!down && (touchInput.dwFlags & TOUCHEVENTF_DOWN)) { + insertActiveTouch(touchPoint); + touchPoint->d->state = Qt::TouchPointPressed; + touchPoint->d->globalPos = touchPoint->d->startGlobalPos = touchPoint->d->lastGlobalPos = globalPos; + touchPoint->d->pressure = qreal(1.); + } else if (down && (touchInput.dwFlags & TOUCHEVENTF_UP)) { + removeActiveTouch(touchPoint); + touchPoint->d->state = Qt::TouchPointReleased; + touchPoint->d->lastGlobalPos = touchPoint->d->globalPos; + touchPoint->d->globalPos = globalPos; + touchPoint->d->pressure = qreal(0.); + } else if (down) { + touchPoint->d->state = globalPos == touchPoint->d->globalPos + ? Qt::TouchPointStationary + : Qt::TouchPointMoved; + touchPoint->d->lastGlobalPos = touchPoint->d->globalPos; + touchPoint->d->globalPos = globalPos; + // pressure should still be 1. + } + } + QApplicationPrivate::CloseTouchInputHandle((HANDLE) msg.lParam); + + bool sendTouchEnd = currentTouchPoints.isEmpty(); + + if (activeTouchPoints.isEmpty()) + return false; + + if (sendTouchBegin) { + // the window under the first touch point gets the touch event + int firstTouchId = activeTouchPoints.first()->id(); + const QPoint &globalPos = allTouchPoints.at(firstTouchId)->d->globalPos.toPoint(); + QWidget *window = q->topLevelAt(globalPos); + if (window) { + QWidget *child = window->childAt(window->mapFromGlobal(globalPos)); + if (!child) + child = window; + currentMultitouchWidget = child; + } + } + + QWidget *widget = q->activePopupWidget(); + if (!widget) + widget = currentMultitouchWidget; + + if (sendTouchEnd) { + // reset currentMultitouchWindow when the last touch is released + currentMultitouchWidget = 0; + if (!currentTouchPoints.isEmpty()) { + qFatal("Qt: INTERNAL ERROR, currentTouchPoints should be empty!"); + } + } + + // deliver the event + if (widget && QApplicationPrivate::tryModalHelper(widget, 0)) { + QTouchEvent touchEvent((sendTouchBegin + ? QEvent::TouchBegin + : sendTouchEnd + ? QEvent::TouchEnd + : QEvent::TouchUpdate), + q->keyboardModifiers(), activeTouchPoints); + updateTouchPointsForWidget(widget, &touchEvent); + + bool res = QApplication::sendSpontaneousEvent(widget, &touchEvent); + return (qt_tabletChokeMouse = res && touchEvent.isAccepted()); + } + + return false; +} + QT_END_NAMESPACE diff --git a/src/gui/kernel/qevent.cpp b/src/gui/kernel/qevent.cpp index 8c7e47d..d571212 100644 --- a/src/gui/kernel/qevent.cpp +++ b/src/gui/kernel/qevent.cpp @@ -3506,4 +3506,168 @@ QMenubarUpdatedEvent::QMenubarUpdatedEvent(QMenuBar * const menuBar) #endif +/*! \class QTouchEvent + \brief The QTouchEvent class contains parameters that describe a touch event +. + \since 4.6 + \ingroup events + + Touch events occur when pressing, releasing, or moving one or more + touch points on a touch device (such as a touch-screen or + track-pad), and if the widget has the Qt::WA_AcceptTouchEvents + attribute. + + Like QMouseEvent, Qt automatically grabs the touch device on the + first press inside a widget; the widget will receive all touch + events until the last touch point is released. + + A touch event contains a special accept flag that indicates + whether the receiver wants the event. By default, the event is + ignored. You should call accept() if the touch event is handled by + your widget. A touch event is propagated up the parent widget + chain until a widget accepts it with accept(), or an event filter + consumes it. If the touch event is neither accepted nor consumed, + then mouse events are simulated from the state of the first touch + point. + + All touch events are of type QEvent::Touch. The touchPoints() + function returns a list of all touch points contained in the + event. Information about each touch point can be retreived using + the QTouchEvent::TouchPoint class. + + The Qt::TouchPointState enum describes the different states that a + touch point may have. + + QTouchEvent::TouchPoint Qt::TouchPointState Qt::WA_AcceptTouchEvents +*/ + +/*! \enum Qt::TouchPointState + \since 4.6 + + This enum represents the state of a touch point at the time the + QTouchEvent occurred. + + \value TouchPointPressed The touch point is now pressed. + \value TouchPointMoved The touch point moved. + \value TouchPointStationary The touch point did not move. + \value TouchPointReleased The touch point was released. +*/ + +/*! \class QTouchEvent::TouchPoint + \brief The QTouchEvent::TouchPoint class provide information about a touch point in a QTouchEvent. + \since 4.6 +*/ + +/*! + Constructs a QTouchEvent with the given \a type and \a + touchPoints. The \a modifiers are the current keyboard modifiers + at the time of the event. +*/ +QTouchEvent::QTouchEvent(QEvent::Type type, + Qt::KeyboardModifiers modifiers, + const QList<TouchPoint *> &touchPoints) + : QInputEvent(type, modifiers), _touchPoints(touchPoints) +{ } + +/*! \fn const QList<QTouchEvent::TouchPoint *> &QTouchEvent::touchPoints() const + + Returns the list of touch points contained in the touch event. +*/ + +/*! \internal + + Constructs a QTouchEvent::TouchPoint for use in a QTouchEvent. +*/ +QTouchEvent::TouchPoint::TouchPoint(int id) + : d(new QTouchEventTouchPointPrivate(id)) +{ } + +/*! \internal + + Destroys the QTouchEvent::TouchPoint. +*/ +QTouchEvent::TouchPoint::~TouchPoint() +{ + delete d; +} + +/*! + Returns the id number of this touch point. Id numbers are + sequential, starting at zero, meaning the first touch point has id + 0, the second has id 1, and so on... +*/ +int QTouchEvent::TouchPoint::id() const +{ + return d->id; +} + +/*! + Returns the current state of this touch point. +*/ +Qt::TouchPointState QTouchEvent::TouchPoint::state() const +{ + return d->state; +} + +/*! + Returns the position of this touch point, relative to the widget + that received the event. +*/ +const QPointF &QTouchEvent::TouchPoint::pos() const +{ + return d->pos; +} + +/*! + Returns the starting position of this touch point, relative to the + widget that received the event. +*/ +const QPointF &QTouchEvent::TouchPoint::startPos() const +{ + return d->startPos; +} + +/*! + Returns the position of this touch point from the previous touch + event, relative to the widget that received the event. +*/ +const QPointF &QTouchEvent::TouchPoint::lastPos() const +{ + return d->lastPos; +} + +/*! + Returns the global position of this touch point. +*/ +const QPointF &QTouchEvent::TouchPoint::globalPos() const +{ + return d->globalPos; +} + +/*! + Returns the global starting position of this touch point. +*/ +const QPointF &QTouchEvent::TouchPoint::startGlobalPos() const +{ + return d->startGlobalPos; +} + +/*! + Returns the global position of this touch point from the previous + touch event. +*/ +const QPointF &QTouchEvent::TouchPoint::lastGlobalPos() const +{ + return d->lastGlobalPos; +} + +/*! + Returns the pressure of this touch point. The return value is in + the range 0.0 to 1.0. +*/ +qreal QTouchEvent::TouchPoint::pressure() const +{ + return d->pressure; +} + QT_END_NAMESPACE diff --git a/src/gui/kernel/qevent.h b/src/gui/kernel/qevent.h index 449730d..506e0c1 100644 --- a/src/gui/kernel/qevent.h +++ b/src/gui/kernel/qevent.h @@ -719,6 +719,49 @@ inline bool operator==(QKeyEvent *e, QKeySequence::StandardKey key){return (e ? inline bool operator==(QKeySequence::StandardKey key, QKeyEvent *e){return (e ? e->matches(key) : false);} #endif // QT_NO_SHORTCUT +class QTouchEventTouchPointPrivate; +class Q_GUI_EXPORT QTouchEvent : public QInputEvent +{ +public: + class Q_GUI_EXPORT TouchPoint + { + public: + TouchPoint(int id = -1); + ~TouchPoint(); + + int id() const; + + Qt::TouchPointState state() const; + + const QPointF &pos() const; + const QPointF &startPos() const; + const QPointF &lastPos() const; + + const QPointF &globalPos() const; + const QPointF &startGlobalPos() const; + const QPointF &lastGlobalPos() const; + + qreal pressure() const; // 0.0 -> 1.0 + + private: + QTouchEventTouchPointPrivate *d; + + friend class QApplicationPrivate; + }; + + QTouchEvent(QEvent::Type type, + Qt::KeyboardModifiers modifiers, + const QList<TouchPoint *> &touchPoints); + + inline const QList<TouchPoint *> &touchPoints() const { return _touchPoints; + } + +protected: + QList<TouchPoint *> _touchPoints; + + friend class QApplicationPrivate; +}; + QT_END_NAMESPACE QT_END_HEADER diff --git a/src/gui/kernel/qevent_p.h b/src/gui/kernel/qevent_p.h index cc94aad..5e24eeb 100644 --- a/src/gui/kernel/qevent_p.h +++ b/src/gui/kernel/qevent_p.h @@ -89,6 +89,22 @@ protected: friend class QMouseEvent; }; +class QTouchEventTouchPointPrivate +{ +public: + inline QTouchEventTouchPointPrivate(int id) + : id(id), + state(Qt::TouchPointReleased), + pressure(qreal(-1.)) + { } + + int id; + Qt::TouchPointState state; + QPointF pos, startPos, lastPos; + QPointF globalPos, startGlobalPos, lastGlobalPos; + qreal pressure; +}; + QT_END_NAMESPACE #endif // QEVENT_P_H diff --git a/src/gui/kernel/qwidget_win.cpp b/src/gui/kernel/qwidget_win.cpp index ffbb341..b55f1c8 100644 --- a/src/gui/kernel/qwidget_win.cpp +++ b/src/gui/kernel/qwidget_win.cpp @@ -503,6 +503,10 @@ void QWidgetPrivate::create_sys(WId window, bool initializeWindow, bool destroyO } } + // ### don't always register for touch events + if (QApplicationPrivate::RegisterTouchWindow && !desktop) + QApplicationPrivate::RegisterTouchWindow(id, 0); + q->setAttribute(Qt::WA_WState_Created); // accept move/resize events hd = 0; // no display context |