summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Yard <peter.yard@nokia.com>2009-08-14 17:35:50 +1000
committerPeter Yard <peter.yard@nokia.com>2009-08-14 17:39:54 +1000
commitff30df236f4f58f69eb7e56685aa7f8b979629f9 (patch)
tree201746e83dcd2523f009d1bb9c2bc938fbf42fbd
parentf3879071f7976bcda3a6e8eed4ca284e80a1a3f9 (diff)
Gesture Overview Documentation
Overview of QGesture class and reference to QStandardGestures Gesture overview using ImageViewer example to demonstrate use of class by implementer.
-rw-r--r--doc/src/gestures.qdoc170
-rw-r--r--doc/src/snippets/gestures/qgesture.cpp283
-rw-r--r--doc/src/snippets/gestures/qgesture.h101
-rw-r--r--doc/src/snippets/gestures/qstandardgestures.cpp483
-rw-r--r--doc/src/snippets/gestures/qstandardgestures.h126
5 files changed, 1163 insertions, 0 deletions
diff --git a/doc/src/gestures.qdoc b/doc/src/gestures.qdoc
new file mode 100644
index 000000000..49a9ae3c2
--- /dev/null
+++ b/doc/src/gestures.qdoc
@@ -0,0 +1,170 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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 http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \page gestures-overview.html
+ \startpage index.html Qt Reference Documentation
+
+ \title Gestures Programming
+ \ingroup howto
+ \brief An overview of the Qt support for Gesture programming.
+
+ The QGesture class provides the ability to form gestures from a series
+ of events independent of the input method. A gesture could be a particular
+ movement of a mouse, a touch screen action, or a series of events from
+ some other source. The nature of the input, the interpretation
+ of the gesture and the action taken are the choice of the implementing
+ developer.
+
+ \tableofcontents
+
+
+ \section1 Creating Your Own Gesture Recognizer
+
+ QGesture is a base class for a user defined gesture recognizer class. In
+ order to implement the recognizer you will need to subclass the
+ QGesture class and implement the pure virtual function \l{QGesture::filterEvent()}{filterEvent()}. Once
+ you have implemented the \l{QGesture::filterEvent()}{filterEvent()} function to
+ make your own recognizer you can process events. A sequence of events may,
+ according to your own rules, represent a gesture. The events can be singly
+ passed to the recognizer via the \l{QGesture::filterEvent()}{filterEvent()} function or as a stream of
+ events by specifying a parent source of events. The events can be from any
+ source and could result in any action as defined by the user. The source
+ and action need not be graphical though that would be the most likely
+ scenario. To find how to connect a source of events to automatically feed into the recognizer see QGesture.
+
+ Recognizers based on QGesture can emit any of the following signals:
+
+ \snippet doc/src/snippets/gestures/qgesture.h qgesture-signals
+
+ These signals are emitted when the state changes with the call to
+ \l{QGesture::updateState()}{updateState()}, more than one signal may
+ be emitted when a change of state occurs. There are four GestureStates
+
+ \table
+ \header \o New State \o Description \o QGesture Actions on Entering this State
+ \row \o Qt::NoGesture \o Initial value \o emit \l {QGesture::cancelled()}{cancelled()}
+ \row \o Qt::GestureStarted \o A continuous gesture has started \o emit \l{QGesture::started()}{started()} and emit \l{QGesture::triggered()}{triggered()}
+ \row \o Qt::GestureUpdated \o A gesture continues \o emit \l{QGesture::triggered()}{triggered()}
+ \row \o Qt::GestureFinished \o A gesture has finished. \o emit \l{QGesture::finished()}{finished()}
+ \endtable
+
+ \note \l{QGesture::started()}{started()} can be emitted if entering any
+ state greater than NoGesture if NoGesture was the previous state. This
+ means that your state machine does not need to explicitly use the
+ Qt::GestureStarted state, you can simply proceed from NoGesture to
+ Qt::GestureUpdated to emit a \l{QGesture::started()}{started()} signal
+ and a \l{QGesture::triggered()}{triggered()} signal.
+
+ You may use some or all of these states when implementing the pure
+ virtual function \l{QGesture::filterEvent()}{filterEvent()}.
+ \l{QGesture::filterEvent()}{filterEvent()} will usually implement a
+ state machine using the GestureState enums, but the details of which
+ states are used is up to the developer.
+
+ You may also need to reimplement the virtual function \l{QGesture::reset()}{reset()}
+ if internal data or objects need to be re-initialized. The function must
+ conclude with a call to \l{QGesture::updateState()}{updateState()} to
+ change the current state to Qt::NoGesture.
+
+ \section1 An Example, ImageViewer
+
+ To illustrate how to use QGesture we will look at the ImageViewer
+ example. This example uses QPanGesture, standard gesture, and an
+ implementation of TapAndHoldGesture. Note that TapAndHoldGesture is
+ platform dependent.
+
+ \snippet doc/src/snippets/gestures/imageviewer/tapandholdgesture.cpp tapandhold-reset
+
+ In ImageViewer we see that the ImageWidget class uses two gestures:
+ \l QPanGesture and TapAndHoldGesture. The
+ QPanGesture is a standard gesture which is part of Qt.
+ TapAndHoldGesture is defined and implemented as part of the example.
+ The ImageWidget listens for signals from the gestures, but is not
+ interested in the \l{QGesture::started()}{started()} signal.
+
+ \snippet doc/src/snippets/gestures/imageviewer/imagewidget.h imagewidget-slots
+
+ TapAndHoldGesture uses QTouchEvent events and mouse events to detect
+ start, update and end events that can be mapped onto the GestureState
+ changes. The implementation in this case uses a timer as well. If the
+ timeout event occurs a given number of times after the start of the gesture
+ then the gesture is considered to have finished whether or not the
+ appropriate touch or mouse event has occurred. Also if a large jump in
+ the position of the event occurs, as calculated by the \l {QPoint::manhattanLength()}{manhattanLength()}
+ call, then the gesture is cancelled by calling \l{QGesture::reset()}{reset()}
+ which tidies up and uses \l{QGesture::updateState()}{updateState()} to
+ change state to NoGesture which will result in the \l{QGesture::cancelled()}{cancelled()}
+ signal being emitted by the recognizer.
+
+ ImageWidget handles the signals by connecting the slots to the signals,
+ although \c cancelled() is not connected here.
+
+ \snippet doc/src/snippets/gestures/imageviewer/imagewidget.cpp imagewidget-connect
+
+ These functions in turn will have to be aware of which gesture
+ object was the source of the signal since we have more than one source
+ per slot. This is easily done by using the QObject::sender() function
+ as shown here
+
+ \snippet doc/src/snippets/gestures/imageviewer/imagewidget.cpp imagewidget-triggered-1
+
+ As \l{QGesture::triggered()}{triggered()} signals are handled by
+ gestureTriggered() there may be position updates invoking calls to,
+ for example, goNextImage(), this will cause a change in the image
+ handling logic of ImageWidget and a call to updateImage() to display
+ the changed state.
+
+ Following the logic of how the QEvent is processed we can summmarize
+ it as follows:
+ \list
+ \o filterEvent() becomes the event filter of the parent ImageWidget object for a QPanGesture object and a
+ TapAndHoldGesture object.
+ \o filterEvent() then calls updateState() to change states
+ \o updateState() emits the appropriate signal(s) for the state change.
+ \o The signals are caught by the defined slots in ImageWidget
+ \o The widget logic changes and an update() results in a paint event.
+ \endlist
+
+
+
+*/
+
diff --git a/doc/src/snippets/gestures/qgesture.cpp b/doc/src/snippets/gestures/qgesture.cpp
new file mode 100644
index 000000000..79dcae1c6
--- /dev/null
+++ b/doc/src/snippets/gestures/qgesture.cpp
@@ -0,0 +1,283 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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 http://qt.nokia.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qgesture.h"
+#include <private/qgesture_p.h>
+#include "qgraphicsitem.h"
+
+QT_BEGIN_NAMESPACE
+
+
+class QEventFilterProxyGraphicsItem : public QGraphicsItem
+{
+public:
+ QEventFilterProxyGraphicsItem(QGesture *g)
+ : gesture(g)
+ {
+ }
+ bool sceneEventFilter(QGraphicsItem *, QEvent *event)
+ {
+ return gesture ? gesture->filterEvent(event) : false;
+ }
+ QRectF boundingRect() const { return QRectF(); }
+ void paint(QPainter*, const QStyleOptionGraphicsItem*, QWidget*) { }
+
+private:
+ QGesture *gesture;
+};
+
+/*!
+ \class QGesture
+ \since 4.6
+
+ \brief The QGesture class is the base class for implementing custom
+ gestures.
+
+ This class represents both an object that recognizes a gesture out of a set
+ of input events (a gesture recognizer), and a gesture object itself that
+ can be used to get extended information about the triggered gesture.
+
+ The class has a list of properties that can be queried by the user to get
+ some gesture-specific parameters (for example, an offset of a Pan gesture).
+
+ Usually gesture recognizer implements a state machine, storing its state
+ internally in the recognizer object. The recognizer receives input events
+ through the \l{QGesture::}{filterEvent()} virtual function and decides
+ whether the event should change the state of the recognizer by emitting an
+ appropriate signal.
+
+ Input events should be either fed to the recognizer one by one with a
+ filterEvent() function, or the gesture recognizer should be attached to an
+ object it filters events for by specifying it as a parent object. The
+ QGesture object installs itself as an event filter to the parent object
+ automatically, the unsetObject() function should be used to remove an event
+ filter from the parent object. To make a
+ gesture that operates on a QGraphicsItem, both the appropriate QGraphicsView
+ should be passed as a parent object and setGraphicsItem() functions should
+ be used to attach a gesture to a graphics item.
+
+ This is a base class, to create a custom gesture type, you should subclass
+ it and implement its pure virtual functions.
+
+ \sa QPanGesture
+*/
+
+/*! \fn bool QGesture::filterEvent(QEvent *event)
+
+ Parses input \a event and emits a signal when detects a gesture.
+
+ In your reimplementation of this function, if you want to filter the \a
+ event out, i.e. stop it being handled further, return true; otherwise
+ return false;
+
+ This is a pure virtual function that needs to be implemented in subclasses.
+*/
+
+/*! \fn void QGesture::started()
+
+ The signal is emitted when the gesture is started. Extended information
+ about the gesture is contained in the signal sender object.
+
+ In addition to started(), a triggered() signal should also be emitted.
+*/
+
+/*! \fn void QGesture::triggered()
+
+ The signal is emitted when the gesture is detected. Extended information
+ about the gesture is contained in the signal sender object.
+*/
+
+/*! \fn void QGesture::finished()
+
+ The signal is emitted when the gesture is finished. Extended information
+ about the gesture is contained in the signal sender object.
+*/
+
+/*! \fn void QGesture::cancelled()
+
+ The signal is emitted when the gesture is cancelled, for example the reset()
+ function is called while the gesture was in the process of emitting a
+ triggered() signal. Extended information about the gesture is contained in
+ the sender object.
+*/
+
+
+/*!
+ Creates a new gesture handler object and marks it as a child of \a parent.
+
+ The \a parent object is also the default event source for the gesture,
+ meaning that the gesture installs itself as an event filter for the \a
+ parent.
+
+ \sa setGraphicsItem()
+*/
+QGesture::QGesture(QObject *parent)
+ : QObject(*new QGesturePrivate, parent)
+{
+ if (parent)
+ parent->installEventFilter(this);
+}
+
+/*! \internal
+ */
+QGesture::QGesture(QGesturePrivate &dd, QObject *parent)
+ : QObject(dd, parent)
+{
+ if (parent)
+ parent->installEventFilter(this);
+}
+
+/*!
+ Destroys the gesture object.
+*/
+QGesture::~QGesture()
+{
+}
+
+/*! \internal
+ */
+bool QGesture::eventFilter(QObject *receiver, QEvent *event)
+{
+ Q_D(QGesture);
+ if (d->graphicsItem && receiver == parent())
+ return false;
+ return filterEvent(event);
+}
+
+/*!
+ \property QGesture::state
+
+ \brief The current state of the gesture.
+*/
+
+/*!
+ Returns the gesture recognition state.
+ */
+Qt::GestureState QGesture::state() const
+{
+ return d_func()->state;
+}
+
+/*!
+ Sets this gesture's recognition state to \a state and emits appropriate
+ signals.
+
+ This functions emits the signals according to the old state and the new
+ \a state, and it should be called after all the internal properties have been
+ initialized.
+
+ \sa started(), triggered(), finished(), cancelled()
+ */
+void QGesture::updateState(Qt::GestureState state)
+{
+ Q_D(QGesture);
+ if (d->state == state) {
+ if (state == Qt::GestureUpdated)
+ emit triggered();
+ return;
+ }
+ const Qt::GestureState oldState = d->state;
+ d->state = state;
+ if (state != Qt::NoGesture && oldState > state) {
+ // comparing the state as ints: state should only be changed from
+ // started to (optionally) updated and to finished.
+ qWarning("QGesture::updateState: incorrect new state");
+ return;
+ }
+ if (oldState == Qt::NoGesture)
+ emit started();
+ if (state == Qt::GestureUpdated)
+ emit triggered();
+ else if (state == Qt::GestureFinished)
+ emit finished();
+ else if (state == Qt::NoGesture)
+ emit cancelled();
+
+ if (state == Qt::GestureFinished) {
+ // gesture is finished, so we reset the internal state.
+ d->state = Qt::NoGesture;
+ }
+}
+
+/*!
+ Sets the \a graphicsItem the gesture is filtering events for.
+
+ The gesture will install an event filter to the \a graphicsItem and
+ redirect them to the filterEvent() function.
+
+ \sa graphicsItem()
+*/
+void QGesture::setGraphicsItem(QGraphicsItem *graphicsItem)
+{
+ Q_D(QGesture);
+ if (d->graphicsItem && d->eventFilterProxyGraphicsItem)
+ d->graphicsItem->removeSceneEventFilter(d->eventFilterProxyGraphicsItem);
+ d->graphicsItem = graphicsItem;
+ if (!d->eventFilterProxyGraphicsItem)
+ d->eventFilterProxyGraphicsItem = new QEventFilterProxyGraphicsItem(this);
+ if (graphicsItem)
+ graphicsItem->installSceneEventFilter(d->eventFilterProxyGraphicsItem);
+}
+
+/*!
+ Returns the graphics item the gesture is filtering events for.
+
+ \sa setGraphicsItem()
+*/
+QGraphicsItem* QGesture::graphicsItem() const
+{
+ return d_func()->graphicsItem;
+}
+
+/*! \fn void QGesture::reset()
+
+ Resets the internal state of the gesture. This function might be called by
+ the filterEvent() implementation in a derived class, or by the user to
+ cancel a gesture. The base class implementation calls
+ updateState(Qt::NoGesture) which emits the cancelled()
+ signal if the state() of the gesture indicated it was active.
+*/
+void QGesture::reset()
+{
+ updateState(Qt::NoGesture);
+}
+
+QT_END_NAMESPACE
diff --git a/doc/src/snippets/gestures/qgesture.h b/doc/src/snippets/gestures/qgesture.h
new file mode 100644
index 000000000..beb3de093
--- /dev/null
+++ b/doc/src/snippets/gestures/qgesture.h
@@ -0,0 +1,101 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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 http://qt.nokia.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGESTURE_H
+#define QGESTURE_H
+
+#include <QtCore/qobject.h>
+#include <QtCore/qlist.h>
+#include <QtCore/qdatetime.h>
+#include <QtCore/qpoint.h>
+#include <QtCore/qrect.h>
+#include <QtCore/qmetatype.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+class QGraphicsItem;
+class QGesturePrivate;
+class Q_GUI_EXPORT QGesture : public QObject
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QGesture)
+
+ Q_PROPERTY(Qt::GestureState state READ state)
+
+public:
+ explicit QGesture(QObject *parent = 0);
+ ~QGesture();
+
+ virtual bool filterEvent(QEvent *event) = 0;
+
+ void setGraphicsItem(QGraphicsItem *);
+ QGraphicsItem *graphicsItem() const;
+
+ Qt::GestureState state() const;
+
+protected:
+ QGesture(QGesturePrivate &dd, QObject *parent);
+ bool eventFilter(QObject*, QEvent*);
+
+ virtual void reset();
+ void updateState(Qt::GestureState state);
+
+//! [qgesture-signals]
+Q_SIGNALS:
+ void started();
+ void triggered();
+ void finished();
+ void cancelled();
+//! [qgesture-signals]
+
+private:
+ friend class QWidget;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QGESTURE_H
diff --git a/doc/src/snippets/gestures/qstandardgestures.cpp b/doc/src/snippets/gestures/qstandardgestures.cpp
new file mode 100644
index 000000000..47f314643
--- /dev/null
+++ b/doc/src/snippets/gestures/qstandardgestures.cpp
@@ -0,0 +1,483 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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 http://qt.nokia.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qstandardgestures.h"
+#include "qstandardgestures_p.h"
+
+#include <qabstractscrollarea.h>
+#include <qscrollbar.h>
+#include <private/qapplication_p.h>
+#include <private/qevent_p.h>
+#include <private/qwidget_p.h>
+
+QT_BEGIN_NAMESPACE
+
+#ifdef Q_WS_WIN
+QWidgetPrivate *qt_widget_private(QWidget *widget);
+#endif
+
+/*!
+ \class QPanGesture
+ \since 4.6
+
+ \brief The QPanGesture class represents a Pan gesture,
+ providing additional information related to panning.
+*/
+
+/*!
+ Creates a new Pan gesture handler object and marks it as a child of \a
+ parent.
+
+ On some platform like Windows it's necessary to provide a non-null widget
+ as \a parent to get native gesture support.
+*/
+QPanGesture::QPanGesture(QWidget *parent)
+ : QGesture(*new QPanGesturePrivate, parent)
+{
+ if (parent) {
+ QApplicationPrivate *qAppPriv = QApplicationPrivate::instance();
+ qAppPriv->widgetGestures[parent].pan = this;
+#ifdef Q_WS_WIN
+ qt_widget_private(parent)->winSetupGestures();
+#endif
+ }
+}
+
+/*! \internal */
+bool QPanGesture::event(QEvent *event)
+{
+ switch (event->type()) {
+ case QEvent::ParentAboutToChange:
+ if (QWidget *w = qobject_cast<QWidget*>(parent())) {
+ QApplicationPrivate::instance()->widgetGestures[w].pan = 0;
+#ifdef Q_WS_WIN
+ qt_widget_private(w)->winSetupGestures();
+#endif
+ }
+ break;
+ case QEvent::ParentChange:
+ if (QWidget *w = qobject_cast<QWidget*>(parent())) {
+ QApplicationPrivate::instance()->widgetGestures[w].pan = this;
+#ifdef Q_WS_WIN
+ qt_widget_private(w)->winSetupGestures();
+#endif
+ }
+ break;
+ default:
+ break;
+ }
+
+#if defined(Q_OS_MAC) && !defined(QT_MAC_USE_COCOA)
+ Q_D(QPanGesture);
+ if (event->type() == QEvent::Timer) {
+ const QTimerEvent *te = static_cast<QTimerEvent *>(event);
+ if (te->timerId() == d->panFinishedTimer) {
+ killTimer(d->panFinishedTimer);
+ d->panFinishedTimer = 0;
+ d->lastOffset = QSize(0, 0);
+ updateState(Qt::GestureFinished);
+ }
+ }
+#endif
+
+ return QObject::event(event);
+}
+
+bool QPanGesture::eventFilter(QObject *receiver, QEvent *event)
+{
+#ifdef Q_WS_WIN
+ Q_D(QPanGesture);
+ if (receiver->isWidgetType() && event->type() == QEvent::NativeGesture) {
+ QNativeGestureEvent *ev = static_cast<QNativeGestureEvent*>(event);
+ QApplicationPrivate *qAppPriv = QApplicationPrivate::instance();
+ QApplicationPrivate::WidgetStandardGesturesMap::iterator it;
+ it = qAppPriv->widgetGestures.find(static_cast<QWidget*>(receiver));
+ if (it == qAppPriv->widgetGestures.end())
+ return false;
+ if (this != it.value().pan)
+ return false;
+ Qt::GestureState nextState = Qt::NoGesture;
+ switch(ev->gestureType) {
+ case QNativeGestureEvent::GestureBegin:
+ // next we might receive the first gesture update event, so we
+ // prepare for it.
+ d->state = Qt::NoGesture;
+ return false;
+ case QNativeGestureEvent::Pan:
+ nextState = Qt::GestureUpdated;
+ event->accept();
+ break;
+ case QNativeGestureEvent::GestureEnd:
+ if (state() == Qt::NoGesture)
+ return false; // some other gesture has ended
+ nextState = Qt::GestureFinished;
+ break;
+ default:
+ return false;
+ }
+ if (state() == Qt::NoGesture) {
+ d->lastOffset = d->totalOffset = QSize();
+ } else {
+ d->lastOffset = QSize(ev->position.x() - d->lastPosition.x(),
+ ev->position.y() - d->lastPosition.y());
+ d->totalOffset += d->lastOffset;
+ }
+ d->lastPosition = ev->position;
+ updateState(nextState);
+ return true;
+ }
+#endif
+ return QGesture::eventFilter(receiver, event);
+}
+
+/*! \internal */
+bool QPanGesture::filterEvent(QEvent *event)
+{
+ Q_D(QPanGesture);
+ if (!event->spontaneous())
+ return false;
+ const QTouchEvent *ev = static_cast<const QTouchEvent*>(event);
+ if (event->type() == QEvent::TouchBegin) {
+ QTouchEvent::TouchPoint p = ev->touchPoints().at(0);
+ d->lastPosition = p.pos().toPoint();
+ d->lastOffset = d->totalOffset = QSize();
+ } else if (event->type() == QEvent::TouchEnd) {
+ if (state() != Qt::NoGesture) {
+ if (!ev->touchPoints().isEmpty()) {
+ QTouchEvent::TouchPoint p = ev->touchPoints().at(0);
+ const QPoint pos = p.pos().toPoint();
+ const QPoint lastPos = p.lastPos().toPoint();
+ const QPoint startPos = p.startPos().toPoint();
+ d->lastOffset = QSize(pos.x() - lastPos.x(), pos.y() - lastPos.y());
+ d->totalOffset = QSize(pos.x() - startPos.x(), pos.y() - startPos.y());
+ }
+ updateState(Qt::GestureFinished);
+ }
+ reset();
+ } else if (event->type() == QEvent::TouchUpdate) {
+ QTouchEvent::TouchPoint p = ev->touchPoints().at(0);
+ const QPoint pos = p.pos().toPoint();
+ const QPoint lastPos = p.lastPos().toPoint();
+ const QPoint startPos = p.startPos().toPoint();
+ d->lastOffset = QSize(pos.x() - lastPos.x(), pos.y() - lastPos.y());
+ d->totalOffset = QSize(pos.x() - startPos.x(), pos.y() - startPos.y());
+ if (d->totalOffset.width() > 10 || d->totalOffset.height() > 10 ||
+ d->totalOffset.width() < -10 || d->totalOffset.height() < -10) {
+ updateState(Qt::GestureUpdated);
+ }
+ }
+#ifdef Q_OS_MAC
+ else if (event->type() == QEvent::Wheel) {
+ // On Mac, there is really no native panning gesture. Instead, a two
+ // finger pan is delivered as mouse wheel events. Otoh, on Windows, you
+ // either get mouse wheel events or pan events. We have decided to make this
+ // the Qt behaviour as well, meaning that on Mac, wheel
+ // events will be masked away when listening for pan events.
+#ifndef QT_MAC_USE_COCOA
+ // In Carbon we receive neither touch-, nor pan gesture events.
+ // So we create pan gestures by converting wheel events. After all, this
+ // is how things are supposed to work on mac in the first place.
+ const QWheelEvent *wev = static_cast<const QWheelEvent*>(event);
+ int offset = wev->delta() / -120;
+ d->lastOffset = wev->orientation() == Qt::Horizontal ? QSize(offset, 0) : QSize(0, offset);
+
+ if (state() == Qt::NoGesture) {
+ d->totalOffset = d->lastOffset;
+ } else {
+ d->totalOffset += d->lastOffset;
+ }
+
+ killTimer(d->panFinishedTimer);
+ d->panFinishedTimer = startTimer(200);
+ updateState(Qt::GestureUpdated);
+#endif
+ return true;
+ }
+#endif
+ return false;
+}
+
+/*! \internal */
+void QPanGesture::reset()
+{
+ Q_D(QPanGesture);
+ d->lastOffset = d->totalOffset = QSize();
+ d->lastPosition = QPoint();
+#if defined(Q_OS_MAC) && !defined(QT_MAC_USE_COCOA)
+ if (d->panFinishedTimer) {
+ killTimer(d->panFinishedTimer);
+ d->panFinishedTimer = 0;
+ }
+#endif
+ QGesture::reset();
+}
+
+/*!
+ \property QPanGesture::totalOffset
+
+ Specifies a total pan offset since the start of the gesture.
+*/
+QSize QPanGesture::totalOffset() const
+{
+ Q_D(const QPanGesture);
+ return d->totalOffset;
+}
+
+/*!
+ \property QPanGesture::lastOffset
+
+ Specifies a pan offset since the last time the gesture was
+ triggered.
+*/
+QSize QPanGesture::lastOffset() const
+{
+ Q_D(const QPanGesture);
+ return d->lastOffset;
+}
+
+
+/*!
+ \class QPinchGesture
+ \since 4.6
+
+ \brief The QPinchGesture class represents a Pinch gesture,
+ providing additional information related to zooming and/or rotation.
+*/
+
+/*!
+ Creates a new Pinch gesture handler object and marks it as a child of \a
+ parent.
+
+ On some platform like Windows it's necessary to provide a non-null widget
+ as \a parent to get native gesture support.
+*/
+QPinchGesture::QPinchGesture(QWidget *parent)
+ : QGesture(*new QPinchGesturePrivate, parent)
+{
+ if (parent) {
+ QApplicationPrivate *qAppPriv = QApplicationPrivate::instance();
+ qAppPriv->widgetGestures[parent].pinch = this;
+#ifdef Q_WS_WIN
+ qt_widget_private(parent)->winSetupGestures();
+#endif
+ }
+}
+
+/*! \internal */
+bool QPinchGesture::event(QEvent *event)
+{
+ switch (event->type()) {
+ case QEvent::ParentAboutToChange:
+ if (QWidget *w = qobject_cast<QWidget*>(parent())) {
+ QApplicationPrivate::instance()->widgetGestures[w].pinch = 0;
+#ifdef Q_WS_WIN
+ qt_widget_private(w)->winSetupGestures();
+#endif
+ }
+ break;
+ case QEvent::ParentChange:
+ if (QWidget *w = qobject_cast<QWidget*>(parent())) {
+ QApplicationPrivate::instance()->widgetGestures[w].pinch = this;
+#ifdef Q_WS_WIN
+ qt_widget_private(w)->winSetupGestures();
+#endif
+ }
+ break;
+ default:
+ break;
+ }
+ return QObject::event(event);
+}
+
+bool QPinchGesture::eventFilter(QObject *receiver, QEvent *event)
+{
+#ifdef Q_WS_WIN
+ Q_D(QPinchGesture);
+ if (receiver->isWidgetType() && event->type() == QEvent::NativeGesture) {
+ QNativeGestureEvent *ev = static_cast<QNativeGestureEvent*>(event);
+ QApplicationPrivate *qAppPriv = QApplicationPrivate::instance();
+ QApplicationPrivate::WidgetStandardGesturesMap::iterator it;
+ it = qAppPriv->widgetGestures.find(static_cast<QWidget*>(receiver));
+ if (it == qAppPriv->widgetGestures.end())
+ return false;
+ if (this != it.value().pinch)
+ return false;
+ Qt::GestureState nextState = Qt::NoGesture;
+ switch(ev->gestureType) {
+ case QNativeGestureEvent::GestureBegin:
+ // next we might receive the first gesture update event, so we
+ // prepare for it.
+ d->state = Qt::NoGesture;
+ d->scaleFactor = d->lastScaleFactor = 1;
+ d->rotationAngle = d->lastRotationAngle = 0;
+ d->startCenterPoint = d->centerPoint = d->lastCenterPoint = QPoint();
+ d->initialDistance = 0;
+ return false;
+ case QNativeGestureEvent::Rotate:
+ d->lastRotationAngle = d->rotationAngle;
+ d->rotationAngle = -1 * GID_ROTATE_ANGLE_FROM_ARGUMENT(ev->argument);
+ nextState = Qt::GestureUpdated;
+ event->accept();
+ break;
+ case QNativeGestureEvent::Zoom:
+ if (d->initialDistance != 0) {
+ d->lastScaleFactor = d->scaleFactor;
+ int distance = int(qint64(ev->argument));
+ d->scaleFactor = (qreal) distance / d->initialDistance;
+ } else {
+ d->initialDistance = int(qint64(ev->argument));
+ }
+ nextState = Qt::GestureUpdated;
+ event->accept();
+ break;
+ case QNativeGestureEvent::GestureEnd:
+ if (state() == Qt::NoGesture)
+ return false; // some other gesture has ended
+ nextState = Qt::GestureFinished;
+ break;
+ default:
+ return false;
+ }
+ if (d->startCenterPoint.isNull())
+ d->startCenterPoint = d->centerPoint;
+ d->lastCenterPoint = d->centerPoint;
+ d->centerPoint = static_cast<QWidget*>(receiver)->mapFromGlobal(ev->position);
+ updateState(nextState);
+ return true;
+ }
+#endif
+ return QGesture::eventFilter(receiver, event);
+}
+
+/*! \internal */
+bool QPinchGesture::filterEvent(QEvent *event)
+{
+ Q_UNUSED(event);
+ return false;
+}
+
+/*! \internal */
+void QPinchGesture::reset()
+{
+ Q_D(QPinchGesture);
+ d->scaleFactor = d->lastScaleFactor = 0;
+ d->rotationAngle = d->lastRotationAngle = 0;
+ d->startCenterPoint = d->centerPoint = d->lastCenterPoint = QPoint();
+ QGesture::reset();
+}
+
+/*!
+ \property QPinchGesture::scaleFactor
+
+ Specifies a scale factor of the pinch gesture.
+*/
+qreal QPinchGesture::scaleFactor() const
+{
+ return d_func()->scaleFactor;
+}
+
+/*!
+ \property QPinchGesture::lastScaleFactor
+
+ Specifies a previous scale factor of the pinch gesture.
+*/
+qreal QPinchGesture::lastScaleFactor() const
+{
+ return d_func()->lastScaleFactor;
+}
+
+/*!
+ \property QPinchGesture::rotationAngle
+
+ Specifies a rotation angle of the gesture.
+*/
+qreal QPinchGesture::rotationAngle() const
+{
+ return d_func()->rotationAngle;
+}
+
+/*!
+ \property QPinchGesture::lastRotationAngle
+
+ Specifies a previous rotation angle of the gesture.
+*/
+qreal QPinchGesture::lastRotationAngle() const
+{
+ return d_func()->lastRotationAngle;
+}
+
+/*!
+ \property QPinchGesture::centerPoint
+
+ Specifies a center point of the gesture. The point can be used as a center
+ point that the object is rotated around.
+*/
+QPoint QPinchGesture::centerPoint() const
+{
+ return d_func()->centerPoint;
+}
+
+/*!
+ \property QPinchGesture::lastCenterPoint
+
+ Specifies a previous center point of the gesture.
+*/
+QPoint QPinchGesture::lastCenterPoint() const
+{
+ return d_func()->lastCenterPoint;
+}
+
+/*!
+ \property QPinchGesture::startCenterPoint
+
+ Specifies an initial center point of the gesture. Difference between the
+ startCenterPoint and the centerPoint is the distance at which pinching
+ fingers has shifted.
+*/
+QPoint QPinchGesture::startCenterPoint() const
+{
+ return d_func()->startCenterPoint;
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qstandardgestures.cpp"
+
diff --git a/doc/src/snippets/gestures/qstandardgestures.h b/doc/src/snippets/gestures/qstandardgestures.h
new file mode 100644
index 000000000..8b5421b66
--- /dev/null
+++ b/doc/src/snippets/gestures/qstandardgestures.h
@@ -0,0 +1,126 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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 http://qt.nokia.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSTANDARDGESTURES_H
+#define QSTANDARDGESTURES_H
+
+#include <QtGui/qevent.h>
+#include <QtCore/qbasictimer.h>
+
+#include <QtGui/qgesture.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+class QPanGesturePrivate;
+class Q_GUI_EXPORT QPanGesture : public QGesture
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QPanGesture)
+
+ Q_PROPERTY(QSize totalOffset READ totalOffset)
+ Q_PROPERTY(QSize lastOffset READ lastOffset)
+
+public:
+ QPanGesture(QWidget *parent);
+
+ bool filterEvent(QEvent *event);
+
+ QSize totalOffset() const;
+ QSize lastOffset() const;
+
+protected:
+ void reset();
+
+private:
+ bool event(QEvent *event);
+ bool eventFilter(QObject *receiver, QEvent *event);
+
+ friend class QWidget;
+};
+
+class QPinchGesturePrivate;
+class Q_GUI_EXPORT QPinchGesture : public QGesture
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QPinchGesture)
+
+ Q_PROPERTY(qreal scaleFactor READ scaleFactor)
+ Q_PROPERTY(qreal lastScaleFactor READ lastScaleFactor)
+
+ Q_PROPERTY(qreal rotationAngle READ rotationAngle)
+ Q_PROPERTY(qreal lastRotationAngle READ lastRotationAngle)
+
+ Q_PROPERTY(QPoint startCenterPoint READ startCenterPoint)
+ Q_PROPERTY(QPoint lastCenterPoint READ lastCenterPoint)
+ Q_PROPERTY(QPoint centerPoint READ centerPoint)
+
+public:
+ QPinchGesture(QWidget *parent);
+
+ bool filterEvent(QEvent *event);
+ void reset();
+
+ QPoint startCenterPoint() const;
+ QPoint lastCenterPoint() const;
+ QPoint centerPoint() const;
+
+ qreal scaleFactor() const;
+ qreal lastScaleFactor() const;
+
+ qreal rotationAngle() const;
+ qreal lastRotationAngle() const;
+
+private:
+ bool event(QEvent *event);
+ bool eventFilter(QObject *receiver, QEvent *event);
+
+ friend class QWidget;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QSTANDARDGESTURES_H