diff options
author | Gunnar Sletta <gunnar@trolltech.com> | 2009-10-19 04:58:20 (GMT) |
---|---|---|
committer | Gunnar Sletta <gunnar@trolltech.com> | 2009-10-19 04:58:20 (GMT) |
commit | 91e133d9eeba0b7ea87a3ddb3f10d2a2b345473d (patch) | |
tree | 499f3a3e0ba67c76da18a33fd331569670578a79 /src/gui/kernel | |
parent | 4a0e3170c779a6a37954c3dfcfd0b9f0ce144701 (diff) | |
parent | c3bab81d5966c9bd3a42d9c5cbb9d8ad35a1b330 (diff) | |
download | Qt-91e133d9eeba0b7ea87a3ddb3f10d2a2b345473d.zip Qt-91e133d9eeba0b7ea87a3ddb3f10d2a2b345473d.tar.gz Qt-91e133d9eeba0b7ea87a3ddb3f10d2a2b345473d.tar.bz2 |
Merge branch '4.6' of git@scm.dev.nokia.troll.no:qt/qt into 4.6
Diffstat (limited to 'src/gui/kernel')
32 files changed, 2895 insertions, 1329 deletions
diff --git a/src/gui/kernel/kernel.pri b/src/gui/kernel/kernel.pri index 760d73c..53c2611 100644 --- a/src/gui/kernel/kernel.pri +++ b/src/gui/kernel/kernel.pri @@ -45,10 +45,11 @@ HEADERS += \ kernel/qkeymapper_p.h \ kernel/qgesture.h \ kernel/qgesture_p.h \ - kernel/qstandardgestures.h \ - kernel/qstandardgestures_p.h \ - kernel/qsoftkeymanager_p.h \ - kernel/qguiplatformplugin_p.h + kernel/qstandardgestures_p.h \ + kernel/qgesturerecognizer.h \ + kernel/qgesturemanager_p.h \ + kernel/qsoftkeymanager_p.h \ + kernel/qguiplatformplugin_p.h SOURCES += \ kernel/qaction.cpp \ @@ -79,13 +80,18 @@ SOURCES += \ kernel/qwidgetaction.cpp \ kernel/qkeymapper.cpp \ kernel/qgesture.cpp \ - kernel/qstandardgestures.cpp \ - kernel/qsoftkeymanager.cpp \ - kernel/qguiplatformplugin.cpp + kernel/qstandardgestures.cpp \ + kernel/qgesturerecognizer.cpp \ + kernel/qgesturemanager.cpp \ + kernel/qsoftkeymanager.cpp \ + kernel/qguiplatformplugin.cpp win32 { DEFINES += QT_NO_DIRECTDRAW + HEADERS += \ + kernel/qwinnativepangesturerecognizer_win_p.h + SOURCES += \ kernel/qapplication_win.cpp \ kernel/qclipboard_win.cpp \ @@ -96,7 +102,8 @@ win32 { kernel/qsound_win.cpp \ kernel/qwidget_win.cpp \ kernel/qole_win.cpp \ - kernel/qkeymapper_win.cpp + kernel/qkeymapper_win.cpp \ + kernel/qwinnativepangesturerecognizer_win.cpp !contains(DEFINES, QT_NO_DIRECTDRAW):LIBS += ddraw.lib } @@ -198,6 +205,7 @@ embedded { qcocoaview_mac_p.h \ qcocoaapplication_mac_p.h \ qcocoaapplicationdelegate_mac_p.h \ + qmacgesturerecognizer_mac_p.h \ qmultitouch_mac_p.h OBJECTIVE_SOURCES += \ @@ -217,7 +225,8 @@ embedded { kernel/qdesktopwidget_mac.mm \ kernel/qeventdispatcher_mac.mm \ kernel/qcocoawindowcustomthemeframe_mac.mm \ - kernel/qmultitouch_mac.mm \ + kernel/qmacgesturerecognizer_mac.mm \ + kernel/qmultitouch_mac.mm HEADERS += \ kernel/qt_cocoa_helpers_mac_p.h \ diff --git a/src/gui/kernel/qapplication.cpp b/src/gui/kernel/qapplication.cpp index 43addb6..6f6d706 100644 --- a/src/gui/kernel/qapplication.cpp +++ b/src/gui/kernel/qapplication.cpp @@ -99,6 +99,9 @@ #include "qapplication.h" +#include "qgesture.h" +#include "private/qgesturemanager_p.h" + #ifndef QT_NO_LIBRARY #include "qlibrary.h" #endif @@ -154,6 +157,14 @@ bool QApplicationPrivate::autoSipEnabled = false; bool QApplicationPrivate::autoSipEnabled = true; #endif +QGestureManager* QGestureManager::instance() +{ + QApplicationPrivate *d = qApp->d_func(); + if (!d->gestureManager) + d->gestureManager = new QGestureManager(qApp); + return d->gestureManager; +} + QApplicationPrivate::QApplicationPrivate(int &argc, char **argv, QApplication::Type type) : QCoreApplicationPrivate(argc, argv) { @@ -177,6 +188,8 @@ QApplicationPrivate::QApplicationPrivate(int &argc, char **argv, QApplication::T directPainters = 0; #endif + gestureManager = 0; + if (!self) self = this; } @@ -930,7 +943,7 @@ void QApplicationPrivate::initialize() graphics_system = QGraphicsSystemFactory::create(graphics_system_name); #endif #ifndef QT_NO_WHEELEVENT -#ifdef Q_OS_MAC +#ifdef Q_OS_MAC QApplicationPrivate::wheel_scroll_lines = 1; #else QApplicationPrivate::wheel_scroll_lines = 3; @@ -1021,11 +1034,11 @@ QApplication::~QApplication() d->eventDispatcher->closingDown(); d->eventDispatcher = 0; + QApplicationPrivate::is_app_closing = true; + QApplicationPrivate::is_app_running = false; delete qt_desktopWidget; qt_desktopWidget = 0; - QApplicationPrivate::is_app_closing = true; - QApplicationPrivate::is_app_running = false; #ifndef QT_NO_CLIPBOARD delete qt_clipboard; @@ -3632,6 +3645,13 @@ bool QApplication::notify(QObject *receiver, QEvent *e) #endif // !QT_NO_WHEELEVENT || !QT_NO_TABLETEVENT } + // walk through parents and check for gestures + if (d->gestureManager) { + if (d->gestureManager->filterEvent(receiver, e)) + return true; + } + + // User input and window activation makes tooltips sleep switch (e->type()) { case QEvent::Wheel: @@ -4133,6 +4153,65 @@ bool QApplication::notify(QObject *receiver, QEvent *e) } break; } + case QEvent::Gesture: + case QEvent::GestureOverride: + { + if (receiver->isWidgetType()) { + QWidget *w = static_cast<QWidget *>(receiver); + QGestureEvent *gestureEvent = static_cast<QGestureEvent *>(e); + QList<QGesture *> allGestures = gestureEvent->allGestures(); + + bool eventAccepted = gestureEvent->isAccepted(); + bool wasAccepted = eventAccepted; + while (w) { + // send only gestures the widget expects + QList<QGesture *> gestures; + QWidgetPrivate *wd = w->d_func(); + for (int i = 0; i < allGestures.size();) { + QGesture *g = allGestures.at(i); + Qt::GestureType type = g->gestureType(); + if (wd->gestureContext.contains(type)) { + allGestures.removeAt(i); + gestures.append(g); + gestureEvent->setAccepted(g, false); + } else { + ++i; + } + } + if (!gestures.isEmpty()) { + QGestureEvent ge(gestures); + ge.t = gestureEvent->t; + ge.spont = gestureEvent->spont; + ge.m_accept = wasAccepted; + res = d->notify_helper(w, &ge); + gestureEvent->spont = false; + eventAccepted = ge.isAccepted(); + if (res && eventAccepted) + break; + if (!eventAccepted) { + // ### two ways to ignore the event/gesture + + // if the whole event wasn't accepted, put back those + // gestures that were not accepted. + for (int i = 0; i < gestures.size(); ++i) { + QGesture *g = gestures.at(i); + if (!ge.isAccepted(g)) + allGestures.append(g); + } + } + } + if (allGestures.isEmpty()) + break; + if (w->isWindow()) + break; + w = w->parentWidget(); + } + gestureEvent->m_accept = eventAccepted; + } else { + res = d->notify_helper(receiver, e); + } + break; + } default: res = d->notify_helper(receiver, e); break; @@ -5540,6 +5619,37 @@ Q_GUI_EXPORT void qt_translateRawTouchEvent(QWidget *window, QApplicationPrivate::translateRawTouchEvent(window, deviceType, touchPoints); } +/*! + \since 4.6 + + Registers the given \a recognizer in the gesture framework and returns a gesture ID + for it. + + The application takes ownership of the \a recognizer and returns the gesture type + ID associated with it. For gesture recognizers which handle custom QGesture + objects (i.e., those which return Qt::CustomGesture in a QGesture::gestureType() + function) the return value is a gesture ID between Qt::CustomGesture and + Qt::LastGestureType, inclusive. + + \sa unregisterGestureRecognizer(), QGestureRecognizer::createGesture(), QGesture +*/ +Qt::GestureType QApplication::registerGestureRecognizer(QGestureRecognizer *recognizer) +{ + return QGestureManager::instance()->registerGestureRecognizer(recognizer); +} + +/*! + \since 4.6 + + Unregisters all gesture recognizers of the specified \a type. + + \sa registerGestureRecognizer() +*/ +void QApplication::unregisterGestureRecognizer(Qt::GestureType type) +{ + QGestureManager::instance()->unregisterGestureRecognizer(type); +} + QT_END_NAMESPACE #include "moc_qapplication.cpp" diff --git a/src/gui/kernel/qapplication.h b/src/gui/kernel/qapplication.h index 5f21a56..12b398d 100644 --- a/src/gui/kernel/qapplication.h +++ b/src/gui/kernel/qapplication.h @@ -86,6 +86,7 @@ class QDecoration; class QApplication; class QApplicationPrivate; +class QGestureRecognizer; #if defined(qApp) #undef qApp #endif @@ -289,6 +290,9 @@ public: static Qt::NavigationMode navigationMode(); #endif + Qt::GestureType registerGestureRecognizer(QGestureRecognizer *recognizer); + void unregisterGestureRecognizer(Qt::GestureType type); + Q_SIGNALS: void lastWindowClosed(); void focusChanged(QWidget *old, QWidget *now); @@ -400,6 +404,7 @@ private: friend class QDirectPainter; friend class QDirectPainterPrivate; #endif + friend class QGestureManager; #if defined(Q_WS_MAC) || defined(Q_WS_X11) Q_PRIVATE_SLOT(d_func(), void _q_alertTimeOut()) diff --git a/src/gui/kernel/qapplication_p.h b/src/gui/kernel/qapplication_p.h index 95b6d28..2d3d18c 100644 --- a/src/gui/kernel/qapplication_p.h +++ b/src/gui/kernel/qapplication_p.h @@ -83,8 +83,8 @@ class QGraphicsSystem; class QInputContext; class QObject; class QWidget; -class QGestureManager; class QSocketNotifier; +class QGestureManager; extern bool qt_is_gui_used; #ifndef QT_NO_CLIPBOARD @@ -265,20 +265,6 @@ typedef struct tagGESTURECONFIG #endif // Q_WS_WIN -class QPanGesture; -class QPinchGesture; -class QSwipeGesture; - -struct QStandardGestures -{ - QPanGesture *pan; - QPinchGesture *pinch; - QSwipeGesture *swipe; - - QStandardGestures() : pan(0), pinch(0), swipe(0) { } -}; - - class QScopedLoopLevelCounter { QThreadData *threadData; @@ -522,6 +508,8 @@ public: void sendSyntheticEnterLeave(QWidget *widget); #endif + QGestureManager *gestureManager; + QMap<int, QWidget *> widgetForTouchPointId; QMap<int, QTouchEvent::TouchPoint> appCurrentTouchPoints; static void updateTouchPointsForWidget(QWidget *widget, QTouchEvent *touchEvent); @@ -536,9 +524,6 @@ public: QTouchEvent::DeviceType deviceType, const QList<QTouchEvent::TouchPoint> &touchPoints); - typedef QMap<QWidget*, QStandardGestures> WidgetStandardGesturesMap; - WidgetStandardGesturesMap widgetGestures; - #if defined(Q_WS_WIN) static PtrRegisterTouchWindow RegisterTouchWindow; static PtrGetTouchInputInfo GetTouchInputInfo; @@ -555,7 +540,6 @@ public: PtrBeginPanningFeedback BeginPanningFeedback; PtrUpdatePanningFeedback UpdatePanningFeedback; PtrEndPanningFeedback EndPanningFeedback; - QWidget *gestureWidget; #endif #ifdef QT_RX71_MULTITOUCH diff --git a/src/gui/kernel/qapplication_s60.cpp b/src/gui/kernel/qapplication_s60.cpp index acd1041..cb9dda4 100644 --- a/src/gui/kernel/qapplication_s60.cpp +++ b/src/gui/kernel/qapplication_s60.cpp @@ -352,7 +352,8 @@ QSymbianControl::~QSymbianControl() { if (S60->curWin == this) S60->curWin = 0; - setFocusSafely(false); + if (!QApplicationPrivate::is_app_closing) + setFocusSafely(false); S60->appUi()->RemoveFromStack(this); delete m_longTapDetector; } @@ -463,12 +464,47 @@ void QSymbianControl::HandlePointerEventL(const TPointerEvent& pEvent) QT_TRYCATCH_LEAVING(HandlePointerEvent(pEvent)); } +typedef QPair<QWidget*,QMouseEvent> Event; + +/* + * Helper function called by HandlePointerEvent - separated to keep that function readable + */ +static void generateEnterLeaveEvents(QList<Event> &events, QWidget *widgetUnderPointer, + QPoint globalPos, Qt::MouseButton button, Qt::KeyboardModifiers modifiers) +{ + //moved to another widget, create enter and leave events + if (S60->lastPointerEventTarget) { + QMouseEvent mEventLeave(QEvent::Leave, S60->lastPointerEventTarget->mapFromGlobal( + S60->lastCursorPos), S60->lastCursorPos, button, QApplicationPrivate::mouse_buttons, + modifiers); + events.append(Event(S60->lastPointerEventTarget, mEventLeave)); + } + if (widgetUnderPointer) { + QMouseEvent mEventEnter(QEvent::Enter, widgetUnderPointer->mapFromGlobal(globalPos), + globalPos, button, QApplicationPrivate::mouse_buttons, modifiers); + + events.append(Event(widgetUnderPointer, mEventEnter)); +#ifndef QT_NO_CURSOR + S60->curWin = widgetUnderPointer->effectiveWinId(); + if (!QApplication::overrideCursor()) { +#ifndef Q_SYMBIAN_FIXED_POINTER_CURSORS + if (S60->brokenPointerCursors) + qt_symbian_set_pointer_sprite(widgetUnderPointer->cursor()); + else +#endif + qt_symbian_setWindowCursor(widgetUnderPointer->cursor(), S60->curWin); + } +#endif + } +} + + void QSymbianControl::HandlePointerEvent(const TPointerEvent& pEvent) { - //### refactor me, getting too complex QMouseEvent::Type type; Qt::MouseButton button; mapS60MouseEventTypeToQt(&type, &button, &pEvent); + Qt::KeyboardModifiers modifiers = mapToQtModifiers(pEvent.iModifiers); if (m_previousEventLongTap) if (type == QEvent::MouseButtonRelease){ @@ -480,79 +516,76 @@ void QSymbianControl::HandlePointerEvent(const TPointerEvent& pEvent) return; // store events for later sending/saving - QWidget *alienWidget; - typedef QPair<QWidget*,QMouseEvent> Event; QList<Event > events; QPoint widgetPos = QPoint(pEvent.iPosition.iX, pEvent.iPosition.iY); TPoint controlScreenPos = PositionRelativeToScreen(); QPoint globalPos = QPoint(controlScreenPos.iX, controlScreenPos.iY) + widgetPos; - if (type == QEvent::MouseButtonPress || type == QEvent::MouseButtonDblClick || type == QEvent::MouseMove) - { - // get the widget where the event happened - alienWidget = qwidget->childAt(widgetPos); - if (!alienWidget) - alienWidget = qwidget; - S60->mousePressTarget = alienWidget; + // widgets interested in the event + QWidget *widgetUnderPointer = qwidget->childAt(widgetPos); + if (!widgetUnderPointer) + widgetUnderPointer = qwidget; //i.e. this container widget + + QWidget *widgetWithMouseGrab = QWidget::mouseGrabber(); + + // handle auto grab of pointer when pressing / releasing + if (!widgetWithMouseGrab && type == QEvent::MouseButtonPress) { + //if previously auto-grabbed, generate a fake mouse release (platform bug: mouse release event was lost) + if (S60->mousePressTarget) { + QMouseEvent mEvent(QEvent::MouseButtonRelease, S60->mousePressTarget->mapFromGlobal(globalPos), globalPos, + button, QApplicationPrivate::mouse_buttons, modifiers); + events.append(Event(S60->mousePressTarget,mEvent)); + } + //auto grab the mouse + widgetWithMouseGrab = S60->mousePressTarget = widgetUnderPointer; + widgetWithMouseGrab->grabMouse(); + } + if (widgetWithMouseGrab && widgetWithMouseGrab == S60->mousePressTarget && type == QEvent::MouseButtonRelease) { + //release the auto grab - note this release event still goes to the autograb widget + S60->mousePressTarget = 0; + widgetWithMouseGrab->releaseMouse(); } - alienWidget = S60->mousePressTarget; + QWidget *widgetToReceiveMouseEvent; + if (widgetWithMouseGrab) + widgetToReceiveMouseEvent = widgetWithMouseGrab; + else + widgetToReceiveMouseEvent = widgetUnderPointer; - if (alienWidget != S60->lastPointerEventTarget) - if (type == QEvent::MouseButtonPress || type == QEvent::MouseButtonDblClick || type == QEvent::MouseMove) - { - //moved to another widget, create enter and leave events - if (S60->lastPointerEventTarget) - { - QMouseEvent mEventLeave(QEvent::Leave, S60->lastPointerEventTarget->mapFromGlobal(S60->lastCursorPos), S60->lastCursorPos, - button, QApplicationPrivate::mouse_buttons, mapToQtModifiers(pEvent.iModifiers)); - events.append(Event(S60->lastPointerEventTarget,mEventLeave)); - } - if (alienWidget) { - QMouseEvent mEventEnter(QEvent::Enter, alienWidget->mapFromGlobal(globalPos), - globalPos, button, QApplicationPrivate::mouse_buttons, mapToQtModifiers( - pEvent.iModifiers)); + //queue QEvent::Enter and QEvent::Leave, if the pointer has moved + if (widgetUnderPointer != S60->lastPointerEventTarget && (type == QEvent::MouseButtonPress || type == QEvent::MouseButtonDblClick || type == QEvent::MouseMove)) + generateEnterLeaveEvents(events, widgetUnderPointer, globalPos, button, modifiers); - events.append(Event(alienWidget, mEventEnter)); -#ifndef QT_NO_CURSOR - S60->curWin = alienWidget->effectiveWinId(); - if (!QApplication::overrideCursor()) { -#ifndef Q_SYMBIAN_FIXED_POINTER_CURSORS - if (S60->brokenPointerCursors) - qt_symbian_set_pointer_sprite(alienWidget->cursor()); - else -#endif - qt_symbian_setWindowCursor(alienWidget->cursor(), S60->curWin); - } -#endif - } - } + //save global state S60->lastCursorPos = globalPos; + S60->lastPointerEventPos = widgetPos; + S60->lastPointerEventTarget = widgetUnderPointer; + #if !defined(QT_NO_CURSOR) && !defined(Q_SYMBIAN_FIXED_POINTER_CURSORS) if (S60->brokenPointerCursors) qt_symbian_move_cursor_sprite(); #endif - S60->lastPointerEventPos = widgetPos; - S60->lastPointerEventTarget = alienWidget; - if (alienWidget) - { - QMouseEvent mEvent(type, alienWidget->mapFromGlobal(globalPos), globalPos, - button, QApplicationPrivate::mouse_buttons, mapToQtModifiers(pEvent.iModifiers)); - events.append(Event(alienWidget,mEvent)); - QEventDispatcherS60 *dispatcher; - // It is theoretically possible for someone to install a different event dispatcher. - if ((dispatcher = qobject_cast<QEventDispatcherS60 *>(alienWidget->d_func()->threadData->eventDispatcher)) != 0) { - if (dispatcher->excludeUserInputEvents()) { - for (int i=0;i < events.count();++i) - { - Event next = events[i]; - dispatcher->saveInputEvent(this, next.first, new QMouseEvent(next.second)); - } - return; + + //queue this event. + Q_ASSERT(widgetToReceiveMouseEvent); + QMouseEvent mEvent(type, widgetToReceiveMouseEvent->mapFromGlobal(globalPos), globalPos, + button, QApplicationPrivate::mouse_buttons, modifiers); + events.append(Event(widgetToReceiveMouseEvent,mEvent)); + QEventDispatcherS60 *dispatcher; + // It is theoretically possible for someone to install a different event dispatcher. + if ((dispatcher = qobject_cast<QEventDispatcherS60 *>(widgetToReceiveMouseEvent->d_func()->threadData->eventDispatcher)) != 0) { + if (dispatcher->excludeUserInputEvents()) { + for (int i=0;i < events.count();++i) + { + Event next = events[i]; + dispatcher->saveInputEvent(this, next.first, new QMouseEvent(next.second)); } + return; } } + + //send events in the queue for (int i=0;i < events.count();++i) { Event next = events[i]; @@ -688,7 +721,7 @@ TKeyResponse QSymbianControl::OfferKeyEvent(const TKeyEvent& keyEvent, TEventCod Qt::KeyboardModifiers mods = mapToQtModifiers(keyEvent.iModifiers); QKeyEventEx qKeyEvent(type == EEventKeyUp ? QEvent::KeyRelease : QEvent::KeyPress, keyCode, mods, qt_keymapper_private()->translateKeyEvent(keyCode, mods), - false, 1, keyEvent.iScanCode, s60Keysym, mods); + false, 1, keyEvent.iScanCode, s60Keysym, keyEvent.iModifiers); // WId wid = reinterpret_cast<RWindowGroup *>(keyEvent.Handle())->Child(); // if (!wid) // Could happen if window isn't shown yet. @@ -948,7 +981,8 @@ void QSymbianControl::setFocusSafely(bool focus) S60->appUi()->RemoveFromStack(this); QT_TRAP_THROWING(S60->appUi()->AddToStackL(this, ECoeStackPriorityDefault, ECoeStackFlagStandard)); - lastFocusedControl = 0; + if(this == lastFocusedControl) + lastFocusedControl = 0; this->SetFocus(false); } } @@ -1121,6 +1155,11 @@ void qt_init(QApplicationPrivate * /* priv */, int) ; } */ + + // Register WId with the metatype system. This is to enable + // QWidgetPrivate::create_sys to used delayed slot invokation in order + // to destroy WId objects during reparenting. + qRegisterMetaType<WId>("WId"); } /***************************************************************************** diff --git a/src/gui/kernel/qapplication_win.cpp b/src/gui/kernel/qapplication_win.cpp index 270562f..5bb25fa 100644 --- a/src/gui/kernel/qapplication_win.cpp +++ b/src/gui/kernel/qapplication_win.cpp @@ -92,8 +92,6 @@ extern void qt_wince_hide_taskbar(HWND hwnd); //defined in qguifunctions_wince.c #include <private/qkeymapper_p.h> #include <private/qlocale_p.h> #include "qevent_p.h" -#include "qstandardgestures.h" -#include "qstandardgestures_p.h" //#define ALIEN_DEBUG @@ -821,13 +819,16 @@ void qt_init(QApplicationPrivate *priv, int) priv->GetGestureInfo = 0; priv->GetGestureExtraArgs = 0; + priv->CloseGestureInfoHandle = 0; + priv->SetGestureConfig = 0; + priv->GetGestureConfig = 0; + priv->BeginPanningFeedback = 0; + priv->UpdatePanningFeedback = 0; + priv->EndPanningFeedback = 0; #if defined(Q_WS_WINCE_WM) && defined(QT_WINCE_GESTURES) priv->GetGestureInfo = (PtrGetGestureInfo) &TKGetGestureInfo; priv->GetGestureExtraArgs = (PtrGetGestureExtraArgs) &TKGetGestureExtraArguments; - priv->CloseGestureInfoHandle = (PtrCloseGestureInfoHandle) 0; - priv->SetGestureConfig = (PtrSetGestureConfig) 0; - priv->GetGestureConfig = (PtrGetGestureConfig) 0; #elif !defined(Q_WS_WINCE) priv->GetGestureInfo = (PtrGetGestureInfo)QLibrary::resolve(QLatin1String("user32"), @@ -854,7 +855,6 @@ void qt_init(QApplicationPrivate *priv, int) (PtrEndPanningFeedback)QLibrary::resolve(QLatin1String("uxtheme"), "EndPanningFeedback"); #endif - priv->gestureWidget = 0; } /***************************************************************************** @@ -2499,24 +2499,24 @@ LRESULT CALLBACK QtWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam if (qAppPriv->GetGestureInfo) bResult = qAppPriv->GetGestureInfo((HANDLE)msg.lParam, &gi); if (bResult) { - if (gi.dwID == GID_BEGIN) { - // find the alien widget for the gesture position. - // This might not be accurate as the position is the center - // point of two fingers for multi-finger gestures. - QPoint pt(gi.ptsLocation.x, gi.ptsLocation.y); - QWidget *w = widget->childAt(widget->mapFromGlobal(pt)); - qAppPriv->gestureWidget = w ? w : widget; - } - if (qAppPriv->gestureWidget) - static_cast<QETWidget*>(qAppPriv->gestureWidget)->translateGestureEvent(msg, gi); - if (qAppPriv->CloseGestureInfoHandle) - qAppPriv->CloseGestureInfoHandle((HANDLE)msg.lParam); - if (gi.dwID == GID_END) - qAppPriv->gestureWidget = 0; - } else { - DWORD dwErr = GetLastError(); - if (dwErr > 0) - qWarning() << "translateGestureEvent: error = " << dwErr; +// if (gi.dwID == GID_BEGIN) { +// // find the alien widget for the gesture position. +// // This might not be accurate as the position is the center +// // point of two fingers for multi-finger gestures. +// QPoint pt(gi.ptsLocation.x, gi.ptsLocation.y); +// QWidget *w = widget->childAt(widget->mapFromGlobal(pt)); +// qAppPriv->gestureWidget = w ? w : widget; +// } +// if (qAppPriv->gestureWidget) +// static_cast<QETWidget*>(qAppPriv->gestureWidget)->translateGestureEvent(msg, gi); +// if (qAppPriv->CloseGestureInfoHandle) +// qAppPriv->CloseGestureInfoHandle((HANDLE)msg.lParam); +// if (gi.dwID == GID_END) +// qAppPriv->gestureWidget = 0; +// } else { +// DWORD dwErr = GetLastError(); +// if (dwErr > 0) +// qWarning() << "translateGestureEvent: error = " << dwErr; } result = true; break; diff --git a/src/gui/kernel/qcocoaview_mac.mm b/src/gui/kernel/qcocoaview_mac.mm index b1c5fc5..4c2a14a 100644 --- a/src/gui/kernel/qcocoaview_mac.mm +++ b/src/gui/kernel/qcocoaview_mac.mm @@ -1066,7 +1066,10 @@ extern "C" { sendToPopup = true; } - if (widgetToGetKey->testAttribute(Qt::WA_InputMethodEnabled)) { + if (widgetToGetKey->testAttribute(Qt::WA_InputMethodEnabled) + && !(widgetToGetKey->inputMethodHints() & Qt::ImhDigitsOnly + || widgetToGetKey->inputMethodHints() & Qt::ImhFormattedNumbersOnly + || widgetToGetKey->inputMethodHints() & Qt::ImhHiddenText)) { [qt_mac_nativeview_for(widgetToGetKey) interpretKeyEvents:[NSArray arrayWithObject: theEvent]]; } if (sendKeyEvents && !composing) { @@ -1420,29 +1423,29 @@ Qt::DropAction QDragManager::drag(QDrag *o) // convert the image to NSImage. NSImage *image = (NSImage *)qt_mac_create_nsimage(pix); [image retain]; - DnDParams *dndParams = [QT_MANGLE_NAMESPACE(QCocoaView) currentMouseEvent]; + DnDParams dndParams = *[QT_MANGLE_NAMESPACE(QCocoaView) currentMouseEvent]; // save supported actions - [dndParams->view setSupportedActions: qt_mac_mapDropActions(dragPrivate()->possible_actions)]; - NSPoint imageLoc = {dndParams->localPoint.x - hotspot.x(), - dndParams->localPoint.y + pix.height() - hotspot.y()}; + [dndParams.view setSupportedActions: qt_mac_mapDropActions(dragPrivate()->possible_actions)]; + NSPoint imageLoc = {dndParams.localPoint.x - hotspot.x(), + dndParams.localPoint.y + pix.height() - hotspot.y()}; NSSize mouseOffset = {0.0, 0.0}; NSPasteboard *pboard = [NSPasteboard pasteboardWithName:NSDragPboard]; - NSPoint windowPoint = [dndParams->theEvent locationInWindow]; + NSPoint windowPoint = [dndParams.theEvent locationInWindow]; dragPrivate()->executed_action = Qt::ActionMask; // do the drag - [dndParams->view retain]; - [dndParams->view dragImage:image + [dndParams.view retain]; + [dndParams.view dragImage:image at:imageLoc offset:mouseOffset - event:dndParams->theEvent + event:dndParams.theEvent pasteboard:pboard - source:dndParams->view + source:dndParams.view slideBack:YES]; - [dndParams->view release]; + [dndParams.view release]; [image release]; dragPrivate()->executed_action = Qt::IgnoreAction; object = 0; - Qt::DropAction performedAction(qt_mac_mapNSDragOperation(dndParams->performedAction)); + Qt::DropAction performedAction(qt_mac_mapNSDragOperation(dndParams.performedAction)); // do post drag processing, if required. if(performedAction != Qt::IgnoreAction) { // check if the receiver points us to a file location. diff --git a/src/gui/kernel/qcursor_s60.cpp b/src/gui/kernel/qcursor_s60.cpp index 0d8283d..7f5c32a 100644 --- a/src/gui/kernel/qcursor_s60.cpp +++ b/src/gui/kernel/qcursor_s60.cpp @@ -110,7 +110,7 @@ void qt_symbian_set_cursor_visible(bool visible) { else cursorSpriteVisible--; Q_ASSERT(cursorSpriteVisible >=0); - + if (cursorSpriteVisible && !S60->mouseInteractionEnabled) { #ifndef Q_SYMBIAN_FIXED_POINTER_CURSORS if (S60->brokenPointerCursors) @@ -119,7 +119,7 @@ void qt_symbian_set_cursor_visible(bool visible) { #endif S60->wsSession().SetPointerCursorMode(EPointerCursorNormal); } else if (!cursorSpriteVisible && S60->mouseInteractionEnabled) { -#ifndef Q_SYMBIAN_FIXED_POINTER_CURSORS +#ifndef Q_SYMBIAN_FIXED_POINTER_CURSORS if (S60->brokenPointerCursors) qt_symbian_hide_pointer_sprite(); else @@ -188,7 +188,7 @@ Qt::HANDLE QCursor::handle() const return reinterpret_cast<Qt::HANDLE> (&(d->pcurs)); #ifdef Q_SYMBIAN_HAS_SYSTEM_CURSORS - // don't construct shape cursors, QApplication_s60 will use the system cursor instead + // don't construct shape cursors, QApplication_s60 will use the system cursor instead if (!(d->bm)) return 0; #endif @@ -228,12 +228,12 @@ void QCursorData::loadShapeFromResource(RWsSpriteBase& target, QString resource, /* * Constructs the native cursor from resources compiled into QtGui * This is needed only when the platform doesn't have system cursors. - * + * * System cursors are higher performance, since they are constructed once * and shared by all applications by specifying the shape number. * Due to symbian platform security considerations, and the fact most * existing phones have a broken RWsPointerCursor, system cursors are not - * being used. + * being used. */ void QCursorData::constructShapeSprite(RWsSpriteBase& target) { @@ -346,7 +346,7 @@ void QCursorData::constructCursorSprite(RWsSpriteBase& target) member->iMaskBitmap = pixmap.mask().toSymbianCFbsBitmap(); } else { - member->iMaskBitmap = pixmap.createHeuristicMask().toSymbianCFbsBitmap(); + member->iMaskBitmap = 0; //opaque rectangle cursor (due to EDrawModePEN) } } @@ -371,11 +371,11 @@ void qt_symbian_show_pointer_sprite() } else { cursorSprite = QCursor(Qt::ArrowCursor); } - + cursorSprite.d->scurs = RWsSprite(S60->wsSession()); QPoint pos = QCursor::pos(); cursorSprite.d->scurs.Construct(S60->windowGroup(), TPoint(pos.x(), pos.y()), ESpriteNoChildClip | ESpriteNoShadows); - + cursorSprite.d->constructCursorSprite(cursorSprite.d->scurs); cursorSprite.d->scurs.Activate(); } @@ -409,7 +409,7 @@ void qt_symbian_set_pointer_sprite(const QCursor& cursor) * RWsPointerCursor, this function is called in response to pointer events * and when QCursor::setPos() is called. * Performance is worse than a real pointer cursor, due to extra context - * switches vs. the window server moving the cursor by itself. + * switches vs. the window server moving the cursor by itself. */ void qt_symbian_move_cursor_sprite() { @@ -421,7 +421,7 @@ void qt_symbian_move_cursor_sprite() /* * Translate from Qt::CursorShape to OS system pointer cursor list index. * Currently we control the implementation of the system pointer cursor list, - * so this function is trivial. That may not always be the case. + * so this function is trivial. That may not always be the case. */ TInt qt_symbian_translate_cursor_shape(Qt::CursorShape shape) { @@ -462,7 +462,7 @@ void qt_symbian_set_cursor(QWidget *w, bool force) /* * Makes the specified cursor appear above a specific native window group * Called from QSymbianControl and QApplication::restoreOverrideCursor - * + * * Window server is needed for this, so there is no equivalent when using * the sprite workaround. */ @@ -486,7 +486,7 @@ void qt_symbian_setWindowGroupCursor(const QCursor &cursor, RWindowTreeNode &nod /* * Makes the specified cursor appear above a specific native window * Called from QSymbianControl and QApplication::restoreOverrideCursor - * + * * Window server is needed for this, so there is no equivalent when using * the sprite workaround. */ diff --git a/src/gui/kernel/qdnd_s60.cpp b/src/gui/kernel/qdnd_s60.cpp index 3d6ecd2..a8d3ac5 100644 --- a/src/gui/kernel/qdnd_s60.cpp +++ b/src/gui/kernel/qdnd_s60.cpp @@ -277,7 +277,7 @@ Qt::DropAction QDragManager::drag(QDrag *o) qApp->installEventFilter(this); - global_accepted_action = Qt::MoveAction; + global_accepted_action = defaultAction(dragPrivate()->possible_actions, Qt::NoModifier); qt_symbian_dnd_dragging = true; eventLoop = new QEventLoop; @@ -288,7 +288,7 @@ Qt::DropAction QDragManager::drag(QDrag *o) #ifndef QT_NO_CURSOR qt_symbian_set_cursor_visible(false); - + overrideCursor = QCursor(); //deref the cursor data qt_symbian_dnd_dragging = false; #endif diff --git a/src/gui/kernel/qevent.cpp b/src/gui/kernel/qevent.cpp index 7b9cc9a..2ff6d65 100644 --- a/src/gui/kernel/qevent.cpp +++ b/src/gui/kernel/qevent.cpp @@ -49,6 +49,8 @@ #include "qmime.h" #include "qdnd_p.h" #include "qevent_p.h" +#include "qgesture.h" +#include "qgesture_p.h" QT_BEGIN_NAMESPACE @@ -3357,6 +3359,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(); @@ -3558,6 +3563,7 @@ QMenubarUpdatedEvent::QMenubarUpdatedEvent(QMenuBar * const menuBar) \brief The QTouchEvent class contains parameters that describe a touch event. \since 4.6 \ingroup events + \ingroup multitouch \section1 Enabling Touch Events @@ -4186,4 +4192,170 @@ QTouchEvent::TouchPoint &QTouchEvent::TouchPoint::operator=(const QTouchEvent::T return *this; } +/*! + \class QGestureEvent + \since 4.6 + \ingroup events + \ingroup gestures + + \brief The QGestureEvent class provides the description of triggered gestures. + + The QGestureEvent class contains a list of gestures, which can be obtained using the + allGestures() function. + + The gestures are either active or canceled. A list of those that are currently being + executed can be obtained using the activeGestures() function. A list of those which + were previously active and have been canceled can be accessed using the + canceledGestures() function. A gesture might be canceled if the current window loses + focus, for example, or because of a timeout, or for other reasons. + + If the event handler does not accept the event by calling the generic + QEvent::accept() function, all individual QGesture object that were not accepted + will be propagated up the parent widget chain until a widget accepts them + individually, by calling QGestureEvent::accept() for each of them, or an event + filter consumes the event. + + \sa QGesture, QGestureRecognizer, + QWidget::grabGesture(), QGraphicsObject::grabGesture() +*/ + +/*! + Creates new QGestureEvent containing a list of \a gestures. +*/ +QGestureEvent::QGestureEvent(const QList<QGesture *> &gestures) + : QEvent(QEvent::Gesture), gestures_(gestures) +{ +} + +/*! + Returns all gestures that are delivered in the event. +*/ +QList<QGesture *> QGestureEvent::allGestures() const +{ + return gestures_; +} + +/*! + Returns a gesture object by \a type. +*/ +QGesture *QGestureEvent::gesture(Qt::GestureType type) const +{ + for(int i = 0; i < gestures_.size(); ++i) + if (gestures_.at(i)->gestureType() == type) + return gestures_.at(i); + return 0; +} + +/*! + Returns a list of active (not canceled) gestures. +*/ +QList<QGesture *> QGestureEvent::activeGestures() const +{ + return gestures_; +} + +/*! + Returns a list of canceled gestures. +*/ +QList<QGesture *> QGestureEvent::canceledGestures() const +{ + return gestures_; +} + +/*! + Sets the accept flag of the given \a gesture object to the specified \a value. + + Setting the accept flag indicates that the event receiver wants the \a gesture. + Unwanted gestures may be propagated to the parent widget. + + By default, gestures in events of type QEvent::Gesture are accepted, and + gestures in QEvent::GestureOverride events are ignored. + + For convenience, the accept flag can also be set with + \l{QGestureEvent::accept()}{accept(gesture)}, and cleared with + \l{QGestureEvent::ignore()}{ignore(gesture)}. +*/ +void QGestureEvent::setAccepted(QGesture *gesture, bool value) +{ + setAccepted(false); + if (gesture) + gesture->d_func()->accept = value; +} + +/*! + Sets the accept flag of the given \a gesture object, the equivalent of calling + \l{QGestureEvent::setAccepted()}{setAccepted(gesture, true)}. + + Setting the accept flag indicates that the event receiver wants the + gesture. Unwanted gestures may be propagated to the parent widget. + + \sa QGestureEvent::ignore() +*/ +void QGestureEvent::accept(QGesture *gesture) +{ + setAccepted(gesture, true); +} + +/*! + Clears the accept flag parameter of the given \a gesture object, the equivalent + of calling \l{QGestureEvent::setAccepted()}{setAccepted(gesture, false)}. + + Clearing the accept flag indicates that the event receiver does not + want the gesture. Unwanted gestures may be propgated to the parent widget. + + \sa QGestureEvent::accept() +*/ +void QGestureEvent::ignore(QGesture *gesture) +{ + setAccepted(gesture, false); +} + +/*! + Returns true if the \a gesture is accepted; otherwise returns false. +*/ +bool QGestureEvent::isAccepted(QGesture *gesture) const +{ + return gesture ? gesture->d_func()->accept : false; +} + +#ifdef Q_NO_USING_KEYWORD +/*! + \fn void QGestureEvent::setAccepted(bool accepted) + + Sets or clears the event's internal flag that determines whether it should + be delivered to other objects. + + Calling this function with a value of true for \a accepted indicates that the + caller has accepted the event and that it should not be propagated further. + Calling this function with a value of false indicates that the caller has + ignored the event and that it should be delivered to other objects. + + For convenience, the accept flag can also be set with accept(), and cleared + with ignore(). + + \sa QEvent::accepted +*/ +/*! + \fn bool QGestureEvent::isAccepted() const + + Returns true is the event has been accepted; otherwise returns false. + + \sa QEvent::accepted +*/ +/*! + \fn void QGestureEvent::accept() + + Accepts the event, the equivalent of calling setAccepted(true). + + \sa QEvent::accept() +*/ +/*! + \fn void QGestureEvent::ignore() + + Ignores the event, the equivalent of calling setAccepted(false). + + \sa QEvent::ignore() +*/ +#endif + QT_END_NAMESPACE diff --git a/src/gui/kernel/qevent.h b/src/gui/kernel/qevent.h index 4396766..3516222 100644 --- a/src/gui/kernel/qevent.h +++ b/src/gui/kernel/qevent.h @@ -819,6 +819,40 @@ protected: friend class QApplicationPrivate; }; +class QGesture; +class Q_GUI_EXPORT QGestureEvent : public QEvent +{ +public: + QGestureEvent(const QList<QGesture *> &gestures); + + QList<QGesture *> allGestures() const; + QGesture *gesture(Qt::GestureType type) const; + + QList<QGesture *> activeGestures() const; + QList<QGesture *> canceledGestures() const; + +#ifdef Q_NO_USING_KEYWORD + inline void setAccepted(bool accepted) { QEvent::setAccepted(accepted); } + inline bool isAccepted() const { return QEvent::isAccepted(); } + + inline void accept() { QEvent::accept(); } + inline void ignore() { QEvent::ignore(); } +#else + using QEvent::setAccepted; + using QEvent::isAccepted; + using QEvent::accept; + using QEvent::ignore; +#endif + + void setAccepted(QGesture *, bool); + void accept(QGesture *); + void ignore(QGesture *); + bool isAccepted(QGesture *) const; + +private: + QList<QGesture *> gestures_; +}; + QT_END_NAMESPACE QT_END_HEADER diff --git a/src/gui/kernel/qeventdispatcher_mac.mm b/src/gui/kernel/qeventdispatcher_mac.mm index 7152705..c9dd949 100644 --- a/src/gui/kernel/qeventdispatcher_mac.mm +++ b/src/gui/kernel/qeventdispatcher_mac.mm @@ -136,14 +136,19 @@ void QEventDispatcherMacPrivate::activateTimer(CFRunLoopTimerRef, void *info) if (tmr == 0 || tmr->pending == true) return; // Can't send another timer event if it's pending. - tmr->pending = true; - QTimerEvent e(tmr->id); - qt_sendSpontaneousEvent(tmr->obj, &e); - // Get the value again in case the timer gets unregistered during the sendEvent. - tmr = macTimerHash.value(timerID); - if (tmr != 0) - tmr->pending = false; + if (blockSendPostedEvents) { + QCoreApplication::postEvent(tmr->obj, new QTimerEvent(tmr->id)); + } else { + tmr->pending = true; + QTimerEvent e(tmr->id); + qt_sendSpontaneousEvent(tmr->obj, &e); + // Get the value again in case the timer gets unregistered during the sendEvent. + tmr = macTimerHash.value(timerID); + if (tmr != 0) + tmr->pending = false; + } + } void QEventDispatcherMac::registerTimer(int timerId, int interval, QObject *obj) @@ -767,7 +772,7 @@ NSModalSession QEventDispatcherMacPrivate::currentModalSession() // Sadly, we need to introduce this little event flush // to stop dialogs from blinking/poping in front if a // modal session restart was needed: - while (NSEvent *event = [NSApp nextEventMatchingMask:NSAnyEventMask + while (NSEvent *event = [NSApp nextEventMatchingMask:0 untilDate:nil inMode:NSDefaultRunLoopMode dequeue: YES]) { @@ -942,7 +947,7 @@ Boolean QEventDispatcherMacPrivate::postedEventSourceEqualCallback(const void *i inline static void processPostedEvents(QEventDispatcherMacPrivate *const d, const bool blockSendPostedEvents) { - if (blockSendPostedEvents) { + if (blockSendPostedEvents || d->interrupt) { CFRunLoopSourceSignal(d->postedEventsSource); } else { if (!d->threadData->canWait || (d->serialNumber != d->lastSerial)) { diff --git a/src/gui/kernel/qgesture.cpp b/src/gui/kernel/qgesture.cpp index 237ce46..fc8df49 100644 --- a/src/gui/kernel/qgesture.cpp +++ b/src/gui/kernel/qgesture.cpp @@ -40,274 +40,585 @@ ****************************************************************************/ #include "qgesture.h" -#include <private/qgesture_p.h> -#include "qgraphicsitem.h" +#include "private/qgesture_p.h" QT_BEGIN_NAMESPACE - -class QEventFilterProxyGraphicsItem : public QGraphicsItem -{ -public: - QEventFilterProxyGraphicsItem(QGesture *g) - : gesture(g) - { - } - bool sceneEventFilter(QGraphicsItem *, QEvent *event) - { - return gesture ? gesture->filterEvent(event) : false; - } - QRectF boundingRect() const { return QRectF(); } - void paint(QPainter*, const QStyleOptionGraphicsItem*, QWidget*) { } - -private: - QGesture *gesture; -}; - -/*! + /*! \class QGesture \since 4.6 - \preliminary + \ingroup gestures + + \brief The QGesture class represents a gesture, containing properties that + describe the corresponding user input. - \brief The QGesture class is the base class for implementing custom - gestures. + Gesture objects are not constructed directly by developers. They are created by + the QGestureRecognizer object that is registered with the application; see + QApplication::registerGestureRecognizer(). - This class represents both an object that recognizes a gesture out of a set - of input events (a gesture recognizer), and a gesture object itself that - can be used to get extended information about the triggered gesture. + \section1 Gesture Properties The class has a list of properties that can be queried by the user to get - some gesture-specific parameters (for example, an offset of a Pan gesture). + some gesture-specific arguments. For example, the pinch gesture has a scale + factor that is exposed as a property. + + Developers of custom gesture recognizers can add additional properties in + order to provide additional information about a gesture. This can be done + by adding new dynamic properties to a QGesture object, or by subclassing + the QGesture class (or one of its subclasses). + + \section1 Lifecycle of a Gesture Object - Usually gesture recognizer implements a state machine, storing its state - internally in the recognizer object. The recognizer receives input events - through the \l{QGesture::}{filterEvent()} virtual function and decides - whether the event should change the state of the recognizer by emitting an - appropriate signal. + A QGesture instance is created when the application calls QWidget::grabGesture() + or QGraphicsObject::grabGesture() to configure a widget or graphics object (the + target object) for gesture input. One gesture object is created for each target + object. - Input events should be either fed to the recognizer one by one with a - filterEvent() function, or the gesture recognizer should be attached to an - object it filters events for by specifying it as a parent object. The - QGesture object installs itself as an event filter to the parent object - automatically, the unsetObject() function should be used to remove an event - filter from the parent object. To make a - gesture that operates on a QGraphicsItem, both the appropriate QGraphicsView - should be passed as a parent object and setGraphicsItem() functions should - be used to attach a gesture to a graphics item. + The registered gesture recognizer monitors the input events for the target + object via its \l{QGestureRecognizer::}{filterEvent()} function, updating the + properties of the gesture object as required. - This is a base class, to create a custom gesture type, you should subclass - it and implement its pure virtual functions. + The gesture object may be delivered to the target object in a QGestureEvent if + the corresponding gesture is active or has just been canceled. Each event that + is delivered contains a list of gesture objects, since support for more than + one gesture may be enabled for the target object. Due to the way events are + handled in Qt, gesture events may be filtered by other objects. - \sa QPanGesture + \sa QGestureEvent, QGestureRecognizer */ -/*! \fn bool QGesture::filterEvent(QEvent *event) +/*! + Constructs a new gesture object with the given \a parent. + + QGesture objects are created by gesture recognizers in the + QGestureRecognizer::createGesture() function. +*/ +QGesture::QGesture(QObject *parent) + : QObject(*new QGesturePrivate, parent) +{ + d_func()->gestureType = Qt::CustomGesture; +} + +/*! + \internal +*/ +QGesture::QGesture(QGesturePrivate &dd, QObject *parent) + : QObject(dd, parent) +{ +} - Parses input \a event and emits a signal when detects a gesture. +/*! + Destroys the gesture object. +*/ +QGesture::~QGesture() +{ +} - In your reimplementation of this function, if you want to filter the \a - event out, i.e. stop it being handled further, return true; otherwise - return false; +/*! + \property QGesture::state + \brief the current state of the gesture +*/ - This is a pure virtual function that needs to be implemented in subclasses. +/*! + \property QGesture::gestureType + \brief the type of the gesture */ -/*! \fn void QGesture::started() +/*! + \property QGesture::hotSpot + + \brief The point that is used to find the receiver for the gesture event. + + If the hot-spot is not set, the targetObject is used as the receiver of the + gesture event. +*/ - The signal is emitted when the gesture is started. Extended information - about the gesture is contained in the signal sender object. +/*! + \property QGesture::hasHotSpot + \brief whether the gesture has a hot-spot +*/ - In addition to started(), a triggered() signal should also be emitted. +/*! + \property QGesture::targetObject + \brief the target object which will receive the gesture event if the hotSpot is + not set */ -/*! \fn void QGesture::triggered() +Qt::GestureType QGesture::gestureType() const +{ + return d_func()->gestureType; +} + +Qt::GestureState QGesture::state() const +{ + return d_func()->state; +} + +QObject *QGesture::targetObject() const +{ + return d_func()->targetObject; +} + +void QGesture::setTargetObject(QObject *value) +{ + d_func()->targetObject = value; +} + +QPointF QGesture::hotSpot() const +{ + return d_func()->hotSpot; +} + +void QGesture::setHotSpot(const QPointF &value) +{ + Q_D(QGesture); + d->hotSpot = value; + d->isHotSpotSet = true; +} + +bool QGesture::hasHotSpot() const +{ + return d_func()->isHotSpotSet; +} + +void QGesture::unsetHotSpot() +{ + d_func()->isHotSpotSet = false; +} + +/*! + \class QPanGesture + \since 4.6 + \brief The QPanGesture class describes a panning gesture made by the user. + \ingroup gestures - The signal is emitted when the gesture is detected. Extended information - about the gesture is contained in the signal sender object. + \image pangesture.png + + \sa {Gestures Programming}, QPinchGesture, QSwipeGesture */ -/*! \fn void QGesture::finished() +/*! + \property QPanGesture::totalOffset + \brief the total offset from the first input position to the current input + position - The signal is emitted when the gesture is finished. Extended information - about the gesture is contained in the signal sender object. + The total offset measures the total change in position of the user's input + covered by the gesture on the input device. */ -/*! \fn void QGesture::canceled() +/*! + \property QPanGesture::lastOffset + \brief the last offset recorded for this gesture + + The last offset contains the change in position of the user's input as + reported in the \l offset property when a previous gesture event was + delivered for this gesture. - The signal is emitted when the gesture is canceled, for example the - reset() function is called while the gesture was in the process of - emitting a triggered() signal. Extended information about the - gesture is contained in the sender object. + If no previous event was delivered with information about this gesture + (i.e., this gesture object contains information about the first movement + in the gesture) then this property contains a zero size. */ /*! - Creates a new gesture handler object and marks it as a child of \a - parent. \a gestureTarget is the object that the gesture will watch - for events. + \property QPanGesture::offset + \brief the offset from the previous input position to the current input + position - The \a parent object is also the default event source for the - gesture, meaning that the gesture installs itself as an event filter - for the \a parent. + The offset measures the change in position of the user's input on the + input device. +*/ - \sa setGraphicsItem() +/*! + \property QPanGesture::acceleration */ -QGesture::QGesture(QObject *gestureTarget, QObject *parent) - : QObject(*new QGesturePrivate, parent) + +/*! + \internal +*/ +QPanGesture::QPanGesture(QObject *parent) + : QGesture(*new QPanGesturePrivate, parent) { - setGestureTarget(gestureTarget); + d_func()->gestureType = Qt::PanGesture; } -/*! \internal - */ -QGesture::QGesture(QGesturePrivate &dd, QObject *gestureTarget, QObject *parent) - : QObject(dd, parent) +QSizeF QPanGesture::totalOffset() const { - setGestureTarget(gestureTarget); + return d_func()->totalOffset; } -/*! - Destroys the gesture object. -*/ -QGesture::~QGesture() +QSizeF QPanGesture::lastOffset() const { + return d_func()->lastOffset; } -/*! - \property QGesture::gestureTarget +QSizeF QPanGesture::offset() const +{ + return d_func()->offset; +} - Gesture target is the object that the gesture will watch for events. - Typically this means that the gesture installs an event filter on the - target object. -*/ -void QGesture::setGestureTarget(QObject *object) +qreal QPanGesture::acceleration() const { - d_func()->setupGestureTarget(object); + return d_func()->acceleration; } -QObject* QGesture::gestureTarget() const + +void QPanGesture::setTotalOffset(const QSizeF &value) { - return d_func()->gestureTarget; + d_func()->totalOffset = value; } -void QGesturePrivate::setupGestureTarget(QObject *object) +void QPanGesture::setLastOffset(const QSizeF &value) { - Q_Q(QGesture); - if (gestureTarget) - gestureTarget->removeEventFilter(q); - if (object) - object->installEventFilter(q); - gestureTarget = object; + d_func()->lastOffset = value; } -/*! \internal - */ -bool QGesture::eventFilter(QObject *receiver, QEvent *event) +void QPanGesture::setOffset(const QSizeF &value) { - Q_D(QGesture); - if (d->graphicsItem && receiver == parent()) - return false; - return filterEvent(event); + d_func()->offset = value; +} + +void QPanGesture::setAcceleration(qreal value) +{ + d_func()->acceleration = value; } /*! - \property QGesture::state + \class QPinchGesture + \since 4.6 + \brief The QPinchGesture class describes a pinch gesture made my the user. + \ingroup multitouch + \ingroup gestures + + A pinch gesture is a form of multitouch user input in which the user typically + touches two points on the input device with a thumb and finger, before moving + them closer together or further apart to change the scale factor, zoom, or level + of detail of the user interface. + + \image pinchgesture.png - \brief The current state of the gesture. + Instead of repeatedly applying the same pinching gesture, the user may + continue to touch the input device in one place, and apply a second touch + to a new point, continuing the gesture. When this occurs, gesture events + will continue to be delivered to the target object, containing an instance + of QPinchGesture in the Qt::GestureUpdated state. + + \sa {Gestures Programming}, QPanGesture, QSwipeGesture */ /*! - Returns the gesture recognition state. - */ -Qt::GestureState QGesture::state() const + \enum QPinchGesture::WhatChange + + This enum describes the changes that can occur to the properties of + the gesture object. + + \value ScaleFactorChanged The scale factor held by scaleFactor changed. + \value RotationAngleChanged The rotation angle held by rotationAngle changed. + \value CenterPointChanged The center point held by centerPoint changed. + + \sa whatChanged +*/ + +/*! + \property QPinchGesture::whatChanged + \brief the property of the gesture that has changed + + This property indicates which of the other properties has changed since + the previous gesture event included information about this gesture. You + can use this information to determine which aspect of your user interface + needs to be updated. + + \sa scaleFactor, rotationAngle, centerPoint +*/ + +/*! + \property QPinchGesture::totalScaleFactor + \brief the total scale factor + + The total scale factor measures the total change in scale factor from the + original value to the current scale factor. + + \sa scaleFactor, lastScaleFactor +*/ +/*! + \property QPinchGesture::lastScaleFactor + \brief the last scale factor recorded for this gesture + + The last scale factor contains the scale factor reported in the + \l scaleFactor property when a previous gesture event included + information about this gesture. + + If no previous event was delivered with information about this gesture + (i.e., this gesture object contains information about the first movement + in the gesture) then this property contains zero. + + \sa scaleFactor, totalScaleFactor +*/ +/*! + \property QPinchGesture::scaleFactor + \brief the current scale factor + + The scale factor measures the scale factor associated with the distance + between two of the user's inputs on a multitouch device. + + \sa totalScaleFactor, lastScaleFactor +*/ + +/*! + \property QPinchGesture::totalRotationAngle + \brief the total angle covered by the gesture + + This total angle measures the complete angle covered by the gesture. Usually, this + is equal to the value held by the \l rotationAngle property, except in the case where + the user performs multiple rotations by removing and repositioning one of the touch + points, as described above. In this case, the total angle will be the sum of the + rotation angles for the multiple stages of the gesture. + + \sa rotationAngle, lastRotationAngle +*/ +/*! + \property QPinchGesture::lastRotationAngle + \brief the last reported angle covered by the gesture motion + + The last rotation angle is the angle as reported in the \l rotationAngle property + when a previous gesture event was delivered for this gesture. + + \sa rotationAngle, totalRotationAngle +*/ +/*! + \property QPinchGesture::rotationAngle + \brief the angle covered by the gesture motion + + \sa totalRotationAngle, lastRotationAngle +*/ + +/*! + \property QPinchGesture::startCenterPoint + \brief the starting position of the center point + + \sa centerPoint, lastCenterPoint +*/ +/*! + \property QPinchGesture::lastCenterPoint + \brief the last position of the center point recorded for this gesture + + \sa centerPoint, startCenterPoint +*/ +/*! + \property QPinchGesture::centerPoint + \brief the current center point + + The center point is the midpoint between the two input points in the gesture. + + \sa startCenterPoint, lastCenterPoint +*/ + +/*! + \internal +*/ +QPinchGesture::QPinchGesture(QObject *parent) + : QGesture(*new QPinchGesturePrivate, parent) { - return d_func()->state; + d_func()->gestureType = Qt::PinchGesture; } -/*! - Sets this gesture's recognition state to \a state and emits appropriate - signals. +QPinchGesture::WhatChanged QPinchGesture::whatChanged() const +{ + return d_func()->whatChanged; +} + +void QPinchGesture::setWhatChanged(QPinchGesture::WhatChanged value) +{ + d_func()->whatChanged = value; +} - This functions emits the signals according to the old state and the new - \a state, and it should be called after all the internal properties have been - initialized. - \sa started(), triggered(), finished(), canceled() - */ -void QGesture::updateState(Qt::GestureState state) +QPointF QPinchGesture::startCenterPoint() const { - Q_D(QGesture); - if (d->state == state) { - if (state == Qt::GestureUpdated) - emit triggered(); - return; - } - const Qt::GestureState oldState = d->state; - if (state != Qt::NoGesture && oldState > state) { - // comparing the state as ints: state should only be changed from - // started to (optionally) updated and to finished. - d->state = state; - qWarning("QGesture::updateState: incorrect new state"); - return; - } - if (oldState == Qt::NoGesture) { - d->state = Qt::GestureStarted; - emit started(); - } - d->state = state; - if (state == Qt::GestureUpdated) - emit triggered(); - else if (state == Qt::GestureFinished) - emit finished(); - else if (state == Qt::NoGesture) - emit canceled(); - - if (state == Qt::GestureFinished) { - // gesture is finished, so we reset the internal state. - d->state = Qt::NoGesture; - } -} - -/*! - Sets the \a graphicsItem the gesture is filtering events for. - - The gesture will install an event filter to the \a graphicsItem and - redirect them to the filterEvent() function. - - \sa graphicsItem() -*/ -void QGesture::setGraphicsItem(QGraphicsItem *graphicsItem) + return d_func()->startCenterPoint; +} + +QPointF QPinchGesture::lastCenterPoint() const { - Q_D(QGesture); - if (d->graphicsItem && d->eventFilterProxyGraphicsItem) - d->graphicsItem->removeSceneEventFilter(d->eventFilterProxyGraphicsItem); - d->graphicsItem = graphicsItem; - if (!d->eventFilterProxyGraphicsItem) - d->eventFilterProxyGraphicsItem = new QEventFilterProxyGraphicsItem(this); - if (graphicsItem) - graphicsItem->installSceneEventFilter(d->eventFilterProxyGraphicsItem); + return d_func()->lastCenterPoint; +} + +QPointF QPinchGesture::centerPoint() const +{ + return d_func()->centerPoint; +} + +void QPinchGesture::setStartCenterPoint(const QPointF &value) +{ + d_func()->startCenterPoint = value; +} + +void QPinchGesture::setLastCenterPoint(const QPointF &value) +{ + d_func()->lastCenterPoint = value; +} + +void QPinchGesture::setCenterPoint(const QPointF &value) +{ + d_func()->centerPoint = value; +} + + +qreal QPinchGesture::totalScaleFactor() const +{ + return d_func()->totalScaleFactor; +} + +qreal QPinchGesture::lastScaleFactor() const +{ + return d_func()->lastScaleFactor; +} + +qreal QPinchGesture::scaleFactor() const +{ + return d_func()->scaleFactor; +} + +void QPinchGesture::setTotalScaleFactor(qreal value) +{ + d_func()->totalScaleFactor = value; +} + +void QPinchGesture::setLastScaleFactor(qreal value) +{ + d_func()->lastScaleFactor = value; +} + +void QPinchGesture::setScaleFactor(qreal value) +{ + d_func()->scaleFactor = value; +} + + +qreal QPinchGesture::totalRotationAngle() const +{ + return d_func()->totalRotationAngle; +} + +qreal QPinchGesture::lastRotationAngle() const +{ + return d_func()->lastRotationAngle; +} + +qreal QPinchGesture::rotationAngle() const +{ + return d_func()->rotationAngle; +} + +void QPinchGesture::setTotalRotationAngle(qreal value) +{ + d_func()->totalRotationAngle = value; +} + +void QPinchGesture::setLastRotationAngle(qreal value) +{ + d_func()->lastRotationAngle = value; +} + +void QPinchGesture::setRotationAngle(qreal value) +{ + d_func()->rotationAngle = value; } /*! - Returns the graphics item the gesture is filtering events for. + \class QSwipeGesture + \since 4.6 + \brief The QSwipeGesture class describes a swipe gesture made by the user. + \ingroup gestures + + \image swipegesture.png - \sa setGraphicsItem() + \sa {Gestures Programming}, QPanGesture, QPinchGesture */ -QGraphicsItem* QGesture::graphicsItem() const + +/*! + \enum QSwipeGesture::SwipeDirection + + This enum describes the possible directions for the gesture's motion + along the horizontal and vertical axes. + + \value NoDirection The gesture had no motion associated with it on a particular axis. + \value Left The gesture involved a horizontal motion to the left. + \value Right The gesture involved a horizontal motion to the right. + \value Up The gesture involved an upward vertical motion. + \value Down The gesture involved a downward vertical motion. +*/ + +/*! + \property QSwipeGesture::horizontalDirection + \brief the horizontal direction of the gesture + + If the gesture has a horizontal component, the horizontal direction + is either Left or Right; otherwise, it is NoDirection. + + \sa verticalDirection, swipeAngle +*/ + +/*! + \property QSwipeGesture::verticalDirection + \brief the vertical direction of the gesture + + If the gesture has a vertical component, the vertical direction + is either Up or Down; otherwise, it is NoDirection. + + \sa horizontalDirection, swipeAngle +*/ + +/*! + \property QSwipeGesture::swipeAngle + \brief the angle of the motion associated with the gesture + + If the gesture has either a horizontal or vertical component, the + swipe angle describes the angle between the direction of motion and the + x-axis as defined using the standard widget + \l{The Coordinate System}{coordinate system}. + + \sa horizontalDirection, verticalDirection +*/ + +/*! + \internal +*/ +QSwipeGesture::QSwipeGesture(QObject *parent) + : QGesture(*new QSwipeGesturePrivate, parent) +{ + d_func()->gestureType = Qt::SwipeGesture; +} + +QSwipeGesture::SwipeDirection QSwipeGesture::horizontalDirection() const { - return d_func()->graphicsItem; + Q_D(const QSwipeGesture); + if (d->swipeAngle < 0 || d->swipeAngle == 90 || d->swipeAngle == 270) + return QSwipeGesture::NoDirection; + else if (d->swipeAngle < 90 || d->swipeAngle > 270) + return QSwipeGesture::Right; + else + return QSwipeGesture::Left; } -/*! \fn void QGesture::reset() +QSwipeGesture::SwipeDirection QSwipeGesture::verticalDirection() const +{ + Q_D(const QSwipeGesture); + if (d->swipeAngle <= 0 || d->swipeAngle == 180) + return QSwipeGesture::NoDirection; + else if (d->swipeAngle < 180) + return QSwipeGesture::Up; + else + return QSwipeGesture::Down; +} - Resets the internal state of the gesture. This function might be called by - the filterEvent() implementation in a derived class, or by the user to - cancel a gesture. The base class implementation calls - updateState(Qt::NoGesture) which emits the canceled() - signal if the state() of the gesture indicated it was active. -*/ -void QGesture::reset() +qreal QSwipeGesture::swipeAngle() const +{ + return d_func()->swipeAngle; +} + +void QSwipeGesture::setSwipeAngle(qreal value) { - updateState(Qt::NoGesture); + d_func()->swipeAngle = value; } QT_END_NAMESPACE diff --git a/src/gui/kernel/qgesture.h b/src/gui/kernel/qgesture.h index 440565e..02eb526 100644 --- a/src/gui/kernel/qgesture.h +++ b/src/gui/kernel/qgesture.h @@ -51,11 +51,12 @@ QT_BEGIN_HEADER +Q_DECLARE_METATYPE(Qt::GestureState) + QT_BEGIN_NAMESPACE QT_MODULE(Gui) -class QGraphicsItem; class QGesturePrivate; class Q_GUI_EXPORT QGesture : public QObject { @@ -63,37 +64,150 @@ class Q_GUI_EXPORT QGesture : public QObject Q_DECLARE_PRIVATE(QGesture) Q_PROPERTY(Qt::GestureState state READ state) - Q_PROPERTY(QObject* gestureTarget READ gestureTarget WRITE setGestureTarget) + Q_PROPERTY(Qt::GestureType gestureType READ gestureType) + Q_PROPERTY(QPointF hotSpot READ hotSpot WRITE setHotSpot RESET unsetHotSpot) + Q_PROPERTY(bool hasHotSpot READ hasHotSpot) + Q_PROPERTY(QObject* targetObject READ targetObject WRITE setTargetObject) public: - explicit QGesture(QObject *gestureTarget = 0, QObject *parent = 0); + explicit QGesture(QObject *parent = 0); ~QGesture(); - virtual bool filterEvent(QEvent *event) = 0; + Qt::GestureType gestureType() const; - void setGestureTarget(QObject *object); - QObject* gestureTarget() const; + Qt::GestureState state() const; - void setGraphicsItem(QGraphicsItem *); - QGraphicsItem *graphicsItem() const; + QObject *targetObject() const; + void setTargetObject(QObject *value); - Qt::GestureState state() const; + QPointF hotSpot() const; + void setHotSpot(const QPointF &value); + bool hasHotSpot() const; + void unsetHotSpot(); protected: - QGesture(QGesturePrivate &dd, QObject *gestureTarget, QObject *parent); - bool eventFilter(QObject*, QEvent*); + QGesture(QGesturePrivate &dd, QObject *parent); + +private: + friend class QGestureEvent; + friend class QGestureRecognizer; + friend class QGestureManager; +}; - virtual void reset(); - void updateState(Qt::GestureState state); +class QPanGesturePrivate; +class Q_GUI_EXPORT QPanGesture : public QGesture +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QPanGesture) -Q_SIGNALS: - void started(); - void triggered(); - void finished(); - void canceled(); + Q_PROPERTY(QSizeF totalOffset READ totalOffset WRITE setTotalOffset) + Q_PROPERTY(QSizeF lastOffset READ lastOffset WRITE setLastOffset) + Q_PROPERTY(QSizeF offset READ offset WRITE setOffset) + Q_PROPERTY(qreal acceleration READ acceleration WRITE setAcceleration) -private: - friend class QWidget; +public: + QPanGesture(QObject *parent = 0); + + QSizeF totalOffset() const; + QSizeF lastOffset() const; + QSizeF offset() const; + qreal acceleration() const; + + void setTotalOffset(const QSizeF &value); + void setLastOffset(const QSizeF &value); + void setOffset(const QSizeF &value); + void setAcceleration(qreal value); + + friend class QPanGestureRecognizer; + friend class QWinNativePanGestureRecognizer; +}; + +class QPinchGesturePrivate; +class Q_GUI_EXPORT QPinchGesture : public QGesture +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QPinchGesture) + +public: + enum WhatChange { + ScaleFactorChanged = 0x1, + RotationAngleChanged = 0x2, + CenterPointChanged = 0x4 + }; + Q_DECLARE_FLAGS(WhatChanged, WhatChange) + + Q_PROPERTY(WhatChanged whatChanged READ whatChanged WRITE setWhatChanged) + + Q_PROPERTY(qreal totalScaleFactor READ totalScaleFactor WRITE setTotalScaleFactor) + Q_PROPERTY(qreal lastScaleFactor READ lastScaleFactor WRITE setLastScaleFactor) + Q_PROPERTY(qreal scaleFactor READ scaleFactor WRITE setScaleFactor) + + Q_PROPERTY(qreal totalRotationAngle READ totalRotationAngle WRITE setTotalRotationAngle) + Q_PROPERTY(qreal lastRotationAngle READ lastRotationAngle WRITE setLastRotationAngle) + Q_PROPERTY(qreal rotationAngle READ rotationAngle WRITE setRotationAngle) + + Q_PROPERTY(QPointF startCenterPoint READ startCenterPoint WRITE setStartCenterPoint) + Q_PROPERTY(QPointF lastCenterPoint READ lastCenterPoint WRITE setLastCenterPoint) + Q_PROPERTY(QPointF centerPoint READ centerPoint WRITE setCenterPoint) + +public: + QPinchGesture(QObject *parent = 0); + + WhatChanged whatChanged() const; + void setWhatChanged(WhatChanged value); + + QPointF startCenterPoint() const; + QPointF lastCenterPoint() const; + QPointF centerPoint() const; + void setStartCenterPoint(const QPointF &value); + void setLastCenterPoint(const QPointF &value); + void setCenterPoint(const QPointF &value); + + qreal totalScaleFactor() const; + qreal lastScaleFactor() const; + qreal scaleFactor() const; + void setTotalScaleFactor(qreal value); + void setLastScaleFactor(qreal value); + void setScaleFactor(qreal value); + + qreal totalRotationAngle() const; + qreal lastRotationAngle() const; + qreal rotationAngle() const; + void setTotalRotationAngle(qreal value); + void setLastRotationAngle(qreal value); + void setRotationAngle(qreal value); + + friend class QPinchGestureRecognizer; +}; + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QPinchGesture::WhatChanged) + +QT_BEGIN_NAMESPACE + +class QSwipeGesturePrivate; +class Q_GUI_EXPORT QSwipeGesture : public QGesture +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QSwipeGesture) + Q_ENUMS(SwipeDirection) + + Q_PROPERTY(SwipeDirection horizontalDirection READ horizontalDirection STORED false) + Q_PROPERTY(SwipeDirection verticalDirection READ verticalDirection STORED false) + Q_PROPERTY(qreal swipeAngle READ swipeAngle WRITE setSwipeAngle) + +public: + enum SwipeDirection { NoDirection, Left, Right, Up, Down }; + QSwipeGesture(QObject *parent = 0); + + SwipeDirection horizontalDirection() const; + SwipeDirection verticalDirection() const; + + qreal swipeAngle() const; + void setSwipeAngle(qreal value); + + friend class QSwipeGestureRecognizer; }; QT_END_NAMESPACE diff --git a/src/gui/kernel/qgesture_p.h b/src/gui/kernel/qgesture_p.h index 52e399f..7f69a4e 100644 --- a/src/gui/kernel/qgesture_p.h +++ b/src/gui/kernel/qgesture_p.h @@ -61,29 +61,83 @@ QT_BEGIN_NAMESPACE -class QObject; -class QGraphicsItem; class QGesturePrivate : public QObjectPrivate { Q_DECLARE_PUBLIC(QGesture) public: QGesturePrivate() - : gestureTarget(0), graphicsItem(0), eventFilterProxyGraphicsItem(0), - state(Qt::NoGesture), implicitGesture(false) + : gestureType(Qt::CustomGesture), state(Qt::NoGesture), isHotSpotSet(false), + targetObject(0), accept(true) { } - virtual void setupGestureTarget(QObject *o); + Qt::GestureType gestureType; + Qt::GestureState state; + QPointF hotSpot; + bool isHotSpotSet; + QObject *targetObject; + bool accept; +}; - QPointer<QObject> gestureTarget; - QGraphicsItem *graphicsItem; - QGraphicsItem *eventFilterProxyGraphicsItem; +class QPanGesturePrivate : public QGesturePrivate +{ + Q_DECLARE_PUBLIC(QPanGesture) - Qt::GestureState state; +public: + QPanGesturePrivate() + : acceleration(0) + { + } + + QSizeF totalOffset; + QSizeF lastOffset; + QSizeF offset; + QPoint lastPosition; + qreal acceleration; +}; + +class QPinchGesturePrivate : public QGesturePrivate +{ + Q_DECLARE_PUBLIC(QPinchGesture) + +public: + QPinchGesturePrivate() + : whatChanged(0), totalScaleFactor(0), lastScaleFactor(0), scaleFactor(0), + totalRotationAngle(0), lastRotationAngle(0), rotationAngle(0) + { + } + + QPinchGesture::WhatChanged whatChanged; + + QPointF startCenterPoint; + QPointF lastCenterPoint; + QPointF centerPoint; + + qreal totalScaleFactor; + qreal lastScaleFactor; + qreal scaleFactor; + + qreal totalRotationAngle; + qreal lastRotationAngle; + qreal rotationAngle; +}; + +class QSwipeGesturePrivate : public QGesturePrivate +{ + Q_DECLARE_PUBLIC(QSwipeGesture) + +public: + QSwipeGesturePrivate() + : horizontalDirection(QSwipeGesture::NoDirection), + verticalDirection(QSwipeGesture::NoDirection), + swipeAngle(0) + { + } - // the flag specifies if the gesture was created implicitely by Qt. - bool implicitGesture; + QSwipeGesture::SwipeDirection horizontalDirection; + QSwipeGesture::SwipeDirection verticalDirection; + qreal swipeAngle; }; QT_END_NAMESPACE diff --git a/src/gui/kernel/qgesturemanager.cpp b/src/gui/kernel/qgesturemanager.cpp new file mode 100644 index 0000000..0f0aef2 --- /dev/null +++ b/src/gui/kernel/qgesturemanager.cpp @@ -0,0 +1,467 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "private/qgesturemanager_p.h" +#include "private/qstandardgestures_p.h" +#include "private/qwidget_p.h" +#include "private/qgesture_p.h" +#include "private/qgraphicsitem_p.h" +#include "qgesture.h" +#include "qevent.h" +#include "qgraphicsitem.h" + +#ifdef Q_WS_MAC +#include "qmacgesturerecognizer_mac_p.h" +#endif + +#include "qdebug.h" + +// #define GESTURE_DEBUG +#ifndef GESTURE_DEBUG +# define DEBUG if (0) qDebug +#else +# define DEBUG qDebug +#endif + +QT_BEGIN_NAMESPACE + +QGestureManager::QGestureManager(QObject *parent) + : QObject(parent), state(NotGesture), lastCustomGestureId(0) +{ + qRegisterMetaType<Qt::GestureState>(); + +#if defined(Q_WS_MAC) + registerGestureRecognizer(new QMacSwipeGestureRecognizer); + registerGestureRecognizer(new QMacPinchGestureRecognizer); + #if defined(QT_MAC_USE_COCOA) + registerGestureRecognizer(new QMacPanGestureRecognizer); + #endif +#else + registerGestureRecognizer(new QPanGestureRecognizer); +#endif +} + +QGestureManager::~QGestureManager() +{ + +} + +Qt::GestureType QGestureManager::registerGestureRecognizer(QGestureRecognizer *recognizer) +{ + QGesture *dummy = recognizer->createGesture(0); + if (!dummy) { + qWarning("QGestureManager::registerGestureRecognizer: the recognizer doesn't provide gesture object"); + return Qt::GestureType(0); + } + Qt::GestureType type = dummy->gestureType(); + if (type == Qt::CustomGesture) { + // generate a new custom gesture id + ++lastCustomGestureId; + type = Qt::GestureType(Qt::CustomGesture + lastCustomGestureId); + } + recognizers.insertMulti(type, recognizer); + delete dummy; + return type; +} + +void QGestureManager::unregisterGestureRecognizer(Qt::GestureType) +{ + +} + +QGesture* QGestureManager::getState(QObject *object, Qt::GestureType type) +{ + // if the widget is being deleted we should be carefull and not to + // create a new state, as it will create QWeakPointer which doesnt work + // from the destructor. + if (object->isWidgetType()) { + if (static_cast<QWidget *>(object)->d_func()->data.in_destructor) + return 0; + } + + QWeakPointer<QGesture> state = objectGestures.value(QGestureManager::ObjectGesture(object, type)); + if (!state) { + QGestureRecognizer *recognizer = recognizers.value(type); + if (recognizer) { + state = recognizer->createGesture(object); + if (!state) + return 0; + if (state.data()->gestureType() == Qt::CustomGesture) { + // if the recognizer didn't fill in the gesture type, then this + // is a custom gesture with autogenerated it and we fill it. + state.data()->d_func()->gestureType = type; + } + objectGestures.insert(QGestureManager::ObjectGesture(object, type), state); + gestureToRecognizer[state.data()] = recognizer; + } + } + return state.data(); +} + +bool QGestureManager::filterEvent(QObject *receiver, QEvent *event) +{ + QSet<QGesture *> triggeredGestures; + QSet<QGesture *> finishedGestures; + QSet<QGesture *> newMaybeGestures; + QSet<QGesture *> canceledGestures; + QSet<QGesture *> notGestures; + + QGraphicsObject *graphicsObject = qobject_cast<QGraphicsObject *>(receiver); + if (receiver->isWidgetType() || graphicsObject) { + QMap<QObject *, Qt::GestureType> contexts; + if (receiver->isWidgetType()) { + QWidget *w = static_cast<QWidget *>(receiver); + if (!w->d_func()->gestureContext.isEmpty()) { + typedef QMap<Qt::GestureType, Qt::GestureContext>::const_iterator ContextIterator; + for(ContextIterator it = w->d_func()->gestureContext.begin(), + e = w->d_func()->gestureContext.end(); it != e; ++it) { + contexts.insertMulti(w, it.key()); + } + } + // find all gesture contexts for the widget tree + w = w->parentWidget(); + while (w) + { + typedef QMap<Qt::GestureType, Qt::GestureContext>::const_iterator ContextIterator; + for (ContextIterator it = w->d_func()->gestureContext.begin(), + e = w->d_func()->gestureContext.end(); it != e; ++it) { + if (it.value() == Qt::WidgetWithChildrenGesture) + contexts.insertMulti(w, it.key()); + } + w = w->parentWidget(); + } + } else { + QGraphicsObject *item = graphicsObject; + if (!item->QGraphicsItem::d_func()->gestureContext.isEmpty()) { + typedef QMap<Qt::GestureType, Qt::GestureContext>::const_iterator ContextIterator; + for(ContextIterator it = item->QGraphicsItem::d_func()->gestureContext.begin(), + e = item->QGraphicsItem::d_func()->gestureContext.end(); it != e; ++it) { + contexts.insertMulti(item, it.key()); + } + } + // find all gesture contexts for the widget tree + item = item->parentObject(); + while (item) + { + typedef QMap<Qt::GestureType, Qt::GestureContext>::const_iterator ContextIterator; + for (ContextIterator it = item->QGraphicsItem::d_func()->gestureContext.begin(), + e = item->QGraphicsItem::d_func()->gestureContext.end(); it != e; ++it) { + if (it.value() == Qt::WidgetWithChildrenGesture) + contexts.insertMulti(item, it.key()); + } + item = item->parentObject(); + } + } + // filter the event through recognizers + typedef QMap<QObject *, Qt::GestureType>::const_iterator ContextIterator; + for (ContextIterator cit = contexts.begin(), ce = contexts.end(); cit != ce; ++cit) { + Qt::GestureType gestureType = cit.value(); + QMap<Qt::GestureType, QGestureRecognizer *>::const_iterator + rit = recognizers.lowerBound(gestureType), + re = recognizers.upperBound(gestureType); + for (; rit != re; ++rit) { + QGestureRecognizer *recognizer = rit.value(); + QObject *target = cit.key(); + QGesture *state = getState(target, gestureType); + if (!state) + continue; + QGestureRecognizer::Result result = recognizer->filterEvent(state, target, event); + QGestureRecognizer::Result type = result & QGestureRecognizer::ResultState_Mask; + if (type == QGestureRecognizer::GestureTriggered) { + DEBUG() << "QGestureManager: gesture triggered: " << state; + triggeredGestures << state; + } else if (type == QGestureRecognizer::GestureFinished) { + DEBUG() << "QGestureManager: gesture finished: " << state; + finishedGestures << state; + } else if (type == QGestureRecognizer::MaybeGesture) { + DEBUG() << "QGestureManager: maybe gesture: " << state; + newMaybeGestures << state; + } else if (type == QGestureRecognizer::NotGesture) { + DEBUG() << "QGestureManager: not gesture: " << state; + notGestures << state; + } else if (type == QGestureRecognizer::Ignore) { + DEBUG() << "QGestureManager: gesture ignored the event: " << state; + } else { + DEBUG() << "QGestureManager: hm, lets assume the recognizer ignored the event: " << state; + } + if (result & QGestureRecognizer::ConsumeEventHint) { + DEBUG() << "QGestureManager: we were asked to consume the event: " << state; + //TODO: consume events if asked + } + } + } + } else if (QGesture *state = qobject_cast<QGesture*>(receiver)) { + if (QGestureRecognizer *recognizer = gestureToRecognizer.value(state)) { + QGestureRecognizer::Result result = recognizer->filterEvent(state, state, event); + QGestureRecognizer::Result type = result & QGestureRecognizer::ResultState_Mask; + if (type == QGestureRecognizer::GestureTriggered) { + DEBUG() << "QGestureManager: gesture triggered: " << state; + triggeredGestures << state; + } else if (type == QGestureRecognizer::GestureFinished) { + DEBUG() << "QGestureManager: gesture finished: " << state; + finishedGestures << state; + } else if (type == QGestureRecognizer::MaybeGesture) { + DEBUG() << "QGestureManager: maybe gesture: " << state; + newMaybeGestures << state; + } else if (type == QGestureRecognizer::NotGesture) { + DEBUG() << "QGestureManager: not gesture: " << state; + notGestures << state; + } else if (type == QGestureRecognizer::Ignore) { + DEBUG() << "QGestureManager: gesture ignored the event: " << state; + } else { + DEBUG() << "QGestureManager: hm, lets assume the recognizer ignored the event: " << state; + } + } + } else { + return false; + } + + QSet<QGesture *> startedGestures = triggeredGestures - activeGestures; + triggeredGestures &= activeGestures; + + // check if a running gesture switched back to maybe state + QSet<QGesture *> activeToMaybeGestures = activeGestures & newMaybeGestures; + + // check if a running gesture switched back to not gesture state, i.e. were canceled + QSet<QGesture *> activeToCancelGestures = activeGestures & notGestures; + canceledGestures += activeToCancelGestures; + + // start timers for new gestures in maybe state + foreach (QGesture *state, newMaybeGestures) { + QBasicTimer &timer = maybeGestures[state]; + if (!timer.isActive()) + timer.start(3000, this); + } + // kill timers for gestures that were in maybe state + QSet<QGesture *> notMaybeGestures = (startedGestures | triggeredGestures | finishedGestures | canceledGestures | notGestures); + foreach(QGesture *gesture, notMaybeGestures) { + QMap<QGesture *, QBasicTimer>::iterator it = + maybeGestures.find(gesture); + if (it != maybeGestures.end()) { + it.value().stop(); + maybeGestures.erase(it); + } + } + + Q_ASSERT((startedGestures & finishedGestures).isEmpty()); + Q_ASSERT((startedGestures & newMaybeGestures).isEmpty()); + Q_ASSERT((startedGestures & canceledGestures).isEmpty()); + Q_ASSERT((finishedGestures & newMaybeGestures).isEmpty()); + Q_ASSERT((finishedGestures & canceledGestures).isEmpty()); + Q_ASSERT((canceledGestures & newMaybeGestures).isEmpty()); + + QSet<QGesture *> notStarted = finishedGestures - activeGestures; + if (!notStarted.isEmpty()) { + // there are some gestures that claim to be finished, but never started. + // probably those are "singleshot" gestures so we'll fake the started state. + foreach (QGesture *gesture, notStarted) + gesture->d_func()->state = Qt::GestureStarted; + deliverEvents(notStarted, receiver); + } + + activeGestures += startedGestures; + // sanity check: all triggered gestures should already be in active gestures list + Q_ASSERT((activeGestures & triggeredGestures).size() == triggeredGestures.size()); + activeGestures -= finishedGestures; + activeGestures -= activeToMaybeGestures; + activeGestures -= canceledGestures; + + // set the proper gesture state on each gesture + foreach (QGesture *gesture, startedGestures) + gesture->d_func()->state = Qt::GestureStarted; + foreach (QGesture *gesture, triggeredGestures) + gesture->d_func()->state = Qt::GestureUpdated; + foreach (QGesture *gesture, finishedGestures) + gesture->d_func()->state = Qt::GestureFinished; + foreach (QGesture *gesture, canceledGestures) + gesture->d_func()->state = Qt::GestureCanceled; + foreach (QGesture *gesture, activeToMaybeGestures) + gesture->d_func()->state = Qt::GestureFinished; + + if (!activeGestures.isEmpty() || !maybeGestures.isEmpty() || + !startedGestures.isEmpty() || !triggeredGestures.isEmpty() || + !finishedGestures.isEmpty() || !canceledGestures.isEmpty()) { + DEBUG() << "QGestureManager::filterEvent:" + << "\n\tactiveGestures:" << activeGestures + << "\n\tmaybeGestures:" << maybeGestures.keys() + << "\n\tstarted:" << startedGestures + << "\n\ttriggered:" << triggeredGestures + << "\n\tfinished:" << finishedGestures + << "\n\tcanceled:" << canceledGestures; + } + + deliverEvents(startedGestures+triggeredGestures+finishedGestures+canceledGestures, receiver); + + // reset gestures that ended + QSet<QGesture *> endedGestures = finishedGestures + canceledGestures; + foreach (QGesture *gesture, endedGestures) { + if (QGestureRecognizer *recognizer = gestureToRecognizer.value(gesture, 0)) { + recognizer->reset(gesture); + } + gestureTargets.remove(gesture); + } + return false; +} + +void QGestureManager::deliverEvents(const QSet<QGesture*> &gestures, QObject *lastReceiver) +{ + if (gestures.isEmpty()) + return; + + // group gestures by widgets + typedef QMap<QObject *, QList<QGesture *> > GesturesPerReceiver; + GesturesPerReceiver groupedGestures; + // for conflicted gestures the key is always the innermost widget (i.e. the child) + GesturesPerReceiver conflictedGestures; + QMultiHash<QObject *, QGesture *> objectGestures; + + foreach (QGesture *gesture, gestures) { + QObject *target = gestureTargets.value(gesture, 0); + if (!target) { + Q_ASSERT(gesture->state() == Qt::GestureStarted); + if (gesture->hasHotSpot()) { + // guess the target using the hotspot of the gesture + QPoint pt = gesture->hotSpot().toPoint(); + if (!pt.isNull()) { + if (QWidget *w = qApp->topLevelAt(pt)) + target = w->childAt(w->mapFromGlobal(pt)); + } + } + if (!target) { + target = gesture->targetObject(); + if (!target) + target = lastReceiver; + } + } + if (target) { + gestureTargets.insert(gesture, target); + if (target->isWidgetType()) + objectGestures.insert(target, gesture); + groupedGestures[target].append(gesture); + } else { + qWarning() << "QGestureManager::deliverEvent: could not find the target for gesture" + << gesture->gestureType(); + } + } + + typedef QMultiHash<QObject *, QGesture *>::const_iterator ObjectGesturesIterator; + for (ObjectGesturesIterator it = objectGestures.begin(), e = objectGestures.end(); it != e; ++it) { + QObject *object1 = it.key(); + QWidget *widget1 = qobject_cast<QWidget *>(object1); + QGraphicsObject *item1 = qobject_cast<QGraphicsObject *>(object1); + QGesture *gesture1 = it.value(); + ObjectGesturesIterator cit = it; + for (++cit; cit != e; ++cit) { + QObject *object2 = cit.key(); + QWidget *widget2 = qobject_cast<QWidget *>(object2); + QGraphicsObject *item2 = qobject_cast<QGraphicsObject *>(object2); + QGesture *gesture2 = cit.value(); + // TODO: ugly, rewrite this. + if ((widget1 && widget2 && widget2->isAncestorOf(widget1)) || + (item1 && item2 && item2->isAncestorOf(item1))) { + groupedGestures[object2].removeOne(gesture2); + groupedGestures[object1].removeOne(gesture1); + conflictedGestures[object1].append(gesture1); + } else if ((widget1 && widget2 && widget1->isAncestorOf(widget2)) || + (item1 && item2 && item1->isAncestorOf(item2))) { + groupedGestures[object2].removeOne(gesture2); + groupedGestures[object1].removeOne(gesture1); + conflictedGestures[object2].append(gesture2); + } + } + } + + DEBUG() << "deliverEvents: conflicted =" << conflictedGestures.values() + << " grouped =" << groupedGestures.values(); + + // if there are conflicting gestures, send the GestureOverride event + for (GesturesPerReceiver::const_iterator it = conflictedGestures.begin(), + e = conflictedGestures.end(); it != e; ++it) { + DEBUG() << "QGestureManager::deliverEvents: sending GestureOverride to" + << it.key() + << " gestures:" << it.value(); + QGestureEvent event(it.value()); + event.t = QEvent::GestureOverride; + event.ignore(); + QApplication::sendEvent(it.key(), &event); + if (!event.isAccepted()) { + // nobody accepted the GestureOverride, put it back to deliver to + // the closest context (i.e. to the inner-most widget). + DEBUG() <<" override was not accepted"; + groupedGestures[it.key()].append(it.value()); + } + } + + for (GesturesPerReceiver::const_iterator it = groupedGestures.begin(), + e = groupedGestures.end(); it != e; ++it) { + if (!it.value().isEmpty()) { + DEBUG() << "QGestureManager::deliverEvents: sending to" << it.key() + << " gestures:" << it.value(); + QGestureEvent event(it.value()); + QApplication::sendEvent(it.key(), &event); + } + } +} + +void QGestureManager::timerEvent(QTimerEvent *event) +{ + QMap<QGesture*, QBasicTimer>::iterator it = maybeGestures.begin(), + e = maybeGestures.end(); + for (; it != e; ) { + QBasicTimer &timer = it.value(); + Q_ASSERT(timer.isActive()); + if (timer.timerId() == event->timerId()) { + timer.stop(); + QGesture *gesture = it.key(); + it = maybeGestures.erase(it); + DEBUG() << "QGestureManager::timerEvent: gesture stopped due to timeout:" << gesture; + QGestureRecognizer *recognizer = gestureToRecognizer.value(gesture, 0); + if (recognizer) + recognizer->reset(gesture); + } else { + ++it; + } + } +} + +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..c61819f --- /dev/null +++ b/src/gui/kernel/qgesturemanager_p.h @@ -0,0 +1,125 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@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 "qobject.h" +#include "qbasictimer.h" +#include "private/qwidget_p.h" +#include "qgesturerecognizer.h" + +QT_BEGIN_NAMESPACE + +class QBasicTimer; +class QGestureManager : public QObject +{ + Q_OBJECT +public: + QGestureManager(QObject *parent); + ~QGestureManager(); + + Qt::GestureType registerGestureRecognizer(QGestureRecognizer *recognizer); + void unregisterGestureRecognizer(Qt::GestureType type); + + bool filterEvent(QObject *receiver, QEvent *event); + + // declared in qapplication.cpp + static QGestureManager* instance(); + +protected: + void timerEvent(QTimerEvent *event); + +private: + QMultiMap<Qt::GestureType, QGestureRecognizer *> recognizers; + + QSet<QGesture *> activeGestures; + QMap<QGesture *, QBasicTimer> maybeGestures; + + enum State { + Gesture, + NotGesture, + MaybeGesture // this means timers are up and waiting for some + // more events, and input events are handled by + // gesture recognizer explicitely + } state; + + struct ObjectGesture + { + QWeakPointer<QObject> object; + Qt::GestureType gesture; + + ObjectGesture(QObject *o, const Qt::GestureType &g) : object(o), gesture(g) { } + inline bool operator<(const ObjectGesture& rhs) const + { + if (object.data() < rhs.object.data()) + return true; + if (object == rhs.object) + return gesture < rhs.gesture; + return false; + } + }; + + QMap<ObjectGesture, QWeakPointer<QGesture> > objectGestures; + QMap<QGesture *, QGestureRecognizer *> gestureToRecognizer; + + QHash<QGesture *, QObject *> gestureTargets; + + int lastCustomGestureId; + + QGesture *getState(QObject *widget, Qt::GestureType gesture); + void deliverEvents(const QSet<QGesture *> &gestures, QObject *lastReceiver); +}; + +QT_END_NAMESPACE + +#endif // QGESTUREMANAGER_P_H diff --git a/src/gui/kernel/qgesturerecognizer.cpp b/src/gui/kernel/qgesturerecognizer.cpp new file mode 100644 index 0000000..9de3bcc --- /dev/null +++ b/src/gui/kernel/qgesturerecognizer.cpp @@ -0,0 +1,200 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qgesturerecognizer.h" + +#include "private/qgesture_p.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QGestureRecognizer + \since 4.6 + \brief The QGestureRecognizer class provides the infrastructure for gesture recognition. + \ingroup gestures + + Gesture recognizers are responsible for creating and managing QGesture objects and + monitoring input events sent to QWidget and QGraphicsObject subclasses. + QGestureRecognizer is the base class for implementing custom gestures. + + Developers that only need to provide gesture recognition for standard gestures do not + need to use this class directly. Instances will be created behind the scenes by the + framework. + + \section1 Recognizing Gestures + + The process of recognizing gestures involves filtering input events sent to specific + objects, and modifying the associated QGesture objects to include relevant information + about the user's input. + + Gestures are created when the framework calls createGesture() to handle user input + for a particular instance of a QWidget or QGraphicsObject subclass. A QGesture object + is created for each widget or item that is configured to use gestures. + + Once a QGesture has been created for a target object, the gesture recognizer will + receive events for it in its filterEvent() handler function. + + When a gesture is canceled, the reset() function is called, giving the recognizer the + chance to update the appropriate properties in the corresponding QGesture object. + + \section1 Supporting New Gestures + + To add support for new gestures, you need to derive from QGestureRecognizer to create + a custom recognizer class, construct an instance of this class, and register it with + the application by calling QApplication::registerGestureRecognizer(). You can also + subclass QGesture to create a custom gesture class, or rely on dynamic properties + to express specific details of the gesture you want to handle. + + Your custom QGestureRecognizer subclass needs to reimplement the filterEvent() function + to handle and filter the incoming input events for QWidget and QGraphicsObject subclasses. + Although the logic for gesture recognition is implemented in this function, you can + store persistent information about the state of the recognition process in the QGesture + object supplied. The filterEvent() function must return a value of Qt::GestureState that + indicates the state of recognition for a given gesture and target object. This determines + whether or not a gesture event will be delivered to a target object. + + If you choose to represent a gesture by a custom QGesture subclass, you will need to + reimplement the createGesture() function to construct instances of your gesture class. + Similarly, you may need to reimplement the reset() function if your custom gesture + objects need to be specially handled when a gesture is canceled. + + \sa QGesture +*/ + +/*! + \enum QGestureRecognizer::ResultFlags + + This enum describes the result of the current event filtering step in + a gesture recognizer state machine. + + The result consists of a state value (one of Ignore, NotGesture, + MaybeGesture, GestureTriggered, GestureFinished) and an optional hint + (ConsumeEventHint). + + \value Ignore The event does not change the state of the recognizer. + + \value NotGesture The event made it clear that it is not a gesture. If the + gesture recognizer was in GestureTriggered state before, then the gesture + is canceled and the appropriate QGesture object will be delivered to the + target as a part of a QGestureEvent. + + \value MaybeGesture The event changed the internal state of the recognizer, + but it isn't clear yet if it is a gesture or not. The recognizer needs to + filter more events to decide. Gesture recognizers in the MaybeGesture state + may be reset automatically if they take too long to recognize gestures. + + \value GestureTriggered The gesture has been triggered and the appropriate + QGesture object will be delivered to the target as a part of a + QGestureEvent. + + \value GestureFinished The gesture has been finished successfully and the + appropriate QGesture object will be delivered to the target as a part of a + QGestureEvent. + + \value ConsumeEventHint This hint specifies that the gesture framework should + consume the filtered event and not deliver it to the receiver. + + \omitvalue ResultState_Mask + \omitvalue ResultHint_Mask + + \sa QGestureRecognizer::filterEvent() +*/ + +/*! + Constructs a new gesture recognizer object. +*/ +QGestureRecognizer::QGestureRecognizer() +{ +} + +/*! + Destroys the gesture recognizer. +*/ +QGestureRecognizer::~QGestureRecognizer() +{ +} + +/*! + This function is called by Qt to create a new QGesture object for the + given \a target (QWidget or QGraphicsObject). + + Reimplement this function to create a custom QGesture-derived gesture + object if necessary. +*/ +QGesture *QGestureRecognizer::createGesture(QObject *target) +{ + Q_UNUSED(target); + return new QGesture; +} + +/*! + This function is called by the framework to reset a given \a gesture. + + Reimplement this function to implement additional requirements for custom QGesture + objects. This may be necessary if you implement a custom QGesture whose properties + need special handling when the gesture is reset. +*/ +void QGestureRecognizer::reset(QGesture *gesture) +{ + if (gesture) { + QGesturePrivate *d = gesture->d_func(); + d->state = Qt::NoGesture; + d->hotSpot = QPointF(); + d->targetObject = 0; + } +} + +/*! + \fn QGestureRecognizer::filterEvent(QGesture *gesture, QObject *watched, QEvent *event) + + Handles the given \a event for the \a watched object, updating the state of the \a gesture + object as required, and returns a suitable Result for the current recognition step. + + This function is called by the framework to allow the recognizer to filter input events + dispatched to QWidget or QGraphicsObject instances that it is monitoring. + + The result reflects how much of the gesture has been recognized. The state of the + \a gesture object is set depending on the result. + + \sa Qt::GestureState +*/ + +QT_END_NAMESPACE diff --git a/src/gui/kernel/qgesturerecognizer.h b/src/gui/kernel/qgesturerecognizer.h new file mode 100644 index 0000000..efd8565 --- /dev/null +++ b/src/gui/kernel/qgesturerecognizer.h @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QGESTURERECOGNIZER_H +#define QGESTURERECOGNIZER_H + +#include <QtCore/qglobal.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Gui) + +class QObject; +class QEvent; +class QGesture; +class Q_GUI_EXPORT QGestureRecognizer +{ +public: + enum ResultFlags + { + Ignore = 0x0001, + NotGesture = 0x0002, + MaybeGesture = 0x0004, + GestureTriggered = 0x0008, // Gesture started or updated + GestureFinished = 0x0010, + + ResultState_Mask = 0x00ff, + + ConsumeEventHint = 0x0100, + // StoreEventHint = 0x0200, + // ReplayStoredEventsHint = 0x0400, + // DiscardStoredEventsHint = 0x0800, + + ResultHint_Mask = 0xff00 + }; + Q_DECLARE_FLAGS(Result, ResultFlags) + + QGestureRecognizer(); + virtual ~QGestureRecognizer(); + + virtual QGesture *createGesture(QObject *target); + virtual QGestureRecognizer::Result filterEvent(QGesture *state, QObject *watched, QEvent *event) = 0; + + virtual void reset(QGesture *state); +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(QGestureRecognizer::Result) + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QGESTURERECOGNIZER_H diff --git a/src/gui/kernel/qmacgesturerecognizer_mac.mm b/src/gui/kernel/qmacgesturerecognizer_mac.mm new file mode 100644 index 0000000..7b19a54 --- /dev/null +++ b/src/gui/kernel/qmacgesturerecognizer_mac.mm @@ -0,0 +1,267 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmacgesturerecognizer_mac_p.h" +#include "qgesture.h" +#include "qgesture_p.h" +#include "qevent.h" +#include "qevent_p.h" +#include "qwidget.h" +#include "qdebug.h" + +QT_BEGIN_NAMESPACE + +QMacSwipeGestureRecognizer::QMacSwipeGestureRecognizer() +{ +} + +QGesture *QMacSwipeGestureRecognizer::createGesture(QObject * /*target*/) +{ + return new QSwipeGesture; +} + +QGestureRecognizer::Result +QMacSwipeGestureRecognizer::filterEvent(QGesture *gesture, QObject *obj, QEvent *event) +{ + if (event->type() == QEvent::NativeGesture && obj->isWidgetType()) { + QNativeGestureEvent *ev = static_cast<QNativeGestureEvent*>(event); + switch (ev->gestureType) { + case QNativeGestureEvent::Swipe: { + QSwipeGesture *g = static_cast<QSwipeGesture *>(gesture); + g->setSwipeAngle(ev->angle); + return QGestureRecognizer::GestureTriggered | QGestureRecognizer::ConsumeEventHint; + break; } + default: + break; + } + } + + return QGestureRecognizer::Ignore; +} + +void QMacSwipeGestureRecognizer::reset(QGesture *gesture) +{ + QSwipeGesture *g = static_cast<QSwipeGesture *>(gesture); + g->setSwipeAngle(0); + QGestureRecognizer::reset(gesture); +} + +//////////////////////////////////////////////////////////////////////// + +QMacPinchGestureRecognizer::QMacPinchGestureRecognizer() +{ +} + +QGesture *QMacPinchGestureRecognizer::createGesture(QObject * /*target*/) +{ + return new QPinchGesture; +} + +QGestureRecognizer::Result +QMacPinchGestureRecognizer::filterEvent(QGesture *gesture, QObject *obj, QEvent *event) +{ + if (event->type() == QEvent::NativeGesture && obj->isWidgetType()) { + QPinchGesture *g = static_cast<QPinchGesture *>(gesture); + QNativeGestureEvent *ev = static_cast<QNativeGestureEvent*>(event); + switch(ev->gestureType) { + case QNativeGestureEvent::GestureBegin: + reset(gesture); + g->setStartCenterPoint(static_cast<QWidget*>(obj)->mapFromGlobal(ev->position)); + g->setCenterPoint(g->startCenterPoint()); + g->setWhatChanged(QPinchGesture::CenterPointChanged); + return QGestureRecognizer::MaybeGesture | QGestureRecognizer::ConsumeEventHint; + case QNativeGestureEvent::Rotate: { + g->setLastScaleFactor(g->scaleFactor()); + g->setLastRotationAngle(g->rotationAngle()); + g->setRotationAngle(g->rotationAngle() + ev->percentage); + g->setWhatChanged(QPinchGesture::RotationAngleChanged); + return QGestureRecognizer::GestureTriggered | QGestureRecognizer::ConsumeEventHint; + break; + } + case QNativeGestureEvent::Zoom: + g->setLastScaleFactor(g->scaleFactor()); + g->setLastRotationAngle(g->rotationAngle()); + g->setScaleFactor(g->scaleFactor() + ev->percentage); + g->setWhatChanged(QPinchGesture::ScaleFactorChanged); + return QGestureRecognizer::GestureTriggered | QGestureRecognizer::ConsumeEventHint; + break; + case QNativeGestureEvent::GestureEnd: + return QGestureRecognizer::GestureFinished | QGestureRecognizer::ConsumeEventHint; + break; + default: + break; + } + } + + return QGestureRecognizer::Ignore; +} + +void QMacPinchGestureRecognizer::reset(QGesture *gesture) +{ + QPinchGesture *g = static_cast<QPinchGesture *>(gesture); + g->setWhatChanged(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); +} + +//////////////////////////////////////////////////////////////////////// + +#if defined(QT_MAC_USE_COCOA) + +QMacPanGestureRecognizer::QMacPanGestureRecognizer() : _panCanceled(true) +{ +} + +QGesture *QMacPanGestureRecognizer::createGesture(QObject *target) +{ + if (!target) + return new QPanGesture; + + if (QWidget *w = qobject_cast<QWidget *>(target)) { + w->setAttribute(Qt::WA_AcceptTouchEvents); + w->setAttribute(Qt::WA_TouchPadAcceptSingleTouchEvents); + return new QPanGesture; + } + return 0; +} + +QGestureRecognizer::Result +QMacPanGestureRecognizer::filterEvent(QGesture *gesture, QObject *target, QEvent *event) +{ + const int panBeginDelay = 300; + const int panBeginRadius = 3; + + QPanGesture *g = static_cast<QPanGesture *>(gesture); + + switch (event->type()) { + case QEvent::TouchBegin: { + const QTouchEvent *ev = static_cast<const QTouchEvent*>(event); + if (ev->touchPoints().size() == 1) { + reset(gesture); + _startPos = QCursor::pos(); + _lastPos = _startPos; + _panTimer.start(panBeginDelay, target); + _panCanceled = false; + return QGestureRecognizer::MaybeGesture; + } + break;} + case QEvent::TouchEnd: { + if (_panCanceled) + break; + + const QTouchEvent *ev = static_cast<const QTouchEvent*>(event); + if (ev->touchPoints().size() == 1) + return QGestureRecognizer::GestureFinished; + break;} + case QEvent::TouchUpdate: { + if (_panCanceled) + break; + + const QTouchEvent *ev = static_cast<const QTouchEvent*>(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::NotGesture; + } + } else { + const QPointF p = QCursor::pos(); + const QPointF posOffset = p - _lastPos; + g->setLastOffset(g->offset()); + g->setOffset(QSizeF(posOffset.x(), posOffset.y())); + g->setTotalOffset(g->lastOffset() + g->offset()); + _lastPos = p; + return QGestureRecognizer::GestureTriggered; + } + } 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::NotGesture; + } + break;} + case QEvent::Timer: { + QTimerEvent *ev = static_cast<QTimerEvent *>(event); + if (ev->timerId() == _panTimer.timerId()) { + _panTimer.stop(); + if (_panCanceled) + break; + // Begin new pan session! + _startPos = QCursor::pos(); + _lastPos = _startPos; + return QGestureRecognizer::GestureTriggered | QGestureRecognizer::ConsumeEventHint; + } + break; } + default: + break; + } + + return QGestureRecognizer::Ignore; +} + +void QMacPanGestureRecognizer::reset(QGesture *gesture) +{ + QPanGesture *g = static_cast<QPanGesture *>(gesture); + _startPos = QPointF(); + _lastPos = QPointF(); + _panCanceled = true; + g->setOffset(QSizeF(0, 0)); + g->setLastOffset(QSizeF(0, 0)); + g->setTotalOffset(QSizeF(0, 0)); + g->setAcceleration(qreal(1)); + QGestureRecognizer::reset(gesture); +} +#endif // QT_MAC_USE_COCOA + +QT_END_NAMESPACE diff --git a/src/gui/kernel/qmacgesturerecognizer_mac_p.h b/src/gui/kernel/qmacgesturerecognizer_mac_p.h new file mode 100644 index 0000000..bdc2e08 --- /dev/null +++ b/src/gui/kernel/qmacgesturerecognizer_mac_p.h @@ -0,0 +1,103 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $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" + +QT_BEGIN_NAMESPACE + +class QMacSwipeGestureRecognizer : public QGestureRecognizer +{ +public: + QMacSwipeGestureRecognizer(); + + QGesture *createGesture(QObject *target); + QGestureRecognizer::Result filterEvent(QGesture *gesture, QObject *watched, QEvent *event); + void reset(QGesture *gesture); +}; + +class QMacPinchGestureRecognizer : public QGestureRecognizer +{ +public: + QMacPinchGestureRecognizer(); + + QGesture *createGesture(QObject *target); + QGestureRecognizer::Result filterEvent(QGesture *gesture, QObject *watched, QEvent *event); + void reset(QGesture *gesture); +}; + +#if defined(QT_MAC_USE_COCOA) + +class QMacPanGestureRecognizer : public QObject, public QGestureRecognizer +{ +public: + QMacPanGestureRecognizer(); + + QGesture *createGesture(QObject *target); + QGestureRecognizer::Result filterEvent(QGesture *gesture, QObject *watched, QEvent *event); + void reset(QGesture *gesture); +private: + QPointF _startPos; + QPointF _lastPos; + QBasicTimer _panTimer; + bool _panCanceled; +}; + +#endif + +QT_END_NAMESPACE + +#endif // QMACSWIPEGESTURERECOGNIZER_MAC_P_H diff --git a/src/gui/kernel/qsoftkeymanager.cpp b/src/gui/kernel/qsoftkeymanager.cpp index cd3ad22..6116a5e 100644 --- a/src/gui/kernel/qsoftkeymanager.cpp +++ b/src/gui/kernel/qsoftkeymanager.cpp @@ -125,7 +125,6 @@ QAction *QSoftKeyManager::createAction(StandardSoftKey standardKey, QWidget *act break; } action->setSoftKeyRole(softKeyRole); - action->setEnabled(actionWidget->isEnabled()); return action; } @@ -200,6 +199,7 @@ bool QSoftKeyManager::event(QEvent *e) void QSoftKeyManagerPrivate::updateSoftKeys_sys(const QList<QAction*> &softkeys) { CEikButtonGroupContainer* nativeContainer = S60->buttonGroupContainer(); + nativeContainer->DrawableWindow()->SetPointerCapturePriority(1); //keep softkeys available in modal dialog QT_TRAP_THROWING(nativeContainer->SetCommandSetL(R_AVKON_SOFTKEYS_EMPTY_WITH_IDS)); int position = -1; @@ -209,7 +209,7 @@ void QSoftKeyManagerPrivate::updateSoftKeys_sys(const QList<QAction*> &softkeys) for (int index = 0; index < softkeys.count(); index++) { const QAction* softKeyAction = softkeys.at(index); switch (softKeyAction->softKeyRole()) { - // Positive Actions go on LSK + // Positive Actions on the LSK case QAction::PositiveSoftKey: position = 0; break; @@ -252,7 +252,8 @@ bool QSoftKeyManager::handleCommand(int command) QAction *action = softKeys.at(i); if (action->softKeyRole() != QAction::NoSoftKey) { if (j == index) { - if (action->isEnabled()) { + QWidget *parent = action->parentWidget(); + if (parent && parent->isEnabled()) { action->activate(QAction::Trigger); return true; } diff --git a/src/gui/kernel/qstandardgestures.cpp b/src/gui/kernel/qstandardgestures.cpp index 3cfb987..dfc3499 100644 --- a/src/gui/kernel/qstandardgestures.cpp +++ b/src/gui/kernel/qstandardgestures.cpp @@ -39,174 +39,45 @@ ** ****************************************************************************/ -#include "qstandardgestures.h" #include "qstandardgestures_p.h" - -#include <qabstractscrollarea.h> -#include <qscrollbar.h> -#include <private/qapplication_p.h> -#include <private/qevent_p.h> -#include <private/qwidget_p.h> -#include <qmath.h> +#include "qgesture.h" +#include "qgesture_p.h" +#include "qevent.h" +#include "qwidget.h" QT_BEGIN_NAMESPACE -#ifdef Q_WS_WIN -QWidgetPrivate *qt_widget_private(QWidget *widget); -#endif - -/*! - \class QPanGesture - \preliminary - \since 4.6 - - \brief The QPanGesture class represents a Pan gesture, - providing additional information related to panning. -*/ - -/*! - \enum QSwipeGesture::SwipeDirection - \brief This enum specifies the direction of the swipe gesture. - - \value NoDirection - \value Left - \value Right - \value Up - \value Down -*/ - -/*! - Creates a new pan gesture handler object and marks it as a child of - \a parent. The pan gesture handler watches \a gestureTarget for its - events. - - On some platform like Windows it's necessary to provide a non-null - widget as \a parent to get native gesture support. -*/ -QPanGesture::QPanGesture(QWidget *gestureTarget, QObject *parent) - : QGesture(*new QPanGesturePrivate, gestureTarget, parent) +QPanGestureRecognizer::QPanGestureRecognizer() { - setObjectName(QLatin1String("QPanGesture")); -} - -void QPanGesturePrivate::setupGestureTarget(QObject *newGestureTarget) -{ - Q_Q(QPanGesture); - QApplicationPrivate *qAppPriv = QApplicationPrivate::instance(); - - if (gestureTarget && gestureTarget->isWidgetType()) { - QWidget *w = static_cast<QWidget*>(gestureTarget.data()); - if (qAppPriv->widgetGestures[w].pan == q) - qAppPriv->widgetGestures[w].pan = 0; -#if defined(Q_WS_WIN) - qt_widget_private(w)->winSetupGestures(); -#elif defined(Q_WS_MAC) - w->setAttribute(Qt::WA_AcceptTouchEvents, false); - w->setAttribute(Qt::WA_TouchPadAcceptSingleTouchEvents, false); -#endif - } - - if (newGestureTarget && newGestureTarget->isWidgetType()) { - QWidget *w = static_cast<QWidget*>(newGestureTarget); - qAppPriv->widgetGestures[w].pan = q; -#if defined(Q_WS_WIN) - qt_widget_private(w)->winSetupGestures(); -#elif defined(Q_WS_MAC) - w->setAttribute(Qt::WA_AcceptTouchEvents); - w->setAttribute(Qt::WA_TouchPadAcceptSingleTouchEvents); -#endif - } - QGesturePrivate::setupGestureTarget(newGestureTarget); -} - -/*! \internal */ -bool QPanGesture::event(QEvent *event) -{ -#if defined(QT_MAC_USE_COCOA) - Q_D(QPanGesture); - if (event->type() == QEvent::Timer) { - const QTimerEvent *te = static_cast<QTimerEvent *>(event); - if (te->timerId() == d->singleTouchPanTimer.timerId()) { - d->singleTouchPanTimer.stop(); - updateState(Qt::GestureStarted); - } - } -#endif - - return QObject::event(event); } -bool QPanGesture::eventFilter(QObject *receiver, QEvent *event) +QGesture *QPanGestureRecognizer::createGesture(QObject *target) { - Q_D(QPanGesture); - - if (d->implicitGesture && d->gestureTarget && d->gestureTarget->isWidgetType() && - static_cast<QWidget*>(d->gestureTarget.data())->testAttribute(Qt::WA_DontUseStandardGestures)) - return false; - -#ifdef Q_WS_WIN - if (receiver->isWidgetType() && event->type() == QEvent::NativeGesture) { - QNativeGestureEvent *ev = static_cast<QNativeGestureEvent*>(event); - QApplicationPrivate *qAppPriv = QApplicationPrivate::instance(); - QApplicationPrivate::WidgetStandardGesturesMap::iterator it; - it = qAppPriv->widgetGestures.find(static_cast<QWidget*>(receiver)); - if (it == qAppPriv->widgetGestures.end()) - return false; - if (this != it.value().pan) - return false; - Qt::GestureState nextState = Qt::NoGesture; - switch(ev->gestureType) { - case QNativeGestureEvent::GestureBegin: - // next we might receive the first gesture update event, so we - // prepare for it. - d->state = Qt::NoGesture; - return false; - case QNativeGestureEvent::Pan: - nextState = Qt::GestureUpdated; - event->accept(); - break; - case QNativeGestureEvent::GestureEnd: - if (state() == Qt::NoGesture) - return false; // some other gesture has ended - nextState = Qt::GestureFinished; - break; - default: - return false; - } - if (state() == Qt::NoGesture) { - d->lastOffset = d->totalOffset = d->offset = QSize(); - } else { - d->lastOffset = d->offset; - d->offset = QSize(ev->position.x() - d->lastPosition.x(), - ev->position.y() - d->lastPosition.y()); - d->totalOffset += d->offset; - } - d->lastPosition = ev->position; - updateState(nextState); - return true; + if (target && target->isWidgetType()) { + static_cast<QWidget *>(target)->setAttribute(Qt::WA_AcceptTouchEvents); } -#endif - return QGesture::eventFilter(receiver, event); + return new QPanGesture; } -/*! \internal */ -bool QPanGesture::filterEvent(QEvent *event) +QGestureRecognizer::Result QPanGestureRecognizer::filterEvent(QGesture *state, QObject *, QEvent *event) { - Q_D(QPanGesture); + QPanGesture *q = static_cast<QPanGesture*>(state); + QPanGesturePrivate *d = q->d_func(); - if (d->implicitGesture && d->gestureTarget && d->gestureTarget->isWidgetType() && - static_cast<QWidget*>(d->gestureTarget.data())->testAttribute(Qt::WA_DontUseStandardGestures)) - return false; - -#if defined(Q_WS_WIN) const QTouchEvent *ev = static_cast<const QTouchEvent*>(event); - if (event->type() == QEvent::TouchBegin) { + QGestureRecognizer::Result result; + + switch (event->type()) { + case QEvent::TouchBegin: { + result = QGestureRecognizer::MaybeGesture; QTouchEvent::TouchPoint p = ev->touchPoints().at(0); d->lastPosition = p.pos().toPoint(); d->lastOffset = d->totalOffset = d->offset = QSize(); - } else if (event->type() == QEvent::TouchEnd) { - if (state() != Qt::NoGesture) { + break; + } + case QEvent::TouchEnd: { + if (q->state() != Qt::NoGesture) { if (ev->touchPoints().size() == 2) { QTouchEvent::TouchPoint p1 = ev->touchPoints().at(0); QTouchEvent::TouchPoint p2 = ev->touchPoints().at(1); @@ -216,11 +87,14 @@ bool QPanGesture::filterEvent(QEvent *event) p1.pos().y() - p1.lastPos().y() + p2.pos().y() - p2.lastPos().y()) / 2; d->totalOffset += d->offset; } - updateState(Qt::GestureFinished); + result = QGestureRecognizer::GestureFinished; + } else { + result = QGestureRecognizer::NotGesture; } - reset(); - } else if (event->type() == QEvent::TouchUpdate) { - if (ev->touchPoints().size() == 2) { + break; + } + case QEvent::TouchUpdate: { + if (ev->touchPoints().size() >= 2) { QTouchEvent::TouchPoint p1 = ev->touchPoints().at(0); QTouchEvent::TouchPoint p2 = ev->touchPoints().at(1); d->lastOffset = d->offset; @@ -230,10 +104,60 @@ bool QPanGesture::filterEvent(QEvent *event) d->totalOffset += d->offset; if (d->totalOffset.width() > 10 || d->totalOffset.height() > 10 || d->totalOffset.width() < -10 || d->totalOffset.height() < -10) { - updateState(Qt::GestureUpdated); + result = QGestureRecognizer::GestureTriggered; + } else { + result = QGestureRecognizer::MaybeGesture; } } + break; + } + case QEvent::MouseButtonPress: + case QEvent::MouseMove: + case QEvent::MouseButtonRelease: + result = QGestureRecognizer::Ignore; + break; + default: + result = QGestureRecognizer::Ignore; + break; + } + return result; +} + +void QPanGestureRecognizer::reset(QGesture *state) +{ + QPanGesture *pan = static_cast<QPanGesture*>(state); + QPanGesturePrivate *d = pan->d_func(); + + d->totalOffset = d->lastOffset = d->offset = QSizeF(); + d->lastPosition = QPoint(); + d->acceleration = 0; + +//#if defined(QT_MAC_USE_COCOA) +// d->singleTouchPanTimer.stop(); +// d->prevMousePos = QPointF(0, 0); +//#endif + + QGestureRecognizer::reset(state); +} + +/*! \internal */ +/* +bool QPanGestureRecognizer::event(QEvent *event) +{ +#if defined(QT_MAC_USE_COCOA) + Q_D(QPanGesture); + if (event->type() == QEvent::Timer) { + const QTimerEvent *te = static_cast<QTimerEvent *>(event); + if (te->timerId() == d->singleTouchPanTimer.timerId()) { + d->singleTouchPanTimer.stop(); + updateState(Qt::GestureStarted); + } } +#endif + + bool consume = false; + +#if defined(Q_WS_WIN) #elif defined(QT_MAC_USE_COCOA) // The following implements single touch // panning on Mac: @@ -244,16 +168,25 @@ bool QPanGesture::filterEvent(QEvent *event) switch (event->type()) { case QEvent::TouchBegin: { if (ev->touchPoints().size() == 1) { + d->delayManager->setEnabled(true); + consume = d->delayManager->append(d->gestureTarget, *event); d->lastPosition = QCursor::pos(); d->singleTouchPanTimer.start(panBeginDelay, this); } break;} case QEvent::TouchEnd: { - if (state() != Qt::NoGesture) + d->delayManager->setEnabled(false); + if (state() != Qt::NoGesture) { updateState(Qt::GestureFinished); + consume = true; + d->delayManager->clear(); + } else { + d->delayManager->replay(); + } reset(); break;} case QEvent::TouchUpdate: { + consume = d->delayManager->append(d->gestureTarget, *event); if (ev->touchPoints().size() == 1) { if (state() == Qt::NoGesture) { // INVARIANT: The singleTouchTimer has still not fired. @@ -261,11 +194,15 @@ bool QPanGesture::filterEvent(QEvent *event) // the starting point that it makes sense to cancel: const QPointF startPos = ev->touchPoints().at(0).startPos().toPoint(); const QPointF p = ev->touchPoints().at(0).pos().toPoint(); - if ((startPos - p).manhattanLength() > panBeginRadius) + if ((startPos - p).manhattanLength() > panBeginRadius) { + d->delayManager->replay(); + consume = false; reset(); - else + } else { d->lastPosition = QCursor::pos(); + } } else { + d->delayManager->clear(); QPointF mousePos = QCursor::pos(); QPointF dist = mousePos - d->lastPosition; d->lastPosition = mousePos; @@ -275,527 +212,25 @@ bool QPanGesture::filterEvent(QEvent *event) updateState(Qt::GestureUpdated); } } else if (state() == Qt::NoGesture) { + d->delayManager->replay(); + consume = false; reset(); } break;} + case QEvent::MouseButtonPress: + case QEvent::MouseMove: + case QEvent::MouseButtonRelease: + if (d->delayManager->isEnabled()) + consume = d->delayManager->append(d->gestureTarget, *event); + break; default: return false; } #else Q_UNUSED(event); #endif - return false; -} - -/*! \internal */ -void QPanGesture::reset() -{ - Q_D(QPanGesture); - d->lastOffset = d->totalOffset = d->offset = QSize(0, 0); - d->lastPosition = QPoint(0, 0); - -#if defined(QT_MAC_USE_COCOA) - d->singleTouchPanTimer.stop(); - d->prevMousePos = QPointF(0, 0); -#endif - - QGesture::reset(); -} - -/*! - \property QPanGesture::totalOffset - - Specifies a total pan offset since the start of the gesture. -*/ -QSizeF QPanGesture::totalOffset() const -{ - Q_D(const QPanGesture); - return d->totalOffset; -} - -/*! - \property QPanGesture::lastOffset - - Specifies a pan offset the last time the gesture was triggered. -*/ -QSizeF QPanGesture::lastOffset() const -{ - Q_D(const QPanGesture); - return d->lastOffset; -} - -/*! - \property QPanGesture::offset - - Specifies the current pan offset since the last time the gesture was - triggered. -*/ -QSizeF QPanGesture::offset() const -{ - Q_D(const QPanGesture); - return d->offset; -} - -////////////////////////////////////////////////////////////////////////////// - -/*! - \class QPinchGesture - \preliminary - \since 4.6 - - \brief The QPinchGesture class represents a Pinch gesture, - providing additional information related to zooming and/or rotation. -*/ - -/*! - Creates a new Pinch gesture handler object and marks it as a child - of \a parent. The pan gesture handler watches \a gestureTarget for its - events. - - On some platform like Windows it's necessary to provide a non-null - widget as \a parent to get native gesture support. -*/ -QPinchGesture::QPinchGesture(QWidget *gestureTarget, QObject *parent) - : QGesture(*new QPinchGesturePrivate, gestureTarget, parent) -{ - setObjectName(QLatin1String("QPinchGesture")); -} - -void QPinchGesturePrivate::setupGestureTarget(QObject *newGestureTarget) -{ - Q_Q(QPinchGesture); - if (gestureTarget && gestureTarget->isWidgetType()) { - QWidget *w = static_cast<QWidget*>(gestureTarget.data()); - QApplicationPrivate::instance()->widgetGestures[w].pinch = 0; -#ifdef Q_WS_WIN - qt_widget_private(w)->winSetupGestures(); -#endif - } - - if (newGestureTarget && newGestureTarget->isWidgetType()) { - QWidget *w = static_cast<QWidget*>(newGestureTarget); - QApplicationPrivate::instance()->widgetGestures[w].pinch = q; -#ifdef Q_WS_WIN - qt_widget_private(w)->winSetupGestures(); -#endif - } - QGesturePrivate::setupGestureTarget(newGestureTarget); -} - -/*! \internal */ -bool QPinchGesture::event(QEvent *event) -{ - return QObject::event(event); -} - -bool QPinchGesture::eventFilter(QObject *receiver, QEvent *event) -{ - Q_D(QPinchGesture); - - if (d->implicitGesture && d->gestureTarget && d->gestureTarget->isWidgetType() && - static_cast<QWidget*>(d->gestureTarget.data())->testAttribute(Qt::WA_DontUseStandardGestures)) - return false; - -#if defined(Q_WS_WIN) || defined(Q_WS_MAC) - if (receiver->isWidgetType() && event->type() == QEvent::NativeGesture) { - QNativeGestureEvent *ev = static_cast<QNativeGestureEvent*>(event); -#if defined(Q_WS_WIN) - QApplicationPrivate *qAppPriv = QApplicationPrivate::instance(); - QApplicationPrivate::WidgetStandardGesturesMap::iterator it; - it = qAppPriv->widgetGestures.find(static_cast<QWidget*>(receiver)); - if (it == qAppPriv->widgetGestures.end()) - return false; - if (this != it.value().pinch) - return false; -#endif - Qt::GestureState nextState = Qt::NoGesture; - - switch(ev->gestureType) { - case QNativeGestureEvent::GestureBegin: - // next we might receive the first gesture update event, so we - // prepare for it. - d->state = Qt::NoGesture; - d->changes = 0; - d->totalScaleFactor = d->scaleFactor = d->lastScaleFactor = 1.; - d->totalRotationAngle = d->rotationAngle = d->lastRotationAngle = 0.; - d->startCenterPoint = d->centerPoint = d->lastCenterPoint = QPointF(); -#if defined(Q_WS_WIN) - d->initialDistance = 0; - d->lastSequenceId = ev->sequenceId; -#endif - return false; - case QNativeGestureEvent::Rotate: { - d->lastScaleFactor = d->scaleFactor; - d->lastRotationAngle = d->rotationAngle; -#if defined(Q_WS_MAC) - d->rotationAngle += ev->percentage; - nextState = Qt::GestureUpdated; -#elif defined(Q_WS_WIN) - // This is a workaround for an issue with the native rotation - // gesture on Windows 7. For some reason the rotation angle in the - // first WM_GESTURE message in a sequence contains value that is - // off a little bit and causes the rotating item to "jump", so - // we just ignore the first WM_GESTURE in every sequence. - bool windowsRotateWorkaround = false; - if (!d->lastSequenceId) { - windowsRotateWorkaround = true; - d->lastSequenceId = ev->sequenceId; - } - if (d->lastSequenceId > 0 && d->lastSequenceId != (ulong)-1 && ev->sequenceId != d->lastSequenceId) { - // this is the first WM_GESTURE message in a sequence. - d->totalRotationAngle += d->rotationAngle; - windowsRotateWorkaround = true; - // a magic value to mark that the next WM_GESTURE message is - // the second message in a sequence and we should clear the - // lastRotationAngle - d->lastSequenceId = (ulong)-1; - } - if (!windowsRotateWorkaround) { - d->rotationAngle = -1 * GID_ROTATE_ANGLE_FROM_ARGUMENT(ev->argument) * 180. / M_PI; - if (d->lastSequenceId == (ulong)-1) { - // a special case since we need to set the lastRotationAngle to - // rotationAngle when the first WM_GESTURE is received in each - // sequence. - d->lastRotationAngle = d->rotationAngle; - } - d->lastSequenceId = ev->sequenceId; - } - if (!windowsRotateWorkaround) - nextState = Qt::GestureUpdated; -#endif - d->changes = QPinchGesture::RotationAngleChanged; - event->accept(); - break; - } - case QNativeGestureEvent::Zoom: - d->lastRotationAngle = d->rotationAngle; - d->lastScaleFactor = d->scaleFactor; -#if defined(Q_WS_WIN) - if (d->initialDistance != 0) { - int distance = int(qint64(ev->argument)); - if (d->lastSequenceId && ev->sequenceId != d->lastSequenceId) { - d->totalScaleFactor *= d->scaleFactor; - d->initialDistance = int(qint64(ev->argument)); - d->lastScaleFactor = d->scaleFactor = (qreal) distance / d->initialDistance; - } else { - d->scaleFactor = (qreal) distance / d->initialDistance; - } - d->lastSequenceId = ev->sequenceId; - } else { - d->initialDistance = int(qint64(ev->argument)); - } -#elif defined(Q_WS_MAC) - d->scaleFactor += ev->percentage; -#endif - nextState = Qt::GestureUpdated; - d->changes = QPinchGesture::ScaleFactorChanged; - event->accept(); - break; - case QNativeGestureEvent::GestureEnd: - if (state() == Qt::NoGesture) - return false; // some other gesture has ended - nextState = Qt::GestureFinished; - break; - default: - return false; - } - if (d->startCenterPoint.isNull()) - d->startCenterPoint = d->centerPoint; - d->lastCenterPoint = d->centerPoint; - d->centerPoint = static_cast<QWidget*>(receiver)->mapFromGlobal(ev->position); - if (d->lastCenterPoint != d->centerPoint) - d->changes |= QPinchGesture::CenterPointChanged; - updateState(nextState); - return true; - } -#endif - return QGesture::eventFilter(receiver, event); -} - - -/*! \internal */ -bool QPinchGesture::filterEvent(QEvent *event) -{ - Q_D(QPinchGesture); - - if (d->implicitGesture && d->gestureTarget && d->gestureTarget->isWidgetType() && - static_cast<QWidget*>(d->gestureTarget.data())->testAttribute(Qt::WA_DontUseStandardGestures)) - return false; - - Q_UNUSED(event); - return false; -} - -/*! \internal */ -void QPinchGesture::reset() -{ - Q_D(QPinchGesture); - d->changes = 0; - d->totalScaleFactor = d->scaleFactor = d->lastScaleFactor = 1.; - d->totalRotationAngle = d->rotationAngle = d->lastRotationAngle = 0.; - d->startCenterPoint = d->centerPoint = d->lastCenterPoint = QPointF(); - QGesture::reset(); -} - -/*! \enum QPinchGesture::WhatChange - \value ScaleFactorChanged - \value RotationAngleChanged - \value CenterPointChanged -*/ - -/*! - \property QPinchGesture::whatChanged - - Specifies which values were changed in the gesture. -*/ -QPinchGesture::WhatChanged QPinchGesture::whatChanged() const -{ - return d_func()->changes; -} - -/*! - \property QPinchGesture::totalScaleFactor - - Specifies a total scale factor of the pinch gesture since the gesture - started. -*/ -qreal QPinchGesture::totalScaleFactor() const -{ - Q_D(const QPinchGesture); - return d->totalScaleFactor * d->scaleFactor; -} - -/*! - \property QPinchGesture::scaleFactor - - Specifies a scale factor of the pinch gesture. - - If the gesture consists of several pinch sequences (i.e. zoom and rotate - sequences), then this property specifies the scale factor in the current - sequence. When pinching changes the rotation angle only, the value of this - property is 1. -*/ -qreal QPinchGesture::scaleFactor() const -{ - return d_func()->scaleFactor; -} - -/*! - \property QPinchGesture::lastScaleFactor - - Specifies a previous scale factor of the pinch gesture. -*/ -qreal QPinchGesture::lastScaleFactor() const -{ - return d_func()->lastScaleFactor; -} - -/*! - \property QPinchGesture::totalRotationAngle - - Specifies a total rotation angle of the gesture since the gesture started. - - The angle is specified in degrees. -*/ -qreal QPinchGesture::totalRotationAngle() const -{ - Q_D(const QPinchGesture); - return d->totalRotationAngle + d->rotationAngle; -} - -/*! - \property QPinchGesture::rotationAngle - - Specifies a rotation angle of the gesture. - - If the gesture consists of several pinch sequences (i.e. zoom and rotate - sequences), then this property specifies the rotation angle in the current - sequence. When pinching changes the scale factor only, the value of this - property is 0. - - The angle is specified in degrees. -*/ -qreal QPinchGesture::rotationAngle() const -{ - return d_func()->rotationAngle; -} - -/*! - \property QPinchGesture::lastRotationAngle - - Specifies a previous rotation angle of the gesture. - - The angle is specified in degrees. -*/ -qreal QPinchGesture::lastRotationAngle() const -{ - return d_func()->lastRotationAngle; -} - -/*! - \property QPinchGesture::centerPoint - - Specifies a center point of the gesture. The point can be used as a center - point that the object is rotated around. -*/ -QPointF QPinchGesture::centerPoint() const -{ - return d_func()->centerPoint; -} - -/*! - \property QPinchGesture::lastCenterPoint - - Specifies a previous center point of the gesture. -*/ -QPointF QPinchGesture::lastCenterPoint() const -{ - return d_func()->lastCenterPoint; -} - -/*! - \property QPinchGesture::startCenterPoint - - Specifies an initial center point of the gesture. Difference between the - startCenterPoint and the centerPoint is the distance at which pinching - fingers has shifted. -*/ -QPointF QPinchGesture::startCenterPoint() const -{ - return d_func()->startCenterPoint; -} - -////////////////////////////////////////////////////////////////////////////// - -/*! - \class QSwipeGesture - \preliminary - \since 4.6 - - \brief The QSwipeGesture class represents a swipe gesture, - providing additional information related to swiping. -*/ - -/*! - Creates a new Swipe gesture handler object and marks it as a - child of \a parent. The swipe gesture handler watches \a - gestureTarget for its events. - - On some platform like Windows it's necessary to provide a non-null - widget as \a parent to get native gesture support. -*/ -QSwipeGesture::QSwipeGesture(QWidget *gestureTarget, QObject *parent) - : QGesture(*new QSwipeGesturePrivate, gestureTarget, parent) -{ - setObjectName(QLatin1String("QSwipeGesture")); -} - -void QSwipeGesturePrivate::setupGestureTarget(QObject *newGestureTarget) -{ - Q_Q(QSwipeGesture); - if (gestureTarget && gestureTarget->isWidgetType()) { - QWidget *w = static_cast<QWidget*>(gestureTarget.data()); - QApplicationPrivate::instance()->widgetGestures[w].swipe = 0; -#if defined(Q_WS_WIN) - qt_widget_private(w)->winSetupGestures(); -#endif - } - - if (newGestureTarget && newGestureTarget->isWidgetType()) { - QWidget *w = static_cast<QWidget*>(newGestureTarget); - QApplicationPrivate::instance()->widgetGestures[w].swipe = q; -#if defined(Q_WS_WIN) - qt_widget_private(w)->winSetupGestures(); -#endif - } - QGesturePrivate::setupGestureTarget(newGestureTarget); -} - -/*! - \property QSwipeGesture::swipeAngle - - Holds the angle of the swipe gesture, 0..360. -*/ -qreal QSwipeGesture::swipeAngle() const -{ - Q_D(const QSwipeGesture); - return d->swipeAngle; -} - -/*! - \property QSwipeGesture::horizontalDirection - - Holds the direction for the horizontal component of the swipe - gesture, SwipeDirection::Left or SwipeDirection::Right. - SwipeDirection::NoDirection if there is no horizontal - component to the swipe gesture. -*/ -QSwipeGesture::SwipeDirection QSwipeGesture::horizontalDirection() const -{ - Q_D(const QSwipeGesture); - if (d->swipeAngle < 0 || d->swipeAngle == 90 || d->swipeAngle == 270) - return QSwipeGesture::NoDirection; - else if (d->swipeAngle < 90 || d->swipeAngle > 270) - return QSwipeGesture::Right; - else - return QSwipeGesture::Left; -} - - -/*! - \property QSwipeGesture::verticalDirection - - Holds the direction for the vertical component of the swipe - gesture, SwipeDirection::Down or SwipeDirection::Up. - SwipeDirection::NoDirection if there is no vertical - component to the swipe gesture. -*/ -QSwipeGesture::SwipeDirection QSwipeGesture::verticalDirection() const -{ - Q_D(const QSwipeGesture); - if (d->swipeAngle <= 0 || d->swipeAngle == 180) - return QSwipeGesture::NoDirection; - else if (d->swipeAngle < 180) - return QSwipeGesture::Up; - else - return QSwipeGesture::Down; -} - -bool QSwipeGesture::eventFilter(QObject *receiver, QEvent *event) -{ - Q_D(QSwipeGesture); - if (receiver->isWidgetType() && event->type() == QEvent::NativeGesture) { - QNativeGestureEvent *ev = static_cast<QNativeGestureEvent*>(event); - switch (ev->gestureType) { - case QNativeGestureEvent::Swipe: - d->swipeAngle = ev->angle; - updateState(Qt::GestureStarted); - updateState(Qt::GestureUpdated); - updateState(Qt::GestureFinished); - break; - default: - return false; - } - return true; - } - return QGesture::eventFilter(receiver, event); -} - -/*! \internal */ -bool QSwipeGesture::filterEvent(QEvent *) -{ - return false; -} - -/*! \internal */ -void QSwipeGesture::reset() -{ - Q_D(QSwipeGesture); - d->swipeAngle = -1; - QGesture::reset(); + return QGestureRecognizer::Ignore; } + */ QT_END_NAMESPACE - -#include "moc_qstandardgestures.cpp" - diff --git a/src/gui/kernel/qstandardgestures.h b/src/gui/kernel/qstandardgestures.h deleted file mode 100644 index 9e8291b..0000000 --- a/src/gui/kernel/qstandardgestures.h +++ /dev/null @@ -1,174 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the QtGui module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** 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.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QSTANDARDGESTURES_H -#define QSTANDARDGESTURES_H - -#include <QtGui/qevent.h> -#include <QtCore/qbasictimer.h> - -#include <QtGui/qgesture.h> - -QT_BEGIN_HEADER - -QT_BEGIN_NAMESPACE - -QT_MODULE(Gui) - -class QPanGesturePrivate; -class Q_GUI_EXPORT QPanGesture : public QGesture -{ - Q_OBJECT - Q_DECLARE_PRIVATE(QPanGesture) - - Q_PROPERTY(QSizeF totalOffset READ totalOffset) - Q_PROPERTY(QSizeF lastOffset READ lastOffset) - Q_PROPERTY(QSizeF offset READ offset) - -public: - QPanGesture(QWidget *gestureTarget, QObject *parent = 0); - - bool filterEvent(QEvent *event); - - QSizeF totalOffset() const; - QSizeF lastOffset() const; - QSizeF offset() const; - -protected: - void reset(); - -private: - bool event(QEvent *event); - bool eventFilter(QObject *receiver, QEvent *event); - - friend class QWidget; - friend class QAbstractScrollAreaPrivate; -}; - -class QPinchGesturePrivate; -class Q_GUI_EXPORT QPinchGesture : public QGesture -{ - Q_OBJECT - Q_DECLARE_PRIVATE(QPinchGesture) - -public: - enum WhatChange { - ScaleFactorChanged = 0x1, - RotationAngleChanged = 0x2, - CenterPointChanged = 0x4 - }; - Q_DECLARE_FLAGS(WhatChanged, WhatChange) - - Q_PROPERTY(WhatChanged whatChanged READ whatChanged) - - Q_PROPERTY(qreal totalScaleFactor READ totalScaleFactor) - Q_PROPERTY(qreal lastScaleFactor READ lastScaleFactor) - Q_PROPERTY(qreal scaleFactor READ scaleFactor) - - Q_PROPERTY(qreal totalRotationAngle READ totalRotationAngle) - Q_PROPERTY(qreal lastRotationAngle READ lastRotationAngle) - Q_PROPERTY(qreal rotationAngle READ rotationAngle) - - Q_PROPERTY(QPointF startCenterPoint READ startCenterPoint) - Q_PROPERTY(QPointF lastCenterPoint READ lastCenterPoint) - Q_PROPERTY(QPointF centerPoint READ centerPoint) - -public: - - QPinchGesture(QWidget *gestureTarget, QObject *parent = 0); - - bool filterEvent(QEvent *event); - void reset(); - - WhatChanged whatChanged() const; - - QPointF startCenterPoint() const; - QPointF lastCenterPoint() const; - QPointF centerPoint() const; - - qreal totalScaleFactor() const; - qreal lastScaleFactor() const; - qreal scaleFactor() const; - - qreal totalRotationAngle() const; - qreal lastRotationAngle() const; - qreal rotationAngle() const; - -private: - bool event(QEvent *event); - bool eventFilter(QObject *receiver, QEvent *event); - - friend class QWidget; -}; - -class QSwipeGesturePrivate; -class Q_GUI_EXPORT QSwipeGesture : public QGesture -{ - Q_OBJECT - Q_ENUMS(SwipeDirection) - - Q_PROPERTY(SwipeDirection horizontalDirection READ horizontalDirection) - Q_PROPERTY(SwipeDirection verticalDirection READ verticalDirection) - Q_PROPERTY(qreal swipeAngle READ swipeAngle) - - Q_DECLARE_PRIVATE(QSwipeGesture) - -public: - enum SwipeDirection { NoDirection, Left, Right, Up, Down }; - QSwipeGesture(QWidget *gestureTarget, QObject *parent = 0); - - bool filterEvent(QEvent *event); - void reset(); - - SwipeDirection horizontalDirection() const; - SwipeDirection verticalDirection() const; - qreal swipeAngle() const; - -private: - bool eventFilter(QObject *receiver, QEvent *event); - - friend class QWidget; -}; -QT_END_NAMESPACE - -QT_END_HEADER - -#endif // QSTANDARDGESTURES_H diff --git a/src/gui/kernel/qstandardgestures_p.h b/src/gui/kernel/qstandardgestures_p.h index 79aadfd..fec5c2f 100644 --- a/src/gui/kernel/qstandardgestures_p.h +++ b/src/gui/kernel/qstandardgestures_p.h @@ -53,83 +53,20 @@ // We mean it. // -#include "qevent.h" -#include "qbasictimer.h" -#include "qdebug.h" - -#include "qgesture.h" -#include "qgesture_p.h" - -#include "qstandardgestures.h" -#include "qbasictimer.h" +#include "qgesturerecognizer.h" +#include "private/qgesture_p.h" QT_BEGIN_NAMESPACE -class QPanGesturePrivate : public QGesturePrivate -{ - Q_DECLARE_PUBLIC(QPanGesture) - -public: - void setupGestureTarget(QObject *o); - - QSizeF totalOffset; - QSizeF lastOffset; - QSizeF offset; - QPointF lastPosition; - -#if defined(QT_MAC_USE_COCOA) - QBasicTimer singleTouchPanTimer; - QPointF prevMousePos; -#endif -}; - -class QPinchGesturePrivate : public QGesturePrivate +class QPanGestureRecognizer : public QGestureRecognizer { - Q_DECLARE_PUBLIC(QPinchGesture) - public: - QPinchGesturePrivate() - : changes(0), totalScaleFactor(0.), lastScaleFactor(0.), scaleFactor(0.), - totalRotationAngle(0.), lastRotationAngle(0.), rotationAngle(0.) -#ifdef Q_WS_WIN - ,initialDistance(0), lastSequenceId(0) -#endif - { - } + QPanGestureRecognizer(); - void setupGestureTarget(QObject *o); - - QPinchGesture::WhatChanged changes; - - qreal totalScaleFactor; // total scale factor, excluding the current sequence. - qreal lastScaleFactor; - qreal scaleFactor; // scale factor in the current sequence. - - qreal totalRotationAngle; // total rotation angle, excluding the current sequence. - qreal lastRotationAngle; - qreal rotationAngle; // rotation angle in the current sequence. - - QPointF startCenterPoint; - QPointF lastCenterPoint; - QPointF centerPoint; -#ifdef Q_WS_WIN - int initialDistance; - ulong lastSequenceId; -#endif -}; - -class QSwipeGesturePrivate : public QGesturePrivate -{ - Q_DECLARE_PUBLIC(QSwipeGesture) - -public: - QSwipeGesturePrivate() - : swipeAngle(-1) - { - } + QGesture *createGesture(QObject *target); - void setupGestureTarget(QObject *o); - qreal swipeAngle; + QGestureRecognizer::Result filterEvent(QGesture *state, QObject *watched, QEvent *event); + void reset(QGesture *state); }; QT_END_NAMESPACE diff --git a/src/gui/kernel/qwidget.cpp b/src/gui/kernel/qwidget.cpp index a071ba6..de08312 100644 --- a/src/gui/kernel/qwidget.cpp +++ b/src/gui/kernel/qwidget.cpp @@ -115,6 +115,7 @@ #include "private/qevent_p.h" #include "private/qgraphicssystem_p.h" +#include "private/qgesturemanager_p.h" // widget/widget data creation count //#define QWIDGET_EXTRA_DEBUG @@ -1503,6 +1504,8 @@ void QWidgetPrivate::setWinId(WId id) // set widget identifier mapper->remove(data.winid); } + const WId oldWinId = data.winid; + data.winid = id; #if defined(Q_WS_X11) hd = id; // X11: hd == ident @@ -1510,6 +1513,16 @@ void QWidgetPrivate::setWinId(WId id) // set widget identifier if (mapper && id && !userDesktopWidget) { mapper->insert(data.winid, q); } + + if(oldWinId != id) { + // Do not emit an event when the old winId is destroyed. This only + // happens (a) during widget destruction, and (b) immediately prior + // to creation of a new winId, for example as a result of re-parenting. + if(id != 0) { + QEvent e(QEvent::WinIdChange); + QCoreApplication::sendEvent(q, &e); + } + } } void QWidgetPrivate::createTLExtra() @@ -2228,8 +2241,8 @@ QWidget *QWidget::find(WId id) against. If Qt is using Carbon, the {WId} is actually an HIViewRef. If Qt is using Cocoa, {WId} is a pointer to an NSView. - \note We recommend that you do not store this value as it is likely to - change at run-time. + This value may change at run-time. An event with type QEvent::WinIdChange + will be sent to the widget following a change in window system identifier. \sa find() */ @@ -8333,6 +8346,9 @@ bool QWidget::event(QEvent *event) (void) QApplication::sendEvent(this, &mouseEvent); break; } + case QEvent::Gesture: + event->ignore(); + break; #ifndef QT_NO_PROPERTIES case QEvent::DynamicPropertyChange: { const QByteArray &propName = static_cast<QDynamicPropertyChangeEvent *>(event)->propertyName(); @@ -11669,6 +11685,19 @@ QGraphicsProxyWidget *QWidget::graphicsProxyWidget() const Synonym for QList<QWidget *>. */ +/*! + Subscribes the widget to a given \a gesture with a \a context. + + \sa QGestureEvent + \since 4.6 +*/ +void QWidget::grabGesture(Qt::GestureType gesture, Qt::GestureContext context) +{ + Q_D(QWidget); + d->gestureContext.insert(gesture, context); + (void)QGestureManager::instance(); // create a gesture manager +} + QT_END_NAMESPACE #include "moc_qwidget.cpp" @@ -11982,3 +12011,10 @@ void QWidget::clearMask() XRender extension is not supported on the X11 display, or if the handle could not be created. */ + +#ifdef Q_OS_SYMBIAN +void QWidgetPrivate::_q_delayedDestroy(WId winId) +{ + delete winId; +} +#endif diff --git a/src/gui/kernel/qwidget.h b/src/gui/kernel/qwidget.h index 76418af..e603a1a 100644 --- a/src/gui/kernel/qwidget.h +++ b/src/gui/kernel/qwidget.h @@ -96,7 +96,6 @@ class QIcon; class QWindowSurface; class QLocale; class QGraphicsProxyWidget; -class QGestureManager; class QGraphicsEffect; #if defined(Q_WS_X11) class QX11Info; @@ -355,6 +354,8 @@ public: QGraphicsEffect *graphicsEffect() const; void setGraphicsEffect(QGraphicsEffect *effect); + void grabGesture(Qt::GestureType type, Qt::GestureContext context = Qt::WidgetWithChildrenGesture); + public Q_SLOTS: void setWindowTitle(const QString &); #ifndef QT_NO_STYLE_STYLESHEET @@ -725,18 +726,17 @@ private: friend class QGLContext; friend class QGLWidget; friend class QGLWindowSurface; - friend class QGLWindowSurfaceGLPaintDevice; - friend class QVGWindowSurface; friend class QX11PaintEngine; friend class QWin32PaintEngine; friend class QShortcutPrivate; friend class QShortcutMap; friend class QWindowSurface; - friend class QD3DWindowSurface; friend class QGraphicsProxyWidget; friend class QGraphicsProxyWidgetPrivate; friend class QStyleSheetStyle; friend struct QWidgetExceptionCleaner; + friend class QGestureManager; + friend class QWinNativePanGestureRecognizer; #ifdef Q_WS_MAC friend class QCoreGraphicsPaintEnginePrivate; @@ -773,6 +773,9 @@ private: private: Q_DISABLE_COPY(QWidget) Q_PRIVATE_SLOT(d_func(), void _q_showIfNotHidden()) +#ifdef Q_OS_SYMBIAN + Q_PRIVATE_SLOT(d_func(), void _q_delayedDestroy(WId winId)) +#endif QWidgetData *data; diff --git a/src/gui/kernel/qwidget_p.h b/src/gui/kernel/qwidget_p.h index c06ef73..f7c2712 100644 --- a/src/gui/kernel/qwidget_p.h +++ b/src/gui/kernel/qwidget_p.h @@ -64,6 +64,8 @@ #include "QtGui/qapplication.h" #include <private/qgraphicseffect_p.h> +#include <private/qgesture_p.h> + #ifdef Q_WS_WIN #include "QtCore/qt_windows.h" #include <private/qdnd_p.h> @@ -294,7 +296,8 @@ public: void setMask_sys(const QRegion &); #ifdef Q_OS_SYMBIAN void setSoftKeys_sys(const QList<QAction*> &softkeys); - void activateSymbianWindow(); + void activateSymbianWindow(WId wid = 0); + void _q_delayedDestroy(WId winId); #endif void raise_sys(); @@ -578,6 +581,7 @@ public: #ifndef QT_NO_ACTION QList<QAction*> actions; #endif + QMap<Qt::GestureType, Qt::GestureContext> gestureContext; // Bit fields. uint high_attributes[3]; // the low ones are in QWidget::widget_attributes @@ -604,6 +608,7 @@ public: bool isBackgroundInherited() const; #elif defined(Q_WS_WIN) // <--------------------------------------------------------- WIN uint noPaintOnScreen : 1; // see qwidget_win.cpp ::paintEngine() + uint nativeGesturePanEnabled : 1; bool shouldShowMaximizeButton(); void winUpdateIsOpaque(); diff --git a/src/gui/kernel/qwidget_s60.cpp b/src/gui/kernel/qwidget_s60.cpp index b0d405a..8ce5001 100644 --- a/src/gui/kernel/qwidget_s60.cpp +++ b/src/gui/kernel/qwidget_s60.cpp @@ -56,6 +56,12 @@ #include <aknappui.h> #endif +// This is necessary in order to be able to perform delayed invokation on slots +// which take arguments of type WId. One example is +// QWidgetPrivate::_q_delayedDestroy, which is used to delay destruction of +// CCoeControl objects until after the CONE event handler has finished running. +Q_DECLARE_METATYPE(WId) + QT_BEGIN_NAMESPACE extern bool qt_nograb(); @@ -318,8 +324,6 @@ void QWidgetPrivate::create_sys(WId window, bool /* initializeWindow */, bool de bool desktop = (type == Qt::Desktop); //bool tool = (type == Qt::Tool || type == Qt::Drawer); - WId id = 0; - if (popup) flags |= Qt::WindowStaysOnTopHint; // a popup stays on top @@ -341,13 +345,10 @@ void QWidgetPrivate::create_sys(WId window, bool /* initializeWindow */, bool de data.crect.setSize(QSize(width, height)); } - CCoeControl *destroyw = 0; + CCoeControl *const destroyw = destroyOldWindow ? data.winid : 0; createExtra(); if (window) { - if (destroyOldWindow) - destroyw = data.winid; - id = window; setWinId(window); TRect tr = window->Rect(); data.crect.setRect(tr.iTl.iX, tr.iTl.iY, tr.Width(), tr.Height()); @@ -355,10 +356,15 @@ void QWidgetPrivate::create_sys(WId window, bool /* initializeWindow */, bool de } else if (topLevel) { if (!q->testAttribute(Qt::WA_Moved) && !q->testAttribute(Qt::WA_DontShowOnScreen)) data.crect.moveTopLeft(QPoint(clientRect.iTl.iX, clientRect.iTl.iY)); - QSymbianControl *control= q_check_ptr(new QSymbianControl(q)); - id = (WId)control; - setWinId(id); - QT_TRAP_THROWING(control->ConstructL(true,desktop)); + + QScopedPointer<QSymbianControl> control( q_check_ptr(new QSymbianControl(q)) ); + QT_TRAP_THROWING(control->ConstructL(true, desktop)); + + // Symbian windows are always created in an inactive state + // We perform this assignment for the case where the window is being re-created + // as aa result of a call to setParent_sys, on either this widget or one of its + // ancestors. + extra->activated = 0; if (!desktop) { TInt stackingFlags; @@ -368,7 +374,7 @@ void QWidgetPrivate::create_sys(WId window, bool /* initializeWindow */, bool de stackingFlags = ECoeStackFlagStandard; } control->MakeVisible(false); - QT_TRAP_THROWING(control->ControlEnv()->AppUi()->AddToStackL(control, ECoeStackPriorityDefault, stackingFlags)); + QT_TRAP_THROWING(control->ControlEnv()->AppUi()->AddToStackL(control.data(), ECoeStackPriorityDefault, stackingFlags)); // Avoid keyboard focus to a hidden window. control->setFocusSafely(false); @@ -391,11 +397,22 @@ void QWidgetPrivate::create_sys(WId window, bool /* initializeWindow */, bool de int x, y, w, h; data.crect.getRect(&x, &y, &w, &h); control->SetRect(TRect(TPoint(x, y), TSize(w, h))); + + // We wait until the control is fully constructed before calling setWinId, because + // this generates a WinIdChanged event. + setWinId(control.take()); + } else if (q->testAttribute(Qt::WA_NativeWindow) || paintOnScreen()) { // create native child widget - QSymbianControl *control = new QSymbianControl(q); - setWinId(control); + + QScopedPointer<QSymbianControl> control( q_check_ptr(new QSymbianControl(q)) ); QT_TRAP_THROWING(control->ConstructL(!parentWidget)); + // Symbian windows are always created in an inactive state + // We perform this assignment for the case where the window is being re-created + // as aa result of a call to setParent_sys, on either this widget or one of its + // ancestors. + extra->activated = 0; + TInt stackingFlags; if ((q->windowType() & Qt::Popup) == Qt::Popup) { stackingFlags = ECoeStackFlagRefusesAllKeys | ECoeStackFlagRefusesFocus; @@ -403,7 +420,7 @@ void QWidgetPrivate::create_sys(WId window, bool /* initializeWindow */, bool de stackingFlags = ECoeStackFlagStandard; } control->MakeVisible(false); - QT_TRAP_THROWING(control->ControlEnv()->AppUi()->AddToStackL(control, ECoeStackPriorityDefault, stackingFlags)); + QT_TRAP_THROWING(control->ControlEnv()->AppUi()->AddToStackL(control.data(), ECoeStackPriorityDefault, stackingFlags)); // Avoid keyboard focus to a hidden window. control->setFocusSafely(false); @@ -418,12 +435,21 @@ void QWidgetPrivate::create_sys(WId window, bool /* initializeWindow */, bool de | EPointerFilterMove | EPointerFilterDrag, 0); if (q->isVisible() && q->testAttribute(Qt::WA_Mapped)) - activateSymbianWindow(); + activateSymbianWindow(control.data()); + + // We wait until the control is fully constructed before calling setWinId, because + // this generates a WinIdChanged event. + setWinId(control.take()); } if (destroyw) { destroyw->ControlEnv()->AppUi()->RemoveFromStack(destroyw); - CBase::Delete(destroyw); + + // Delay deletion of the control in case this function is called in the + // context of a CONE event handler such as + // CCoeControl::ProcessPointerEventL + QMetaObject::invokeMethod(q, "_q_delayedDestroy", + Qt::QueuedConnection, Q_ARG(WId, destroyw)); } if (q->testAttribute(Qt::WA_AcceptTouchEvents)) @@ -468,7 +494,7 @@ void QWidgetPrivate::show_sys() invalidateBuffer(q->rect()); } -void QWidgetPrivate::activateSymbianWindow() +void QWidgetPrivate::activateSymbianWindow(WId wid) { Q_Q(QWidget); @@ -476,8 +502,12 @@ void QWidgetPrivate::activateSymbianWindow() Q_ASSERT(q->testAttribute(Qt::WA_Mapped)); Q_ASSERT(!extra->activated); - WId id = q->internalWinId(); - QT_TRAP_THROWING(id->ActivateL()); + if(!wid) + wid = q->internalWinId(); + + Q_ASSERT(wid); + + QT_TRAP_THROWING(wid->ActivateL()); extra->activated = 1; } @@ -571,8 +601,14 @@ void QWidgetPrivate::reparentChildren() w->d_func()->invalidateBuffer(w->rect()); WId parent = q->effectiveWinId(); WId child = w->effectiveWinId(); - if (parent != child) - child->SetParent(parent); + if (parent != child) { + // Child widget is native. Because Symbian windows cannot be + // re-parented, we must re-create the window. + const WId window = 0; + const bool initializeWindow = false; + const bool destroyOldWindow = true; + w->d_func()->create_sys(window, initializeWindow, destroyOldWindow); + } // ### TODO: We probably also need to update the component array here w->d_func()->reparentChildren(); } else { diff --git a/src/gui/kernel/qwidget_win.cpp b/src/gui/kernel/qwidget_win.cpp index a0982f4..2b11bec 100644 --- a/src/gui/kernel/qwidget_win.cpp +++ b/src/gui/kernel/qwidget_win.cpp @@ -2029,11 +2029,6 @@ void QWidgetPrivate::winSetupGestures() if (!q || !q->isVisible()) return; QApplicationPrivate *qAppPriv = QApplicationPrivate::instance(); - QApplicationPrivate::WidgetStandardGesturesMap::const_iterator it = - qAppPriv->widgetGestures.find(q); - if (it == qAppPriv->widgetGestures.end()) - return; - const QStandardGestures &gestures = it.value(); WId winid = q->effectiveWinId(); bool needh = false; @@ -2052,10 +2047,10 @@ void QWidgetPrivate::winSetupGestures() singleFingerPanEnabled = asa->d_func()->singleFingerPanEnabled; } if (winid && qAppPriv->SetGestureConfig) { - GESTURECONFIG gc[3]; + GESTURECONFIG gc[1]; memset(gc, 0, sizeof(gc)); gc[0].dwID = GID_PAN; - if (gestures.pan) { + if (nativeGesturePanEnabled) { gc[0].dwWant = GC_PAN; if (needv && singleFingerPanEnabled) gc[0].dwWant |= GC_PAN_WITH_SINGLE_FINGER_VERTICALLY; @@ -2069,16 +2064,16 @@ void QWidgetPrivate::winSetupGestures() gc[0].dwBlock = GC_PAN; } - gc[1].dwID = GID_ZOOM; - if (gestures.pinch) - gc[1].dwWant = GC_ZOOM; - else - gc[1].dwBlock = GC_ZOOM; - gc[2].dwID = GID_ROTATE; - if (gestures.pinch) - gc[2].dwWant = GC_ROTATE; - else - gc[2].dwBlock = GC_ROTATE; +// gc[1].dwID = GID_ZOOM; +// if (gestures.pinch) +// gc[1].dwWant = GC_ZOOM; +// else +// gc[1].dwBlock = GC_ZOOM; +// gc[2].dwID = GID_ROTATE; +// if (gestures.pinch) +// gc[2].dwWant = GC_ROTATE; +// else +// gc[2].dwBlock = GC_ROTATE; qAppPriv->SetGestureConfig(winid, 0, sizeof(gc)/sizeof(gc[0]), gc, sizeof(gc[0])); } diff --git a/src/gui/kernel/qwinnativepangesturerecognizer_win.cpp b/src/gui/kernel/qwinnativepangesturerecognizer_win.cpp new file mode 100644 index 0000000..4619594 --- /dev/null +++ b/src/gui/kernel/qwinnativepangesturerecognizer_win.cpp @@ -0,0 +1,124 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "private/qwinnativepangesturerecognizer_win_p.h" + +#include "qevent.h" +#include "qgraphicsitem.h" +#include "qgesture.h" + +#include "private/qgesture_p.h" +#include "private/qevent_p.h" +#include "private/qapplication_p.h" +#include "private/qwidget_p.h" + +QT_BEGIN_NAMESPACE + +QWinNativePanGestureRecognizer::QWinNativePanGestureRecognizer() +{ +} + +QGesture* QWinNativePanGestureRecognizer::createGesture(QObject *target) const +{ + if (!target) + return new QPanGesture; // a special case + if (qobject_cast<QGraphicsObject*>(target)) + return 0; + if (!target->isWidgetType()) + return 0; + + QWidget *q = static_cast<QWidget*>(target); + QWidgetPrivate *d = q->d_func(); + d->nativeGesturePanEnabled = true; + d->winSetupGestures(); + + return new QPanGesture; +} + +QGestureRecognizer::Result QWinNativePanGestureRecognizer::filterEvent(QGesture *state, QObject *, QEvent *event) +{ + QPanGesture *q = static_cast<QPanGesture*>(state); + QPanGesturePrivate *d = q->d_func(); + + QGestureRecognizer::Result result = QGestureRecognizer::Ignore; + if (event->type() == QEvent::NativeGesture) { + QNativeGestureEvent *ev = static_cast<QNativeGestureEvent*>(event); + switch(ev->gestureType) { + case QNativeGestureEvent::GestureBegin: + break; + case QNativeGestureEvent::Pan: + result = QGestureRecognizer::GestureTriggered; + event->accept(); + break; + case QNativeGestureEvent::GestureEnd: + if (q->state() == Qt::NoGesture) + return QGestureRecognizer::Ignore; // some other gesture has ended + result = QGestureRecognizer::GestureFinished; + break; + default: + return QGestureRecognizer::Ignore; + } + if (q->state() == Qt::NoGesture) { + d->lastOffset = d->totalOffset = d->offset = QSize(); + } else { + d->lastOffset = d->offset; + d->offset = QSize(ev->position.x() - d->lastPosition.x(), + ev->position.y() - d->lastPosition.y()); + d->totalOffset += d->offset; + } + d->lastPosition = ev->position; + } + return result; +} + +void QWinNativePanGestureRecognizer::reset(QGesture *state) +{ + QPanGesture *pan = static_cast<QPanGesture*>(state); + QPanGesturePrivate *d = pan->d_func(); + + d->totalOffset = d->lastOffset = d->offset = QSizeF(); + d->lastPosition = QPoint(); + d->acceleration = 0; + + QGestureRecognizer::reset(state); +} + +QT_END_NAMESPACE diff --git a/src/gui/kernel/qwinnativepangesturerecognizer_win_p.h b/src/gui/kernel/qwinnativepangesturerecognizer_win_p.h new file mode 100644 index 0000000..a1e8511 --- /dev/null +++ b/src/gui/kernel/qwinnativepangesturerecognizer_win_p.h @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWINNATIVEPANGESTURERECOGNIZER_WIN_P_H +#define QWINNATIVEPANGESTURERECOGNIZER_WIN_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 <QGestureRecognizer> + +QT_BEGIN_NAMESPACE + +class QWinNativePanGestureRecognizer : public QGestureRecognizer +{ +public: + QWinNativePanGestureRecognizer(); + + QGesture* createGesture(QObject *target) const; + + QGestureRecognizer::Result filterEvent(QGesture *state, QObject *watched, QEvent *event); + void reset(QGesture *state); +}; + +QT_END_NAMESPACE + +#endif // QWINNATIVEPANGESTURERECOGNIZER_WIN_P_H |