summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDenis Dzyubenko <denis.dzyubenko@nokia.com>2009-02-26 15:39:00 +0100
committerDenis Dzyubenko <denis.dzyubenko@nokia.com>2009-05-11 15:38:54 +0200
commita3d8cfb1ee89e0600add864db53d67552820b95a (patch)
treed396d751de49d26c052b8752c94d5247503083e2
parent7396eea79c9464d0c246106834cbce02320e7989 (diff)
Merge of the maemo-gestures branch onto qt/4.5.0
This is a squashed merge of all of the changes in the maemo-gestures branch on-top of the qt/4.5.0 branch.
-rw-r--r--examples/gestures/gestures.pro11
-rw-r--r--examples/gestures/graphicsview/graphicsview.pro2
-rw-r--r--examples/gestures/graphicsview/main.cpp151
-rw-r--r--examples/gestures/imageviewer/imageviewer.pro12
-rw-r--r--examples/gestures/imageviewer/imagewidget.cpp338
-rw-r--r--examples/gestures/imageviewer/imagewidget.h122
-rw-r--r--examples/gestures/imageviewer/main.cpp88
-rw-r--r--src/corelib/global/qnamespace.h15
-rw-r--r--src/corelib/kernel/qcoreevent.h2
-rw-r--r--src/gui/graphicsview/qgraphicsitem.cpp28
-rw-r--r--src/gui/graphicsview/qgraphicsitem.h3
-rw-r--r--src/gui/graphicsview/qgraphicsitem_p.h2
-rw-r--r--src/gui/graphicsview/qgraphicsscene.cpp62
-rw-r--r--src/gui/graphicsview/qgraphicsscene.h2
-rw-r--r--src/gui/graphicsview/qgraphicsscene_p.h9
-rw-r--r--src/gui/graphicsview/qgraphicsview.cpp9
-rw-r--r--src/gui/kernel/kernel.pri14
-rw-r--r--src/gui/kernel/qapplication.cpp57
-rw-r--r--src/gui/kernel/qapplication.h1
-rw-r--r--src/gui/kernel/qapplication_p.h1
-rw-r--r--src/gui/kernel/qapplication_x11.cpp2
-rw-r--r--src/gui/kernel/qdirectionrecognizer.cpp176
-rw-r--r--src/gui/kernel/qdirectionrecognizer_p.h121
-rw-r--r--src/gui/kernel/qdirectionsimplificator_p.h172
-rw-r--r--src/gui/kernel/qevent.cpp24
-rw-r--r--src/gui/kernel/qevent.h34
-rw-r--r--src/gui/kernel/qgesture.cpp133
-rw-r--r--src/gui/kernel/qgesture.h128
-rw-r--r--src/gui/kernel/qgesture_p.h100
-rw-r--r--src/gui/kernel/qgesturemanager.cpp405
-rw-r--r--src/gui/kernel/qgesturemanager_p.h102
-rw-r--r--src/gui/kernel/qgesturerecognizer.h83
-rw-r--r--src/gui/kernel/qgesturestandardrecognizers.cpp543
-rw-r--r--src/gui/kernel/qgesturestandardrecognizers_p.h169
-rw-r--r--src/gui/kernel/qwidget.cpp45
-rw-r--r--src/gui/kernel/qwidget.h10
-rw-r--r--src/gui/kernel/qwidget_p.h3
-rw-r--r--src/gui/widgets/qabstractscrollarea.cpp1
38 files changed, 3174 insertions, 6 deletions
diff --git a/examples/gestures/gestures.pro b/examples/gestures/gestures.pro
new file mode 100644
index 000000000..1e0f1a73e
--- /dev/null
+++ b/examples/gestures/gestures.pro
@@ -0,0 +1,11 @@
+TEMPLATE = \
+ subdirs
+SUBDIRS = \
+ imageviewer \
+ graphicsview
+
+# install
+target.path = $$[QT_INSTALL_EXAMPLES]/gestures
+sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS gestures.pro README
+sources.path = $$[QT_INSTALL_EXAMPLES]/gestures
+INSTALLS += target sources
diff --git a/examples/gestures/graphicsview/graphicsview.pro b/examples/gestures/graphicsview/graphicsview.pro
new file mode 100644
index 000000000..9cef5643f
--- /dev/null
+++ b/examples/gestures/graphicsview/graphicsview.pro
@@ -0,0 +1,2 @@
+SOURCES = main.cpp
+
diff --git a/examples/gestures/graphicsview/main.cpp b/examples/gestures/graphicsview/main.cpp
new file mode 100644
index 000000000..a0236ef6d
--- /dev/null
+++ b/examples/gestures/graphicsview/main.cpp
@@ -0,0 +1,151 @@
+/****************************************************************************
+**
+** 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 <QtGui>
+
+class PannableGraphicsView : public QGraphicsView
+{
+public:
+ PannableGraphicsView()
+ {
+ grabGesture(Qt::Pan);
+ }
+protected:
+ bool event(QEvent *event)
+ {
+ if (event->type() == QEvent::Gesture) {
+ QGestureEvent *ge = static_cast<QGestureEvent*>(event);
+ if (const QGesture *g = ge->gesture(Qt::Pan)) {
+ QPoint pt = g->pos() - g->lastPos();
+ horizontalScrollBar()->setValue(horizontalScrollBar()->value() - pt.x());
+ verticalScrollBar()->setValue(verticalScrollBar()->value() - pt.y());
+ event->accept();
+ return true;
+ }
+ }
+ return QGraphicsView::event(event);
+ }
+};
+
+class ImageItem : public QGraphicsItem
+{
+public:
+ ImageItem()
+ : colored(false)
+ {
+ grabGesture(Qt::DoubleTap);
+ }
+
+ QRectF boundingRect() const
+ {
+ return pixmap.isNull() ? QRectF(0, 0, 100, 100)
+ : QRectF(QPointF(0,0), QSizeF(pixmap.size()));
+ }
+
+ void paint(QPainter *painter, const QStyleOptionGraphicsItem*, QWidget*)
+ {
+ if (pixmap.isNull()) {
+ painter->setBrush(QBrush( colored ? Qt::green : Qt::white));
+ painter->drawRect(0, 0, 100, 100);
+ painter->drawLine(0, 0, 100, 100);
+ painter->drawLine(0, 100, 100, 0);
+ return;
+ }
+ painter->drawPixmap(0, 0, pixmap);
+ }
+
+ bool sceneEvent(QEvent *event)
+ {
+ if (event->type() == QEvent::Gesture) {
+ QGestureEvent *gestureEvent = static_cast<QGestureEvent*>(event);
+ if (gestureEvent->gesture(Qt::DoubleTap)) {
+ event->accept();
+ colored = !colored;
+ update();
+ return true;
+ } else {
+ qWarning("Item received unknown gesture");
+ }
+ }
+ return QGraphicsItem::sceneEvent(event);
+ }
+
+private:
+ QPixmap pixmap;
+ bool colored;
+};
+
+class MainWidget : public QWidget
+{
+ Q_OBJECT
+
+public:
+ MainWidget(QWidget *parent = 0)
+ : QWidget(parent)
+ {
+ QVBoxLayout *l = new QVBoxLayout(this);
+ view = new PannableGraphicsView;
+ l->addWidget(view);
+ scene = new QGraphicsScene(0, 0, 1024, 768, view);
+ view->setScene(scene);
+
+ ImageItem *item = new ImageItem;
+ scene->addItem(item);
+ item->setPos(scene->width()/3, scene->height()/3);
+ }
+
+signals:
+public slots:
+private:
+ QGraphicsView *view;
+ QGraphicsScene *scene;
+};
+
+int main(int argc, char *argv[])
+{
+ QApplication app(argc, argv);
+ QApplication::setAttribute(Qt::AA_EnableGestures);
+ MainWidget w;
+ w.show();
+ return app.exec();
+}
+
+#include "main.moc"
diff --git a/examples/gestures/imageviewer/imageviewer.pro b/examples/gestures/imageviewer/imageviewer.pro
new file mode 100644
index 000000000..4c35dcec2
--- /dev/null
+++ b/examples/gestures/imageviewer/imageviewer.pro
@@ -0,0 +1,12 @@
+######################################################################
+# Automatically generated by qmake (2.01a) Thu Sep 11 17:18:17 2008
+######################################################################
+
+TEMPLATE = app
+TARGET =
+DEPENDPATH += .
+INCLUDEPATH += .
+
+# Input
+HEADERS += imagewidget.h
+SOURCES += imagewidget.cpp main.cpp
diff --git a/examples/gestures/imageviewer/imagewidget.cpp b/examples/gestures/imageviewer/imagewidget.cpp
new file mode 100644
index 000000000..8932e297d
--- /dev/null
+++ b/examples/gestures/imageviewer/imagewidget.cpp
@@ -0,0 +1,338 @@
+/****************************************************************************
+**
+** 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 "imagewidget.h"
+
+#include <QtGui>
+
+ImageWidget::ImageWidget(QWidget *parent)
+ : QWidget(parent)
+{
+ setAttribute(Qt::WA_PaintOnScreen);
+ setAttribute(Qt::WA_OpaquePaintEvent);
+ setAttribute(Qt::WA_NoSystemBackground);
+
+ setObjectName("ImageWidget");
+
+ setMinimumSize(QSize(100,100));
+
+ position = 0;
+ zoomed = rotated = false;
+
+ zoomedIn = false;
+ horizontalOffset = 0;
+ verticalOffset = 0;
+
+ grabGesture(Qt::DoubleTap);
+ grabGesture(Qt::Pan);
+ grabGesture(Qt::LongTap);
+}
+
+void ImageWidget::paintEvent(QPaintEvent*)
+{
+ QPainter p(this);
+ if (currentImage.isNull()) {
+ p.fillRect(geometry(), Qt::white);
+ return;
+ }
+ int hoffset = 0;
+ int voffset = 0;
+ const int w = pixmap.width();
+ const int h = pixmap.height();
+ p.save();
+ if (zoomedIn) {
+ hoffset = horizontalOffset;
+ voffset = verticalOffset;
+ if (horizontalOffset > 0)
+ p.fillRect(0, 0, horizontalOffset, height(), Qt::white);
+ if (verticalOffset > 0)
+ p.fillRect(0, 0, width(), verticalOffset, Qt::white);
+ }
+ p.drawPixmap(hoffset, voffset, pixmap);
+ if (hoffset + w < width())
+ p.fillRect(hoffset + w, 0, width() - w - hoffset, height(), Qt::white);
+ if (voffset + h < height())
+ p.fillRect(0, voffset + h, width(), height() - h - voffset, Qt::white);
+
+ // paint touch feedback
+ if (touchFeedback.tapped || touchFeedback.doubleTapped) {
+ p.setPen(QPen(Qt::gray, 2));
+ p.drawEllipse(touchFeedback.position, 5, 5);
+ if (touchFeedback.doubleTapped) {
+ p.setPen(QPen(Qt::gray, 2, Qt::DotLine));
+ p.drawEllipse(touchFeedback.position, 15, 15);
+ } else if (touchFeedback.tapAndHoldState != 0) {
+ QPoint pts[8] = {
+ touchFeedback.position + QPoint( 0, -15),
+ touchFeedback.position + QPoint( 10, -10),
+ touchFeedback.position + QPoint( 15, 0),
+ touchFeedback.position + QPoint( 10, 10),
+ touchFeedback.position + QPoint( 0, 15),
+ touchFeedback.position + QPoint(-10, 10),
+ touchFeedback.position + QPoint(-15, 0)
+ };
+ for (int i = 0; i < (touchFeedback.tapAndHoldState-20)/10; ++i)
+ p.drawEllipse(pts[i], 3, 3);
+ }
+ } else if (touchFeedback.sliding) {
+ p.setPen(QPen(Qt::red, 3));
+ QPoint endPos = QPoint(touchFeedback.position.x(), touchFeedback.slidingStartPosition.y());
+ p.drawLine(touchFeedback.slidingStartPosition, endPos);
+ int dx = 10;
+ if (touchFeedback.slidingStartPosition.x() < endPos.x())
+ dx = -1*dx;
+ p.drawLine(endPos, endPos + QPoint(dx, 5));
+ p.drawLine(endPos, endPos + QPoint(dx, -5));
+ }
+
+ for (int i = 0; i < TouchFeedback::MaximumNumberOfTouches; ++i) {
+ if (touchFeedback.touches[i].isNull())
+ break;
+ p.drawEllipse(touchFeedback.touches[i], 10, 10);
+ }
+ p.restore();
+}
+
+void ImageWidget::gestureEvent(QGestureEvent *event)
+{
+ touchFeedback.doubleTapped = false;
+
+ Q_ASSERT(event);
+ if (event->contains(Qt::Tap)) {
+ //
+ } else if (const QGesture *g = event->gesture(Qt::DoubleTap)) {
+ touchFeedback.doubleTapped = true;
+ horizontalOffset = g->hotSpot().x() - currentImage.width()*1.0*g->hotSpot().x()/width();
+ verticalOffset = g->hotSpot().y() - currentImage.height()*1.0*g->hotSpot().y()/height();
+ setZoomedIn(!zoomedIn);
+ zoomed = rotated = false;
+ updateImage();
+ } else if (const QGesture *g = event->gesture(Qt::Pan)) {
+ if (zoomedIn) {
+ // usual panning
+ if (g->state() == Qt::GestureStarted)
+ setCursor(Qt::SizeAllCursor);
+ else
+ setCursor(Qt::ArrowCursor);
+ const int dx = g->pos().x() - g->lastPos().x();
+ const int dy = g->pos().y() - g->lastPos().y();
+ horizontalOffset += dx;
+ verticalOffset += dy;
+ update();
+ } else {
+ // only slide gesture should be accepted
+ const QPannableGesture *pg = dynamic_cast<const QPannableGesture*>(g);
+ if (pg && pg->direction() != pg->lastDirection()) {
+ // ###: event->cancel();
+ }
+ if (g->state() == Qt::GestureFinished) {
+ touchFeedback.sliding = false;
+ zoomed = rotated = false;
+ if (pg->direction() == QPannableGesture::Right) {
+ qDebug() << "slide right";
+ goNextImage();
+ } else if (pg->direction() == QPannableGesture::Left) {
+ qDebug() << "slide left";
+ goPrevImage();
+ }
+ updateImage();
+ }
+ }
+ } else if (const QGesture *g = event->gesture(Qt::LongTap)) {
+ if (g->state() == Qt::GestureFinished) {
+ qDebug() << "tap and hold detected";
+ touchFeedback.reset();
+ update();
+
+ QMenu menu;
+ menu.addAction("Action 1");
+ menu.addAction("Action 2");
+ menu.addAction("Action 3");
+ menu.exec(mapToGlobal(g->hotSpot()));
+ }
+ } else if (const QGesture *g = event->gesture(Qt::LongTap)) {
+ qDebug() << "long tap: " << (g->state() == Qt::GestureStarted ? "started" : "finished");
+ } else {
+ qDebug() << "unknown gesture";
+ }
+ feedbackFadeOutTimer.start(500, this);
+ event->accept();
+}
+
+void ImageWidget::resizeEvent(QResizeEvent*)
+{
+ updateImage();
+}
+
+void ImageWidget::updateImage()
+{
+ // should use qtconcurrent here?
+ transformation = QTransform();
+ if (zoomedIn) {
+ } else {
+ if (currentImage.isNull())
+ return;
+ if (zoomed) {
+ transformation = transformation.scale(zoom, zoom);
+ } else {
+ double xscale = (double)width()/currentImage.width();
+ double yscale = (double)height()/currentImage.height();
+ if (xscale < yscale)
+ yscale = xscale;
+ else
+ xscale = yscale;
+ transformation = transformation.scale(xscale, yscale);
+ }
+ if (rotated)
+ transformation = transformation.rotate(angle);
+ }
+ pixmap = QPixmap::fromImage(currentImage).transformed(transformation);
+ update();
+}
+
+void ImageWidget::openDirectory(const QString &path)
+{
+ this->path = path;
+ QDir dir(path);
+ QStringList nameFilters;
+ nameFilters << "*.jpg" << "*.png";
+ files = dir.entryList(nameFilters, QDir::Files|QDir::Readable, QDir::Name);
+
+ position = 0;
+ goToImage(0);
+ updateImage();
+}
+
+QImage ImageWidget::loadImage(const QString &fileName)
+{
+ QImageReader reader(fileName);
+ if (!reader.canRead()) {
+ qDebug() << fileName << ": can't load image";
+ return QImage();
+ }
+ QImage image;
+ if (!reader.read(&image)) {
+ qDebug() << fileName << ": corrupted image";
+ return QImage();
+ }
+ return image;
+}
+
+void ImageWidget::setZoomedIn(bool zoomed)
+{
+ zoomedIn = zoomed;
+}
+
+void ImageWidget::goNextImage()
+{
+ if (files.isEmpty())
+ return;
+ if (position < files.size()-1) {
+ ++position;
+ prevImage = currentImage;
+ currentImage = nextImage;
+ if (position+1 < files.size())
+ nextImage = loadImage(path+QLatin1String("/")+files.at(position+1));
+ else
+ nextImage = QImage();
+ }
+ setZoomedIn(false);
+ updateImage();
+}
+
+void ImageWidget::goPrevImage()
+{
+ if (files.isEmpty())
+ return;
+ if (position > 0) {
+ --position;
+ nextImage = currentImage;
+ currentImage = prevImage;
+ if (position > 0)
+ prevImage = loadImage(path+QLatin1String("/")+files.at(position-1));
+ else
+ prevImage = QImage();
+ }
+ setZoomedIn(false);
+ updateImage();
+}
+
+void ImageWidget::goToImage(int index)
+{
+ if (files.isEmpty())
+ return;
+ if (index < 0 || index >= files.size()) {
+ qDebug() << "goToImage: invalid index: " << index;
+ return;
+ }
+ if (index == position+1) {
+ goNextImage();
+ return;
+ }
+ if (position > 0 && index == position-1) {
+ goPrevImage();
+ return;
+ }
+ position = index;
+ pixmap = QPixmap();
+ if (index > 0)
+ prevImage = loadImage(path+QLatin1String("/")+files.at(position-1));
+ else
+ prevImage = QImage();
+ currentImage = loadImage(path+QLatin1String("/")+files.at(position));
+ if (position+1 < files.size())
+ nextImage = loadImage(path+QLatin1String("/")+files.at(position+1));
+ else
+ nextImage = QImage();
+ setZoomedIn(false);
+ updateImage();
+}
+
+void ImageWidget::timerEvent(QTimerEvent *event)
+{
+ if (event->timerId() == touchFeedback.tapTimer.timerId()) {
+ touchFeedback.tapTimer.stop();
+ } else if (event->timerId() == feedbackFadeOutTimer.timerId()) {
+ feedbackFadeOutTimer.stop();
+ touchFeedback.reset();
+ }
+ update();
+}
diff --git a/examples/gestures/imageviewer/imagewidget.h b/examples/gestures/imageviewer/imagewidget.h
new file mode 100644
index 000000000..56fcb4055
--- /dev/null
+++ b/examples/gestures/imageviewer/imagewidget.h
@@ -0,0 +1,122 @@
+/****************************************************************************
+**
+** 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 IMAGEWIDGET_H
+#define IMAGEWIDGET_H
+
+#include <QWidget>
+#include <QImage>
+#include <QPixmap>
+
+#include <QtGui>
+
+class ImageWidget : public QWidget
+{
+public:
+ ImageWidget(QWidget *parent = 0);
+
+ void openDirectory(const QString &path);
+
+protected:
+ void paintEvent(QPaintEvent*);
+ void gestureEvent(QGestureEvent *event);
+ void resizeEvent(QResizeEvent*);
+ void timerEvent(QTimerEvent*);
+
+private:
+ void updateImage();
+ QImage loadImage(const QString &fileName);
+ void loadImage();
+ void setZoomedIn(bool zoomed);
+ void goNextImage();
+ void goPrevImage();
+ void goToImage(int index);
+
+ QString path;
+ QStringList files;
+ int position;
+
+ QImage prevImage, nextImage;
+ QImage currentImage;
+ QPixmap pixmap;
+ QTransform transformation;
+
+ bool zoomedIn;
+ int horizontalOffset;
+ int verticalOffset;
+
+ bool zoomed;
+ qreal zoom;
+ bool rotated;
+ qreal angle;
+
+ struct TouchFeedback
+ {
+ bool tapped;
+ QPoint position;
+ bool sliding;
+ QPoint slidingStartPosition;
+ QBasicTimer tapTimer;
+ int tapState;
+ bool doubleTapped;
+ int tapAndHoldState;
+
+ enum { MaximumNumberOfTouches = 5 };
+ QPoint touches[MaximumNumberOfTouches];
+
+ inline TouchFeedback() { reset(); }
+ inline void reset()
+ {
+ tapped = false;
+ sliding = false;
+ tapTimer.stop();
+ tapState = 0;
+ doubleTapped = false;
+ tapAndHoldState = 0;
+ for (int i = 0; i < MaximumNumberOfTouches; ++i) {
+ touches[i] = QPoint();
+ }
+ }
+ } touchFeedback;
+ QBasicTimer feedbackFadeOutTimer;
+};
+
+#endif
diff --git a/examples/gestures/imageviewer/main.cpp b/examples/gestures/imageviewer/main.cpp
new file mode 100644
index 000000000..5494b1236
--- /dev/null
+++ b/examples/gestures/imageviewer/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 <QtGui>
+
+#include "imagewidget.h"
+
+class MainWidget : public QMainWindow
+{
+ Q_OBJECT
+
+public:
+ MainWidget(QWidget *parent = 0);
+
+public slots:
+ void openDirectory(const QString &path);
+
+private:
+ bool loadImage(const QString &fileName);
+
+ ImageWidget *imageWidget;
+};
+
+MainWidget::MainWidget(QWidget *parent)
+ : QMainWindow(parent)
+{
+ resize(400, 300);
+ imageWidget = new ImageWidget(this);
+ setCentralWidget(imageWidget);
+}
+
+void MainWidget::openDirectory(const QString &path)
+{
+ imageWidget->openDirectory(path);
+}
+
+int main(int argc, char *argv[])
+{
+ QApplication app(argc, argv);
+ QApplication::setAttribute(Qt::AA_EnableGestures);
+
+ MainWidget w;
+ w.show();
+
+ if (QApplication::arguments().size() > 1)
+ w.openDirectory(QApplication::arguments().at(1));
+ return app.exec();
+}
+
+#include "main.moc"
diff --git a/src/corelib/global/qnamespace.h b/src/corelib/global/qnamespace.h
index 1635f8a9e..5747c3c62 100644
--- a/src/corelib/global/qnamespace.h
+++ b/src/corelib/global/qnamespace.h
@@ -1550,6 +1550,21 @@ public:
TouchPointStationary,
TouchPointReleased
};
+
+ typedef QString GestureType;
+ static const char UnknownGesture[] = "???";
+ static const char Tap[] = "Tap";
+ static const char DoubleTap[] = "DoubleTap";
+ static const char LongTap[] = "LongTap";
+ static const char Pan[] = "Pan";
+ static const char Pinch[] = "Pinch";
+
+ enum GestureState
+ {
+ GestureStarted = 0,
+ GestureFinished = 1
+ };
+
}
#ifdef Q_MOC_RUN
;
diff --git a/src/corelib/kernel/qcoreevent.h b/src/corelib/kernel/qcoreevent.h
index 42a75f8d6..c9f9f242c 100644
--- a/src/corelib/kernel/qcoreevent.h
+++ b/src/corelib/kernel/qcoreevent.h
@@ -273,6 +273,8 @@ public:
GraphicsSceneTouchUpdate = 197,
GraphicsSceneTouchEnd = 198,
+ Gesture = 191,
+
// 512 reserved for Qt Jambi's MetaCall event
// 513 reserved for Qt Jambi's DeleteOnMainThread event
diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp
index 3eef396fc..58f04f067 100644
--- a/src/gui/graphicsview/qgraphicsitem.cpp
+++ b/src/gui/graphicsview/qgraphicsitem.cpp
@@ -5788,6 +5788,20 @@ QVariant QGraphicsItem::inputMethodQuery(Qt::InputMethodQuery query) const
return QVariant();
}
+void QGraphicsItem::grabGesture(const Qt::GestureType &type)
+{
+ d_ptr->gestures.insert(type);
+ if (d_ptr->scene)
+ d_ptr->scene->d_func()->grabGesture(this, type);
+}
+
+void QGraphicsItem::releaseGesture(const Qt::GestureType &type)
+{
+ d_ptr->gestures.remove(type);
+ if (d_ptr->scene)
+ d_ptr->scene->d_func()->releaseGesture(this, type);
+}
+
/*!
This virtual function is called by QGraphicsItem to notify custom items
that some part of the item's state changes. By reimplementing this
@@ -5812,6 +5826,20 @@ QVariant QGraphicsItem::inputMethodQuery(Qt::InputMethodQuery query) const
QVariant QGraphicsItem::itemChange(GraphicsItemChange change, const QVariant &value)
{
Q_UNUSED(change);
+ if (change == QGraphicsItem::ItemSceneChange) {
+ if (!qVariantValue<QGraphicsScene*>(value)) {
+ // the item has been removed from a scene, unsubscribe gestures.
+ Q_ASSERT(d_ptr->scene);
+ foreach(const Qt::GestureType &gesture, d_ptr->gestures)
+ d_ptr->scene->d_func()->releaseGesture(this, gesture);
+ }
+ } else if (change == QGraphicsItem::ItemSceneHasChanged) {
+ if (QGraphicsScene *scene = qVariantValue<QGraphicsScene*>(value)) {
+ // item has been added to the scene
+ foreach(const Qt::GestureType &gesture, d_ptr->gestures)
+ scene->d_func()->grabGesture(this, gesture);
+ }
+ }
return value;
}
diff --git a/src/gui/graphicsview/qgraphicsitem.h b/src/gui/graphicsview/qgraphicsitem.h
index ec3373a31..42a5110e7 100644
--- a/src/gui/graphicsview/qgraphicsitem.h
+++ b/src/gui/graphicsview/qgraphicsitem.h
@@ -338,6 +338,9 @@ public:
QVariant data(int key) const;
void setData(int key, const QVariant &value);
+ void grabGesture(const Qt::GestureType &type);
+ void releaseGesture(const Qt::GestureType &type);
+
enum {
Type = 1,
UserType = 65536
diff --git a/src/gui/graphicsview/qgraphicsitem_p.h b/src/gui/graphicsview/qgraphicsitem_p.h
index 5e77dfdef..a67a49ae4 100644
--- a/src/gui/graphicsview/qgraphicsitem_p.h
+++ b/src/gui/graphicsview/qgraphicsitem_p.h
@@ -54,6 +54,7 @@
//
#include "qgraphicsitem.h"
+#include "qset.h"
#if !defined(QT_NO_GRAPHICSVIEW) || (QT_EDITION & QT_MODULE_GRAPHICSVIEW) != QT_MODULE_GRAPHICSVIEW
@@ -297,6 +298,7 @@ public:
int siblingIndex;
int index;
int depth;
+ QSet<Qt::GestureType> gestures;
// Packed 32 bytes
quint32 acceptedMouseButtons : 5;
diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp
index f32230506..fe6dde13b 100644
--- a/src/gui/graphicsview/qgraphicsscene.cpp
+++ b/src/gui/graphicsview/qgraphicsscene.cpp
@@ -3950,6 +3950,9 @@ bool QGraphicsScene::event(QEvent *event)
// geometries that do not have an explicit style set.
update();
break;
+ case QEvent::Gesture:
+ gestureEvent(static_cast<QGestureEvent*>(event));
+ break;
case QEvent::GraphicsSceneTouchBegin:
d->touchBeginEvent(static_cast<QGraphicsSceneTouchEvent *>(event));
break;
@@ -5586,6 +5589,65 @@ void QGraphicsScene::setActiveWindow(QGraphicsWidget *widget)
}
}
+void QGraphicsScenePrivate::addView(QGraphicsView *view)
+{
+ views << view;
+ foreach(const Qt::GestureType &gesture, grabbedGestures)
+ view->grabGesture(gesture);
+}
+
+void QGraphicsScenePrivate::removeView(QGraphicsView *view)
+{
+ views.removeAll(view);
+ foreach(const Qt::GestureType &gesture, grabbedGestures)
+ view->releaseGesture(gesture);
+}
+
+void QGraphicsScenePrivate::sendGestureEvent(QGraphicsItem *item, QGestureEvent *event)
+{
+ //### TODO: position translation
+ sendEvent(item, event);
+}
+
+void QGraphicsScene::gestureEvent(QGestureEvent *event)
+{
+ Q_D(QGraphicsScene);
+ QList<Qt::GestureType> gestureTypes = event->gestureTypes();
+ QList<QPointF> pts;
+ QGraphicsView *view = qobject_cast<QGraphicsView*>(event->targetWidget());
+ if (!view) {
+ // something is wrong.
+ Q_ASSERT(view);
+ return;
+ }
+ foreach(const Qt::GestureType &type, gestureTypes)
+ pts << view->mapToScene(event->gesture(type)->hotSpot());
+ foreach(QGraphicsItem *item, d->itemsWithGestures) {
+ for (int i = 0; i < pts.size(); ++i) {
+ if (item->contains(item->mapFromScene(pts.at(i)))) {
+ d->sendGestureEvent(item, event);
+ if (event->isAccepted())
+ break;
+ }
+ }
+ }
+}
+
+void QGraphicsScenePrivate::grabGesture(QGraphicsItem *item, const Qt::GestureType &type)
+{
+ if (!grabbedGestures.contains(type)) {
+ foreach(QGraphicsView *view, views)
+ view->grabGesture(type);
+ }
+ itemsWithGestures << item;
+ grabbedGestures << type;
+}
+
+void QGraphicsScenePrivate::releaseGesture(QGraphicsItem *item, const Qt::GestureType &type)
+{
+ //###
+}
+
// ### FIXME: the code for touch event support is mosly copied from
// ### QGraphicsScenePrivate::mousePressEventHandler() and friends, need to
// ### refactor to reduce code duplication
diff --git a/src/gui/graphicsview/qgraphicsscene.h b/src/gui/graphicsview/qgraphicsscene.h
index 9802f8755..4680455b8 100644
--- a/src/gui/graphicsview/qgraphicsscene.h
+++ b/src/gui/graphicsview/qgraphicsscene.h
@@ -50,6 +50,7 @@
#include <QtGui/qtransform.h>
#include <QtGui/qmatrix.h>
#include <QtGui/qpen.h>
+#include <QtGui/qevent.h>
QT_BEGIN_HEADER
@@ -254,6 +255,7 @@ protected:
virtual void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event);
virtual void wheelEvent(QGraphicsSceneWheelEvent *event);
virtual void inputMethodEvent(QInputMethodEvent *event);
+ virtual void gestureEvent(QGestureEvent *event);
virtual void drawBackground(QPainter *painter, const QRectF &rect);
virtual void drawForeground(QPainter *painter, const QRectF &rect);
diff --git a/src/gui/graphicsview/qgraphicsscene_p.h b/src/gui/graphicsview/qgraphicsscene_p.h
index de392057e..cea0553d6 100644
--- a/src/gui/graphicsview/qgraphicsscene_p.h
+++ b/src/gui/graphicsview/qgraphicsscene_p.h
@@ -182,6 +182,9 @@ public:
void storeMouseButtonsForMouseGrabber(QGraphicsSceneMouseEvent *event);
QList<QGraphicsView *> views;
+ void addView(QGraphicsView *view);
+ void removeView(QGraphicsView *view);
+
bool painterStateProtection;
QMultiMap<QGraphicsItem *, QGraphicsItem *> sceneEventFilters;
@@ -264,6 +267,12 @@ public:
void resolvePalette();
void updatePalette(const QPalette &palette);
+ QSet<QGraphicsItem*> itemsWithGestures;
+ QSet<Qt::GestureType> grabbedGestures;
+ void grabGesture(QGraphicsItem *item, const Qt::GestureType &type);
+ void releaseGesture(QGraphicsItem *item, const Qt::GestureType &type);
+ void sendGestureEvent(QGraphicsItem *item, QGestureEvent *event);
+
mutable QVector<QTransform> sceneTransformCache;
mutable QBitArray validTransforms;
mutable QVector<int> freeSceneTransformSlots;
diff --git a/src/gui/graphicsview/qgraphicsview.cpp b/src/gui/graphicsview/qgraphicsview.cpp
index 1aaaab9e0..acce71747 100644
--- a/src/gui/graphicsview/qgraphicsview.cpp
+++ b/src/gui/graphicsview/qgraphicsview.cpp
@@ -1690,7 +1690,7 @@ void QGraphicsView::setScene(QGraphicsScene *scene)
this, SLOT(updateScene(QList<QRectF>)));
disconnect(d->scene, SIGNAL(sceneRectChanged(QRectF)),
this, SLOT(updateSceneRect(QRectF)));
- d->scene->d_func()->views.removeAll(this);
+ d->scene->d_func()->removeView(this);
}
// Assign the new scene and update the contents (scrollbars, etc.)).
@@ -1698,7 +1698,7 @@ void QGraphicsView::setScene(QGraphicsScene *scene)
connect(d->scene, SIGNAL(sceneRectChanged(QRectF)),
this, SLOT(updateSceneRect(QRectF)));
d->updateSceneSlotReimplementedChecked = false;
- d->scene->d_func()->views << this;
+ d->scene->d_func()->addView(this);
d->recalculateContentSize();
d->lastCenterPoint = sceneRect().center();
d->keepLastCenterPoint = true;
@@ -2860,6 +2860,11 @@ bool QGraphicsView::event(QEvent *event)
}
}
break;
+ case QEvent::Gesture:
+ QApplication::sendEvent(d->scene, event);
+ if (event->isAccepted())
+ return true;
+ break;
default:
break;
}
diff --git a/src/gui/kernel/kernel.pri b/src/gui/kernel/kernel.pri
index a1b982a1a..b6ef6b21c 100644
--- a/src/gui/kernel/kernel.pri
+++ b/src/gui/kernel/kernel.pri
@@ -41,7 +41,13 @@ HEADERS += \
kernel/qwidgetaction.h \
kernel/qwidgetaction_p.h \
kernel/qwindowdefs.h \
- kernel/qkeymapper_p.h
+ kernel/qkeymapper_p.h \
+ kernel/qgesture.h \
+ kernel/qgesturemanager_p.h \
+ kernel/qgesturerecognizer.h \
+ kernel/qgesturestandardrecognizers_p.h \
+ kernel/qdirectionrecognizer_p.h \
+ kernel/qdirectionsimplificator_p.h
SOURCES += \
kernel/qaction.cpp \
@@ -70,7 +76,11 @@ SOURCES += \
kernel/qwhatsthis.cpp \
kernel/qwidget.cpp \
kernel/qwidgetaction.cpp \
- kernel/qkeymapper.cpp
+ kernel/qkeymapper.cpp \
+ kernel/qgesture.cpp \
+ kernel/qgesturemanager.cpp \
+ kernel/qgesturestandardrecognizers.cpp \
+ kernel/qdirectionrecognizer.cpp
win32 {
DEFINES += QT_NO_DIRECTDRAW
diff --git a/src/gui/kernel/qapplication.cpp b/src/gui/kernel/qapplication.cpp
index 1f4e1fe43..b39cbc34c 100644
--- a/src/gui/kernel/qapplication.cpp
+++ b/src/gui/kernel/qapplication.cpp
@@ -90,6 +90,8 @@
#include "qapplication.h"
+#include <private/qgesturemanager_p.h>
+
#ifdef Q_WS_WINCE
#include "qdatetime.h"
#include "qguifunctions_wince.h"
@@ -98,6 +100,8 @@ extern bool qt_wince_is_mobile(); //qguifunctions_wince.cpp
extern bool qt_wince_is_pocket_pc(); //qguifunctions_wince.cpp
#endif
+#include "qdatetime.h"
+
//#define ALIEN_DEBUG
static void initResources()
@@ -133,6 +137,8 @@ int QApplicationPrivate::autoMaximizeThreshold = -1;
bool QApplicationPrivate::autoSipEnabled = false;
#endif
+QGestureManager *gestureManager = 0;
+
QApplicationPrivate::QApplicationPrivate(int &argc, char **argv, QApplication::Type type)
: QCoreApplicationPrivate(argc, argv)
{
@@ -3700,6 +3706,27 @@ bool QApplication::notify(QObject *receiver, QEvent *e)
QMouseEvent* mouse = static_cast<QMouseEvent*>(e);
QPoint relpos = mouse->pos();
+ if (QApplication::testAttribute(Qt::AA_EnableGestures)) {
+ if (!gestureManager)
+ gestureManager = new QGestureManager;
+ // if we are in gesture mode, we send all mouse events
+ // directly to gesture recognizer.
+ if (gestureManager->inGestureMode()) {
+ // ### should I send events through all application event filters?
+ if (gestureManager->filterEvent(e))
+ return true;
+ }
+ if (w && (mouse->type() != QEvent::MouseMove || mouse->buttons() != 0)) {
+ // find the gesture target widget
+ QWidget *target = w;
+ while (target && target->gestures().isEmpty())
+ target = target->parentWidget();
+ if (target) {
+ gestureManager->setGestureTargetWidget(target);
+ res = gestureManager->filterEvent(e);
+ }
+ }
+ }
if (e->spontaneous()) {
if (e->type() == QEvent::MouseButtonPress) {
QApplicationPrivate::giveFocusAccordingToFocusPolicy(w,
@@ -3993,6 +4020,35 @@ bool QApplication::notify(QObject *receiver, QEvent *e)
}
break;
#endif
+
+ case QEvent::Gesture: {
+ QWidget *w = static_cast<QWidget*>(receiver);
+ QGestureEvent *g = static_cast<QGestureEvent*>(e);
+ bool eventAccepted = g->isAccepted();
+ // Q_ASSERT(g->gesture() != 0);
+ // const QGesture &gesture = *g->gesture();
+ QPoint relPos(0,0);
+ while (w) {
+ // QGesture qge(gesture.gestureType(), gesture.startPos()+relPos, gesture.lastPos()+relPos,
+ // gesture.currentPos()+relPos, gesture.direction(), gesture.rect().translated(relPos),
+ // gesture.hotSpot()+relPos, gesture.state(), gesture.startTime());
+ // QGestureEvent ge(&qge, false);
+ // ### TODO: fix widget-relative positions in gesture event.
+ QGestureEvent ge = *g;
+ ge.m_targetWidget = w;
+ ge.spont = g->spontaneous();
+ res = d->notify_helper(w, w == receiver ? g : &ge);
+ g->spont = false;
+ eventAccepted = (w == receiver ? g : &ge)->isAccepted();
+ if (res && eventAccepted)
+ break;
+ if (w->isWindow())
+ break;
+ relPos += w->pos();
+ w = w->parentWidget();
+ }
+ break;
+ }
case QEvent::TouchBegin:
// Note: TouchUpdate and TouchEnd events are sent to d->currentMultitouchWidget and never propagated
{
@@ -4000,7 +4056,6 @@ bool QApplication::notify(QObject *receiver, QEvent *e)
QWidget *origin = widget;
QTouchEvent *touchEvent = static_cast<QTouchEvent *>(e);
bool eventAccepted = touchEvent->isAccepted();
-
if (widget->testAttribute(Qt::WA_AcceptTouchEvents) && e->spontaneous()) {
// give the widget focus if the focus policy allows it
QApplicationPrivate::giveFocusAccordingToFocusPolicy(widget,
diff --git a/src/gui/kernel/qapplication.h b/src/gui/kernel/qapplication.h
index 2baf6dc62..634226fcc 100644
--- a/src/gui/kernel/qapplication.h
+++ b/src/gui/kernel/qapplication.h
@@ -374,6 +374,7 @@ private:
friend class QDirectPainter;
friend class QDirectPainterPrivate;
#endif
+ friend class QGestureManager;
#if defined(Q_WS_WIN)
friend QApplicationPrivate* getQApplicationPrivateInternal();
diff --git a/src/gui/kernel/qapplication_p.h b/src/gui/kernel/qapplication_p.h
index 1a2bad266..40e928d37 100644
--- a/src/gui/kernel/qapplication_p.h
+++ b/src/gui/kernel/qapplication_p.h
@@ -428,6 +428,7 @@ public:
void sendSyntheticEnterLeave(QWidget *widget);
#endif
+ QMap<Qt::GestureType, int> grabbedGestures;
static void updateTouchPointsForWidget(QWidget *widget, QTouchEvent *touchEvent);
#if defined(Q_WS_WIN)
diff --git a/src/gui/kernel/qapplication_x11.cpp b/src/gui/kernel/qapplication_x11.cpp
index 90376b335..060e9485b 100644
--- a/src/gui/kernel/qapplication_x11.cpp
+++ b/src/gui/kernel/qapplication_x11.cpp
@@ -4414,7 +4414,6 @@ bool QETWidget::translateMouseEvent(const XEvent *event)
QMouseEvent e(type, pos, globalPos, button, buttons, modifiers);
QApplicationPrivate::sendMouseEvent(widget, &e, alienWidget, this, &qt_button_down,
qt_last_mouse_receiver);
-
if (type == QEvent::MouseButtonPress
&& button == Qt::RightButton
&& (openPopupCount == oldOpenPopupCount)) {
@@ -5022,6 +5021,7 @@ bool QETWidget::translatePropertyEvent(const XEvent *event)
return true;
}
+
//
// Paint event translation
//
diff --git a/src/gui/kernel/qdirectionrecognizer.cpp b/src/gui/kernel/qdirectionrecognizer.cpp
new file mode 100644
index 000000000..37b64e7a0
--- /dev/null
+++ b/src/gui/kernel/qdirectionrecognizer.cpp
@@ -0,0 +1,176 @@
+/****************************************************************************
+**
+** 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 "qdirectionrecognizer_p.h"
+
+#include <math.h>
+
+QT_BEGIN_NAMESPACE
+
+static const int SIZE = 20;
+
+QDirectionSimpleRecognizer::QDirectionSimpleRecognizer()
+{
+}
+
+Direction QDirectionSimpleRecognizer::addPosition(const QPoint &pos)
+{
+ if (!directions.isEmpty()) {
+ const QPoint tmp = pos - directions.back().point;
+ if (tmp.manhattanLength() < 5)
+ return Direction();
+ }
+ if (lastPoint.isNull()) {
+ lastPoint = pos;
+ return Direction();
+ }
+ int dx = pos.x() - lastPoint.x();
+ int dy = pos.y() - lastPoint.y();
+ Direction::DirectionType direction = Direction::None;
+ if (dx < 0) {
+ if (-1*dx >= SIZE/2)
+ direction = Direction::Left;
+ } else {
+ if (dx >= SIZE/2)
+ direction = Direction::Right;
+ }
+ if (dy < 0) {
+ if (-1*dy >= SIZE/2)
+ direction = Direction::Up;
+ } else {
+ if (dy >= SIZE/2)
+ direction = Direction::Down;
+ }
+ if (direction == Direction::None)
+ return Direction();
+
+ lastPoint = pos;
+ directions.push_back(Direction(direction, pos));
+ return Direction(direction, pos);
+}
+
+
+DirectionList QDirectionSimpleRecognizer::getDirections() const
+{
+ return directions;
+}
+
+void QDirectionSimpleRecognizer::reset()
+{
+ directions.clear();
+ lastPoint = QPoint();
+}
+
+
+/// QDirectionDiagonalRecognizer
+
+QDirectionDiagonalRecognizer::QDirectionDiagonalRecognizer()
+{
+}
+
+Direction QDirectionDiagonalRecognizer::addPosition(const QPoint &pos)
+{
+ if (!directions.isEmpty()) {
+ const QPoint tmp = pos - directions.back().point;
+ if (tmp.manhattanLength() < 5)
+ return Direction();
+ }
+ if (lastPoint.isNull()) {
+ lastPoint = pos;
+ return Direction();
+ }
+ int dx = pos.x() - lastPoint.x();
+ int dy = pos.y() - lastPoint.y();
+ int distance = sqrt(static_cast<double>(dx*dx + dy*dy));
+ if (distance < SIZE/2)
+ return Direction();
+
+ Direction::DirectionType direction = Direction::None;
+ double angle = atan(1.0*qAbs(lastPoint.y() - pos.y())/qAbs(pos.x() - lastPoint.x())) * 180. / M_PI;
+ if (dx < 0 && dy <= 0) {
+ angle = 180 - angle;
+ } else if (dx <= 0 && dy > 0) {
+ angle += 180;
+ } else if (dx > 0 && dy > 0) {
+ angle = 360-angle;
+ }
+ if (angle < 0)
+ angle += 360;
+ if (angle <= 20)
+ direction = Direction::Right;
+ else if (angle <= 65)
+ direction = Direction::RightUp;
+ else if (angle <= 110)
+ direction = Direction::Up;
+ else if (angle <= 155)
+ direction = Direction::LeftUp;
+ else if (angle <= 200)
+ direction = Direction::Left;
+ else if (angle <= 245)
+ direction = Direction::LeftDown;
+ else if (angle <= 290)
+ direction = Direction::Down;
+ else if (angle <= 335)
+ direction = Direction::RightDown;
+ else
+ direction = Direction::Right;
+
+ if (direction == Direction::None)
+ return Direction();
+
+ lastPoint = pos;
+ directions.push_back(Direction(direction, pos));
+ return Direction(direction, pos);
+}
+
+
+DirectionList QDirectionDiagonalRecognizer::getDirections() const
+{
+ return directions;
+}
+
+void QDirectionDiagonalRecognizer::reset()
+{
+ directions.clear();
+ lastPoint = QPoint();
+}
+
+QT_END_NAMESPACE
diff --git a/src/gui/kernel/qdirectionrecognizer_p.h b/src/gui/kernel/qdirectionrecognizer_p.h
new file mode 100644
index 000000000..639099058
--- /dev/null
+++ b/src/gui/kernel/qdirectionrecognizer_p.h
@@ -0,0 +1,121 @@
+/****************************************************************************
+**
+** 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 QDIRECTIONRECOGNIZER_P_H
+#define QDIRECTIONRECOGNIZER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qpoint.h"
+#include "qlist.h"
+
+QT_BEGIN_NAMESPACE
+
+struct Direction
+{
+ enum DirectionType
+ {
+ None = 0,
+ LeftDown = 1,
+ DownLeft = LeftDown,
+ Down = 2,
+ RightDown = 3,
+ DownRight = RightDown,
+ Left = 4,
+ Right = 6,
+ LeftUp = 7,
+ UpLeft = LeftUp,
+ Up = 8,
+ RightUp = 9,
+ UpRight = RightUp
+ };
+ DirectionType direction;
+ QPoint point;
+
+ Direction(DirectionType dir, const QPoint &pt)
+ : direction(dir), point(pt) { }
+ Direction()
+ : direction(None) { }
+
+ inline bool isEmpty() const { return direction == None; }
+ inline bool isNull() const { return direction == None; }
+};
+
+typedef QList<Direction> DirectionList;
+
+class QDirectionSimpleRecognizer
+{
+public:
+ QDirectionSimpleRecognizer();
+ Direction addPosition(const QPoint &pos);
+ DirectionList getDirections() const;
+ void reset();
+
+private:
+ QPoint lastPoint;
+ DirectionList directions;
+};
+
+class QDirectionDiagonalRecognizer
+{
+public:
+ QDirectionDiagonalRecognizer();
+ Direction addPosition(const QPoint &pos);
+ DirectionList getDirections() const;
+ void reset();
+
+private:
+ QPoint lastPoint;
+ DirectionList directions;
+};
+
+QT_END_NAMESPACE
+
+#endif // QDIRECTIONRECOGNIZER_P_H
diff --git a/src/gui/kernel/qdirectionsimplificator_p.h b/src/gui/kernel/qdirectionsimplificator_p.h
new file mode 100644
index 000000000..7b71ca0ba
--- /dev/null
+++ b/src/gui/kernel/qdirectionsimplificator_p.h
@@ -0,0 +1,172 @@
+/****************************************************************************
+**
+** 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 QDIRECTIONSIMPLIFICATOR_P_H
+#define QDIRECTIONSIMPLIFICATOR_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "private/qdirectionrecognizer_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QDirectionSimplificator
+{
+public:
+ QDirectionSimplificator(const DirectionList &dir);
+
+ bool simplify(DirectionList *result);
+
+private:
+ DirectionList directions;
+ DirectionList lastResult;
+ enum State {
+ None,
+ Trim, // remove first and last element
+ AccidentalMoves, // 66866 => 6666
+ ComplexAccidentalMoves, // 778788 => 777888 (swapping elements without changing direction)
+ ShortMoves, // (moves of length 1)
+ } state;
+
+ struct SimplifyTrim
+ {
+ SimplifyTrim() : state(0) { }
+ bool operator()(DirectionList &directions)
+ {
+ if (state == 0) {
+ directions.removeFirst();
+ state = 1;
+ } else if (state == 1) {
+ directions.removeLast();
+ state = 2;
+ } else if (state == 2 && directions.size() >= 2) {
+ directions.removeFirst();
+ directions.removeLast();
+ state = 3;
+ } else {
+ return false;
+ }
+ return true;
+ }
+ int state;
+ };
+ struct SimplifyAccidentalMoves
+ {
+ SimplifyAccidentalMoves() : state(0) { }
+ bool operator()(DirectionList &directions)
+ {
+ return false;
+ }
+ int state;
+ };
+ struct SimplifyComplexAccidentalMoves
+ {
+ SimplifyComplexAccidentalMoves() : state(0) { }
+ bool operator()(DirectionList &directions)
+ {
+ return false;
+ }
+ int state;
+ };
+
+ SimplifyTrim trim;
+ SimplifyAccidentalMoves accidentalMoves;
+ SimplifyComplexAccidentalMoves complexAccidentalMoves;
+ //SimplifyShortMoves shortMoves;
+};
+
+QDirectionSimplificator::QDirectionSimplificator(const DirectionList &dir)
+ : directions(dir), state(None)
+{
+}
+
+bool QDirectionSimplificator::simplify(DirectionList *result)
+{
+ if (directions.isEmpty() || !result)
+ return false;
+ *result = directions;
+ switch(state) {
+ case None:
+ state = Trim;
+ trim = SimplifyTrim();
+ case Trim:
+ if (trim(*result))
+ break;
+ *result = lastResult;
+ state = AccidentalMoves;
+ accidentalMoves = SimplifyAccidentalMoves();
+ case AccidentalMoves:
+ if (accidentalMoves(*result))
+ break;
+ *result = lastResult;
+ state = ComplexAccidentalMoves;
+ complexAccidentalMoves = SimplifyComplexAccidentalMoves();
+ case ComplexAccidentalMoves:
+ if (complexAccidentalMoves(*result))
+ break;
+ *result = lastResult;
+ // state = ShortMoves;
+ // shortMoves = SimplifyShortMoves();
+ // case ShortMoves:
+ // if (shortMoves(*result))
+ // break;
+ // state = None;
+ default:
+ return false;
+ }
+ lastResult = *result;
+ if (lastResult.isEmpty())
+ return false;
+ return true;
+}
+
+QT_END_NAMESPACE
+
+#endif // QDIRECTIONSIMPLIFICATOR_P_H
diff --git a/src/gui/kernel/qevent.cpp b/src/gui/kernel/qevent.cpp
index d571212ec..a7e1101fb 100644
--- a/src/gui/kernel/qevent.cpp
+++ b/src/gui/kernel/qevent.cpp
@@ -3310,6 +3310,9 @@ QDebug operator<<(QDebug dbg, const QEvent *e) {
case QEvent::ChildRemoved: n = n ? n : "ChildRemoved";
dbg.nospace() << "QChildEvent(" << n << ", " << (static_cast<const QChildEvent*>(e))->child();
return dbg.space();
+ case QEvent::Gesture:
+ n = "Gesture";
+ break;
default:
dbg.nospace() << "QEvent(" << (const void *)e << ", type = " << e->type() << ')';
return dbg.space();
@@ -3506,6 +3509,27 @@ QMenubarUpdatedEvent::QMenubarUpdatedEvent(QMenuBar * const menuBar)
#endif
+QGestureEvent::QGestureEvent(QWidget *targetWidget, const QList<QGesture*> &gestures,
+ const QSet<Qt::GestureType> &cancelledGestures)
+ : QEvent(QEvent::Gesture), m_targetWidget(targetWidget),
+ m_cancelledGestures(cancelledGestures)
+{
+ foreach(QGesture *r, gestures)
+ m_gestures.insert(r->gestureType(), QSharedPointer<QGesture>(r));
+}
+
+QGestureEvent::QGestureEvent(const QGestureEvent &event, const QPoint &offset)
+ : QEvent(QEvent::Gesture), m_targetWidget(event.m_targetWidget),
+ m_gestures(event.m_gestures),
+ m_cancelledGestures(event.m_cancelledGestures)
+{
+ //### use offset!
+}
+
+QGestureEvent::~QGestureEvent()
+{
+}
+
/*! \class QTouchEvent
\brief The QTouchEvent class contains parameters that describe a touch event
.
diff --git a/src/gui/kernel/qevent.h b/src/gui/kernel/qevent.h
index e9a1386ab..858e2eaaa 100644
--- a/src/gui/kernel/qevent.h
+++ b/src/gui/kernel/qevent.h
@@ -52,6 +52,10 @@
#include <QtGui/qmime.h>
#include <QtGui/qdrag.h>
#include <QtCore/qvariant.h>
+#include <QtCore/qmap.h>
+#include <QtCore/qset.h>
+#include <QtCore/qsharedpointer.h>
+#include <QtGui/qgesture.h>
QT_BEGIN_HEADER
@@ -710,6 +714,36 @@ private:
};
#endif
+class Q_GUI_EXPORT QGestureEvent : public QEvent
+{
+public:
+ QGestureEvent(QWidget *targetWidget, const QList<QGesture*> &gestures,
+ const QSet<Qt::GestureType> &cancelledGestures = QSet<Qt::GestureType>());
+ // internal ctor
+ QGestureEvent(const QGestureEvent &gestures, const QPoint &offset);
+ ~QGestureEvent();
+
+ QWidget *targetWidget() const
+ { return m_targetWidget; }
+
+ inline bool contains(const Qt::GestureType &gestureType) const
+ { return gesture(gestureType) != 0; }
+ inline QList<Qt::GestureType> gestureTypes() const
+ { return m_gestures.keys(); }
+ inline const QGesture* gesture(const Qt::GestureType &gestureType) const
+ { return m_gestures.value(gestureType, QSharedPointer<QGesture>()).data(); }
+
+ inline QSet<Qt::GestureType> cancelledGestures() const
+ { return m_cancelledGestures; }
+
+protected:
+ QWidget *m_targetWidget;
+ QHash<Qt::GestureType, QSharedPointer<QGesture> > m_gestures;
+ QSet<Qt::GestureType> m_cancelledGestures;
+
+ friend class QApplication;
+};
+
#ifndef QT_NO_DEBUG_STREAM
Q_GUI_EXPORT QDebug operator<<(QDebug, const QEvent *);
#endif
diff --git a/src/gui/kernel/qgesture.cpp b/src/gui/kernel/qgesture.cpp
new file mode 100644
index 000000000..fbabb8f4f
--- /dev/null
+++ b/src/gui/kernel/qgesture.cpp
@@ -0,0 +1,133 @@
+/****************************************************************************
+**
+** 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 "qgesture.h"
+#include <private/qgesture_p.h>
+
+QGesture::QGesture(const Qt::GestureType &type, Qt::GestureState state)
+ : d(new QGesturePrivate), gestureType_(type), gestureState_(state)
+{
+}
+
+QGesture::QGesture(const Qt::GestureType &type, const QPoint &startPos,
+ const QPoint &lastPos, const QPoint &pos, const QRect &rect,
+ const QPoint &hotSpot, const QDateTime &startTime,
+ uint duration, Qt::GestureState state)
+ : d(new QGesturePrivate), gestureType_(type), gestureState_(state)
+{
+ d->init(startPos, lastPos, pos, rect, hotSpot, startTime, duration);
+}
+
+QGesture::QGesture(QGesturePrivate &dd, const Qt::GestureType &type,
+ Qt::GestureState state)
+ : d(&dd), gestureType_(type), gestureState_(state)
+{
+}
+
+QGesture::~QGesture()
+{
+ delete d; d = 0;
+}
+
+QRect QGesture::rect() const
+{
+ return d->rect;
+}
+
+QPoint QGesture::hotSpot() const
+{
+ return d->hotSpot;
+}
+
+QDateTime QGesture::startTime() const
+{
+ return d->startTime;
+}
+
+uint QGesture::duration() const
+{
+ return d->duration;
+}
+
+QPoint QGesture::startPos() const
+{
+ return d->startPos;
+}
+
+QPoint QGesture::lastPos() const
+{
+ return d->lastPos;
+}
+
+QPoint QGesture::pos() const
+{
+ return d->pos;
+}
+
+QPannableGesture::QPannableGesture(const Qt::GestureType &type, Qt::GestureState state)
+ : QGesture(*new QPannableGesturePrivate, type, state)
+{
+}
+
+QPannableGesture::QPannableGesture(const Qt::GestureType &type, const QPoint &startPos,
+ const QPoint &lastPos, const QPoint &pos, const QRect &rect,
+ const QPoint &hotSpot, const QDateTime &startTime,
+ uint duration, Qt::GestureState state)
+ : QGesture(*new QPannableGesturePrivate, type, state)
+{
+ d->init(startPos, lastPos, pos, rect, hotSpot, startTime, duration);
+ ((QPannableGesturePrivate*)d)->lastDirection = QPannableGesture::None;
+ ((QPannableGesturePrivate*)d)->direction = QPannableGesture::None;
+}
+
+QPannableGesture::~QPannableGesture()
+{
+}
+
+QPannableGesture::DirectionType QPannableGesture::lastDirection() const
+{
+ return ((QPannableGesturePrivate*)d)->lastDirection;
+}
+
+QPannableGesture::DirectionType QPannableGesture::direction() const
+{
+ return ((QPannableGesturePrivate*)d)->direction;
+}
diff --git a/src/gui/kernel/qgesture.h b/src/gui/kernel/qgesture.h
new file mode 100644
index 000000000..16a5704ce
--- /dev/null
+++ b/src/gui/kernel/qgesture.h
@@ -0,0 +1,128 @@
+/****************************************************************************
+**
+** 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 QGESTURE_H
+#define QGESTURE_H
+
+#include "qobject.h"
+#include "qlist.h"
+#include "qdatetime.h"
+#include "qpoint.h"
+#include "qrect.h"
+#include "qsharedpointer.h"
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+class QGesturePrivate;
+class Q_GUI_EXPORT QGesture
+{
+public:
+ explicit QGesture(const Qt::GestureType &type, Qt::GestureState state = Qt::GestureStarted);
+ QGesture(const Qt::GestureType &type, const QPoint &startPos,
+ const QPoint &lastPos, const QPoint &pos, const QRect &rect,
+ const QPoint &hotSpot, const QDateTime &startTime,
+ uint duration, Qt::GestureState state);
+ virtual ~QGesture();
+
+ inline Qt::GestureType gestureType() const { return gestureType_; }
+ inline Qt::GestureState state() const { return gestureState_; }
+
+ QRect rect() const;
+ QPoint hotSpot() const;
+ QDateTime startTime() const;
+ uint duration() const;
+
+ QPoint startPos() const;
+ QPoint lastPos() const;
+ QPoint pos() const;
+
+protected:
+ QGesture(QGesturePrivate &dd, const Qt::GestureType &type, Qt::GestureState state = Qt::GestureStarted);
+ QGesturePrivate *d;
+
+private:
+ Qt::GestureType gestureType_;
+ Qt::GestureState gestureState_;
+};
+
+class Q_GUI_EXPORT QPannableGesture : public QGesture
+{
+public:
+ enum DirectionType
+ {
+ None = 0,
+ LeftDown = 1,
+ DownLeft = LeftDown,
+ Down = 2,
+ RightDown = 3,
+ DownRight = RightDown,
+ Left = 4,
+ Right = 6,
+ LeftUp = 7,
+ UpLeft = LeftUp,
+ Up = 8,
+ RightUp = 9,
+ UpRight = RightUp
+ };
+
+public:
+ explicit QPannableGesture(const Qt::GestureType &type, Qt::GestureState state = Qt::GestureStarted);
+ QPannableGesture(const Qt::GestureType &type, const QPoint &startPos,
+ const QPoint &lastPos, const QPoint &pos, const QRect &rect,
+ const QPoint &hotSpot, const QDateTime &startTime,
+ uint duration, Qt::GestureState state);
+ ~QPannableGesture();
+
+ DirectionType lastDirection() const;
+ DirectionType direction() const;
+
+ friend class QGestureRecognizerPan;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QGESTURE_H
diff --git a/src/gui/kernel/qgesture_p.h b/src/gui/kernel/qgesture_p.h
new file mode 100644
index 000000000..745590bf6
--- /dev/null
+++ b/src/gui/kernel/qgesture_p.h
@@ -0,0 +1,100 @@
+/****************************************************************************
+**
+** 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 QGESTURE_P_H
+#define QGESTURE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qrect.h"
+#include "qpoint.h"
+#include "qdatetime.h"
+
+QT_BEGIN_NAMESPACE
+
+class QGesturePrivate
+{
+public:
+ QGesturePrivate()
+ : duration(0) { }
+
+ void init(const QPoint &startPos, const QPoint &lastPos,
+ const QPoint &pos, const QRect &rect,
+ const QPoint &hotSpot, const QDateTime &startTime,
+ uint duration)
+ {
+ this->rect = rect;
+ this->hotSpot = hotSpot;
+ this->startTime = startTime;
+ this->duration = duration;
+ this->startPos = startPos;
+ this->lastPos = lastPos;
+ this->pos = pos;
+ }
+
+ QRect rect;
+ QPoint hotSpot;
+ QDateTime startTime;
+ uint duration;
+ QPoint startPos;
+ QPoint lastPos;
+ QPoint pos;
+};
+
+class QPannableGesturePrivate : public QGesturePrivate
+{
+public:
+ QPannableGesture::DirectionType lastDirection;
+ QPannableGesture::DirectionType direction;
+};
+
+QT_END_NAMESPACE
+
+#endif // QGESTURE_P_H
diff --git a/src/gui/kernel/qgesturemanager.cpp b/src/gui/kernel/qgesturemanager.cpp
new file mode 100644
index 000000000..c244a0b71
--- /dev/null
+++ b/src/gui/kernel/qgesturemanager.cpp
@@ -0,0 +1,405 @@
+/****************************************************************************
+**
+** 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 "qgesturemanager_p.h"
+#include "qgesture.h"
+#include "qevent.h"
+
+#include "qapplication.h"
+#include "private/qapplication_p.h"
+
+#include "private/qgesturestandardrecognizers_p.h"
+
+#include "qdebug.h"
+
+// #define GESTURE_DEBUG
+#ifndef GESTURE_DEBUG
+# define DEBUG if (0) qDebug
+#else
+# define DEBUG qDebug
+#endif
+
+QT_BEGIN_NAMESPACE
+
+bool qt_sendSpontaneousEvent(QObject *receiver, QEvent *event);
+static bool qt_sendGestureEvent(QWidget *receiver, QGestureEvent *event)
+{
+ QSet<Qt::GestureType> eventGestures = event->gestureTypes().toSet();
+ while (receiver && (receiver->gestures() & eventGestures).isEmpty())
+ receiver = receiver->parentWidget();
+ return receiver ? qt_sendSpontaneousEvent(receiver, event) : false;
+}
+
+static const unsigned int maximumGestureRecognitionTimeout = 2000;
+
+QGestureManager::QGestureManager()
+ : targetWidget(0), state(NotGesture)
+{
+ recognizers << new QDoubleTapGestureRecognizer();
+ recognizers << new QLongTapGestureRecognizer();
+ recognizers << new QGestureRecognizerPan();
+ // recognizers << new QMultiTouchGestureRecognizer();
+
+ foreach(QGestureRecognizer *r, recognizers)
+ connect(r, SIGNAL(triggered(QGestureRecognizer::Result)),
+ this, SLOT(recognizerTriggered(QGestureRecognizer::Result)));
+}
+
+bool QGestureManager::filterEvent(QEvent *event)
+{
+ if (!QApplication::testAttribute(Qt::AA_EnableGestures))
+ return false;
+
+ QList<QEvent*> events;
+ events << event;
+
+ QPoint currentPos;
+ switch (event->type()) {
+ case QEvent::MouseButtonPress:
+ case QEvent::MouseButtonRelease:
+ case QEvent::MouseButtonDblClick:
+ case QEvent::MouseMove:
+ currentPos = static_cast<QMouseEvent*>(event)->pos(); break;
+ default: break;
+ }
+
+ const QMap<Qt::GestureType, int> &grabbedGestures = qApp->d_func()->grabbedGestures;
+
+ bool ret = false;
+ QSet<QGestureRecognizer*> startedGestures;
+ QSet<QGestureRecognizer*> finishedGestures;
+ QSet<QGestureRecognizer*> newMaybeGestures;
+ QSet<QGestureRecognizer*> cancelledGestures;
+ QSet<QGestureRecognizer*> notGestures;
+ if (state == NotGesture || state == MaybeGesture) {
+ DEBUG() << "QGestureManager: current event processing state: "
+ << (state == NotGesture ? "NotGesture" : "MaybeGesture");
+
+ Q_ASSERT(targetWidget != 0);
+ QSet<QGestureRecognizer*> stillMaybeGestures;
+ // try other recognizers.
+ foreach(QGestureRecognizer *r, recognizers) {
+ if (grabbedGestures.value(r->gestureType(), 0) <= 0)
+ continue;
+ QGestureRecognizer::Result result = r->recognize(events);
+ if (result == QGestureRecognizer::GestureStarted) {
+ DEBUG() << "QGestureManager: gesture started: " << r;
+ startedGestures << r;
+ } else if (result == QGestureRecognizer::GestureFinished) {
+ DEBUG() << "QGestureManager: gesture finished: " << r;
+ finishedGestures << r;
+ } else if (result == QGestureRecognizer::MaybeGesture) {
+ DEBUG() << "QGestureManager: maybe gesture: " << r;
+ newMaybeGestures << r;
+ } else {
+ // if it was maybe gesture, but isn't a gesture anymore.
+ DEBUG() << "QGestureManager: not gesture: " << r;
+ notGestures << r;
+ }
+ }
+ activeGestures -= newMaybeGestures;
+ activeGestures += startedGestures;
+ foreach(QGestureRecognizer *r, startedGestures+notGestures) {
+ QMap<QGestureRecognizer*, int>::iterator it = maybeGestures.find(r);
+ if (it != maybeGestures.end()) {
+ killTimer(it.value());
+ maybeGestures.erase(it);
+ }
+ }
+ foreach(QGestureRecognizer *r, newMaybeGestures) {
+ if (!maybeGestures.contains(r)) {
+ int timerId = startTimer(maximumGestureRecognitionTimeout);
+ if (!timerId)
+ qWarning("QGestureManager: couldn't start timer!");
+ maybeGestures.insert(r, timerId);
+ }
+ }
+ if (!finishedGestures.isEmpty() || !activeGestures.isEmpty()) {
+ // gesture found!
+ ret = true;
+ DEBUG() << "QGestureManager: sending gesture event for: "
+ << activeGestures << " and " << finishedGestures;
+
+ QList<QGesture*> gestures;
+ foreach(QGestureRecognizer *r, finishedGestures) {
+ if (QGesture *gesture = r->makeEvent())
+ gestures << gesture;
+ }
+ foreach(QGestureRecognizer *r, activeGestures) {
+ if (QGesture *gesture = r->makeEvent())
+ gestures << gesture;
+ }
+ Q_ASSERT(!gestures.isEmpty());
+ QGestureEvent event(targetWidget, gestures);
+ qt_sendGestureEvent(targetWidget, &event);
+
+ if (!activeGestures.isEmpty()) {
+ DEBUG() << "QGestureManager: new state = Gesture";
+ state = Gesture;
+ } else if (!maybeGestures.isEmpty()) {
+ DEBUG() << "QGestureManager: new state = Maybe";
+ state = MaybeGesture;
+ } else {
+ DEBUG() << "QGestureManager: new state = NotGesture";
+ state = NotGesture;
+ }
+ } else if (!maybeGestures.isEmpty()) {
+ if (state != MaybeGesture) {
+ // We got a new set of events that look like a start
+ // of some gesture, so we switch to state MaybeGesture
+ // and wait for more events.
+ DEBUG() << "QGestureManager: new state = Maybe. Waiting for events";
+ state = MaybeGesture;
+ // start gesture timer
+ } else {
+ // we still not sure if it is a gesture or not.
+ }
+ } else if (state == MaybeGesture) {
+ // last time we thought it looks like gesture, but now we
+ // know for sure that it isn't.
+ DEBUG() << "QGestureManager: new state = NotGesture";
+ state = NotGesture;
+ }
+ foreach(QGestureRecognizer *r, finishedGestures)
+ r->reset();
+ foreach(QGestureRecognizer *r, cancelledGestures)
+ r->reset();
+ foreach(QGestureRecognizer *r, notGestures)
+ r->reset();
+ } else if (state == Gesture) {
+ DEBUG() << "QGestureManager: current event processing state: Gesture";
+ Q_ASSERT(!activeGestures.isEmpty());
+
+ foreach(QGestureRecognizer *r, recognizers) {
+ if (grabbedGestures.value(r->gestureType(), 0) <= 0)
+ continue;
+ QGestureRecognizer::Result result = r->recognize(events);
+ if (result == QGestureRecognizer::GestureStarted) {
+ DEBUG() << "QGestureManager: gesture started: " << r;
+ startedGestures << r;
+ } else if (result == QGestureRecognizer::GestureFinished) {
+ DEBUG() << "QGestureManager: gesture finished: " << r;
+ finishedGestures << r;
+ } else if (result == QGestureRecognizer::MaybeGesture) {
+ DEBUG() << "QGestureManager: maybe gesture: " << r;
+ newMaybeGestures << r;
+ } else {
+ // if it was an active gesture, but isn't a gesture anymore.
+ if (activeGestures.contains(r)) {
+ DEBUG() << "QGestureManager: cancelled gesture: " << r;
+ cancelledGestures << r;
+ } else {
+ DEBUG() << "QGestureManager: not gesture: " << r;
+ notGestures << r;
+ }
+ }
+ }
+
+ activeGestures -= newMaybeGestures;
+ activeGestures -= cancelledGestures;
+ activeGestures -= finishedGestures;
+ activeGestures += startedGestures;
+ foreach(QGestureRecognizer *r, startedGestures+finishedGestures+notGestures) {
+ QMap<QGestureRecognizer*, int>::iterator it = maybeGestures.find(r);
+ if (it != maybeGestures.end()) {
+ killTimer(it.value());
+ maybeGestures.erase(it);
+ }
+ }
+ foreach(QGestureRecognizer *r, newMaybeGestures) {
+ if (!maybeGestures.contains(r)) {
+ int timerId = startTimer(maximumGestureRecognitionTimeout);
+ if (!timerId)
+ qWarning("QGestureManager: couldn't start timer!");
+ maybeGestures.insert(r, timerId);
+ }
+ }
+ QList<QGesture*> gestures;
+ if (!finishedGestures.isEmpty() || !activeGestures.isEmpty()) {
+ // another gesture found!
+ ret = true;
+ DEBUG() << "QGestureManager: sending gesture event for: "
+ << activeGestures << " and " << finishedGestures;
+
+ foreach(QGestureRecognizer *r, finishedGestures) {
+ if (QGesture *gesture = r->makeEvent())
+ gestures << gesture;
+ }
+ foreach(QGestureRecognizer *r, activeGestures) {
+ if (QGesture *gesture = r->makeEvent())
+ gestures << gesture;
+ }
+ }
+ QSet<Qt::GestureType> cancelledGestureNames;
+ foreach(QGestureRecognizer *r, cancelledGestures)
+ cancelledGestureNames << r->gestureType();
+ if(!gestures.isEmpty()) {
+ QGestureEvent event(targetWidget, gestures, cancelledGestureNames);
+ qt_sendGestureEvent(targetWidget, &event);
+ }
+
+ foreach(QGestureRecognizer *r, finishedGestures)
+ r->reset();
+ foreach(QGestureRecognizer *r, cancelledGestures)
+ r->reset();
+ foreach(QGestureRecognizer *r, notGestures)
+ r->reset();
+ if (!activeGestures.isEmpty()) {
+ // nothing changed, we are still handling a gesture
+ } else if (!maybeGestures.isEmpty()) {
+ DEBUG() << "QGestureManager: new state = Maybe. Waiting for events: " << maybeGestures;
+ state = MaybeGesture;
+ } else {
+ DEBUG() << "QGestureManager: new state = NotGesture";
+ state = NotGesture;
+ }
+ ret = true;
+ }
+
+ lastPos = currentPos;
+ return ret;
+}
+
+void QGestureManager::timerEvent(QTimerEvent *event)
+{
+ // sanity checks, remove later
+ Q_ASSERT((state == Gesture && !activeGestures.isEmpty()) || (state != Gesture && activeGestures.isEmpty()));
+
+ typedef QMap<QGestureRecognizer*, int> MaybeGestureMap;
+ for (MaybeGestureMap::iterator it = maybeGestures.begin(), e = maybeGestures.end();
+ it != e; ++it) {
+ if (it.value() == event->timerId()) {
+ DEBUG() << "QGestureManager: gesture timeout.";
+ QGestureRecognizer *r = it.key();
+ r->reset();
+ maybeGestures.erase(it);
+ killTimer(event->timerId());
+ break;
+ }
+ }
+
+ if (state == MaybeGesture && maybeGestures.isEmpty()) {
+ DEBUG() << "QGestureManager: new state = NotGesture because of timeout";
+ state = NotGesture;
+ }
+}
+
+bool QGestureManager::inGestureMode()
+{
+ return state == Gesture;
+}
+
+void QGestureManager::setGestureTargetWidget(QWidget *widget)
+{
+ targetWidget = widget;
+}
+
+void QGestureManager::recognizerTriggered(QGestureRecognizer::Result result)
+{
+ if (!QApplication::testAttribute(Qt::AA_EnableGestures))
+ return;
+
+ QGestureRecognizer *recognizer = qobject_cast<QGestureRecognizer*>(sender());
+ if (!recognizer)
+ return;
+ if (qApp->d_func()->grabbedGestures.value(recognizer->gestureType(), 0) <= 0) {
+ recognizer->reset();
+ return;
+ }
+
+ switch (result) {
+ case QGestureRecognizer::GestureStarted:
+ case QGestureRecognizer::GestureFinished: {
+ if (result == QGestureRecognizer::GestureStarted) {
+ DEBUG() << "QGestureManager: gesture started: " << recognizer;
+ activeGestures << recognizer;
+ DEBUG() << "QGestureManager: new state = Gesture";
+ state = Gesture;
+ } else {
+ DEBUG() << "QGestureManager: gesture finished: " << recognizer;
+ }
+ if (maybeGestures.contains(recognizer)) {
+ killTimer(maybeGestures.value(recognizer));
+ maybeGestures.remove(recognizer);
+ }
+ QList<QGesture*> gestures;
+ if (QGesture *gesture = recognizer->makeEvent())
+ gestures << gesture;
+ if(!gestures.isEmpty()) {
+ QGestureEvent event(targetWidget, gestures);
+ qt_sendGestureEvent(targetWidget, &event);
+ }
+ if (result == QGestureRecognizer::GestureFinished)
+ recognizer->reset();
+ }
+ break;
+ case QGestureRecognizer::MaybeGesture: {
+ DEBUG() << "QGestureManager: maybe gesture: " << recognizer;
+ if (activeGestures.contains(recognizer)) {
+ QGestureEvent event(targetWidget, QList<QGesture*>(),
+ QSet<Qt::GestureType>() << recognizer->gestureType());
+ qt_sendGestureEvent(targetWidget, &event);
+ }
+ if (!maybeGestures.contains(recognizer)) {
+ int timerId = startTimer(maximumGestureRecognitionTimeout);
+ if (!timerId)
+ qWarning("QGestureManager: couldn't start timer!");
+ maybeGestures.insert(recognizer, timerId);
+ }
+ }
+ break;
+ case QGestureRecognizer::NotGesture:
+ DEBUG() << "QGestureManager: not gesture: " << recognizer;
+ if (maybeGestures.contains(recognizer)) {
+ killTimer(maybeGestures.value(recognizer));
+ maybeGestures.remove(recognizer);
+ }
+ recognizer->reset();
+ break;
+ default:
+ Q_ASSERT(false);
+ }
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qgesturemanager_p.cpp"
+
diff --git a/src/gui/kernel/qgesturemanager_p.h b/src/gui/kernel/qgesturemanager_p.h
new file mode 100644
index 000000000..9853f1afb
--- /dev/null
+++ b/src/gui/kernel/qgesturemanager_p.h
@@ -0,0 +1,102 @@
+/****************************************************************************
+**
+** 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 QGESTUREMANAGER_P_H
+#define QGESTUREMANAGER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qlist.h"
+#include "qset.h"
+#include "qevent.h"
+#include "qbasictimer.h"
+
+#include "qgesturerecognizer.h"
+
+QT_BEGIN_NAMESPACE
+
+class Q_GUI_EXPORT QGestureManager : public QObject
+{
+ Q_OBJECT
+public:
+ QGestureManager();
+
+ // should be internal
+ void setGestureTargetWidget(QWidget *widget);
+
+ bool filterEvent(QEvent *event);
+ bool inGestureMode();
+
+protected:
+ void timerEvent(QTimerEvent *event);
+
+private slots:
+ void recognizerTriggered(QGestureRecognizer::Result);
+
+private:
+ QSet<QGestureRecognizer*> activeGestures;
+ QMap<QGestureRecognizer*, int> maybeGestures;
+ QSet<QGestureRecognizer*> recognizers;
+
+ QWidget *targetWidget;
+ QPoint lastPos;
+
+ enum State {
+ Gesture,
+ NotGesture,
+ MaybeGesture // that mean timers are up and waiting for some
+ // more events, and input events are handled by
+ // gesture recognizer explicitely
+ } state;
+};
+
+QT_END_NAMESPACE
+
+#endif // QGESTUREMANAGER_P_H
diff --git a/src/gui/kernel/qgesturerecognizer.h b/src/gui/kernel/qgesturerecognizer.h
new file mode 100644
index 000000000..3ed96c0b6
--- /dev/null
+++ b/src/gui/kernel/qgesturerecognizer.h
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** 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 QGESTURERECOGNIZER_H
+#define QGESTURERECOGNIZER_H
+
+#include "qgesture.h"
+#include "qevent.h"
+#include "qlist.h"
+#include "qset.h"
+
+QT_BEGIN_NAMESPACE
+
+class QGestureRecognizer : public QObject
+{
+ Q_OBJECT
+public:
+ enum Result
+ {
+ NotGesture,
+ GestureStarted,
+ GestureFinished,
+ MaybeGesture
+ };
+
+ inline QGestureRecognizer() { }
+ //### remove this ctor
+ inline QGestureRecognizer(const char *type) : type_(QLatin1String(type)) { }
+ inline QGestureRecognizer(const Qt::GestureType &type) : type_(type) { }
+ inline Qt::GestureType gestureType() const { return type_; }
+
+ virtual Result recognize(const QList<QEvent*> &inputEvents) = 0;
+ virtual QGesture* makeEvent() const = 0;
+ virtual void reset() = 0;
+
+signals:
+ void triggered(QGestureRecognizer::Result result);
+
+protected:
+ Qt::GestureType type_;
+};
+
+QT_END_NAMESPACE
+
+#endif // QGESTURERECOGNIZER_P_H
diff --git a/src/gui/kernel/qgesturestandardrecognizers.cpp b/src/gui/kernel/qgesturestandardrecognizers.cpp
new file mode 100644
index 000000000..3a2fa1d8e
--- /dev/null
+++ b/src/gui/kernel/qgesturestandardrecognizers.cpp
@@ -0,0 +1,543 @@
+/****************************************************************************
+**
+** 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 "qgesturestandardrecognizers_p.h"
+#include "qgesture_p.h"
+
+// #define GESTURE_RECOGNIZER_DEBUG
+#ifndef GESTURE_RECOGNIZER_DEBUG
+# define DEBUG if (0) qDebug
+#else
+# define DEBUG qDebug
+#endif
+
+QT_BEGIN_NAMESPACE
+/*
+QGestureRecognizerMouseTwoButtons::QGestureRecognizerMouseTwoButtons()
+ : QGestureRecognizer(Qt::MouseTwoButtonClick)
+{
+ clear();
+}
+
+QGestureRecognizer::Result QGestureRecognizerMouseTwoButtons::recognize(const QList<QEvent*> &inputEvents)
+{
+ // get all mouse events
+ QList<QMouseEvent*> events;
+ for(int i = 0; i < inputEvents.count(); ++i) {
+ QEvent *event = inputEvents.at(i);
+ switch (event->type()) {
+ case QEvent::MouseButtonPress:
+ case QEvent::MouseButtonRelease:
+ events.push_back(static_cast<QMouseEvent*>(event));
+ default:
+ break;
+ }
+ }
+
+ QGestureRecognizer::Result result = QGestureRecognizer::NotGesture;
+ for(int i = 0; i < events.count(); ++i) {
+ QMouseEvent *event = events.at(i);
+ if (event->type() == QEvent::MouseButtonPress) {
+ if (userEvents[3]) {
+ // something wrong, we already has a gesture.
+ clear();
+ } else if (userEvents[2]) {
+ // 1d, 2d, 1u, and user press another button. not gesture.
+ DEBUG() << "1";
+ result = QGestureRecognizer::NotGesture;
+ clear();
+ break;
+ } else if (userEvents[1]) {
+ // 1d, 2d, and user pressed third button. not gesture.
+ DEBUG() << "2";
+ result = QGestureRecognizer::NotGesture;
+ clear();
+ break;
+ } else if (userEvents[0]) {
+ // second button press.
+ DEBUG() << "3";
+ userEvents[1] = event;
+ result = QGestureRecognizer::MaybeGesture;
+ } else {
+ // first button press.
+ DEBUG() << "4";
+ userEvents[0] = event;
+ result = QGestureRecognizer::MaybeGesture;
+ }
+ } else if (event->type() == QEvent::MouseButtonRelease) {
+ if (userEvents[3]) {
+ // something wrong, we already has a gesture.
+ clear();
+ } else if (userEvents[2]) {
+ // 1d, 2d, 1u, and button release
+ DEBUG() << "5";
+ if (userEvents[1]->button() != event->button()) {
+ // got weird buttonreleased event. doesn't look like gesture.
+ result = QGestureRecognizer::NotGesture;
+ clear();
+ break;
+ }
+ // gesture!
+ userEvents[3] = event;
+ result = QGestureRecognizer::GestureFinished;
+ break;
+ } else if (userEvents[1]) {
+ // 1d, 2d, and button release
+ DEBUG() << "6";
+ if (userEvents[0]->button() != event->button()) {
+ // user released the wrong button. not gesture.
+ result = QGestureRecognizer::NotGesture;
+ clear();
+ break;
+ }
+ // user released the right button! looks like gesture
+ userEvents[2] = event;
+ result = QGestureRecognizer::MaybeGesture;
+ } else if (userEvents[0]) {
+ // 1d, and some button was released. not a gesture.
+ DEBUG() << "7";
+ result = QGestureRecognizer::NotGesture;
+ clear();
+ break;
+ }
+ }
+ }
+ return result;
+}
+
+QGesture* QGestureRecognizerMouseTwoButtons::makeEvent() const
+{
+ if (!userEvents[0] || !userEvents[1] || !userEvents[2] || !userEvents[3])
+ return 0;
+ QGesture::Direction direction =
+ (userEvents[0]->button() < userEvents[1]->button() ?
+ QGesture::Left : QGesture::Right);
+ QList<QPoint> points;
+ points.push_back(userEvents[0]->globalPos());
+ points.push_back(userEvents[1]->globalPos());
+ QGesture *gesture =
+ new QGesture(Qt::MouseTwoButtonClick, points.at(0), points.at(1), points.at(1),
+ direction,
+ QRect(points.at(0), points.at(1)),
+ points.at(0));
+ return gesture;
+}
+
+void QGestureRecognizerMouseTwoButtons::reset()
+{
+ clear();
+}
+
+void QGestureRecognizerMouseTwoButtons::clear()
+{
+ userEvents[0] = userEvents[1] = userEvents[2] = userEvents[3] = 0;
+}
+*/
+
+//
+// QGestureRecognizerPan
+//
+
+QGestureRecognizerPan::QGestureRecognizerPan()
+ : QGestureRecognizer(Qt::Pan), mousePressed(false), gestureFinished(false),
+ lastDirection(Direction::None)
+{
+}
+
+QGestureRecognizer::Result QGestureRecognizerPan::recognize(const QList<QEvent*> &inputEvents)
+{
+ // get all mouse events
+ QList<QMouseEvent*> events;
+ for(int i = 0; i < inputEvents.count(); ++i) {
+ QEvent *event = inputEvents.at(i);
+ switch (event->type()) {
+ case QEvent::MouseButtonPress:
+ case QEvent::MouseButtonRelease:
+ case QEvent::MouseMove:
+ events.push_back(static_cast<QMouseEvent*>(event));
+ default:
+ break;
+ }
+ }
+
+ QGestureRecognizer::Result result = QGestureRecognizer::NotGesture;
+ for(int i = 0; i < events.count(); ++i) {
+ QMouseEvent *event = events.at(i);
+ if (event->type() == QEvent::MouseButtonPress) {
+ if (lastDirection != Direction::None) {
+ DEBUG() << "Pan: MouseButtonPress: fail. another press during pan";
+ result = QGestureRecognizer::NotGesture;
+ reset();
+ break;
+ }
+ DEBUG() << "Pan: MouseButtonPress: maybe gesture started";
+ result = QGestureRecognizer::MaybeGesture;
+ mousePressed = true;
+ pressedPos = lastPos = currentPos = event->pos();
+ } else if (event->type() == QEvent::MouseButtonRelease) {
+ if (mousePressed && lastDirection != Direction::None) {
+ DEBUG() << "Pan: MouseButtonRelease: pan detected";
+ result = QGestureRecognizer::GestureFinished;
+ gestureFinished = true;
+ currentPos = event->pos();
+ internalReset();
+ break;
+ }
+ DEBUG() << "Pan: MouseButtonRelease: some weird release detected, ignoring";
+ result = QGestureRecognizer::NotGesture;
+ reset();
+ break;
+ } else if (event->type() == QEvent::MouseMove) {
+ if (!mousePressed)
+ continue;
+ lastPos = currentPos;
+ currentPos = event->pos();
+ Direction::DirectionType direction =
+ simpleRecognizer.addPosition(event->pos()).direction;
+ DEBUG() << "Pan: MouseMove: simplerecognizer result = " << direction;
+ if (lastDirection == Direction::None) {
+ if (direction == Direction::None)
+ result = QGestureRecognizer::MaybeGesture;
+ else
+ result = QGestureRecognizer::GestureStarted;
+ } else {
+ result = QGestureRecognizer::GestureStarted;
+ }
+ if (direction != Direction::None)
+ lastDirection = direction;
+ }
+ }
+ return result;
+}
+
+QGesture* QGestureRecognizerPan::makeEvent() const
+{
+ QPannableGesture::DirectionType dir = QPannableGesture::None;
+ if (lastDirection == Direction::Left)
+ dir = QPannableGesture::Left;
+ else if (lastDirection == Direction::Right)
+ dir = QPannableGesture::Right;
+ else if (lastDirection == Direction::Up)
+ dir = QPannableGesture::Up;
+ else if (lastDirection == Direction::Down)
+ dir = QPannableGesture::Down;
+ else
+ return 0;
+ QPannableGesture *g =
+ new QPannableGesture(Qt::Pan, pressedPos, lastPos, currentPos,
+ QRect(), pressedPos, QDateTime(), 0,
+ gestureFinished ? Qt::GestureFinished : Qt::GestureStarted);
+ QPannableGesturePrivate *d = (QPannableGesturePrivate*)g->d;
+ d->lastDirection = dir; ///###
+ d->direction = dir;
+
+ return g;
+}
+
+void QGestureRecognizerPan::reset()
+{
+ mousePressed = false;
+ lastDirection = Direction::None;
+ gestureFinished = false;
+ diagonalRecognizer.reset();
+ simpleRecognizer.reset();
+}
+
+void QGestureRecognizerPan::internalReset()
+{
+ mousePressed = false;
+ diagonalRecognizer.reset();
+ simpleRecognizer.reset();
+}
+
+
+//
+// QDoubleTapGestureRecognizer
+//
+QDoubleTapGestureRecognizer::QDoubleTapGestureRecognizer()
+ : QGestureRecognizer(Qt::DoubleTap)
+{
+}
+
+QGestureRecognizer::Result QDoubleTapGestureRecognizer::recognize(const QList<QEvent*> &inputEvents)
+{
+ // get all mouse events
+ QList<QMouseEvent*> events;
+ for(int i = 0; i < inputEvents.count(); ++i) {
+ QEvent *event = inputEvents.at(i);
+ switch (event->type()) {
+ case QEvent::MouseButtonPress:
+ case QEvent::MouseButtonRelease:
+ case QEvent::MouseButtonDblClick:
+ case QEvent::MouseMove:
+ events.push_back(static_cast<QMouseEvent*>(event));
+ default:
+ break;
+ }
+ }
+
+ QGestureRecognizer::Result result = QGestureRecognizer::NotGesture;
+ for(int i = 0; i < events.count(); ++i) {
+ QMouseEvent *event = events.at(i);
+ if (event->type() == QEvent::MouseButtonPress) {
+ if (pressedPosition.isNull()) {
+ result = QGestureRecognizer::MaybeGesture;
+ pressedPosition = event->pos();
+ } else if ((pressedPosition - event->pos()).manhattanLength() < 10) {
+ result = QGestureRecognizer::GestureFinished;
+ }
+ } else if (event->type() == QEvent::MouseButtonRelease) {
+ if (!pressedPosition.isNull() && (pressedPosition - event->pos()).manhattanLength() < 10)
+ result = QGestureRecognizer::MaybeGesture;
+ } else if (event->type() == QEvent::MouseButtonDblClick) {
+ result = QGestureRecognizer::GestureFinished;
+ pressedPosition = event->pos();
+ break;
+ }
+ }
+ return result;
+}
+
+QGesture* QDoubleTapGestureRecognizer::makeEvent() const
+{
+ return new QGesture(Qt::DoubleTap,
+ pressedPosition, pressedPosition, pressedPosition,
+ QRect(), pressedPosition, QDateTime(), 0, Qt::GestureFinished);
+}
+
+void QDoubleTapGestureRecognizer::reset()
+{
+ pressedPosition = QPoint();
+}
+
+//
+// QLongTapGestureRecognizer
+//
+const int QLongTapGestureRecognizer::iterationCount = 40;
+const int QLongTapGestureRecognizer::iterationTimeout = 50;
+
+QLongTapGestureRecognizer::QLongTapGestureRecognizer()
+ : QGestureRecognizer(Qt::LongTap), iteration(0)
+{
+}
+
+QGestureRecognizer::Result QLongTapGestureRecognizer::recognize(const QList<QEvent*> &inputEvents)
+{
+ // get all mouse events
+ QList<QMouseEvent*> events;
+ for(int i = 0; i < inputEvents.count(); ++i) {
+ QEvent *event = inputEvents.at(i);
+ switch (event->type()) {
+ case QEvent::MouseButtonPress:
+ case QEvent::MouseButtonRelease:
+ case QEvent::MouseMove:
+ events.push_back(static_cast<QMouseEvent*>(event));
+ default:
+ break;
+ }
+ }
+
+ QGestureRecognizer::Result result = QGestureRecognizer::NotGesture;
+ for(int i = 0; i < events.count(); ++i) {
+ QMouseEvent *event = events.at(i);
+ if (event->type() == QEvent::MouseButtonPress) {
+ if (timer.isActive())
+ timer.stop();
+ timer.start(QLongTapGestureRecognizer::iterationTimeout, this);
+ pressedPosition = event->pos();
+ result = QGestureRecognizer::MaybeGesture;
+ } else if (event->type() == QEvent::MouseMove) {
+ if ((pressedPosition - event->pos()).manhattanLength() < 15)
+ result = QGestureRecognizer::GestureStarted;
+ else
+ result = QGestureRecognizer::NotGesture;
+ } else if (event->type() == QEvent::MouseButtonRelease) {
+ result = QGestureRecognizer::NotGesture;
+ timer.stop();
+ break;
+ }
+ }
+ return result;
+}
+
+void QLongTapGestureRecognizer::timerEvent(QTimerEvent *event)
+{
+ if (event->timerId() != timer.timerId())
+ return;
+ if (++iteration == QLongTapGestureRecognizer::iterationCount) {
+ emit triggered(QGestureRecognizer::GestureFinished);
+ timer.stop();
+ } else {
+ emit triggered(QGestureRecognizer::GestureStarted);
+ }
+}
+
+QGesture* QLongTapGestureRecognizer::makeEvent() const
+{
+ return new QGesture(Qt::LongTap,
+ pressedPosition, pressedPosition, pressedPosition,
+ QRect(), pressedPosition, QDateTime(), 0,
+ iteration >= QLongTapGestureRecognizer::iterationCount ?
+ Qt::GestureFinished : Qt::GestureStarted);
+}
+
+void QLongTapGestureRecognizer::reset()
+{
+ pressedPosition = QPoint();
+ timer.stop();
+ iteration = 0;
+}
+
+//
+// QMultiTouchGestureRecognizer
+//
+
+/*
+QMultiTouchGestureRecognizer::QMultiTouchGestureRecognizer()
+ : QGestureRecognizer(Qt::Pinch)
+{
+}
+
+QGestureRecognizer::Result QMultiTouchGestureRecognizer::recognize(const QList<QEvent*> &inputEvents)
+{
+ QGestureRecognizer::Result result = QGestureRecognizer::NotGesture;
+ for(int i = 0; i < inputEvents.count(); ++i) {
+ QEvent *inputEvent = inputEvents.at(i);
+ if (inputEvent->type() != QEvent::Pointer) {
+ if (touches.size() == 2)
+ result = QGestureRecognizer::GestureStarted;
+ else if (touches.size() == 1)
+ result = QGestureRecognizer::MaybeGesture;
+ continue;
+ }
+ QPointerEvent *event = static_cast<QPointerEvent*>(inputEvent);
+ Q_ASSERT(event->pointerCount() > 0);
+ for (int idx = 0; idx < event->pointerCount(); ++idx) {
+ switch (event->state(idx)) {
+ case QPointerEvent::Begin:
+ qDebug() << "Begin" << idx;
+ if (touches.size() == 2) {
+ // too many touches
+ qDebug() << "too many touches";
+ result = QGestureRecognizer::MaybeGesture;
+ continue;
+ }
+ touches[event->pointerId(idx)].startPosition = event->pos(idx);
+ if (touches.size() == 1) {
+ result = QGestureRecognizer::MaybeGesture;
+ } else if (touches.size() == 2) {
+ result = QGestureRecognizer::GestureStarted;
+ } else {
+ result = QGestureRecognizer::NotGesture;
+ }
+ break;
+
+ case QPointerEvent::Move:
+ qDebug() << "Move" << idx;
+ touches[event->pointerId(idx)].lastPosition = touches[event->pointerId(idx)].currentPosition;
+ touches[event->pointerId(idx)].currentPosition = event->pos(idx);
+ if (touches.size() == 1)
+ result = QGestureRecognizer::MaybeGesture;
+ else if (touches.size() == 2)
+ result = QGestureRecognizer::GestureStarted;
+ else
+ result = QGestureRecognizer::NotGesture;
+ break;
+
+ case QPointerEvent::End:
+ qDebug() << "End" << idx;
+ touches.remove(event->pointerId(idx));
+ if (touches.size() == 1) {
+ result = QGestureRecognizer::MaybeGesture;
+ } else if (touches.size() == 0) {
+ result = QGestureRecognizer::NotGesture;
+ } else {
+ qDebug() << "unexpected touch end event";
+ return QGestureRecognizer::NotGesture;
+ }
+ break;
+
+ case QPointerEvent::Stationary:
+ qDebug() << "Stationary" << idx;
+ if (touches.size() == 2)
+ result = QGestureRecognizer::GestureStarted;
+ else if (touches.size() == 1)
+ result = QGestureRecognizer::MaybeGesture;
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+ return result;
+}
+
+QGesture* QMultiTouchGestureRecognizer::makeEvent() const
+{
+ if (touches.size() != 2)
+ return 0;
+
+ QGesture *g = new QGesture(Qt::Pinch);
+ QGesture::Data data;
+
+ TapMap::const_iterator it = touches.begin();
+ data.startPos = it->startPosition.toPoint();
+ data.lastPos = it->lastPosition.toPoint();
+ data.currentPos = it->currentPosition.toPoint();
+ g->datas.push_back(data);
+
+ ++it;
+ data.startPos = it->startPosition.toPoint();
+ data.lastPos = it->lastPosition.toPoint();
+ data.currentPos = it->currentPosition.toPoint();
+ g->datas.push_back(data);
+
+ return g;
+}
+
+void QMultiTouchGestureRecognizer::reset()
+{
+ touches.clear();
+}
+*/
+
+QT_END_NAMESPACE
diff --git a/src/gui/kernel/qgesturestandardrecognizers_p.h b/src/gui/kernel/qgesturestandardrecognizers_p.h
new file mode 100644
index 000000000..3b314e7e2
--- /dev/null
+++ b/src/gui/kernel/qgesturestandardrecognizers_p.h
@@ -0,0 +1,169 @@
+/****************************************************************************
+**
+** 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 QGESTURESTANDARDRECOGNIZERS_P_H
+#define QGESTURESTANDARDRECOGNIZERS_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qevent.h"
+#include "qbasictimer.h"
+#include "qdebug.h"
+
+#include "qgesturerecognizer.h"
+#include "private/qdirectionrecognizer_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*
+class QGestureRecognizerMouseTwoButtons : public QGestureRecognizer
+{
+ Q_OBJECT
+public:
+ QGestureRecognizerMouseTwoButtons();
+ QGestureRecognizer::Result recognize(const QList<QEvent*> &inputEvents);
+
+ QGesture* makeEvent() const;
+ void reset();
+
+private:
+ void clear();
+
+ // find the last two button click events
+ QMouseEvent* userEvents[4];
+};
+*/
+
+class QGestureRecognizerPan : public QGestureRecognizer
+{
+ Q_OBJECT
+public:
+ QGestureRecognizerPan();
+
+ QGestureRecognizer::Result recognize(const QList<QEvent*> &inputEvents);
+ QGesture* makeEvent() const;
+
+ void reset();
+
+private:
+ void internalReset();
+
+ QPoint pressedPos;
+ QPoint lastPos;
+ QPoint currentPos;
+ bool mousePressed;
+ bool gestureFinished;
+ Direction::DirectionType lastDirection;
+ QDirectionDiagonalRecognizer diagonalRecognizer;
+ QDirectionSimpleRecognizer simpleRecognizer;
+};
+
+class QDoubleTapGestureRecognizer : public QGestureRecognizer
+{
+ Q_OBJECT
+public:
+ QDoubleTapGestureRecognizer();
+
+ QGestureRecognizer::Result recognize(const QList<QEvent*> &inputEvents);
+ QGesture* makeEvent() const;
+ void reset();
+
+private:
+ QPoint pressedPosition;
+};
+
+class QLongTapGestureRecognizer : public QGestureRecognizer
+{
+ Q_OBJECT
+public:
+ QLongTapGestureRecognizer();
+
+ QGestureRecognizer::Result recognize(const QList<QEvent*> &inputEvents);
+ QGesture* makeEvent() const;
+ void reset();
+
+protected:
+ void timerEvent(QTimerEvent *event);
+
+private:
+ QPoint pressedPosition;
+ QBasicTimer timer;
+ int iteration;
+ static const int iterationCount;
+ static const int iterationTimeout;
+};
+
+/*
+class QMultiTouchGestureRecognizer : public QGestureRecognizer
+{
+ Q_OBJECT
+public:
+ QMultiTouchGestureRecognizer();
+
+ QMap<Qt::GestureType, int> maybeGestureCompletion();
+ QGestureRecognizer::Result recognize(const QList<QEvent*> &inputEvents);
+ QGesture* makeEvent() const;
+ void reset();
+
+private:
+ struct Tap {
+ //### should I use QPointF everywhere internally ??
+ QPointF startPosition;
+ QPointF lastPosition;
+ QPointF currentPosition;
+ };
+ typedef QMap<int, Tap> TapMap;
+ TapMap touches;
+};
+*/
+
+QT_END_NAMESPACE
+
+#endif // QGESTURESTANDARDRECOGNIZERS_P_H
diff --git a/src/gui/kernel/qwidget.cpp b/src/gui/kernel/qwidget.cpp
index 968a423a4..f6be73030 100644
--- a/src/gui/kernel/qwidget.cpp
+++ b/src/gui/kernel/qwidget.cpp
@@ -7532,6 +7532,7 @@ bool QWidget::event(QEvent *event)
#ifndef QT_NO_WHEELEVENT
case QEvent::Wheel:
#endif
+ case QEvent::Gesture:
return false;
default:
break;
@@ -7927,6 +7928,9 @@ bool QWidget::event(QEvent *event)
d->needWindowChange = false;
break;
#endif
+ case QEvent::Gesture:
+ gestureEvent((QGestureEvent*)event);
+ break;
#ifndef QT_NO_PROPERTIES
case QEvent::DynamicPropertyChange: {
const QByteArray &propName = static_cast<QDynamicPropertyChangeEvent *>(event)->propertyName();
@@ -8732,6 +8736,11 @@ bool QWidget::qwsEvent(QWSEvent *)
#endif
+void QWidget::gestureEvent(QGestureEvent *event)
+{
+ event->ignore();
+}
+
/*!
Ensures that the widget has been polished by QStyle (i.e., has a
@@ -11016,6 +11025,42 @@ QWindowSurface *QWidget::windowSurface() const
return bs ? bs->windowSurface : 0;
}
+void QWidget::grabGesture(Qt::GestureType gesture)
+{
+ Q_D(QWidget);
+ if (d->gestures.contains(gesture))
+ return;
+ d->gestures << gesture;
+ ++qApp->d_func()->grabbedGestures[gesture];
+}
+
+void QWidget::grabGestures(const QSet<Qt::GestureType> &gestures)
+{
+ Q_D(QWidget);
+ foreach(const Qt::GestureType &gesture, gestures) {
+ if (!d->gestures.contains(gesture))
+ ++qApp->d_func()->grabbedGestures[gesture];
+ }
+ d->gestures.unite(gestures);
+}
+
+void QWidget::releaseGesture(Qt::GestureType gesture)
+{
+ Q_D(QWidget);
+ QMap<Qt::GestureType, int>::iterator it =
+ qApp->d_func()->grabbedGestures.find(gesture);
+ if (it != qApp->d_func()->grabbedGestures.end() &&
+ d->gestures.contains(gesture))
+ ++it.value();
+ d->gestures.remove(gesture);
+}
+
+QSet<Qt::GestureType> QWidget::gestures()
+{
+ Q_D(const QWidget);
+ return d->gestures;
+}
+
void QWidgetPrivate::getLayoutItemMargins(int *left, int *top, int *right, int *bottom) const
{
if (left)
diff --git a/src/gui/kernel/qwidget.h b/src/gui/kernel/qwidget.h
index 6703d2651..afe637d14 100644
--- a/src/gui/kernel/qwidget.h
+++ b/src/gui/kernel/qwidget.h
@@ -59,6 +59,8 @@
#include <QtGui/qevent.h>
#endif
+#include <QtGui/qgesture.h>
+
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
@@ -90,6 +92,7 @@ class QDragLeaveEvent;
class QDropEvent;
class QShowEvent;
class QHideEvent;
+class QGestureEvent;
class QInputContext;
class QIcon;
class QWindowSurface;
@@ -610,6 +613,11 @@ public:
void setWindowSurface(QWindowSurface *surface);
QWindowSurface *windowSurface() const;
+ void grabGesture(Qt::GestureType gesture);
+ void grabGestures(const QSet<Qt::GestureType> &gestures);
+ void releaseGesture(Qt::GestureType gesture);
+ QSet<Qt::GestureType> gestures();
+
Q_SIGNALS:
void customContextMenuRequested(const QPoint &pos);
@@ -669,6 +677,8 @@ protected:
// Misc. protected functions
virtual void changeEvent(QEvent *);
+ virtual void gestureEvent(QGestureEvent *);
+
int metric(PaintDeviceMetric) const;
virtual void inputMethodEvent(QInputMethodEvent *);
diff --git a/src/gui/kernel/qwidget_p.h b/src/gui/kernel/qwidget_p.h
index 5f5e1b11b..178f7ba07 100644
--- a/src/gui/kernel/qwidget_p.h
+++ b/src/gui/kernel/qwidget_p.h
@@ -57,6 +57,7 @@
#include "private/qobject_p.h"
#include "QtCore/qrect.h"
#include "QtCore/qlocale.h"
+#include "QtCore/qset.h"
#include "QtGui/qregion.h"
#include "QtGui/qsizepolicy.h"
#include "QtGui/qstyle.h"
@@ -592,6 +593,8 @@ public:
uint isGLWidget : 1;
#endif
+ QSet<Qt::GestureType> gestures;
+
#if defined(Q_WS_X11) || defined (Q_WS_WIN) || defined(Q_WS_MAC)
#ifdef Q_WS_MAC
void setWSGeometry(bool dontShow=false, const QRect &oldRect = QRect());
diff --git a/src/gui/widgets/qabstractscrollarea.cpp b/src/gui/widgets/qabstractscrollarea.cpp
index 988696915..190dbb536 100644
--- a/src/gui/widgets/qabstractscrollarea.cpp
+++ b/src/gui/widgets/qabstractscrollarea.cpp
@@ -908,6 +908,7 @@ bool QAbstractScrollArea::event(QEvent *e)
case QEvent::DragMove:
case QEvent::DragLeave:
#endif
+ case QEvent::Gesture:
return false;
case QEvent::StyleChange:
case QEvent::LayoutDirectionChange: