/tools/designer/

ent.cpp +++ b/src/corelib/kernel/qcoreevent.cpp @@ -222,6 +222,12 @@ QT_BEGIN_NAMESPACE \value ZOrderChange The widget's z-order has changed. This event is never sent to top level windows. \value KeyboardLayoutChange The keyboard layout has changed. \value DynamicPropertyChange A dynamic property was added, changed or removed from the object. + \value TouchBegin Beginning of a sequence of touch-screen and/or track-pad events (QTouchEvent) + \value TouchUpdate Touch-screen event (QTouchEvent) + \value TouchEnd End of touch-event sequence (QTouchEvent) + \value GraphicsSceneTouchBegin Beginning of a sequence of touch-screen and/or track-pad events in a graphics scene (QGraphicsSceneTouchEvent) + \value GraphicsSceneTouchUpdate Touch-screen event in a graphics scene (QGraphicsSceneTouchEvent) + \value GraphicsSceneTouchEnd End of touch-event sequence in a graphics scene (QGraphicsSceneTouchEvent) User events should have values between \c User and \c{MaxUser}: diff --git a/src/corelib/kernel/qcoreevent.h b/src/corelib/kernel/qcoreevent.h index 5487703..639f488 100644 --- a/src/corelib/kernel/qcoreevent.h +++ b/src/corelib/kernel/qcoreevent.h @@ -265,6 +265,13 @@ public: UngrabKeyboard = 189, CocoaRequestModal = 190, // Internal for requesting an application modal Cocoa Window + TouchBegin = 193, + TouchUpdate = 194, + TouchEnd = 195, + GraphicsSceneTouchBegin = 196, + GraphicsSceneTouchUpdate = 197, + GraphicsSceneTouchEnd = 198, + // 512 reserved for Qt Jambi's MetaCall event // 513 reserved for Qt Jambi's DeleteOnMainThread event -- cgit v0.12 From 07696ec4844e6eb9b9aec58a381d9c0f9403e7c2 Mon Sep 17 00:00:00 2001 From: "Bradley T. Hughes" Date: Tue, 24 Mar 2009 11:04:45 +0100 Subject: add the Qt::WA_AcceptTouchEvents attribute this attribute must be set for a widget to get touch events (otherwise the widget will only get mouse events). --- doc/src/qnamespace.qdoc | 5 +++++ src/corelib/global/qnamespace.h | 2 ++ 2 files changed, 7 insertions(+) diff --git a/doc/src/qnamespace.qdoc b/doc/src/qnamespace.qdoc index 6220795..07972af 100644 --- a/doc/src/qnamespace.qdoc +++ b/doc/src/qnamespace.qdoc @@ -1192,6 +1192,11 @@ on Mac when using Carbon. This attribute has no effect on Cocoa. The attribute is off by default and can be enabled on a per-window basis. + \value WA_AcceptTouchEvents Allows touch events (see QTouchEvent) + to be sent to the widget. Must be set on all widgets that can + handle touch events. Without this attribute set, events from a + touch device will be sent as mouse events. + \omitvalue WA_SetLayoutDirection \omitvalue WA_InputMethodTransparent \omitvalue WA_WState_CompressKeys diff --git a/src/corelib/global/qnamespace.h b/src/corelib/global/qnamespace.h index fb7fa0c..193c5dc 100644 --- a/src/corelib/global/qnamespace.h +++ b/src/corelib/global/qnamespace.h @@ -485,6 +485,8 @@ public: WA_WState_WindowOpacitySet = 119, // internal WA_TranslucentBackground = 120, + WA_AcceptTouchEvents = 121, + // Add new attributes before this line WA_AttributeCount }; -- cgit v0.12 From cbac8c9c6c8bdb2868434563a20cdc16d9cc6402 Mon Sep 17 00:00:00 2001 From: "Bradley T. Hughes" Date: Tue, 24 Mar 2009 11:19:06 +0100 Subject: add QTouchEvent and QGraphicsSceneTouchEvent these events contain a list of all touch points. note that the coordinates for QTouchEvent are floating point, since many devices offer sub-pixel resolution. --- src/corelib/global/qnamespace.h | 7 + src/gui/graphicsview/qgraphicssceneevent.cpp | 338 ++++++++++++++++++++++++++- src/gui/graphicsview/qgraphicssceneevent.h | 64 +++++ src/gui/kernel/qevent.cpp | 164 +++++++++++++ src/gui/kernel/qevent.h | 41 ++++ src/gui/kernel/qevent_p.h | 16 ++ 6 files changed, 619 insertions(+), 11 deletions(-) diff --git a/src/corelib/global/qnamespace.h b/src/corelib/global/qnamespace.h index 193c5dc..361a2c5 100644 --- a/src/corelib/global/qnamespace.h +++ b/src/corelib/global/qnamespace.h @@ -1535,6 +1535,13 @@ public: BottomLeftSection, TitleBarArea // For move }; + + enum TouchPointState { + TouchPointPressed, + TouchPointMoved, + TouchPointStationary, + TouchPointReleased + }; } #ifdef Q_MOC_RUN ; 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 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::touchPoints() const +{ + Q_D(const QGraphicsSceneTouchEvent); + return d->touchPoints; +} + +/*! \internal */ +void QGraphicsSceneTouchEvent::setTouchPoints(const QList &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 &touchPoints() const; + void setTouchPoints(const QList &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/kernel/qevent.cpp b/src/gui/kernel/qevent.cpp index 3f1df5e..ff69c24 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 &touchPoints) + : QInputEvent(type, modifiers), _touchPoints(touchPoints) +{ } + +/*! \fn const QList &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..3cb712d 100644 --- a/src/gui/kernel/qevent.h +++ b/src/gui/kernel/qevent.h @@ -719,6 +719,47 @@ 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 &touchPoints); + + inline const QList &touchPoints() const { return _touchPoints; + } + +protected: + QList _touchPoints; +}; + 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 -- cgit v0.12 From 075a8a30560e20fee94d47aa447daa15f4cb138f Mon Sep 17 00:00:00 2001 From: "Bradley T. Hughes" Date: Tue, 24 Mar 2009 12:01:44 +0100 Subject: add QGraphicsItem::acceptTouchEvents() and setAcceptTouchEvents() like Qt::WA_AcceptTouchEvents, QGraphicsItems don't receive touch events unless touch events are explicitly enabled. --- src/gui/graphicsview/qgraphicsitem.cpp | 25 +++++++++++++++++++++++++ src/gui/graphicsview/qgraphicsitem.h | 2 ++ src/gui/graphicsview/qgraphicsitem_p.h | 2 ++ 3 files changed, 29 insertions(+) diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index fc81f39..0b51c8c 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -2063,6 +2063,31 @@ void QGraphicsItem::setAcceptsHoverEvents(bool enabled) d_ptr->acceptsHover = quint32(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 af0b077..228368c 100644 --- a/src/gui/graphicsview/qgraphicsitem_p.h +++ b/src/gui/graphicsview/qgraphicsitem_p.h @@ -138,6 +138,7 @@ public: dirty(0), dirtyChildren(0), localCollisionHack(0), + acceptTouchEvents(0), globalStackingOrder(-1), sceneTransformIndex(-1), q_ptr(0) @@ -272,6 +273,7 @@ public: quint32 dirty : 1; quint32 dirtyChildren : 1; quint32 localCollisionHack : 1; + quint32 acceptTouchEvents : 1; // Optional stacking order int globalStackingOrder; -- cgit v0.12 From b9b9fc18d8ea5e9ddc2508ac6e9ce24960a8c24a Mon Sep 17 00:00:00 2001 From: "Bradley T. Hughes" Date: Tue, 24 Mar 2009 12:03:21 +0100 Subject: implement support for touch events in QGraphicsScene QGraphicsView will convert QTouchEvents to QGraphicsSceneTouchEvents and send them to the scene. The scene will then send the touch events to the appropriate item. Like mouse event support, the item that accepts the touch begin is the item that will get all subsequent touch events. if no item accepts the touch begin event, then no touch events are sent to any item (and mouse events are sent instead). --- src/gui/graphicsview/qgraphicsscene.cpp | 166 ++++++++++++++++++++++++++++++++ src/gui/graphicsview/qgraphicsscene_p.h | 6 ++ src/gui/graphicsview/qgraphicsview.cpp | 106 ++++++++++++++++++++ src/gui/graphicsview/qgraphicsview_p.h | 5 + 4 files changed, 283 insertions(+) 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(event)); + break; + case QEvent::GraphicsSceneTouchUpdate: + d->touchUpdateEvent(static_cast(event)); + break; + case QEvent::GraphicsSceneTouchEnd: + d->touchEndEvent(static_cast(event)); + break; case QEvent::Timer: if (d->indexTimerId && static_cast(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 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(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 sceneTransformCache; mutable QBitArray validTransforms; mutable QVector 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(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 originalTouchPoints = originalEvent->touchPoints(); + QList 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 -- cgit v0.12 From 96741cb1aba9feaf0099910884bee5241e52f794 Mon Sep 17 00:00:00 2001 From: "Bradley T. Hughes" Date: Tue, 24 Mar 2009 14:59:07 +0100 Subject: add a multitouch pinchzoom example, based on the collidingmice example --- examples/multitouch/multitouch.pro | 2 + examples/multitouch/pinchzoom/graphicsview.cpp | 78 +++++++++ examples/multitouch/pinchzoom/graphicsview.h | 53 +++++++ examples/multitouch/pinchzoom/images/cheese.jpg | Bin 0 -> 3029 bytes examples/multitouch/pinchzoom/main.cpp | 88 +++++++++++ examples/multitouch/pinchzoom/mice.qrc | 5 + examples/multitouch/pinchzoom/mouse.cpp | 200 ++++++++++++++++++++++++ examples/multitouch/pinchzoom/mouse.h | 72 +++++++++ examples/multitouch/pinchzoom/pinchzoom.pro | 16 ++ 9 files changed, 514 insertions(+) create mode 100644 examples/multitouch/multitouch.pro create mode 100644 examples/multitouch/pinchzoom/graphicsview.cpp create mode 100644 examples/multitouch/pinchzoom/graphicsview.h create mode 100644 examples/multitouch/pinchzoom/images/cheese.jpg create mode 100644 examples/multitouch/pinchzoom/main.cpp create mode 100644 examples/multitouch/pinchzoom/mice.qrc create mode 100644 examples/multitouch/pinchzoom/mouse.cpp create mode 100644 examples/multitouch/pinchzoom/mouse.h create mode 100644 examples/multitouch/pinchzoom/pinchzoom.pro diff --git a/examples/multitouch/multitouch.pro b/examples/multitouch/multitouch.pro new file mode 100644 index 0000000..7efa412 --- /dev/null +++ b/examples/multitouch/multitouch.pro @@ -0,0 +1,2 @@ +TEMPLATE = subdirs +SUBDIRS = pinchzoom \ No newline at end of file diff --git a/examples/multitouch/pinchzoom/graphicsview.cpp b/examples/multitouch/pinchzoom/graphicsview.cpp new file mode 100644 index 0000000..b77c926 --- /dev/null +++ b/examples/multitouch/pinchzoom/graphicsview.cpp @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial Usage +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "graphicsview.h" + +#include + + +GraphicsView::GraphicsView(QGraphicsScene *scene, QWidget *parent) + : QGraphicsView(scene, parent) +{ + setAttribute(Qt::WA_AcceptTouchEvents); +} + +bool GraphicsView::event(QEvent *event) +{ + switch (event->type()) { + case QEvent::TouchBegin: + case QEvent::TouchUpdate: + case QEvent::TouchEnd: + { + qDebug("touch events"); + + QList touchPoints = static_cast(event)->touchPoints(); + if (touchPoints.count() == 2) { + // determine scale factor + const QTouchEvent::TouchPoint *touchPoint0 = touchPoints.first(); + const QTouchEvent::TouchPoint *touchPoint1 = touchPoints.last(); + const qreal scaleFactor = QLineF(touchPoint0->pos(), touchPoint1->pos()).length() + / QLineF(touchPoint0->startPos(), touchPoint1->startPos()).length(); + setTransform(QTransform().scale(scaleFactor, scaleFactor)); + } + event->accept(); + return true; + } + default: + break; + } + return QGraphicsView::event(event); +} diff --git a/examples/multitouch/pinchzoom/graphicsview.h b/examples/multitouch/pinchzoom/graphicsview.h new file mode 100644 index 0000000..626f23c --- /dev/null +++ b/examples/multitouch/pinchzoom/graphicsview.h @@ -0,0 +1,53 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial Usage +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#pragma once +#include + +class GraphicsView : public QGraphicsView +{ + Q_OBJECT + +public: + GraphicsView(QGraphicsScene *scene = 0, QWidget *parent = 0); + + bool event(QEvent *event); +}; diff --git a/examples/multitouch/pinchzoom/images/cheese.jpg b/examples/multitouch/pinchzoom/images/cheese.jpg new file mode 100644 index 0000000..dea5795 Binary files /dev/null and b/examples/multitouch/pinchzoom/images/cheese.jpg differ diff --git a/examples/multitouch/pinchzoom/main.cpp b/examples/multitouch/pinchzoom/main.cpp new file mode 100644 index 0000000..6b25060 --- /dev/null +++ b/examples/multitouch/pinchzoom/main.cpp @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial Usage +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "graphicsview.h" +#include "mouse.h" + +#include + +#include + +static const int MouseCount = 7; + +//! [0] +int main(int argc, char **argv) +{ + QApplication app(argc, argv); + qsrand(QTime(0,0,0).secsTo(QTime::currentTime())); +//! [0] + +//! [1] + QGraphicsScene scene; + scene.setSceneRect(-300, -300, 600, 600); +//! [1] //! [2] + scene.setItemIndexMethod(QGraphicsScene::NoIndex); +//! [2] + +//! [3] + for (int i = 0; i < MouseCount; ++i) { + Mouse *mouse = new Mouse; + mouse->setPos(::sin((i * 6.28) / MouseCount) * 200, + ::cos((i * 6.28) / MouseCount) * 200); + scene.addItem(mouse); + } +//! [3] + +//! [4] + GraphicsView view(&scene); + view.setRenderHint(QPainter::Antialiasing); + view.setBackgroundBrush(QPixmap(":/images/cheese.jpg")); +//! [4] //! [5] + view.setCacheMode(QGraphicsView::CacheBackground); + view.setViewportUpdateMode(QGraphicsView::BoundingRectViewportUpdate); + view.setDragMode(QGraphicsView::ScrollHandDrag); +//! [5] //! [6] + view.setWindowTitle(QT_TRANSLATE_NOOP(QGraphicsView, "Colliding Mice")); + view.showMaximized(); + + return app.exec(); +} +//! [6] diff --git a/examples/multitouch/pinchzoom/mice.qrc b/examples/multitouch/pinchzoom/mice.qrc new file mode 100644 index 0000000..accdb4d --- /dev/null +++ b/examples/multitouch/pinchzoom/mice.qrc @@ -0,0 +1,5 @@ + + + images/cheese.jpg + + diff --git a/examples/multitouch/pinchzoom/mouse.cpp b/examples/multitouch/pinchzoom/mouse.cpp new file mode 100644 index 0000000..1d9fa89 --- /dev/null +++ b/examples/multitouch/pinchzoom/mouse.cpp @@ -0,0 +1,200 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial Usage +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "mouse.h" + +#include +#include +#include + +#include + +static const double Pi = 3.14159265358979323846264338327950288419717; +static double TwoPi = 2.0 * Pi; + +static qreal normalizeAngle(qreal angle) +{ + while (angle < 0) + angle += TwoPi; + while (angle > TwoPi) + angle -= TwoPi; + return angle; +} + +//! [0] +Mouse::Mouse() + : angle(0), speed(0), mouseEyeDirection(0), + color(qrand() % 256, qrand() % 256, qrand() % 256) +{ + rotate(qrand() % (360 * 16)); + startTimer(1000 / 33); +} +//! [0] + +//! [1] +QRectF Mouse::boundingRect() const +{ + qreal adjust = 0.5; + return QRectF(-18 - adjust, -22 - adjust, + 36 + adjust, 60 + adjust); +} +//! [1] + +//! [2] +QPainterPath Mouse::shape() const +{ + QPainterPath path; + path.addRect(-10, -20, 20, 40); + return path; +} +//! [2] + +//! [3] +void Mouse::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *) +{ + // Body + painter->setBrush(color); + painter->drawEllipse(-10, -20, 20, 40); + + // Eyes + painter->setBrush(Qt::white); + painter->drawEllipse(-10, -17, 8, 8); + painter->drawEllipse(2, -17, 8, 8); + + // Nose + painter->setBrush(Qt::black); + painter->drawEllipse(QRectF(-2, -22, 4, 4)); + + // Pupils + painter->drawEllipse(QRectF(-8.0 + mouseEyeDirection, -17, 4, 4)); + painter->drawEllipse(QRectF(4.0 + mouseEyeDirection, -17, 4, 4)); + + // Ears + painter->setBrush(scene()->collidingItems(this).isEmpty() ? Qt::darkYellow : Qt::red); + painter->drawEllipse(-17, -12, 16, 16); + painter->drawEllipse(1, -12, 16, 16); + + // Tail + QPainterPath path(QPointF(0, 20)); + path.cubicTo(-5, 22, -5, 22, 0, 25); + path.cubicTo(5, 27, 5, 32, 0, 30); + path.cubicTo(-5, 32, -5, 42, 0, 35); + painter->setBrush(Qt::NoBrush); + painter->drawPath(path); +} +//! [3] + +//! [4] +void Mouse::timerEvent(QTimerEvent *) +{ +//! [4] + // Don't move too far away +//! [5] + QLineF lineToCenter(QPointF(0, 0), mapFromScene(0, 0)); + if (lineToCenter.length() > 150) { + qreal angleToCenter = ::acos(lineToCenter.dx() / lineToCenter.length()); + if (lineToCenter.dy() < 0) + angleToCenter = TwoPi - angleToCenter; + angleToCenter = normalizeAngle((Pi - angleToCenter) + Pi / 2); + + if (angleToCenter < Pi && angleToCenter > Pi / 4) { + // Rotate left + angle += (angle < -Pi / 2) ? 0.25 : -0.25; + } else if (angleToCenter >= Pi && angleToCenter < (Pi + Pi / 2 + Pi / 4)) { + // Rotate right + angle += (angle < Pi / 2) ? 0.25 : -0.25; + } + } else if (::sin(angle) < 0) { + angle += 0.25; + } else if (::sin(angle) > 0) { + angle -= 0.25; +//! [5] //! [6] + } +//! [6] + + // Try not to crash with any other mice +//! [7] + QList dangerMice = scene()->items(QPolygonF() + << mapToScene(0, 0) + << mapToScene(-30, -50) + << mapToScene(30, -50)); + foreach (QGraphicsItem *item, dangerMice) { + if (item == this) + continue; + + QLineF lineToMouse(QPointF(0, 0), mapFromItem(item, 0, 0)); + qreal angleToMouse = ::acos(lineToMouse.dx() / lineToMouse.length()); + if (lineToMouse.dy() < 0) + angleToMouse = TwoPi - angleToMouse; + angleToMouse = normalizeAngle((Pi - angleToMouse) + Pi / 2); + + if (angleToMouse >= 0 && angleToMouse < Pi / 2) { + // Rotate right + angle += 0.5; + } else if (angleToMouse <= TwoPi && angleToMouse > (TwoPi - Pi / 2)) { + // Rotate left + angle -= 0.5; +//! [7] //! [8] + } +//! [8] //! [9] + } +//! [9] + + // Add some random movement +//! [10] + if (dangerMice.size() > 1 && (qrand() % 10) == 0) { + if (qrand() % 1) + angle += (qrand() % 100) / 500.0; + else + angle -= (qrand() % 100) / 500.0; + } +//! [10] + +//! [11] + speed += (-50 + qrand() % 100) / 100.0; + + qreal dx = ::sin(angle) * 10; + mouseEyeDirection = (qAbs(dx / 5) < 1) ? 0 : dx / 5; + + rotate(dx); + setPos(mapToParent(0, -(3 + sin(speed) * 3))); +} +//! [11] diff --git a/examples/multitouch/pinchzoom/mouse.h b/examples/multitouch/pinchzoom/mouse.h new file mode 100644 index 0000000..7545fe6 --- /dev/null +++ b/examples/multitouch/pinchzoom/mouse.h @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial Usage +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef MOUSE_H +#define MOUSE_H + +#include +#include + +//! [0] +class Mouse : public QObject, public QGraphicsItem +{ + Q_OBJECT + +public: + Mouse(); + + QRectF boundingRect() const; + QPainterPath shape() const; + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, + QWidget *widget); + +protected: + void timerEvent(QTimerEvent *event); + +private: + qreal angle; + qreal speed; + qreal mouseEyeDirection; + QColor color; +}; +//! [0] + +#endif diff --git a/examples/multitouch/pinchzoom/pinchzoom.pro b/examples/multitouch/pinchzoom/pinchzoom.pro new file mode 100644 index 0000000..bd87cf7 --- /dev/null +++ b/examples/multitouch/pinchzoom/pinchzoom.pro @@ -0,0 +1,16 @@ +HEADERS += \ + mouse.h \ + graphicsview.h +SOURCES += \ + main.cpp \ + mouse.cpp \ + graphicsview.cpp + +RESOURCES += \ + mice.qrc + +# install +target.path = $$[QT_INSTALL_EXAMPLES]/multitouch/pinchzoom +sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS pinchzoom.pro images +sources.path = $$[QT_INSTALL_EXAMPLES]/multitouch/pinchzoom +INSTALLS += target sources -- cgit v0.12 From 98619f427322ac7889b3db6f8991ca079209cec7 Mon Sep 17 00:00:00 2001 From: "Bradley T. Hughes" Date: Wed, 25 Mar 2009 11:31:33 +0100 Subject: add the multitouch fingerpaint example, based on the scribble example --- examples/multitouch/fingerpaint/fingerpaint.pro | 11 ++ examples/multitouch/fingerpaint/main.cpp | 52 ++++++ examples/multitouch/fingerpaint/mainwindow.cpp | 218 +++++++++++++++++++++++ examples/multitouch/fingerpaint/mainwindow.h | 89 +++++++++ examples/multitouch/fingerpaint/scribblearea.cpp | 213 ++++++++++++++++++++++ examples/multitouch/fingerpaint/scribblearea.h | 81 +++++++++ 6 files changed, 664 insertions(+) create mode 100644 examples/multitouch/fingerpaint/fingerpaint.pro create mode 100644 examples/multitouch/fingerpaint/main.cpp create mode 100644 examples/multitouch/fingerpaint/mainwindow.cpp create mode 100644 examples/multitouch/fingerpaint/mainwindow.h create mode 100644 examples/multitouch/fingerpaint/scribblearea.cpp create mode 100644 examples/multitouch/fingerpaint/scribblearea.h diff --git a/examples/multitouch/fingerpaint/fingerpaint.pro b/examples/multitouch/fingerpaint/fingerpaint.pro new file mode 100644 index 0000000..1d45635 --- /dev/null +++ b/examples/multitouch/fingerpaint/fingerpaint.pro @@ -0,0 +1,11 @@ +HEADERS = mainwindow.h \ + scribblearea.h +SOURCES = main.cpp \ + mainwindow.cpp \ + scribblearea.cpp + +# install +target.path = $$[QT_INSTALL_EXAMPLES]/multitouch/fingerpaint +sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS fingerpaint.pro +sources.path = $$[QT_INSTALL_EXAMPLES]/multitouch/fingerpaint +INSTALLS += target sources diff --git a/examples/multitouch/fingerpaint/main.cpp b/examples/multitouch/fingerpaint/main.cpp new file mode 100644 index 0000000..49bf25b --- /dev/null +++ b/examples/multitouch/fingerpaint/main.cpp @@ -0,0 +1,52 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial Usage +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include "mainwindow.h" + +int main(int argc, char *argv[]) +{ + QApplication app(argc, argv); + MainWindow window; + window.showMaximized(); + return app.exec(); +} diff --git a/examples/multitouch/fingerpaint/mainwindow.cpp b/examples/multitouch/fingerpaint/mainwindow.cpp new file mode 100644 index 0000000..546c685 --- /dev/null +++ b/examples/multitouch/fingerpaint/mainwindow.cpp @@ -0,0 +1,218 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial Usage +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include "mainwindow.h" +#include "scribblearea.h" + +//! [0] +MainWindow::MainWindow() +{ + scribbleArea = new ScribbleArea; + setCentralWidget(scribbleArea); + + createActions(); + createMenus(); + + setWindowTitle(tr("Scribble")); + resize(500, 500); +} +//! [0] + +//! [1] +void MainWindow::closeEvent(QCloseEvent *event) +//! [1] //! [2] +{ + if (maybeSave()) { + event->accept(); + } else { + event->ignore(); + } +} +//! [2] + +//! [3] +void MainWindow::open() +//! [3] //! [4] +{ + if (maybeSave()) { + QString fileName = QFileDialog::getOpenFileName(this, + tr("Open File"), QDir::currentPath()); + if (!fileName.isEmpty()) + scribbleArea->openImage(fileName); + } +} +//! [4] + +//! [5] +void MainWindow::save() +//! [5] //! [6] +{ + QAction *action = qobject_cast(sender()); + QByteArray fileFormat = action->data().toByteArray(); + saveFile(fileFormat); +} +//! [6] + +//! [11] +void MainWindow::about() +//! [11] //! [12] +{ + QMessageBox::about(this, tr("About Scribble"), + tr("

The Scribble example shows how to use QMainWindow as the " + "base widget for an application, and how to reimplement some of " + "QWidget's event handlers to receive the events generated for " + "the application's widgets:

We reimplement the mouse event " + "handlers to facilitate drawing, the paint event handler to " + "update the application and the resize event handler to optimize " + "the application's appearance. In addition we reimplement the " + "close event handler to intercept the close events before " + "terminating the application.

The example also demonstrates " + "how to use QPainter to draw an image in real time, as well as " + "to repaint widgets.

")); +} +//! [12] + +//! [13] +void MainWindow::createActions() +//! [13] //! [14] +{ + openAct = new QAction(tr("&Open..."), this); + openAct->setShortcut(tr("Ctrl+O")); + connect(openAct, SIGNAL(triggered()), this, SLOT(open())); + + foreach (QByteArray format, QImageWriter::supportedImageFormats()) { + QString text = tr("%1...").arg(QString(format).toUpper()); + + QAction *action = new QAction(text, this); + action->setData(format); + connect(action, SIGNAL(triggered()), this, SLOT(save())); + saveAsActs.append(action); + } + + printAct = new QAction(tr("&Print..."), this); + connect(printAct, SIGNAL(triggered()), scribbleArea, SLOT(print())); + + exitAct = new QAction(tr("E&xit"), this); + exitAct->setShortcut(tr("Ctrl+Q")); + connect(exitAct, SIGNAL(triggered()), this, SLOT(close())); + + clearScreenAct = new QAction(tr("&Clear Screen"), this); + clearScreenAct->setShortcut(tr("Ctrl+L")); + connect(clearScreenAct, SIGNAL(triggered()), + scribbleArea, SLOT(clearImage())); + + aboutAct = new QAction(tr("&About"), this); + connect(aboutAct, SIGNAL(triggered()), this, SLOT(about())); + + aboutQtAct = new QAction(tr("About &Qt"), this); + connect(aboutQtAct, SIGNAL(triggered()), qApp, SLOT(aboutQt())); +} +//! [14] + +//! [15] +void MainWindow::createMenus() +//! [15] //! [16] +{ + saveAsMenu = new QMenu(tr("&Save As"), this); + foreach (QAction *action, saveAsActs) + saveAsMenu->addAction(action); + + fileMenu = new QMenu(tr("&File"), this); + fileMenu->addAction(openAct); + fileMenu->addMenu(saveAsMenu); + fileMenu->addAction(printAct); + fileMenu->addSeparator(); + fileMenu->addAction(exitAct); + + optionMenu = new QMenu(tr("&Options"), this); + optionMenu->addAction(clearScreenAct); + + helpMenu = new QMenu(tr("&Help"), this); + helpMenu->addAction(aboutAct); + helpMenu->addAction(aboutQtAct); + + menuBar()->addMenu(fileMenu); + menuBar()->addMenu(optionMenu); + menuBar()->addMenu(helpMenu); +} +//! [16] + +//! [17] +bool MainWindow::maybeSave() +//! [17] //! [18] +{ + if (scribbleArea->isModified()) { + QMessageBox::StandardButton ret; + ret = QMessageBox::warning(this, tr("Scribble"), + tr("The image has been modified.\n" + "Do you want to save your changes?"), + QMessageBox::Save | QMessageBox::Discard + | QMessageBox::Cancel); + if (ret == QMessageBox::Save) { + return saveFile("png"); + } else if (ret == QMessageBox::Cancel) { + return false; + } + } + return true; +} +//! [18] + +//! [19] +bool MainWindow::saveFile(const QByteArray &fileFormat) +//! [19] //! [20] +{ + QString initialPath = QDir::currentPath() + "/untitled." + fileFormat; + + QString fileName = QFileDialog::getSaveFileName(this, tr("Save As"), + initialPath, + tr("%1 Files (*.%2);;All Files (*)") + .arg(QString(fileFormat.toUpper())) + .arg(QString(fileFormat))); + if (fileName.isEmpty()) { + return false; + } else { + return scribbleArea->saveImage(fileName, fileFormat); + } +} +//! [20] diff --git a/examples/multitouch/fingerpaint/mainwindow.h b/examples/multitouch/fingerpaint/mainwindow.h new file mode 100644 index 0000000..fdb790d --- /dev/null +++ b/examples/multitouch/fingerpaint/mainwindow.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial Usage +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include +#include + +class ScribbleArea; + +//! [0] +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + MainWindow(); + +protected: + void closeEvent(QCloseEvent *event); + +private slots: + void open(); + void save(); + void about(); + +private: + void createActions(); + void createMenus(); + bool maybeSave(); + bool saveFile(const QByteArray &fileFormat); + + ScribbleArea *scribbleArea; + + QMenu *saveAsMenu; + QMenu *fileMenu; + QMenu *optionMenu; + QMenu *helpMenu; + + QAction *openAct; + QList saveAsActs; + QAction *exitAct; + QAction *printAct; + QAction *clearScreenAct; + QAction *aboutAct; + QAction *aboutQtAct; +}; +//! [0] + +#endif diff --git a/examples/multitouch/fingerpaint/scribblearea.cpp b/examples/multitouch/fingerpaint/scribblearea.cpp new file mode 100644 index 0000000..a042fe7 --- /dev/null +++ b/examples/multitouch/fingerpaint/scribblearea.cpp @@ -0,0 +1,213 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial Usage +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include "scribblearea.h" + +//! [0] +ScribbleArea::ScribbleArea(QWidget *parent) + : QWidget(parent) +{ + setAttribute(Qt::WA_AcceptTouchEvents); + setAttribute(Qt::WA_StaticContents); + modified = false; + + myPenColors + << QColor("green") + << QColor("purple") + << QColor("red") + << QColor("blue") + << QColor("yellow") + + << QColor("pink") + << QColor("orange") + << QColor("brown") + << QColor("grey") + << QColor("black"); +} +//! [0] + +//! [1] +bool ScribbleArea::openImage(const QString &fileName) +//! [1] //! [2] +{ + QImage loadedImage; + if (!loadedImage.load(fileName)) + return false; + + QSize newSize = loadedImage.size().expandedTo(size()); + resizeImage(&loadedImage, newSize); + image = loadedImage; + modified = false; + update(); + return true; +} +//! [2] + +//! [3] +bool ScribbleArea::saveImage(const QString &fileName, const char *fileFormat) +//! [3] //! [4] +{ + QImage visibleImage = image; + resizeImage(&visibleImage, size()); + + if (visibleImage.save(fileName, fileFormat)) { + modified = false; + return true; + } else { + return false; + } +} +//! [4] + +//! [9] +void ScribbleArea::clearImage() +//! [9] //! [10] +{ + image.fill(qRgb(255, 255, 255)); + modified = true; + update(); +} +//! [10] + +//! [12] //! [13] +void ScribbleArea::paintEvent(QPaintEvent *event) +//! [13] //! [14] +{ + QPainter painter(this); + const QRect rect = event->rect(); + painter.drawImage(rect.topLeft(), image, rect); +} +//! [14] + +//! [15] +void ScribbleArea::resizeEvent(QResizeEvent *event) +//! [15] //! [16] +{ + if (width() > image.width() || height() > image.height()) { + int newWidth = qMax(width() + 128, image.width()); + int newHeight = qMax(height() + 128, image.height()); + resizeImage(&image, QSize(newWidth, newHeight)); + update(); + } + QWidget::resizeEvent(event); +} +//! [16] + +//! [19] +void ScribbleArea::resizeImage(QImage *image, const QSize &newSize) +//! [19] //! [20] +{ + if (image->size() == newSize) + return; + + QImage newImage(newSize, QImage::Format_RGB32); + newImage.fill(qRgb(255, 255, 255)); + QPainter painter(&newImage); + painter.drawImage(QPoint(0, 0), *image); + *image = newImage; +} +//! [20] + +//! [21] +void ScribbleArea::print() +{ +#ifndef QT_NO_PRINTER + QPrinter printer(QPrinter::HighResolution); + + QPrintDialog *printDialog = new QPrintDialog(&printer, this); +//! [21] //! [22] + if (printDialog->exec() == QDialog::Accepted) { + QPainter painter(&printer); + QRect rect = painter.viewport(); + QSize size = image.size(); + size.scale(rect.size(), Qt::KeepAspectRatio); + painter.setViewport(rect.x(), rect.y(), size.width(), size.height()); + painter.setWindow(image.rect()); + painter.drawImage(0, 0, image); + } +#endif // QT_NO_PRINTER +} +//! [22] + +bool ScribbleArea::event(QEvent *event) +{ + switch (event->type()) { + case QEvent::TouchBegin: + case QEvent::TouchUpdate: + case QEvent::TouchEnd: + { + QList touchPoints = static_cast(event)->touchPoints(); + foreach (QTouchEvent::TouchPoint *touchPoint, touchPoints) { + switch (touchPoint->state()) { + case Qt::TouchPointStationary: + // don't do anything if this touch point hasn't moved + continue; + default: + { + int diameter = int(50 * touchPoint->pressure()); + QRectF rectF(0, 0, diameter, diameter); + rectF.moveCenter(touchPoint->pos()); + QRect rect = rectF.toRect(); + + QPainter painter(&image); + painter.setPen(Qt::NoPen); + painter.setBrush(myPenColors.at(touchPoint->id())); + painter.drawEllipse(rectF); + painter.end(); + + modified = true; + int rad = 2; + update(rect.adjusted(-rad,-rad, +rad, +rad)); + } + break; + } + } + + event->accept(); + return true; + } + default: + break; + } + return QWidget::event(event); +} diff --git a/examples/multitouch/fingerpaint/scribblearea.h b/examples/multitouch/fingerpaint/scribblearea.h new file mode 100644 index 0000000..8928ce1 --- /dev/null +++ b/examples/multitouch/fingerpaint/scribblearea.h @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial Usage +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef SCRIBBLEAREA_H +#define SCRIBBLEAREA_H + +#include +#include +#include +#include + +//! [0] +class ScribbleArea : public QWidget +{ + Q_OBJECT + +public: + ScribbleArea(QWidget *parent = 0); + + bool openImage(const QString &fileName); + bool saveImage(const QString &fileName, const char *fileFormat); + + bool isModified() const { return modified; } + +public slots: + void clearImage(); + void print(); + +protected: + void paintEvent(QPaintEvent *event); + void resizeEvent(QResizeEvent *event); + bool event(QEvent *event); + +private: + void resizeImage(QImage *image, const QSize &newSize); + + bool modified; + QList myPenColors; + QImage image; +}; +//! [0] + +#endif -- cgit v0.12 From b5236dedd9ab72d6e0bd09151a6f55bb40a7034c Mon Sep 17 00:00:00 2001 From: "Bradley T. Hughes" Date: Wed, 25 Mar 2009 11:32:52 +0100 Subject: have the window title in the fingerpaint example say Finger Paint, not Scribble --- examples/multitouch/fingerpaint/mainwindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/multitouch/fingerpaint/mainwindow.cpp b/examples/multitouch/fingerpaint/mainwindow.cpp index 546c685..e510f89 100644 --- a/examples/multitouch/fingerpaint/mainwindow.cpp +++ b/examples/multitouch/fingerpaint/mainwindow.cpp @@ -53,7 +53,7 @@ MainWindow::MainWindow() createActions(); createMenus(); - setWindowTitle(tr("Scribble")); + setWindowTitle(tr("Finger Paint")); resize(500, 500); } //! [0] -- cgit v0.12 From 81b5a795a47f6d03c81756d7b5b4501f60528c41 Mon Sep 17 00:00:00 2001 From: "Bradley T. Hughes" Date: Wed, 25 Mar 2009 11:34:20 +0100 Subject: add fingerpaint to examples\multitouch.pro --- examples/multitouch/multitouch.pro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/multitouch/multitouch.pro b/examples/multitouch/multitouch.pro index 7efa412..b2b2b76 100644 --- a/examples/multitouch/multitouch.pro +++ b/examples/multitouch/multitouch.pro @@ -1,2 +1,2 @@ TEMPLATE = subdirs -SUBDIRS = pinchzoom \ No newline at end of file +SUBDIRS = pinchzoom fingerpaint -- cgit v0.12 From e1dd9242895e27afa63b255198ad541f738c06ef Mon Sep 17 00:00:00 2001 From: "Bradley T. Hughes" Date: Wed, 25 Mar 2009 11:52:33 +0100 Subject: remove code duplication for setting the focus widget based on t he focus policy refactor duplicated code in the mouse and wheel event handlers that sets the focus widget based on the widget's (or its ancestors) focus policy --- src/gui/kernel/qapplication.cpp | 46 ++++++++++++++++++++--------------------- src/gui/kernel/qapplication_p.h | 4 ++++ 2 files changed, 27 insertions(+), 23 deletions(-) diff --git a/src/gui/kernel/qapplication.cpp b/src/gui/kernel/qapplication.cpp index 1bbb019..34c2d74 100644 --- a/src/gui/kernel/qapplication.cpp +++ b/src/gui/kernel/qapplication.cpp @@ -3735,19 +3735,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) { @@ -3829,17 +3820,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) { @@ -5033,6 +5016,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; diff --git a/src/gui/kernel/qapplication_p.h b/src/gui/kernel/qapplication_p.h index 7487f0a..6d75f37 100644 --- a/src/gui/kernel/qapplication_p.h +++ b/src/gui/kernel/qapplication_p.h @@ -430,6 +430,10 @@ private: #endif static QApplicationPrivate *self; + + static void giveFocusAccordingToFocusPolicy(QWidget *w, + Qt::FocusPolicy focusPolicy, + Qt::FocusReason focusReason); static bool shouldSetFocus(QWidget *w, Qt::FocusPolicy policy); }; -- cgit v0.12 From 480b0fe494cc7dec7d8082860c6216e970ce6a57 Mon Sep 17 00:00:00 2001 From: "Bradley T. Hughes" Date: Wed, 25 Mar 2009 11:57:14 +0100 Subject: implement event propagation for touch events behavior is similar to that of QGraphicsScene mouse events: the first touch event (the TouchBegin) is propagated to all parents. if a widget accepts the event, it will receive all other touch events (the TouchUpdate and TouchEnd events). If no widget accepts the TouchBegin, then we will fallback to normal mouse events (TBD). --- src/gui/kernel/qapplication.cpp | 48 +++++++++++++++++++++++++++++++++++++++++ src/gui/kernel/qapplication_p.h | 3 +++ src/gui/kernel/qevent.h | 2 ++ 3 files changed, 53 insertions(+) diff --git a/src/gui/kernel/qapplication.cpp b/src/gui/kernel/qapplication.cpp index 34c2d74..9c70208 100644 --- a/src/gui/kernel/qapplication.cpp +++ b/src/gui/kernel/qapplication.cpp @@ -85,6 +85,7 @@ #include #include "qapplication_p.h" +#include "qevent_p.h" #include "qwidget_p.h" #include "qapplication.h" @@ -4027,7 +4028,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(receiver); + QTouchEvent *touchEvent = static_cast(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; @@ -5046,6 +5081,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 6d75f37..252d0cb 100644 --- a/src/gui/kernel/qapplication_p.h +++ b/src/gui/kernel/qapplication_p.h @@ -424,6 +424,9 @@ public: void sendSyntheticEnterLeave(QWidget *widget); #endif + QPointer currentMultitouchWidget; + static void updateTouchPointsForWidget(QWidget *widget, QTouchEvent *touchEvent); + private: #ifdef Q_WS_QWS QMap maxWindowRects; diff --git a/src/gui/kernel/qevent.h b/src/gui/kernel/qevent.h index 3cb712d..506e0c1 100644 --- a/src/gui/kernel/qevent.h +++ b/src/gui/kernel/qevent.h @@ -758,6 +758,8 @@ public: protected: QList _touchPoints; + + friend class QApplicationPrivate; }; QT_END_NAMESPACE -- cgit v0.12 From aa50245865b5bf8655ee3d476ee961009f0c314e Mon Sep 17 00:00:00 2001 From: "Bradley T. Hughes" Date: Wed, 25 Mar 2009 13:38:02 +0100 Subject: add a multitouch example that shows how to handle multitouch events in QGraphicsItems --- examples/multitouch/knobs/knob.cpp | 93 +++++++++++++++++++++++++++++++++++++ examples/multitouch/knobs/knob.h | 55 ++++++++++++++++++++++ examples/multitouch/knobs/knobs.pro | 2 + examples/multitouch/knobs/main.cpp | 66 ++++++++++++++++++++++++++ examples/multitouch/multitouch.pro | 2 +- 5 files changed, 217 insertions(+), 1 deletion(-) create mode 100644 examples/multitouch/knobs/knob.cpp create mode 100644 examples/multitouch/knobs/knob.h create mode 100644 examples/multitouch/knobs/knobs.pro create mode 100644 examples/multitouch/knobs/main.cpp diff --git a/examples/multitouch/knobs/knob.cpp b/examples/multitouch/knobs/knob.cpp new file mode 100644 index 0000000..4622f69 --- /dev/null +++ b/examples/multitouch/knobs/knob.cpp @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial Usage +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "knob.h" + +#include +#include + +Knob::Knob() + : QGraphicsEllipseItem(-50, -50, 100, 100) +{ + setAcceptTouchEvents(true); + setBrush(Qt::lightGray); + + QGraphicsEllipseItem *leftItem = new QGraphicsEllipseItem(0, 0, 10, 10, this); + leftItem->setPos(-45, -5); + leftItem->setBrush(Qt::darkGreen); + + QGraphicsEllipseItem *rightItem = new QGraphicsEllipseItem(0, 0, 10, 10, this); + rightItem->setPos(35, -5); + rightItem->setBrush(Qt::darkRed); +} + +bool Knob::sceneEvent(QEvent *event) +{ + switch (event->type()) { + case QEvent::GraphicsSceneTouchBegin: + event->accept(); + break; + + case QEvent::GraphicsSceneTouchUpdate: + case QEvent::GraphicsSceneTouchEnd: + { + QGraphicsSceneTouchEvent *touchEvent = static_cast(event); + + if (touchEvent->touchPoints().count() == 2) { + QGraphicsSceneTouchEvent::TouchPoint *touchPoint1 = touchEvent->touchPoints().first(); + QGraphicsSceneTouchEvent::TouchPoint *touchPoint2 = touchEvent->touchPoints().last(); + + QLineF line1(touchPoint1->lastScenePos(), touchPoint2->lastScenePos()); + QLineF line2(touchPoint1->scenePos(), touchPoint2->scenePos()); + + rotate(line2.angleTo(line1)); + } + + touchEvent->accept(); + break; + } + + default: + return QGraphicsItem::sceneEvent(event); + } + + return true; +} diff --git a/examples/multitouch/knobs/knob.h b/examples/multitouch/knobs/knob.h new file mode 100644 index 0000000..1079483 --- /dev/null +++ b/examples/multitouch/knobs/knob.h @@ -0,0 +1,55 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial Usage +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef KNOB_H +#define KNOB_H + +#include + +class Knob : public QGraphicsEllipseItem +{ +public: + Knob(); + + bool sceneEvent(QEvent *event); +}; + +#endif // KNOB_H diff --git a/examples/multitouch/knobs/knobs.pro b/examples/multitouch/knobs/knobs.pro new file mode 100644 index 0000000..90f0ba5 --- /dev/null +++ b/examples/multitouch/knobs/knobs.pro @@ -0,0 +1,2 @@ +HEADERS = knob.h +SOURCES = main.cpp knob.cpp diff --git a/examples/multitouch/knobs/main.cpp b/examples/multitouch/knobs/main.cpp new file mode 100644 index 0000000..c5a7ea7 --- /dev/null +++ b/examples/multitouch/knobs/main.cpp @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial Usage +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include + +#include "knob.h" + +int main(int argc, char **argv) +{ + QApplication app(argc, argv); + + QGraphicsScene scene; + QGraphicsView view(&scene); + view.viewport()->setAttribute(Qt::WA_AcceptTouchEvents); + + Knob *knob1 = new Knob; + knob1->setPos(-110, 0); + Knob *knob2 = new Knob; + + scene.addItem(knob1); + scene.addItem(knob2); + + view.showFullScreen(); + view.fitInView(scene.sceneRect().adjusted(-20, -20, 20, 20), Qt::KeepAspectRatio); + + return app.exec(); +} diff --git a/examples/multitouch/multitouch.pro b/examples/multitouch/multitouch.pro index b2b2b76..b3d1d55 100644 --- a/examples/multitouch/multitouch.pro +++ b/examples/multitouch/multitouch.pro @@ -1,2 +1,2 @@ TEMPLATE = subdirs -SUBDIRS = pinchzoom fingerpaint +SUBDIRS = pinchzoom fingerpaint knobs -- cgit v0.12 From 0103e7871000f224a1048649b4eca18a7840fe3b Mon Sep 17 00:00:00 2001 From: "Bradley T. Hughes" Date: Wed, 25 Mar 2009 13:30:38 +0100 Subject: initial implementation of multitouch support on Windows 7 WM_TOUCH* messages are translated to QTouchEvents and sent to the appropriate widget. we set the qt_tabletChokeMouse variable according to the result of the event processing to make sure that mouse events are sent when touch events are not handled. --- src/gui/kernel/qapplication_p.h | 27 ++++- src/gui/kernel/qapplication_win.cpp | 192 ++++++++++++++++++++++++++++++++++++ src/gui/kernel/qwidget_win.cpp | 4 + 3 files changed, 220 insertions(+), 3 deletions(-) diff --git a/src/gui/kernel/qapplication_p.h b/src/gui/kernel/qapplication_p.h index 252d0cb..ccd9f41 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; @@ -427,6 +431,23 @@ public: QPointer 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 touchInputIDToTouchPointID; + QVector allTouchPoints; + QList currentTouchPoints, activeTouchPoints; + + static bool sendTouchEvent(QWidget *widget, QTouchEvent *touchEvent); + + void initializeMultitouch(); + void insertActiveTouch(QTouchEvent::TouchPoint *touchPoint); + void removeActiveTouch(QTouchEvent::TouchPoint *touchPoint); + bool translateTouchEvent(const MSG &msg); +#endif + private: #ifdef Q_WS_QWS QMap maxWindowRects; diff --git a/src/gui/kernel/qapplication_win.cpp b/src/gui/kernel/qapplication_win.cpp index fae0335..7c7f7f6 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 #include +#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 #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); @@ -3953,4 +3994,155 @@ 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(library.resolve("RegisterTouchWindow")); + GetTouchInputInfo = static_cast(library.resolve("GetTouchInputInfo")); + CloseTouchInputHandle = static_cast(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 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); + return (qt_tabletChokeMouse = sendTouchEvent(widget, &touchEvent)); + } + + return false; +} + +bool QApplicationPrivate::sendTouchEvent(QWidget *widget, QTouchEvent *touchEvent) +{ + bool res = QApplication::sendSpontaneousEvent(widget, touchEvent); + return res && touchEvent->isAccepted(); +} + QT_END_NAMESPACE 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 -- cgit v0.12 From 761cac16eb0a6d32f9e7d558867c5c1bbfb244f9 Mon Sep 17 00:00:00 2001 From: "Bradley T. Hughes" Date: Wed, 25 Mar 2009 13:49:34 +0100 Subject: show the example maximized, not fullscreen --- examples/multitouch/knobs/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/multitouch/knobs/main.cpp b/examples/multitouch/knobs/main.cpp index c5a7ea7..8f78cf9 100644 --- a/examples/multitouch/knobs/main.cpp +++ b/examples/multitouch/knobs/main.cpp @@ -59,7 +59,7 @@ int main(int argc, char **argv) scene.addItem(knob1); scene.addItem(knob2); - view.showFullScreen(); + view.showMaximized(); view.fitInView(scene.sceneRect().adjusted(-20, -20, 20, 20), Qt::KeepAspectRatio); return app.exec(); -- cgit v0.12 From e14f2ddd25a72f07a3215c1bc7f4755c48dd6e3a Mon Sep 17 00:00:00 2001 From: "Bradley T. Hughes" Date: Thu, 12 Mar 2009 13:45:18 +0100 Subject: add a test for touch event propagation --- tests/auto/qapplication/tst_qapplication.cpp | 143 +++++++++++++++++++++++++++ 1 file changed, 143 insertions(+) diff --git a/tests/auto/qapplication/tst_qapplication.cpp b/tests/auto/qapplication/tst_qapplication.cpp index cee3125..356768e 100644 --- a/tests/auto/qapplication/tst_qapplication.cpp +++ b/tests/auto/qapplication/tst_qapplication.cpp @@ -48,6 +48,7 @@ #include "qabstracteventdispatcher.h" #include +#include "private/qapplication_p.h" #include "private/qstylesheetstyle_p.h" #ifdef Q_OS_WINCE #include @@ -117,6 +118,8 @@ private slots: void windowsCommandLine_data(); void windowsCommandLine(); + + void touchEventPropagation(); }; class MyInputContext : public QInputContext @@ -1773,6 +1776,146 @@ void tst_QApplication::windowsCommandLine() #endif } +class TouchEventPropagationTestWidget : public QWidget +{ + Q_OBJECT + +public: + bool seenTouchEvent, acceptTouchEvent, seenMouseEvent, acceptMouseEvent; + + TouchEventPropagationTestWidget(QWidget *parent = 0) + : QWidget(parent), seenTouchEvent(false), acceptTouchEvent(false), seenMouseEvent(false), acceptMouseEvent(false) + { } + + void reset() + { + seenTouchEvent = acceptTouchEvent = seenMouseEvent = acceptMouseEvent = false; + } + + bool event(QEvent *event) + { + switch (event->type()) { + case QEvent::MouseButtonPress: + case QEvent::MouseMove: + case QEvent::MouseButtonRelease: + // qDebug() << objectName() << "seenMouseEvent = true"; + seenMouseEvent = true; + event->setAccepted(acceptMouseEvent); + break; + case QEvent::TouchBegin: + case QEvent::TouchUpdate: + case QEvent::TouchEnd: + // qDebug() << objectName() << "seenTouchEvent = true"; + seenTouchEvent = true; + event->setAccepted(acceptTouchEvent); + break; + default: + return QWidget::event(event); + } + return true; + } +}; + +void tst_QApplication::touchEventPropagation() +{ + int argc = 1; + QApplication app(argc, &argv0, QApplication::GuiServer); + QTouchEvent::TouchPoint touchPoint(0); + QTouchEvent touchEvent(QEvent::TouchBegin, Qt::NoModifier, QList() << (&touchPoint)); + + { + // touch event behavior on a window + TouchEventPropagationTestWidget window; + window.setObjectName("1. window"); + + QApplicationPrivate::sendTouchEvent(&window, &touchEvent); + QVERIFY(!window.seenTouchEvent); + QVERIFY(window.seenMouseEvent); + + window.reset(); + window.setAttribute(Qt::WA_AcceptsTouchEvents); + QApplicationPrivate::sendTouchEvent(&window, &touchEvent); + QVERIFY(window.seenTouchEvent); + QVERIFY(window.seenMouseEvent); + + window.reset(); + window.acceptTouchEvent = true; + QApplicationPrivate::sendTouchEvent(&window, &touchEvent); + QVERIFY(window.seenTouchEvent); + QVERIFY(!window.seenMouseEvent); + } + + { + // touch event behavior on a window with a child widget + TouchEventPropagationTestWidget window; + window.setObjectName("2. window"); + TouchEventPropagationTestWidget widget(&window); + widget.setObjectName("2. widget"); + + QApplicationPrivate::sendTouchEvent(&widget, &touchEvent); + QVERIFY(!widget.seenTouchEvent); + QVERIFY(widget.seenMouseEvent); + QVERIFY(!window.seenTouchEvent); + QVERIFY(window.seenMouseEvent); + + window.reset(); + widget.reset(); + widget.setAttribute(Qt::WA_AcceptsTouchEvents); + QApplicationPrivate::sendTouchEvent(&widget, &touchEvent); + QVERIFY(widget.seenTouchEvent); + QVERIFY(widget.seenMouseEvent); + QVERIFY(!window.seenTouchEvent); + QVERIFY(window.seenMouseEvent); + + window.reset(); + widget.reset(); + widget.acceptMouseEvent = true; + QApplicationPrivate::sendTouchEvent(&widget, &touchEvent); + QVERIFY(widget.seenTouchEvent); + QVERIFY(widget.seenMouseEvent); + QVERIFY(!window.seenTouchEvent); + QVERIFY(!window.seenMouseEvent); + + window.reset(); + widget.reset(); + widget.acceptTouchEvent = true; + QApplicationPrivate::sendTouchEvent(&widget, &touchEvent); + QVERIFY(widget.seenTouchEvent); + QVERIFY(!widget.seenMouseEvent); + QVERIFY(!window.seenTouchEvent); + QVERIFY(!window.seenMouseEvent); + + window.reset(); + widget.reset(); + widget.setAttribute(Qt::WA_AcceptsTouchEvents, false); + window.setAttribute(Qt::WA_AcceptsTouchEvents); + QApplicationPrivate::sendTouchEvent(&widget, &touchEvent); + QVERIFY(!widget.seenTouchEvent); + QVERIFY(widget.seenMouseEvent); + QVERIFY(window.seenTouchEvent); + QVERIFY(window.seenMouseEvent); + + window.reset(); + widget.reset(); + window.acceptTouchEvent = true; + QApplicationPrivate::sendTouchEvent(&widget, &touchEvent); + QVERIFY(!widget.seenTouchEvent); + QVERIFY(!widget.seenMouseEvent); + QVERIFY(window.seenTouchEvent); + QVERIFY(!window.seenMouseEvent); + + window.reset(); + widget.reset(); + widget.acceptMouseEvent = true; // doesn't matter, touch events are propagated first + window.acceptTouchEvent = true; + QApplicationPrivate::sendTouchEvent(&widget, &touchEvent); + QVERIFY(!widget.seenTouchEvent); + QVERIFY(!widget.seenMouseEvent); + QVERIFY(window.seenTouchEvent); + QVERIFY(!window.seenMouseEvent); + } +} + //QTEST_APPLESS_MAIN(tst_QApplication) int main(int argc, char *argv[]) { -- cgit v0.12 From b2824b384485ddba95091e49f81733485f1a73be Mon Sep 17 00:00:00 2001 From: "Bradley T. Hughes" Date: Thu, 26 Mar 2009 08:24:39 +0100 Subject: remove QApplicationPrivate::sendTouchEvent --- src/gui/kernel/qapplication_p.h | 2 -- src/gui/kernel/qapplication_win.cpp | 10 +++------- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/src/gui/kernel/qapplication_p.h b/src/gui/kernel/qapplication_p.h index ccd9f41..ce7110d 100644 --- a/src/gui/kernel/qapplication_p.h +++ b/src/gui/kernel/qapplication_p.h @@ -440,8 +440,6 @@ public: QVector allTouchPoints; QList currentTouchPoints, activeTouchPoints; - static bool sendTouchEvent(QWidget *widget, QTouchEvent *touchEvent); - void initializeMultitouch(); void insertActiveTouch(QTouchEvent::TouchPoint *touchPoint); void removeActiveTouch(QTouchEvent::TouchPoint *touchPoint); diff --git a/src/gui/kernel/qapplication_win.cpp b/src/gui/kernel/qapplication_win.cpp index 7c7f7f6..cef8cf2 100644 --- a/src/gui/kernel/qapplication_win.cpp +++ b/src/gui/kernel/qapplication_win.cpp @@ -4133,16 +4133,12 @@ bool QApplicationPrivate::translateTouchEvent(const MSG &msg) : QEvent::TouchUpdate), q->keyboardModifiers(), activeTouchPoints); updateTouchPointsForWidget(widget, &touchEvent); - return (qt_tabletChokeMouse = sendTouchEvent(widget, &touchEvent)); + + bool res = QApplication::sendSpontaneousEvent(widget, &touchEvent); + return (qt_tabletChokeMouse = res && touchEvent.isAccepted()); } return false; } -bool QApplicationPrivate::sendTouchEvent(QWidget *widget, QTouchEvent *touchEvent) -{ - bool res = QApplication::sendSpontaneousEvent(widget, touchEvent); - return res && touchEvent->isAccepted(); -} - QT_END_NAMESPACE -- cgit v0.12 From b3a2c210973a77d1517d017637a3d6ef849f4089 Mon Sep 17 00:00:00 2001 From: "Bradley T. Hughes" Date: Thu, 26 Mar 2009 08:54:36 +0100 Subject: implement panning using touch events since we don't get mouse events to send to QGraphicsView's ScrollHandDrag handlers, we need to do it ourselves --- examples/multitouch/pinchzoom/graphicsview.cpp | 13 ++++++++----- examples/multitouch/pinchzoom/main.cpp | 1 - 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/examples/multitouch/pinchzoom/graphicsview.cpp b/examples/multitouch/pinchzoom/graphicsview.cpp index b77c926..f763e6f 100644 --- a/examples/multitouch/pinchzoom/graphicsview.cpp +++ b/examples/multitouch/pinchzoom/graphicsview.cpp @@ -41,9 +41,9 @@ #include "graphicsview.h" +#include #include - GraphicsView::GraphicsView(QGraphicsScene *scene, QWidget *parent) : QGraphicsView(scene, parent) { @@ -57,10 +57,13 @@ bool GraphicsView::event(QEvent *event) case QEvent::TouchUpdate: case QEvent::TouchEnd: { - qDebug("touch events"); - - QList touchPoints = static_cast(event)->touchPoints(); - if (touchPoints.count() == 2) { + QList touchPoints = static_cast(event)->touchPoints(); + if (touchPoints.count() == 1) { + const QTouchEvent::TouchPoint *touchPoint = touchPoints.first(); + QPointF delta = touchPoint->pos() - touchPoint->lastPos(); + horizontalScrollBar()->setValue(horizontalScrollBar()->value() - delta.x()); + verticalScrollBar()->setValue(verticalScrollBar()->value() - delta.y()); + } else if (touchPoints.count() == 2) { // determine scale factor const QTouchEvent::TouchPoint *touchPoint0 = touchPoints.first(); const QTouchEvent::TouchPoint *touchPoint1 = touchPoints.last(); diff --git a/examples/multitouch/pinchzoom/main.cpp b/examples/multitouch/pinchzoom/main.cpp index 6b25060..bb86870 100644 --- a/examples/multitouch/pinchzoom/main.cpp +++ b/examples/multitouch/pinchzoom/main.cpp @@ -78,7 +78,6 @@ int main(int argc, char **argv) //! [4] //! [5] view.setCacheMode(QGraphicsView::CacheBackground); view.setViewportUpdateMode(QGraphicsView::BoundingRectViewportUpdate); - view.setDragMode(QGraphicsView::ScrollHandDrag); //! [5] //! [6] view.setWindowTitle(QT_TRANSLATE_NOOP(QGraphicsView, "Colliding Mice")); view.showMaximized(); -- cgit v0.12 From 46caddc9fa82df4fba88ea4ef87dba692b18c1c9 Mon Sep 17 00:00:00 2001 From: "Bradley T. Hughes" Date: Mon, 30 Mar 2009 11:08:12 +0200 Subject: compile --- src/network/kernel/qauthenticator.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/kernel/qauthenticator.cpp b/src/network/kernel/qauthenticator.cpp index 4f477bd..19243aa 100644 --- a/src/network/kernel/qauthenticator.cpp +++ b/src/network/kernel/qauthenticator.cpp @@ -52,7 +52,7 @@ QT_BEGIN_NAMESPACE -#include <../3rdparty/des/des.cpp> +#include <../../3rdparty/des/des.cpp> static QByteArray qNtlmPhase1(); static QByteArray qNtlmPhase3(QAuthenticatorPrivate *ctx, const QByteArray& phase2data); -- cgit v0.12 From be8b6047ccd43df1127beb4c602c58408ff9b612 Mon Sep 17 00:00:00 2001 From: "Bradley T. Hughes" Date: Tue, 31 Mar 2009 13:19:23 +0200 Subject: Add QSysInfo::WV_WINDOWS7 --- src/corelib/global/qglobal.cpp | 9 ++++++++- src/corelib/global/qglobal.h | 2 ++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/corelib/global/qglobal.cpp b/src/corelib/global/qglobal.cpp index 459167e..bcb17a2 100644 --- a/src/corelib/global/qglobal.cpp +++ b/src/corelib/global/qglobal.cpp @@ -1054,6 +1054,7 @@ bool qSharedBuild() \value WV_XP Windows XP (operating system version 5.1) \value WV_2003 Windows Server 2003, Windows Server 2003 R2, Windows Home Server, Windows XP Professional x64 Edition (operating system version 5.2) \value WV_VISTA Windows Vista, Windows Server 2008 (operating system version 6.0) + \value WV_WINDOWS7 Windows 7 (operating system version 6.1) Alternatively, you may use the following macros which correspond directly to the Windows operating system version number: @@ -1062,6 +1063,7 @@ bool qSharedBuild() \value WV_5_1 Operating system version 5.1, corresponds to Windows XP \value WV_5_2 Operating system version 5.2, corresponds to Windows Server 2003, Windows Server 2003 R2, Windows Home Server, and Windows XP Professional x64 Edition \value WV_6_0 Operating system version 6.0, corresponds to Windows Vista and Windows Server 2008 + \value WV_6_1 Operation system version 6.1, corresponds to Windows 7 CE-based versions: @@ -1632,7 +1634,10 @@ QSysInfo::WinVersion QSysInfo::windowsVersion() if (osver.dwMajorVersion < 5) { winver = QSysInfo::WV_NT; } else if (osver.dwMajorVersion == 6) { - winver = QSysInfo::WV_VISTA; + if (osver.dwMinorVersion == 0) + winver = QSysInfo::WV_VISTA; + else + winver = QSysInfo::WV_WINDOWS7; } else if (osver.dwMinorVersion == 0) { winver = QSysInfo::WV_2000; } else if (osver.dwMinorVersion == 1) { @@ -1667,6 +1672,8 @@ QSysInfo::WinVersion QSysInfo::windowsVersion() winver = QSysInfo::WV_XP; else if (override == "VISTA") winver = QSysInfo::WV_VISTA; + else if (override == "WINDOWS7") + winver = QSysInfo::WV_WINDOWS7; } #endif diff --git a/src/corelib/global/qglobal.h b/src/corelib/global/qglobal.h index 9522e39..872dcf5 100644 --- a/src/corelib/global/qglobal.h +++ b/src/corelib/global/qglobal.h @@ -1309,6 +1309,7 @@ public: WV_XP = 0x0030, WV_2003 = 0x0040, WV_VISTA = 0x0080, + WV_WINDOWS7 = 0x0090, WV_NT_based = 0x00f0, /* version numbers */ @@ -1317,6 +1318,7 @@ public: WV_5_1 = WV_XP, WV_5_2 = WV_2003, WV_6_0 = WV_VISTA, + WV_6_1 = WV_WINDOWS7, WV_CE = 0x0100, WV_CENET = 0x0200, -- cgit v0.12 From 726694c873104ac484a3d09c1a9f64f06a88f864 Mon Sep 17 00:00:00 2001 From: "Bradley T. Hughes" Date: Thu, 23 Apr 2009 14:57:12 +0200 Subject: the start of a manual test for touch events --- tests/manual/qtouchevent/form.ui | 1843 ++++++++++++++++++++++++++++++ tests/manual/qtouchevent/main.cpp | 58 + tests/manual/qtouchevent/multitouch.pro | 5 + tests/manual/qtouchevent/touchwidget.cpp | 56 + tests/manual/qtouchevent/touchwidget.h | 42 + 5 files changed, 2004 insertions(+) create mode 100644 tests/manual/qtouchevent/form.ui create mode 100644 tests/manual/qtouchevent/main.cpp create mode 100644 tests/manual/qtouchevent/multitouch.pro create mode 100644 tests/manual/qtouchevent/touchwidget.cpp create mode 100644 tests/manual/qtouchevent/touchwidget.h diff --git a/tests/manual/qtouchevent/form.ui b/tests/manual/qtouchevent/form.ui new file mode 100644 index 0000000..00e15ae --- /dev/null +++ b/tests/manual/qtouchevent/form.ui @@ -0,0 +1,1843 @@ + + + Form + + + + 0 + 0 + 791 + 499 + + + + Form + + + + + + + 0 + 0 + + + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 170 + 0 + + + + + + + 0 + 255 + 0 + + + + + + + 0 + 212 + 0 + + + + + + + 0 + 85 + 0 + + + + + + + 0 + 113 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 0 + 170 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 127 + 212 + 127 + + + + + + + 255 + 255 + 220 + + + + + + + 0 + 0 + 0 + + + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 170 + 0 + + + + + + + 0 + 255 + 0 + + + + + + + 0 + 212 + 0 + + + + + + + 0 + 85 + 0 + + + + + + + 0 + 113 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 0 + 170 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 127 + 212 + 127 + + + + + + + 255 + 255 + 220 + + + + + + + 0 + 0 + 0 + + + + + + + + + 0 + 85 + 0 + + + + + + + 0 + 170 + 0 + + + + + + + 0 + 255 + 0 + + + + + + + 0 + 212 + 0 + + + + + + + 0 + 85 + 0 + + + + + + + 0 + 113 + 0 + + + + + + + 0 + 85 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 0 + 85 + 0 + + + + + + + 0 + 170 + 0 + + + + + + + 0 + 170 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 170 + 0 + + + + + + + 255 + 255 + 220 + + + + + + + 0 + 0 + 0 + + + + + + + + true + + + + + + Qt::Vertical + + + + 20 + 290 + + + + + + + + Qt::Horizontal + + + + 84 + 20 + + + + + + + + + 180 + 120 + + + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 170 + + + + + + + 0 + 0 + 255 + + + + + + + 0 + 0 + 212 + + + + + + + 0 + 0 + 85 + + + + + + + 0 + 0 + 113 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 0 + 0 + 170 + + + + + + + 0 + 0 + 0 + + + + + + + 127 + 127 + 212 + + + + + + + 255 + 255 + 220 + + + + + + + 0 + 0 + 0 + + + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 170 + + + + + + + 0 + 0 + 255 + + + + + + + 0 + 0 + 212 + + + + + + + 0 + 0 + 85 + + + + + + + 0 + 0 + 113 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 0 + 0 + 170 + + + + + + + 0 + 0 + 0 + + + + + + + 127 + 127 + 212 + + + + + + + 255 + 255 + 220 + + + + + + + 0 + 0 + 0 + + + + + + + + + 0 + 0 + 85 + + + + + + + 0 + 0 + 170 + + + + + + + 0 + 0 + 255 + + + + + + + 0 + 0 + 212 + + + + + + + 0 + 0 + 85 + + + + + + + 0 + 0 + 113 + + + + + + + 0 + 0 + 85 + + + + + + + 255 + 255 + 255 + + + + + + + 0 + 0 + 85 + + + + + + + 0 + 0 + 170 + + + + + + + 0 + 0 + 170 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 170 + + + + + + + 255 + 255 + 220 + + + + + + + 0 + 0 + 0 + + + + + + + + true + + + + + + + Qt::Horizontal + + + + 84 + 20 + + + + + + + + + + + + 0 + 0 + + + + + + + + + 0 + 0 + 0 + + + + + + + 170 + 0 + 0 + + + + + + + 255 + 0 + 0 + + + + + + + 212 + 0 + 0 + + + + + + + 85 + 0 + 0 + + + + + + + 113 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 170 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 212 + 127 + 127 + + + + + + + 255 + 255 + 220 + + + + + + + 0 + 0 + 0 + + + + + + + + + 0 + 0 + 0 + + + + + + + 170 + 0 + 0 + + + + + + + 255 + 0 + 0 + + + + + + + 212 + 0 + 0 + + + + + + + 85 + 0 + 0 + + + + + + + 113 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 170 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 212 + 127 + 127 + + + + + + + 255 + 255 + 220 + + + + + + + 0 + 0 + 0 + + + + + + + + + 85 + 0 + 0 + + + + + + + 170 + 0 + 0 + + + + + + + 255 + 0 + 0 + + + + + + + 212 + 0 + 0 + + + + + + + 85 + 0 + 0 + + + + + + + 113 + 0 + 0 + + + + + + + 85 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 85 + 0 + 0 + + + + + + + 170 + 0 + 0 + + + + + + + 170 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 170 + 0 + 0 + + + + + + + 255 + 255 + 220 + + + + + + + 0 + 0 + 0 + + + + + + + + true + + + + + + Qt::Vertical + + + + 20 + 290 + + + + + + + + Qt::Horizontal + + + + 84 + 20 + + + + + + + + + 180 + 120 + + + + + + + + + 255 + 255 + 255 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 220 + + + + + + + 0 + 0 + 0 + + + + + + + + + 255 + 255 + 255 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 220 + + + + + + + 0 + 0 + 0 + + + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 220 + + + + + + + 0 + 0 + 0 + + + + + + + + true + + + + + + + Qt::Horizontal + + + + 83 + 20 + + + + + + + + + + + + 75 + true + + + + Test Name + + + + + + + Test description + + + + + + + + TouchWidget + QWidget +
touchwidget.h
+ 1 +
+
+ + +
diff --git a/tests/manual/qtouchevent/main.cpp b/tests/manual/qtouchevent/main.cpp new file mode 100644 index 0000000..c406543 --- /dev/null +++ b/tests/manual/qtouchevent/main.cpp @@ -0,0 +1,58 @@ +#include +#include + +#include "ui_form.h" +#include "touchwidget.h" + +class MultitouchTestWidget : public QWidget, public Ui::Form +{ + Q_OBJECT + +public: + MultitouchTestWidget(QWidget *parent = 0) + : QWidget(parent) + { + setupUi(this); + } +}; + +class tst_ManualMultitouch : public QObject +{ + Q_OBJECT + +public: + tst_ManualMultitouch(); + ~tst_ManualMultitouch(); + +private slots: + void touchBeginPropagation(); +}; + +tst_ManualMultitouch::tst_ManualMultitouch() +{ } + +tst_ManualMultitouch::~tst_ManualMultitouch() +{ } + +void tst_ManualMultitouch::touchBeginPropagation() +{ + MultitouchTestWidget testWidget; + testWidget.testNameLabel->setText("Touch event propagation"); + testWidget.testDescriptionLabel->setText("Touch, move, and release your finger over the green widget, the close this window."); + testWidget.greenWidget->setAttribute(Qt::WA_AcceptTouchEvents); + testWidget.greenWidget->acceptTouchBegin = true; + testWidget.show(); + + (void) qApp->exec(); + + QVERIFY(testWidget.greenWidget->seenTouchBegin); + QVERIFY(testWidget.greenWidget->seenTouchUpdate); + QVERIFY(testWidget.greenWidget->seenTouchEnd); + QVERIFY(!testWidget.greenWidget->seenMousePress); + QVERIFY(!testWidget.greenWidget->seenMouseMove); + QVERIFY(!testWidget.greenWidget->seenMouseRelease); +} + +QTEST_MAIN(tst_ManualMultitouch) + +#include "main.moc" diff --git a/tests/manual/qtouchevent/multitouch.pro b/tests/manual/qtouchevent/multitouch.pro new file mode 100644 index 0000000..de1ee06 --- /dev/null +++ b/tests/manual/qtouchevent/multitouch.pro @@ -0,0 +1,5 @@ +QT += testlib +SOURCES = main.cpp \ + touchwidget.cpp +FORMS += form.ui +HEADERS += touchwidget.h diff --git a/tests/manual/qtouchevent/touchwidget.cpp b/tests/manual/qtouchevent/touchwidget.cpp new file mode 100644 index 0000000..5205504 --- /dev/null +++ b/tests/manual/qtouchevent/touchwidget.cpp @@ -0,0 +1,56 @@ +#include "touchwidget.h" + +#include +#include + +bool TouchWidget::event(QEvent *event) +{ + switch (event->type()) { + case QEvent::TouchBegin: + seenTouchBegin = true; + if (acceptTouchBegin) { + event->accept(); + return true; + } + break; + case QEvent::TouchUpdate: + seenTouchUpdate = true; + if (acceptTouchUpdate) { + event->accept(); + return true; + } + break; + case QEvent::TouchEnd: + seenTouchEnd = true; + if (acceptTouchEnd) { + event->accept(); + return true; + } + break; + case QEvent::MouseButtonPress: + case QEvent::MouseButtonDblClick: + seenMousePress = true; + if (acceptMousePress) { + event->accept(); + return true; + } + break; + case QEvent::MouseMove: + seenMouseMove = true; + if (acceptMouseMove) { + event->accept(); + return true; + } + break; + case QEvent::MouseButtonRelease: + seenMouseRelease = true; + if (acceptMouseRelease) { + event->accept(); + return true; + } + break; + default: + break; + } + return QWidget::event(event); +} diff --git a/tests/manual/qtouchevent/touchwidget.h b/tests/manual/qtouchevent/touchwidget.h new file mode 100644 index 0000000..f438a87 --- /dev/null +++ b/tests/manual/qtouchevent/touchwidget.h @@ -0,0 +1,42 @@ +#ifndef TOUCHWIDGET_H +#define TOUCHWIDGET_H + +#include + +class TouchWidget : public QWidget +{ + Q_OBJECT + +public: + bool acceptTouchBegin, acceptTouchUpdate, acceptTouchEnd; + bool seenTouchBegin, seenTouchUpdate, seenTouchEnd; + bool acceptMousePress, acceptMouseMove, acceptMouseRelease; + bool seenMousePress, seenMouseMove, seenMouseRelease; + + inline TouchWidget(QWidget *parent = 0) + : QWidget(parent) + { + reset(); + } + + void reset() + { + acceptTouchBegin + = acceptTouchUpdate + = acceptTouchEnd + = seenTouchBegin + = seenTouchUpdate + = seenTouchEnd + = acceptMousePress + = acceptMouseMove + = acceptMouseRelease + = seenMousePress + = seenMouseMove + = seenMouseRelease + = false; + } + + bool event(QEvent *event); +}; + +#endif // TOUCHWIDGET_H -- cgit v0.12 From 704261859297dae22f90be32ed0e4b675fd02ed3 Mon Sep 17 00:00:00 2001 From: "Bradley T. Hughes" Date: Thu, 23 Apr 2009 15:54:06 +0200 Subject: Initial test for TouchBegin propagation and TouchUpdate/TouchEnd handling --- tests/manual/qtouchevent/main.cpp | 54 ++++++++++++++++++++++++++++++-- tests/manual/qtouchevent/touchwidget.cpp | 26 +++++++++++++++ tests/manual/qtouchevent/touchwidget.h | 20 +++--------- 3 files changed, 82 insertions(+), 18 deletions(-) diff --git a/tests/manual/qtouchevent/main.cpp b/tests/manual/qtouchevent/main.cpp index c406543..2aab4ca 100644 --- a/tests/manual/qtouchevent/main.cpp +++ b/tests/manual/qtouchevent/main.cpp @@ -38,13 +38,63 @@ void tst_ManualMultitouch::touchBeginPropagation() { MultitouchTestWidget testWidget; testWidget.testNameLabel->setText("Touch event propagation"); - testWidget.testDescriptionLabel->setText("Touch, move, and release your finger over the green widget, the close this window."); + testWidget.testDescriptionLabel->setText("Touch, move, and release your finger over the green widget."); testWidget.greenWidget->setAttribute(Qt::WA_AcceptTouchEvents); testWidget.greenWidget->acceptTouchBegin = true; - testWidget.show(); + testWidget.greenWidget->acceptTouchUpdate = true; + testWidget.greenWidget->acceptTouchEnd = true; + testWidget.greenWidget->closeWindowOnTouchEnd = true; + testWidget.showMaximized(); (void) qApp->exec(); + QVERIFY(testWidget.greenWidget->seenTouchBegin); + QVERIFY(testWidget.greenWidget->seenTouchUpdate); + QVERIFY(testWidget.greenWidget->seenTouchEnd); + QVERIFY(!testWidget.greenWidget->seenMousePress); + QVERIFY(!testWidget.greenWidget->seenMouseMove); + QVERIFY(!testWidget.greenWidget->seenMouseRelease); + + // again, ignoring the TouchEnd + testWidget.greenWidget->reset(); + testWidget.greenWidget->acceptTouchBegin = true; + testWidget.greenWidget->acceptTouchUpdate = true; + // testWidget.greenWidget->acceptTouchEnd = true; + testWidget.greenWidget->closeWindowOnTouchEnd = true; + testWidget.showMaximized(); + (void) qApp->exec(); + QVERIFY(testWidget.greenWidget->seenTouchBegin); + QVERIFY(testWidget.greenWidget->seenTouchUpdate); + QVERIFY(testWidget.greenWidget->seenTouchEnd); + QVERIFY(!testWidget.greenWidget->seenMousePress); + QVERIFY(!testWidget.greenWidget->seenMouseMove); + QVERIFY(!testWidget.greenWidget->seenMouseRelease); + + // again, ignoring TouchUpdates + testWidget.greenWidget->reset(); + testWidget.greenWidget->acceptTouchBegin = true; + // testWidget.greenWidget->acceptTouchUpdate = true; + testWidget.greenWidget->acceptTouchEnd = true; + testWidget.greenWidget->closeWindowOnTouchEnd = true; + testWidget.showMaximized(); + + (void) qApp->exec(); + QVERIFY(testWidget.greenWidget->seenTouchBegin); + QVERIFY(testWidget.greenWidget->seenTouchUpdate); + QVERIFY(testWidget.greenWidget->seenTouchEnd); + QVERIFY(!testWidget.greenWidget->seenMousePress); + QVERIFY(!testWidget.greenWidget->seenMouseMove); + QVERIFY(!testWidget.greenWidget->seenMouseRelease); + + // last time, ignoring Touch