diff options
author | Denis Dzyubenko <denis.dzyubenko@nokia.com> | 2009-02-26 14:39:00 (GMT) |
---|---|---|
committer | Denis Dzyubenko <denis.dzyubenko@nokia.com> | 2009-05-11 13:38:54 (GMT) |
commit | a3d8cfb1ee89e0600add864db53d67552820b95a (patch) | |
tree | d396d751de49d26c052b8752c94d5247503083e2 /src | |
parent | 7396eea79c9464d0c246106834cbce02320e7989 (diff) | |
download | Qt-a3d8cfb1ee89e0600add864db53d67552820b95a.zip Qt-a3d8cfb1ee89e0600add864db53d67552820b95a.tar.gz Qt-a3d8cfb1ee89e0600add864db53d67552820b95a.tar.bz2 |
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.
Diffstat (limited to 'src')
31 files changed, 2450 insertions, 6 deletions
diff --git a/src/corelib/global/qnamespace.h b/src/corelib/global/qnamespace.h index 1635f8a..5747c3c 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 42a75f8..c9f9f24 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 3eef396..58f04f0 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 ec3373a..42a5110 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 5e77dfd..a67a49a 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 f322305..fe6dde1 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 9802f87..4680455 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 de39205..cea0553 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 1aaaab9..acce717 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 a1b982a..b6ef6b2 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 1f4e1fe..b39cbc3 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 2baf6dc..634226f 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 1a2bad2..40e928d 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 90376b3..060e948 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 0000000..37b64e7 --- /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 0000000..6390990 --- /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 0000000..7b71ca0 --- /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 d571212..a7e1101 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 e9a1386..858e2ea 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 0000000..fbabb8f --- /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 0000000..16a5704 --- /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 0000000..745590b --- /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 0000000..c244a0b --- /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 0000000..9853f1a --- /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 0000000..3ed96c0 --- /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 0000000..3a2fa1d --- /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 0000000..3b314e7 --- /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 968a423..f6be730 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 6703d26..afe637d 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 5f5e1b1..178f7ba 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 9886969..190dbb5 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: |