diff --git a/src/corelib/global/qnamespace.h b/src/corelib/global/qnamespace.h index e2c6039989..8a46f3a6ab 100644 --- a/src/corelib/global/qnamespace.h +++ b/src/corelib/global/qnamespace.h @@ -1557,6 +1557,18 @@ public: IgnoredGesturesPropagateToParent = 0x04 }; Q_DECLARE_FLAGS(GestureFlags, GestureFlag) + + enum NativeGestureType + { + BeginNativeGesture, + EndNativeGesture, + PanNativeGesture, + ZoomNativeGesture, + SmartZoomNativeGesture, + RotateNativeGesture, + SwipeNativeGesture + }; + #endif // QT_NO_GESTURES enum NavigationMode diff --git a/src/corelib/kernel/qcoreevent.h b/src/corelib/kernel/qcoreevent.h index 2ca0a7d0b0..e974c4d226 100644 --- a/src/corelib/kernel/qcoreevent.h +++ b/src/corelib/kernel/qcoreevent.h @@ -249,7 +249,7 @@ public: TouchEnd = 196, #ifndef QT_NO_GESTURES - NativeGesture = 197, // Internal for platform gesture support + NativeGesture = 197, // QtGui native gesture #endif RequestSoftwareInputPanel = 199, CloseSoftwareInputPanel = 200, diff --git a/src/gui/kernel/qevent.cpp b/src/gui/kernel/qevent.cpp index ef9a3a1225..06fa1f3550 100644 --- a/src/gui/kernel/qevent.cpp +++ b/src/gui/kernel/qevent.cpp @@ -2263,6 +2263,121 @@ QTabletEvent::~QTabletEvent() #endif // QT_NO_TABLETEVENT +/*! + \class QNativeGestureEvent + \since 5.2 + \brief The QNativeGestureEvent class contains parameters that describe a gesture event. + \inmodule QtGui + \ingroup events + + Native gesture events are generated by the operating system, typically by + interpreting touch events. Gesture events are high-level events such + as zoom or rotate. + + \table + \header + \li Event Type + \li Description + \li Touch equence + \row + \li Qt::ZoomNativeGesture + \li Magnification delta in percent. + \li OS X: Two-finger pinch. + \row + \li Qt::SmartZoomNativeGesture + \li Boolean magnification state. + \li OS X: Two-finger douple tap (trackpad) / One-finger douple tap (magic mouse). + \row + \li Qt::RotateNativeGesture + \li Rotation delta in degrees. + \li OS X: Two-finger rotate. + \endtable + + + In addition, BeginNativeGesture and EndNativeGesture are sent before and after + gesture event streams: + + BeginNativeGesture + ZoomNativeGesture + ZoomNativeGesture + ZoomNativeGesture + EndNativeGesture + + \sa Qt::NativeGestureType, QGestureEvent +*/ + +/*! + Constructs a native gesture event of type \a type. + + The points \a localPos, \a windowPos and \a screenPos specify the + gesture position relative to the receiving widget or item, + window, and screen, respectively. + + \a realValue is the OS X event parameter, \a sequenceId and \a intValue are the Windows event parameters. +*/ +QNativeGestureEvent::QNativeGestureEvent(Qt::NativeGestureType type, const QPointF &localPos, const QPointF &windowPos, + const QPointF &screenPos, qreal realValue, ulong sequenceId, quint64 intValue) + : QInputEvent(QEvent::NativeGesture), mGestureType(type), + mLocalPos(localPos), mWindowPos(windowPos), mScreenPos(screenPos), mRealValue(realValue), + mSequenceId(sequenceId), mIntValue(intValue) +{ } + +/*! + \fn QNativeGestureEvent::gestureType() const + \since 5.2 + + Returns the gesture type. +*/ + +/*! + \fn QNativeGestureEvent::value() const + \since 5.2 + + Returns the gesture value. The value should be interpreted based on the + gesture type. For example, a Zoom gesture provides a scale factor while a Rotate + gesture provides a rotation delta. + + \sa QNativeGestureEvent, gestureType() +*/ + +/*! + \fn QPoint QNativeGestureEvent::globalPos() const + \since 5.2 + + Returns the position of the gesture as a QPointF in screen coordinates +*/ + +/*! + \fn QPoint QNativeGestureEvent::pos() const + \since 5.2 + + Returns the position of the mouse cursor, relative to the widget + or item that received the event. +*/ + +/*! + \fn QPointF QNativeGestureEvent::localPos() const + \since 5.2 + + Returns the position of the gesture as a QPointF, relative to the + widget or item that received the event. +*/ + +/*! + \fn QPointF QNativeGestureEvent::screenPos() const + \since 5.2 + + Returns the position of the gesture as a QPointF in screen coordinates. +*/ + +/*! + \fn QPointF QNativeGestureEvent::windowPos() const + \since 5.2 + + Returns the position of the gesture as a QPointF, relative to the + window that received the event. +*/ + #ifndef QT_NO_DRAGANDDROP /*! Creates a QDragMoveEvent of the required \a type indicating diff --git a/src/gui/kernel/qevent.h b/src/gui/kernel/qevent.h index 0c1cf70420..d22e423248 100644 --- a/src/gui/kernel/qevent.h +++ b/src/gui/kernel/qevent.h @@ -268,6 +268,34 @@ protected: }; #endif // QT_NO_TABLETEVENT +#ifndef QT_NO_GESTURES +class Q_GUI_EXPORT QNativeGestureEvent : public QInputEvent +{ +public: + QNativeGestureEvent(Qt::NativeGestureType type, const QPointF &localPos, const QPointF &windowPos, + const QPointF &screenPos, qreal value, ulong sequenceId, quint64 intArgument); + Qt::NativeGestureType gestureType() const { return mGestureType; } + qreal value() const { return mRealValue; } + +#ifndef QT_NO_INTEGER_EVENT_COORDINATES + inline const QPoint pos() const { return mLocalPos.toPoint(); } + inline const QPoint globalPos() const { return mScreenPos.toPoint(); } +#endif + const QPointF &localPos() const { return mLocalPos; } + const QPointF &windowPos() const { return mWindowPos; } + const QPointF &screenPos() const { return mScreenPos; } + +protected: + Qt::NativeGestureType mGestureType; + QPointF mLocalPos; + QPointF mWindowPos; + QPointF mScreenPos; + qreal mRealValue; + ulong mSequenceId; + quint64 mIntValue; +}; +#endif // QT_NO_GESTURES + class Q_GUI_EXPORT QKeyEvent : public QInputEvent { public: diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp index 1e3ea3092f..d254f7c9bc 100644 --- a/src/gui/kernel/qguiapplication.cpp +++ b/src/gui/kernel/qguiapplication.cpp @@ -1473,6 +1473,10 @@ void QGuiApplicationPrivate::processWindowSystemEvent(QWindowSystemInterfacePriv QGuiApplicationPrivate::processTabletLeaveProximityEvent( static_cast(e)); break; + case QWindowSystemInterfacePrivate::Gesture: + QGuiApplicationPrivate::processGestureEvent( + static_cast(e)); + break; case QWindowSystemInterfacePrivate::PlatformPanel: QGuiApplicationPrivate::processPlatformPanelEvent( static_cast(e)); @@ -1958,6 +1962,15 @@ void QGuiApplicationPrivate::processTabletLeaveProximityEvent(QWindowSystemInter #endif } +#ifndef QT_NO_GESTURES +void QGuiApplicationPrivate::processGestureEvent(QWindowSystemInterfacePrivate::GestureEvent *e) +{ + QNativeGestureEvent ev(e->type, e->pos, e->pos, e->globalPos, e->realValue, e->sequenceId, e->intValue); + ev.setTimestamp(e->timestamp); + QGuiApplication::sendSpontaneousEvent(e->window, &ev); +} +#endif // QT_NO_GESTURES + void QGuiApplicationPrivate::processPlatformPanelEvent(QWindowSystemInterfacePrivate::PlatformPanelEvent *e) { if (!e->window) diff --git a/src/gui/kernel/qguiapplication_p.h b/src/gui/kernel/qguiapplication_p.h index d1716a6e28..65c6d814e6 100644 --- a/src/gui/kernel/qguiapplication_p.h +++ b/src/gui/kernel/qguiapplication_p.h @@ -148,6 +148,7 @@ public: static void processTabletEvent(QWindowSystemInterfacePrivate::TabletEvent *e); static void processTabletEnterProximityEvent(QWindowSystemInterfacePrivate::TabletEnterProximityEvent *e); static void processTabletLeaveProximityEvent(QWindowSystemInterfacePrivate::TabletLeaveProximityEvent *e); + static void processGestureEvent(QWindowSystemInterfacePrivate::GestureEvent *e); static void processPlatformPanelEvent(QWindowSystemInterfacePrivate::PlatformPanelEvent *e); #ifndef QT_NO_CONTEXTMENU diff --git a/src/gui/kernel/qwindowsysteminterface.cpp b/src/gui/kernel/qwindowsysteminterface.cpp index d62330083e..902c32419d 100644 --- a/src/gui/kernel/qwindowsysteminterface.cpp +++ b/src/gui/kernel/qwindowsysteminterface.cpp @@ -669,6 +669,35 @@ void QWindowSystemInterface::handleTabletLeaveProximityEvent(int device, int poi handleTabletLeaveProximityEvent(time, device, pointerType, uid); } +#ifndef QT_NO_GESTURES +void QWindowSystemInterface::handleGestureEvent(QWindow *window, ulong timestamp, Qt::NativeGestureType type, + QPointF &local, QPointF &global) +{ + QWindowSystemInterfacePrivate::GestureEvent *e = + new QWindowSystemInterfacePrivate::GestureEvent(window, timestamp, type, local, global); + QWindowSystemInterfacePrivate::handleWindowSystemEvent(e); +} + +void QWindowSystemInterface::handleGestureEventWithRealValue(QWindow *window, ulong timestamp, Qt::NativeGestureType type, + qreal value, QPointF &local, QPointF &global) +{ + QWindowSystemInterfacePrivate::GestureEvent *e = + new QWindowSystemInterfacePrivate::GestureEvent(window, timestamp, type, local, global); + e->realValue = value; + QWindowSystemInterfacePrivate::handleWindowSystemEvent(e); +} + +void QWindowSystemInterface::handleGestureEventWithSequenceIdAndValue(QWindow *window, ulong timestamp, Qt::NativeGestureType type, + ulong sequenceId, quint64 value, QPointF &local, QPointF &global) +{ + QWindowSystemInterfacePrivate::GestureEvent *e = + new QWindowSystemInterfacePrivate::GestureEvent(window, timestamp, type, local, global); + e->sequenceId = sequenceId; + e->intValue = value; + QWindowSystemInterfacePrivate::handleWindowSystemEvent(e); +} +#endif // QT_NO_GESTURES + void QWindowSystemInterface::handlePlatformPanelEvent(QWindow *w) { QWindowSystemInterfacePrivate::PlatformPanelEvent *e = diff --git a/src/gui/kernel/qwindowsysteminterface.h b/src/gui/kernel/qwindowsysteminterface.h index c8e464f985..d8d0922b96 100644 --- a/src/gui/kernel/qwindowsysteminterface.h +++ b/src/gui/kernel/qwindowsysteminterface.h @@ -177,6 +177,15 @@ public: static void handleTabletLeaveProximityEvent(ulong timestamp, int device, int pointerType, qint64 uid); static void handleTabletLeaveProximityEvent(int device, int pointerType, qint64 uid); +#ifndef QT_NO_GESTURES + static void handleGestureEvent(QWindow *window, ulong timestamp, Qt::NativeGestureType type, + QPointF &local, QPointF &global); + static void handleGestureEventWithRealValue(QWindow *window, ulong timestamp, Qt::NativeGestureType type, + qreal value, QPointF &local, QPointF &global); + static void handleGestureEventWithSequenceIdAndValue(QWindow *window, ulong timestamp,Qt::NativeGestureType type, + ulong sequenceId, quint64 value, QPointF &local, QPointF &global); +#endif // QT_NO_GESTURES + static void handlePlatformPanelEvent(QWindow *w); #ifndef QT_NO_CONTEXTMENU static void handleContextMenuEvent(QWindow *w, bool mouseTriggered, diff --git a/src/gui/kernel/qwindowsysteminterface_p.h b/src/gui/kernel/qwindowsysteminterface_p.h index 46479701cc..03e2d420f0 100644 --- a/src/gui/kernel/qwindowsysteminterface_p.h +++ b/src/gui/kernel/qwindowsysteminterface_p.h @@ -91,6 +91,7 @@ public: PlatformPanel = UserInputEvent | 0x17, ContextMenu = UserInputEvent | 0x18, EnterWhatsThisMode = UserInputEvent | 0x19, + Gesture = UserInputEvent | 0x1a, ApplicationStateChanged = 0x19, FlushEvents = 0x20, WindowScreenChanged = 0x21 @@ -398,6 +399,21 @@ public: }; #endif + class GestureEvent : public InputEvent { + public: + GestureEvent(QWindow *window, ulong time, Qt::NativeGestureType type, QPointF pos, QPointF globalPos) + : InputEvent(window, time, Gesture, Qt::NoModifier), type(type), pos(pos), globalPos(globalPos), + realValue(0), sequenceId(0), intValue(0) { } + Qt::NativeGestureType type; + QPointF pos; + QPointF globalPos; + // Mac + qreal realValue; + // Windows + ulong sequenceId; + quint64 intValue; + }; + class WindowSystemEventList { QList impl; mutable QMutex mutex; diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm index f471a61aa0..f90fc6b205 100644 --- a/src/plugins/platforms/cocoa/qnsview.mm +++ b/src/plugins/platforms/cocoa/qnsview.mm @@ -975,6 +975,102 @@ static QTabletEvent::TabletDevice wacomTabletDevice(NSEvent *theEvent) QWindowSystemInterface::handleTouchEvent(m_window, timestamp * 1000, touchDevice, points); } +#ifndef QT_NO_GESTURES +//#define QT_COCOA_ENABLE_GESTURE_DEBUG +- (void)magnifyWithEvent:(NSEvent *)event +{ +#ifdef QT_COCOA_ENABLE_GESTURE_DEBUG + qDebug() << "magnifyWithEvent" << [event magnification]; +#endif + const NSTimeInterval timestamp = [event timestamp]; + QPointF windowPoint; + QPointF screenPoint; + [self convertFromEvent:event toWindowPoint:&windowPoint andScreenPoint:&screenPoint]; + QWindowSystemInterface::handleGestureEventWithRealValue(m_window, timestamp, Qt::ZoomNativeGesture, + [event magnification], windowPoint, screenPoint); +} + +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8 +- (void)smartMagnifyWithEvent:(NSEvent *)event +{ + static bool zoomIn = true; +#ifdef QT_COCOA_ENABLE_GESTURE_DEBUG + qDebug() << "smartMagnifyWithEvent" << zoomIn; +#endif + const NSTimeInterval timestamp = [event timestamp]; + QPointF windowPoint; + QPointF screenPoint; + [self convertFromEvent:event toWindowPoint:&windowPoint andScreenPoint:&screenPoint]; + QWindowSystemInterface::handleGestureEventWithRealValue(m_window, timestamp, Qt::SmartZoomNativeGesture, + zoomIn ? 1.0f : 0.0f, windowPoint, screenPoint); + zoomIn = !zoomIn; +} +#endif + +- (void)rotateWithEvent:(NSEvent *)event +{ +#ifdef QT_COCOA_ENABLE_GESTURE_DEBUG + qDebug() << "rotateWithEvent" << [event rotation]; +#endif + const NSTimeInterval timestamp = [event timestamp]; + QPointF windowPoint; + QPointF screenPoint; + [self convertFromEvent:event toWindowPoint:&windowPoint andScreenPoint:&screenPoint]; + QWindowSystemInterface::handleGestureEventWithRealValue(m_window, timestamp, Qt::RotateNativeGesture, + -[event rotation], windowPoint, screenPoint); +} + +- (void)swipeWithEvent:(NSEvent *)event +{ +#ifdef QT_COCOA_ENABLE_GESTURE_DEBUG + qDebug() << "swipeWithEvent" << [event deltaX] << [event deltaY]; +#endif + const NSTimeInterval timestamp = [event timestamp]; + QPointF windowPoint; + QPointF screenPoint; + [self convertFromEvent:event toWindowPoint:&windowPoint andScreenPoint:&screenPoint]; + + qreal angle = 0.0f; + if ([event deltaX] == 1) + angle = 180.0f; + else if ([event deltaX] == -1) + angle = 0.0f; + else if ([event deltaY] == 1) + angle = 90.0f; + else if ([event deltaY] == -1) + angle = 270.0f; + + QWindowSystemInterface::handleGestureEventWithRealValue(m_window, timestamp, Qt::SwipeNativeGesture, + angle, windowPoint, screenPoint); +} + +- (void)beginGestureWithEvent:(NSEvent *)event +{ +#ifdef QT_COCOA_ENABLE_GESTURE_DEBUG + qDebug() << "beginGestureWithEvent"; +#endif + const NSTimeInterval timestamp = [event timestamp]; + QPointF windowPoint; + QPointF screenPoint; + [self convertFromEvent:event toWindowPoint:&windowPoint andScreenPoint:&screenPoint]; + QWindowSystemInterface::handleGestureEvent(m_window, timestamp, Qt::BeginNativeGesture, + windowPoint, screenPoint); +} + +- (void)endGestureWithEvent:(NSEvent *)event +{ +#ifdef QT_COCOA_ENABLE_GESTURE_DEBUG + qDebug() << "endGestureWithEvent"; +#endif + const NSTimeInterval timestamp = [event timestamp]; + QPointF windowPoint; + QPointF screenPoint; + [self convertFromEvent:event toWindowPoint:&windowPoint andScreenPoint:&screenPoint]; + QWindowSystemInterface::handleGestureEvent(m_window, timestamp, Qt::EndNativeGesture, + windowPoint, screenPoint); +} +#endif // QT_NO_GESTURES + #ifndef QT_NO_WHEELEVENT - (void)scrollWheel:(NSEvent *)theEvent { diff --git a/src/widgets/kernel/kernel.pri b/src/widgets/kernel/kernel.pri index 533b696faa..444b9b687f 100644 --- a/src/widgets/kernel/kernel.pri +++ b/src/widgets/kernel/kernel.pri @@ -66,59 +66,9 @@ SOURCES += \ kernel/qwidgetwindow.cpp \ kernel/qwindowcontainer.cpp - -# TODO -false:!x11:mac { - SOURCES += \ - kernel/qclipboard_mac.cpp \ - kernel/qmime_mac.cpp \ - kernel/qt_mac.cpp \ - kernel/qkeymapper_mac.cpp - - OBJECTIVE_HEADERS += \ - qcocoawindow_mac_p.h \ - qcocoapanel_mac_p.h \ - qcocoawindowdelegate_mac_p.h \ - qcocoaview_mac_p.h \ - qcocoaapplication_mac_p.h \ - qcocoaapplicationdelegate_mac_p.h \ - qmacgesturerecognizer_mac_p.h \ - qmultitouch_mac_p.h \ - qcocoasharedwindowmethods_mac_p.h \ - qcocoaintrospection_p.h - - OBJECTIVE_SOURCES += \ - kernel/qcursor_mac.mm \ - kernel/qdnd_mac.mm \ - kernel/qapplication_mac.mm \ - kernel/qwidget_mac.mm \ - kernel/qcocoapanel_mac.mm \ - kernel/qcocoaview_mac.mm \ - kernel/qcocoawindow_mac.mm \ - kernel/qcocoawindowdelegate_mac.mm \ - kernel/qcocoaapplication_mac.mm \ - kernel/qcocoaapplicationdelegate_mac.mm \ - kernel/qt_cocoa_helpers_mac.mm \ - kernel/qdesktopwidget_mac.mm \ - kernel/qeventdispatcher_mac.mm \ - kernel/qcocoawindowcustomthemeframe_mac.mm \ - kernel/qmacgesturerecognizer_mac.mm \ - kernel/qmultitouch_mac.mm \ - kernel/qcocoaintrospection_mac.mm - - HEADERS += \ - kernel/qt_cocoa_helpers_mac_p.h \ - kernel/qcocoaapplication_mac_p.h \ - kernel/qcocoaapplicationdelegate_mac_p.h \ - kernel/qeventdispatcher_mac_p.h - - MENU_NIB.files = mac/qt_menu.nib - MENU_NIB.path = Resources - MENU_NIB.version = Versions - QMAKE_BUNDLE_DATA += MENU_NIB - RESOURCES += mac/macresources.qrc - - LIBS_PRIVATE += -framework AppKit +macx: { + HEADERS += kernel/qmacgesturerecognizer_p.h + SOURCES += kernel/qmacgesturerecognizer.cpp } wince*: { diff --git a/src/widgets/kernel/qgesture_p.h b/src/widgets/kernel/qgesture_p.h index c041af7317..ae203d2819 100644 --- a/src/widgets/kernel/qgesture_p.h +++ b/src/widgets/kernel/qgesture_p.h @@ -190,41 +190,6 @@ public: static int Timeout; }; -#ifndef QT_NO_GESTURES -class QNativeGestureEvent : public QEvent -{ -public: - enum Type { - None, - GestureBegin, - GestureEnd, - Pan, - Zoom, - Rotate, - Swipe - }; - - QNativeGestureEvent() - : QEvent(QEvent::NativeGesture), gestureType(None), percentage(0) -#ifdef Q_WS_WIN - , sequenceId(0), argument(0) -#endif - { - } - - Type gestureType; - float percentage; - QPoint position; - float angle; -#ifdef Q_WS_WIN - ulong sequenceId; - quint64 argument; -#endif -}; - -#endif // QT_NO_GESTURES - - QT_END_NAMESPACE #endif // QT_NO_GESTURES diff --git a/src/widgets/kernel/qgesturemanager.cpp b/src/widgets/kernel/qgesturemanager.cpp index d90b187bf0..6a0ccacdaa 100644 --- a/src/widgets/kernel/qgesturemanager.cpp +++ b/src/widgets/kernel/qgesturemanager.cpp @@ -51,8 +51,8 @@ #include "qevent.h" #include "qgraphicsitem.h" -#ifdef Q_WS_MAC -#include "qmacgesturerecognizer_mac_p.h" +#ifdef Q_OS_MAC +#include "qmacgesturerecognizer_p.h" #endif #if defined(Q_WS_WIN) && !defined(QT_NO_NATIVE_GESTURES) #include "qwinnativepangesturerecognizer_win_p.h" @@ -76,7 +76,7 @@ QGestureManager::QGestureManager(QObject *parent) { qRegisterMetaType(); -#if defined(Q_WS_MAC) +#if defined(Q_OS_MAC) registerGestureRecognizer(new QMacSwipeGestureRecognizer); registerGestureRecognizer(new QMacPinchGestureRecognizer); registerGestureRecognizer(new QMacPanGestureRecognizer); diff --git a/src/widgets/kernel/qmacgesturerecognizer.cpp b/src/widgets/kernel/qmacgesturerecognizer.cpp new file mode 100644 index 0000000000..feb779e53f --- /dev/null +++ b/src/widgets/kernel/qmacgesturerecognizer.cpp @@ -0,0 +1,275 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtWidgets module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** 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, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, 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. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmacgesturerecognizer_p.h" +#include "qgesture.h" +#include "qgesture_p.h" +#include "qevent.h" +#include "qwidget.h" +#include "qdebug.h" + +#ifndef QT_NO_GESTURES + +QT_BEGIN_NAMESPACE + +QMacSwipeGestureRecognizer::QMacSwipeGestureRecognizer() +{ +} + +QGesture *QMacSwipeGestureRecognizer::create(QObject * /*target*/) +{ + return new QSwipeGesture; +} + +QGestureRecognizer::Result +QMacSwipeGestureRecognizer::recognize(QGesture *gesture, QObject *obj, QEvent *event) +{ + if (event->type() == QEvent::NativeGesture && obj->isWidgetType()) { + QNativeGestureEvent *ev = static_cast(event); + switch (ev->gestureType()) { + case Qt::SwipeNativeGesture: { + QSwipeGesture *g = static_cast(gesture); + g->setSwipeAngle(ev->value()); + g->setHotSpot(ev->screenPos()); + return QGestureRecognizer::FinishGesture | QGestureRecognizer::ConsumeEventHint; + break; } + default: + break; + } + } + + return QGestureRecognizer::Ignore; +} + +void QMacSwipeGestureRecognizer::reset(QGesture *gesture) +{ + QSwipeGesture *g = static_cast(gesture); + g->setSwipeAngle(0); + QGestureRecognizer::reset(gesture); +} + +//////////////////////////////////////////////////////////////////////// + +QMacPinchGestureRecognizer::QMacPinchGestureRecognizer() +{ +} + +QGesture *QMacPinchGestureRecognizer::create(QObject * /*target*/) +{ + return new QPinchGesture; +} + +QGestureRecognizer::Result +QMacPinchGestureRecognizer::recognize(QGesture *gesture, QObject *obj, QEvent *event) +{ + if (event->type() == QEvent::NativeGesture && obj->isWidgetType()) { + QPinchGesture *g = static_cast(gesture); + QNativeGestureEvent *ev = static_cast(event); + switch (ev->gestureType()) { + case Qt::BeginNativeGesture: + reset(gesture); + g->setStartCenterPoint(static_cast(obj)->mapFromGlobal(ev->screenPos().toPoint())); + g->setCenterPoint(g->startCenterPoint()); + g->setChangeFlags(QPinchGesture::CenterPointChanged); + g->setTotalChangeFlags(g->totalChangeFlags() | g->changeFlags()); + g->setHotSpot(ev->screenPos()); + return QGestureRecognizer::MayBeGesture | QGestureRecognizer::ConsumeEventHint; + case Qt::RotateNativeGesture: + g->setLastScaleFactor(g->scaleFactor()); + g->setLastRotationAngle(g->rotationAngle()); + g->setRotationAngle(g->rotationAngle() + ev->value()); + g->setChangeFlags(QPinchGesture::RotationAngleChanged); + g->setTotalChangeFlags(g->totalChangeFlags() | g->changeFlags()); + g->setHotSpot(ev->screenPos()); + return QGestureRecognizer::TriggerGesture | QGestureRecognizer::ConsumeEventHint; + case Qt::ZoomNativeGesture: + g->setLastScaleFactor(g->scaleFactor()); + g->setLastRotationAngle(g->rotationAngle()); + g->setScaleFactor(g->scaleFactor() * (1 + ev->value())); + g->setChangeFlags(QPinchGesture::ScaleFactorChanged); + g->setTotalChangeFlags(g->totalChangeFlags() | g->changeFlags()); + g->setHotSpot(ev->screenPos()); + return QGestureRecognizer::TriggerGesture | QGestureRecognizer::ConsumeEventHint; + case Qt::SmartZoomNativeGesture: + g->setLastScaleFactor(g->scaleFactor()); + g->setLastRotationAngle(g->rotationAngle()); + g->setScaleFactor(ev->value() ? 1.7f : 1.0f); + g->setChangeFlags(QPinchGesture::ScaleFactorChanged); + g->setTotalChangeFlags(g->totalChangeFlags() | g->changeFlags()); + g->setHotSpot(ev->screenPos()); + return QGestureRecognizer::TriggerGesture | QGestureRecognizer::ConsumeEventHint; + case Qt::EndNativeGesture: + return QGestureRecognizer::FinishGesture | QGestureRecognizer::ConsumeEventHint; + default: + break; + } + } + + return QGestureRecognizer::Ignore; +} + +void QMacPinchGestureRecognizer::reset(QGesture *gesture) +{ + QPinchGesture *g = static_cast(gesture); + g->setChangeFlags(0); + g->setTotalChangeFlags(0); + g->setScaleFactor(1.0f); + g->setTotalScaleFactor(1.0f); + g->setLastScaleFactor(1.0f); + g->setRotationAngle(0.0f); + g->setTotalRotationAngle(0.0f); + g->setLastRotationAngle(0.0f); + g->setCenterPoint(QPointF()); + g->setStartCenterPoint(QPointF()); + g->setLastCenterPoint(QPointF()); + QGestureRecognizer::reset(gesture); +} + +//////////////////////////////////////////////////////////////////////// + +QMacPanGestureRecognizer::QMacPanGestureRecognizer() : _panCanceled(true) +{ +} + +QGesture *QMacPanGestureRecognizer::create(QObject *target) +{ + if (!target) + return new QPanGesture; + + if (QWidget *w = qobject_cast(target)) { + w->setAttribute(Qt::WA_AcceptTouchEvents); + w->setAttribute(Qt::WA_TouchPadAcceptSingleTouchEvents); + return new QPanGesture; + } + return 0; +} + +QGestureRecognizer::Result +QMacPanGestureRecognizer::recognize(QGesture *gesture, QObject *target, QEvent *event) +{ + const int panBeginDelay = 300; + const int panBeginRadius = 3; + + QPanGesture *g = static_cast(gesture); + + switch (event->type()) { + case QEvent::TouchBegin: { + const QTouchEvent *ev = static_cast(event); + if (ev->touchPoints().size() == 1) { + reset(gesture); + _startPos = QCursor::pos(); + _panTimer.start(panBeginDelay, target); + _panCanceled = false; + return QGestureRecognizer::MayBeGesture; + } + break;} + case QEvent::TouchEnd: { + if (_panCanceled) + break; + + const QTouchEvent *ev = static_cast(event); + if (ev->touchPoints().size() == 1) + return QGestureRecognizer::FinishGesture; + break;} + case QEvent::TouchUpdate: { + if (_panCanceled) + break; + + const QTouchEvent *ev = static_cast(event); + if (ev->touchPoints().size() == 1) { + if (_panTimer.isActive()) { + // INVARIANT: Still in maybeGesture. Check if the user + // moved his finger so much that it makes sense to cancel the pan: + const QPointF p = QCursor::pos(); + if ((p - _startPos).manhattanLength() > panBeginRadius) { + _panCanceled = true; + _panTimer.stop(); + return QGestureRecognizer::CancelGesture; + } + } else { + const QPointF p = QCursor::pos(); + const QPointF posOffset = p - _startPos; + g->setLastOffset(g->offset()); + g->setOffset(QPointF(posOffset.x(), posOffset.y())); + g->setHotSpot(_startPos); + return QGestureRecognizer::TriggerGesture; + } + } else if (_panTimer.isActive()) { + // I only want to cancel the pan if the user is pressing + // more than one finger, and the pan hasn't started yet: + _panCanceled = true; + _panTimer.stop(); + return QGestureRecognizer::CancelGesture; + } + break;} + case QEvent::Timer: { + QTimerEvent *ev = static_cast(event); + if (ev->timerId() == _panTimer.timerId()) { + _panTimer.stop(); + if (_panCanceled) + break; + // Begin new pan session! + _startPos = QCursor::pos(); + g->setHotSpot(_startPos); + return QGestureRecognizer::TriggerGesture | QGestureRecognizer::ConsumeEventHint; + } + break; } + default: + break; + } + + return QGestureRecognizer::Ignore; +} + +void QMacPanGestureRecognizer::reset(QGesture *gesture) +{ + QPanGesture *g = static_cast(gesture); + _startPos = QPointF(); + _panCanceled = true; + g->setOffset(QPointF(0, 0)); + g->setLastOffset(QPointF(0, 0)); + g->setAcceleration(qreal(1)); + QGestureRecognizer::reset(gesture); +} + +QT_END_NAMESPACE + +#endif // QT_NO_GESTURES diff --git a/src/widgets/kernel/qmacgesturerecognizer_p.h b/src/widgets/kernel/qmacgesturerecognizer_p.h new file mode 100644 index 0000000000..02f836b3f7 --- /dev/null +++ b/src/widgets/kernel/qmacgesturerecognizer_p.h @@ -0,0 +1,102 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtWidgets module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** 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, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, 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. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMACSWIPEGESTURERECOGNIZER_MAC_P_H +#define QMACSWIPEGESTURERECOGNIZER_MAC_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 "qtimer.h" +#include "qpoint.h" +#include "qgesturerecognizer.h" + +#ifndef QT_NO_GESTURES + +QT_BEGIN_NAMESPACE + +class QMacSwipeGestureRecognizer : public QGestureRecognizer +{ +public: + QMacSwipeGestureRecognizer(); + + QGesture *create(QObject *target); + QGestureRecognizer::Result recognize(QGesture *gesture, QObject *watched, QEvent *event); + void reset(QGesture *gesture); +}; + +class QMacPinchGestureRecognizer : public QGestureRecognizer +{ +public: + QMacPinchGestureRecognizer(); + + QGesture *create(QObject *target); + QGestureRecognizer::Result recognize(QGesture *gesture, QObject *watched, QEvent *event); + void reset(QGesture *gesture); +}; + +class QMacPanGestureRecognizer : public QObject, public QGestureRecognizer +{ +public: + QMacPanGestureRecognizer(); + + QGesture *create(QObject *target); + QGestureRecognizer::Result recognize(QGesture *gesture, QObject *watched, QEvent *event); + void reset(QGesture *gesture); +private: + QPointF _startPos; + QBasicTimer _panTimer; + bool _panCanceled; +}; + +QT_END_NAMESPACE + +#endif // QT_NO_GESTURES + +#endif // QMACSWIPEGESTURERECOGNIZER_MAC_P_H diff --git a/src/widgets/kernel/qwidgetwindow.cpp b/src/widgets/kernel/qwidgetwindow.cpp index f2bd389769..668d5b0fc0 100644 --- a/src/widgets/kernel/qwidgetwindow.cpp +++ b/src/widgets/kernel/qwidgetwindow.cpp @@ -49,6 +49,7 @@ #endif #include #include +#include QT_BEGIN_NAMESPACE @@ -220,6 +221,13 @@ bool QWidgetWindow::event(QEvent *event) handleTabletEvent(static_cast(event)); return true; #endif + +#ifndef QT_NO_GESTURES + case QEvent::NativeGesture: + handleGestureEvent(static_cast(event)); + return true; +#endif + #ifndef QT_NO_CONTEXTMENU case QEvent::ContextMenu: handleContextMenuEvent(static_cast(event)); @@ -732,6 +740,25 @@ void QWidgetWindow::handleTabletEvent(QTabletEvent *event) } #endif // QT_NO_TABLETEVENT +#ifndef QT_NO_GESTURES +void QWidgetWindow::handleGestureEvent(QNativeGestureEvent *e) +{ + // copy-pasted code to find correct widget follows: + QObject *receiver = 0; + if (QApplicationPrivate::inPopupMode()) { + QWidget *popup = QApplication::activePopupWidget(); + QWidget *popupFocusWidget = popup->focusWidget(); + receiver = popupFocusWidget ? popupFocusWidget : popup; + } + if (!receiver) + receiver = QApplication::widgetAt(e->globalPos()); + if (!receiver) + receiver = m_widget; // last resort + + QApplication::sendSpontaneousEvent(receiver, e); +} +#endif // QT_NO_GESTURES + #ifndef QT_NO_CONTEXTMENU void QWidgetWindow::handleContextMenuEvent(QContextMenuEvent *e) { diff --git a/src/widgets/kernel/qwidgetwindow_qpa_p.h b/src/widgets/kernel/qwidgetwindow_qpa_p.h index cb7bef8f3e..341aaba0d5 100644 --- a/src/widgets/kernel/qwidgetwindow_qpa_p.h +++ b/src/widgets/kernel/qwidgetwindow_qpa_p.h @@ -91,6 +91,9 @@ protected: #ifndef QT_NO_TABLETEVENT void handleTabletEvent(QTabletEvent *); #endif +#ifndef QT_NO_GESTURES + void handleGestureEvent(QNativeGestureEvent *); +#endif #ifndef QT_NO_CONTEXTMENU void handleContextMenuEvent(QContextMenuEvent *); #endif