diff --git a/include/wx/qt/private/winevent.h b/include/wx/qt/private/winevent.h index 21f0e505b6..54db552c44 100644 --- a/include/wx/qt/private/winevent.h +++ b/include/wx/qt/private/winevent.h @@ -19,6 +19,9 @@ #include "wx/qt/private/converter.h" #include "wx/qt/private/utils.h" +#include +#include + class QPaintEvent; template< typename Handler > @@ -327,6 +330,132 @@ protected: virtual bool winEvent ( MSG * message, long * result ) { } virtual bool x11Event ( XEvent * event ) { } */ + virtual bool event(QEvent *event) + { + if (event->type() == QEvent::Gesture) + { + return gestureEvent(static_cast(event), event); + } + + return Widget::event(event); + } + + bool gestureEvent(QGestureEvent *gesture, QEvent *event) + { + if (QGesture *tah = gesture->gesture(Qt::TapAndHoldGesture)) + { + // Set the policy so that accepted gestures are taken by the first window that gets them + tah->setGestureCancelPolicy ( QGesture::CancelAllInContext ); + tapandholdTriggered(static_cast(tah), event); + } + + if (QGesture *pan = gesture->gesture(Qt::PanGesture)) + { + panTriggered(static_cast(pan), event); + } + + if (QGesture *pinch = gesture->gesture(Qt::PinchGesture)) + { + pinchTriggered(static_cast(pinch), event); + } + + return true; + } + + void tapandholdTriggered(QTapAndHoldGesture *gesture, QEvent *event) + { + wxWindow *win = wxWindow::QtRetrieveWindowPointer( this ); + + if (gesture->state() == Qt::GestureFinished) + { + if ( win ) + { + wxLongPressEvent ev(win->GetId()); + ev.SetPosition( wxQtConvertPoint( gesture->position().toPoint() ) ); + + ev.SetGestureEnd(); + win->ProcessWindowEvent( ev ); + event->accept(); + } + + } + else if (gesture->state() == Qt::GestureStarted) + { + event->accept(); + } + else + { + event->accept(); + } + } + + void panTriggered(QPanGesture *gesture, QEvent *event) + { + wxWindow *win = wxWindow::QtRetrieveWindowPointer( this ); + + if (win) + { + wxPanGestureEvent evp(win->GetId()); + QPoint pos = QCursor::pos(); + evp.SetPosition( wxQtConvertPoint( pos ) ); + + QPoint offset = gesture->offset().toPoint(); + QPoint offset_last = gesture->lastOffset().toPoint(); + QPoint delta(offset.x() - offset_last.x(), offset.y() - offset_last.y()); + + evp.SetDelta( wxQtConvertPoint( delta ) ); + + switch(gesture->state()) + { + case Qt::GestureStarted: + evp.SetGestureStart(); + break; + case Qt::GestureFinished: + case Qt::GestureCanceled: + evp.SetGestureEnd(); + break; + default: + break; + } + + win->ProcessWindowEvent( evp ); + + event->accept(); + } + } + + void pinchTriggered(QPinchGesture *gesture, QEvent *event) + { + wxWindow *win = wxWindow::QtRetrieveWindowPointer( this ); + if (win) + { + + qreal this_sf = gesture->scaleFactor(); + QPoint center_point = gesture->centerPoint().toPoint(); + + wxZoomGestureEvent evp(win->GetId()); + evp.SetPosition( wxQtConvertPoint( center_point ) ); + evp.SetZoomFactor( this_sf); + + switch(gesture->state()) + { + case Qt::GestureStarted: + evp.SetGestureStart(); + break; + case Qt::GestureFinished: + case Qt::GestureCanceled: + evp.SetGestureEnd(); + break; + default: + break; + } + + win->ProcessWindowEvent( evp ); + + event->accept(); + + } + } }; #endif diff --git a/include/wx/qt/window.h b/include/wx/qt/window.h index a426af9f67..2f4d26aa28 100644 --- a/include/wx/qt/window.h +++ b/include/wx/qt/window.h @@ -221,6 +221,7 @@ protected: // itself. virtual QWidget* QtGetParentWidget() const { return GetHandle(); } + virtual bool EnableTouchEvents(int eventsMask) wxOVERRIDE; QWidget *m_qtWindow; diff --git a/src/qt/glcanvas.cpp b/src/qt/glcanvas.cpp index 29e6c09dd7..2fea936c55 100644 --- a/src/qt/glcanvas.cpp +++ b/src/qt/glcanvas.cpp @@ -13,6 +13,8 @@ #include "wx/glcanvas.h" #include +#include +#include #if defined(__VISUALC__) #pragma message("OpenGL support is not implemented in wxQt") @@ -347,6 +349,29 @@ bool wxGLContext::SetCurrent(const wxGLCanvas&) const return false; } +//--------------------------------------------------------------------------- +// PanGestureRecognizer - helper class for wxGLCanvas +//--------------------------------------------------------------------------- + +class PanGestureRecognizer : public QGestureRecognizer +{ +private: + static const int MINIMUM_DISTANCE = 10; + + typedef QGestureRecognizer parent; + + bool IsValidMove(int dx, int dy); + + virtual QGesture* create(QObject* pTarget); + + virtual QGestureRecognizer::Result recognize(QGesture* pGesture, QObject *pWatched, QEvent *pEvent); + + void reset (QGesture *pGesture); + + QPointF m_startPoint; + QPointF m_lastPoint; +}; + //--------------------------------------------------------------------------- // wxGlCanvas //--------------------------------------------------------------------------- @@ -416,6 +441,10 @@ bool wxGLCanvas::Create(wxWindow *parent, m_qtWindow = new wxQtGLWidget(parent, this, format); + // Create and register a custom pan recognizer, available to all instances of this class. + QGestureRecognizer* pPanRecognizer = new PanGestureRecognizer(); + QGestureRecognizer::registerRecognizer(pPanRecognizer); + return wxWindow::Create( parent, id, pos, size, style, name ); } @@ -567,4 +596,123 @@ bool wxGLApp::InitGLVisual(const int *attribList) return false; } +// ----------------------------------------------------------------------------------------- +// We want a private pan gesture recognizer for GL canvas, +// since the Qt standard recognizers do not function well for this window. +// ----------------------------------------------------------------------------------------- + +bool +PanGestureRecognizer::IsValidMove(int dx, int dy) +{ + // The moved distance is to small to count as not just a glitch. + if ((qAbs(dx) < MINIMUM_DISTANCE) && (qAbs(dy) < MINIMUM_DISTANCE)) + return false; + + return true; +} + + +// virtual +QGesture* +PanGestureRecognizer::create(QObject* pTarget) +{ + return new QPanGesture(pTarget); +} + + +// virtual +QGestureRecognizer::Result +PanGestureRecognizer::recognize(QGesture* pGesture, QObject *pWatched, QEvent *pEvent) +{ + wxUnusedVar(pWatched); + QGestureRecognizer::Result result = QGestureRecognizer::Ignore; + QPanGesture *pPan = static_cast(pGesture); + + const QTouchEvent *ev = static_cast(pEvent); + + switch (pEvent->type()) + { + case QEvent::TouchBegin: + { + QTouchEvent::TouchPoint p1 = ev->touchPoints().at(0); + m_startPoint = p1.startScreenPos().toPoint(); + m_lastPoint = m_startPoint; + + pPan->setLastOffset(QPointF(0,0)); + pPan->setOffset(QPointF(0,0)); + + result = QGestureRecognizer::MayBeGesture; + } + break; + + case QEvent::TouchEnd: + { + QTouchEvent::TouchPoint p1 = ev->touchPoints().at(0); + QPointF endPoint = p1.screenPos().toPoint(); + + pPan->setLastOffset(pPan->offset()); + pPan->setOffset(QPointF(p1.pos().x() - p1.startPos().x(), + p1.pos().y() - p1.startPos().y())); + + pPan->setHotSpot(p1.startScreenPos()); + + // process distance and direction + int dx = endPoint.x() - m_startPoint.x(); + int dy = endPoint.y() - m_startPoint.y(); + + if (!IsValidMove(dx, dy)) + { + // Just a click, so no gesture. + result = QGestureRecognizer::Ignore; + } + else + { + result = QGestureRecognizer::FinishGesture; + } + + } + break; + + case QEvent::TouchUpdate: + { + QTouchEvent::TouchPoint p1 = ev->touchPoints().at(0); + QPointF upPoint = p1.screenPos().toPoint(); + + pPan->setLastOffset(pPan->offset()); + pPan->setOffset(QPointF(p1.pos().x() - p1.startPos().x(), + p1.pos().y() - p1.startPos().y())); + + pPan->setHotSpot(p1.startScreenPos()); + + int dx = upPoint.x() - m_lastPoint.x(); + int dy = upPoint.y() - m_lastPoint.y(); + + if( (dx > 2) || (dx < -2) || (dy > 2) || (dy < -2)) + { + result = QGestureRecognizer::TriggerGesture; + + } + else + { + result = QGestureRecognizer::Ignore; + } + + m_lastPoint = upPoint; + } + break; + + default: + break; + } + + return result; +} + +void +PanGestureRecognizer::reset(QGesture *pGesture) +{ + pGesture->setProperty("startPoint", QVariant(QVariant::Invalid)); + parent::reset(pGesture); +} + #endif // wxUSE_GLCANVAS diff --git a/src/qt/window.cpp b/src/qt/window.cpp index d07dfcc221..3474337f99 100644 --- a/src/qt/window.cpp +++ b/src/qt/window.cpp @@ -85,6 +85,28 @@ bool wxQtScrollArea::event(QEvent *e) break; } } + // QGesture events arrive without mouse capture + else if ( handler ) + { + switch ( e->type() ) + { + case QEvent::Gesture: + { + QScrollArea::event(e); + + if ( QScrollBar *vBar = verticalScrollBar() ) + vBar->triggerAction( QAbstractSlider::SliderMove ); + if ( QScrollBar *hBar = horizontalScrollBar() ) + hBar->triggerAction( QAbstractSlider::SliderMove ); + + return true; + } + + default: + break; + } + } + return QScrollArea::event(e); } @@ -1683,3 +1705,33 @@ QPainter *wxWindowQt::QtGetPainter() { return m_qtPainter.get(); } + +bool wxWindowQt::EnableTouchEvents(int eventsMask) +{ + wxCHECK_MSG( GetHandle(), false, "can't be called before creating the window" ); + + if ( eventsMask == wxTOUCH_NONE ) + { + m_qtWindow->setAttribute(Qt::WA_AcceptTouchEvents, false); + return true; + } + + if ( eventsMask & wxTOUCH_PRESS_GESTURES ) + { + m_qtWindow->setAttribute(Qt::WA_AcceptTouchEvents, true); + m_qtWindow->grabGesture(Qt::TapAndHoldGesture); + QTapAndHoldGesture::setTimeout ( 1000 ); + } + if ( eventsMask & wxTOUCH_PAN_GESTURES ) + { + m_qtWindow->setAttribute(Qt::WA_AcceptTouchEvents, true); + m_qtWindow->grabGesture(Qt::PanGesture); + } + if ( eventsMask & wxTOUCH_ZOOM_GESTURE ) + { + m_qtWindow->setAttribute(Qt::WA_AcceptTouchEvents, true); + m_qtWindow->grabGesture(Qt::PinchGesture); + } + + return true; +}