From 5b333c5e71dcef48bacdab7e0085c89d0aebb926 Mon Sep 17 00:00:00 2001 From: Raphael Dumusc Date: Fri, 6 May 2016 15:36:13 +0200 Subject: [PATCH] Detect two-fingers swipe gestures [DISCL-356] --- doc/Changelog.md | 3 + tide/master/MultitouchArea.cpp | 76 +++++++++++++++---- tide/master/MultitouchArea.h | 11 ++- tide/master/resources/MasterContentWindow.qml | 4 + 4 files changed, 79 insertions(+), 15 deletions(-) diff --git a/doc/Changelog.md b/doc/Changelog.md index 641e8f14..a5f15bc6 100644 --- a/doc/Changelog.md +++ b/doc/Changelog.md @@ -3,6 +3,9 @@ Changelog {#Changelog} # git master (1.1.0) +* [14](https://github.com/BlueBrain/Tide/pull/14): + Detect two-fingers swipe gestures [DISCL-356]. Swipe left and right to + navigate through PDF pages and Webbrowser history. * [12](https://github.com/BlueBrain/Tide/pull/12): Added a basic REST interface with support for open/load/save commands. diff --git a/tide/master/MultitouchArea.cpp b/tide/master/MultitouchArea.cpp index 9e098a90..9bb5ca65 100644 --- a/tide/master/MultitouchArea.cpp +++ b/tide/master/MultitouchArea.cpp @@ -45,9 +45,11 @@ namespace { const qreal wheelFactor = 0.3; -const qreal defaultPanThreshold = 20; -const qreal pinchThreshold = 10; -const qreal doubleTapThreshold = 40; +const qreal defaultPanThresholdPx = 20; +const qreal pinchThresholdPx = 10; +const qreal swipeMaxFingersIntervalPx = 75; +const qreal swipeThresholdPx = 120; +const qreal doubleTapThresholdPx = 40; const uint tapAndHoldTimeout = 1000; const uint doubleTapTimeout = 750; } @@ -55,9 +57,10 @@ const uint doubleTapTimeout = 750; MultitouchArea::MultitouchArea( QQuickItem* parent_ ) : QQuickItem( parent_ ) , _referenceItem( nullptr ) - , _panThreshold( defaultPanThreshold ) + , _panThreshold( defaultPanThresholdPx ) , _panning( false ) - , _pinchDetectionStarted( false ) + , _twoFingersDetectionStarted( false ) + , _canBeSwipe( false ) , _pinching( false ) , _lastPinchDist( 0.0 ) , _tapCounter( 0 ) @@ -182,7 +185,7 @@ void MultitouchArea::_handleSinglePoint( const QTouchEvent::TouchPoint& point ) _startDoubleTapGesture(); if( ++_tapCounter == 2 ) { - if( (pos - _tapStartPos).manhattanLength() < doubleTapThreshold ) + if( (pos - _tapStartPos).manhattanLength() < doubleTapThresholdPx ) emit doubleTap( pos ); _tapCounter = 0; } @@ -195,7 +198,7 @@ void MultitouchArea::_handleSinglePoint( const QTouchEvent::TouchPoint& point ) break; case Qt::TouchPointMoved: - if( !_panning && (pos - _tapStartPos).manhattanLength() > _panThreshold ) + if( !_panning && (pos - _tapStartPos).manhattanLength() > _panThreshold) { _startPanGesture( pos ); _lastPanPos = pos; @@ -268,27 +271,37 @@ qreal MultitouchArea::_getPinchDistance( const QTouchEvent::TouchPoint& p0, return _getDist(_getScenePos( p0 ), _getScenePos( p1 )) - _initialPinchDist; } +QPointF MultitouchArea::_getCenter( const QTouchEvent::TouchPoint& p0, + const QTouchEvent::TouchPoint& p1 ) +{ + return ( _getScenePos( p0 ) + _getScenePos( p1 )) / 2; +} + void MultitouchArea::_handleTwoPoints( const QTouchEvent::TouchPoint& p0, const QTouchEvent::TouchPoint& p1 ) { if( p0.state() == Qt::TouchPointReleased || - p1.state() == Qt::TouchPointReleased ) + p1.state() == Qt::TouchPointReleased ) { - _pinchDetectionStarted = false; + _canBeSwipe = false; _pinching = false; + _twoFingersDetectionStarted = false; return; } - if( !_pinchDetectionStarted ) + if( !_twoFingersDetectionStarted ) { - _pinchDetectionStarted = true; + _twoFingersDetectionStarted = true; _initialPinchDist = _getDist( _getScenePos( p0 ), _getScenePos( p1 )); _cancelPanGesture(); _cancelTapAndHoldGesture(); _cancelDoubleTapGesture(); + + _canBeSwipe = _initialPinchDist < swipeMaxFingersIntervalPx; + _twoFingersStartPos = _getCenter( p0, p1 ); } - if( !_pinching && std::abs( _getPinchDistance( p0, p1 )) > pinchThreshold ) + if( !_pinching && std::abs( _getPinchDistance( p0, p1 )) > pinchThresholdPx) { _pinching = true; _lastPinchDist = _getPinchDistance( p0, p1 ); @@ -299,7 +312,42 @@ void MultitouchArea::_handleTwoPoints( const QTouchEvent::TouchPoint& p0, const auto pinchDist = _getPinchDistance( p0, p1 ); const auto pinchDelta = pinchDist - _lastPinchDist; _lastPinchDist = pinchDist; - const auto pinchCenter = ( _getScenePos( p0 ) + _getScenePos( p1 )) / 2; - emit pinch( pinchCenter, pinchDelta ); + emit pinch( _getCenter( p0, p1 ), pinchDelta ); + } + + if( _canBeSwipe ) + { + const qreal fingersInterval = _getDist( _getScenePos( p0 ), + _getScenePos( p1 )); + if( fingersInterval > swipeMaxFingersIntervalPx ) + _canBeSwipe = false; + else + { + const QPointF twoFingersPos = _getCenter( p0, p1 ); + const qreal dist = _getDist( _twoFingersStartPos, twoFingersPos ); + if( dist > swipeThresholdPx ) + { + const qreal dx = twoFingersPos.x() - _twoFingersStartPos.x(); + const qreal dy = twoFingersPos.y() - _twoFingersStartPos.y(); + + if( std::abs( dx ) > std::abs( dy )) + { + // Horizontal swipe + if( dx > 0.0 ) + emit swipeRight(); + else + emit swipeLeft(); + } + else + { + // Vertical swipe + if( dy > 0.0 ) + emit swipeDown(); + else + emit swipeUp(); + } + _canBeSwipe = false; // Only allow one swipe + } + } } } diff --git a/tide/master/MultitouchArea.h b/tide/master/MultitouchArea.h index ff2294ca..c353c405 100644 --- a/tide/master/MultitouchArea.h +++ b/tide/master/MultitouchArea.h @@ -86,6 +86,11 @@ public slots: void pinch( QPointF pos, qreal pixelDelta ); + void swipeLeft(); + void swipeRight(); + void swipeUp(); + void swipeDown(); + private: void mousePressEvent( QMouseEvent* event ) override; void mouseMoveEvent( QMouseEvent* event ) override; @@ -100,6 +105,8 @@ public slots: qreal _getPinchDistance( const QTouchEvent::TouchPoint& p0, const QTouchEvent::TouchPoint& p1 ); + QPointF _getCenter( const QTouchEvent::TouchPoint& p0, + const QTouchEvent::TouchPoint& p1 ); void _handleSinglePoint( const QTouchEvent::TouchPoint& point ); @@ -123,9 +130,11 @@ public slots: bool _panning; QPointF _lastPanPos; - bool _pinchDetectionStarted; + bool _twoFingersDetectionStarted; + bool _canBeSwipe; bool _pinching; qreal _lastPinchDist; + QPointF _twoFingersStartPos; QPointF _tapStartPos; uint _tapCounter; diff --git a/tide/master/resources/MasterContentWindow.qml b/tide/master/resources/MasterContentWindow.qml index 21ec2eed..c47e25c3 100644 --- a/tide/master/resources/MasterContentWindow.qml +++ b/tide/master/resources/MasterContentWindow.qml @@ -85,6 +85,10 @@ BaseContentWindow { onTapAndHold: contentwindow.delegate.tapAndHold(pos) onPan: contentwindow.delegate.pan(pos, Qt.point(delta.x, delta.y)) onPinch: contentwindow.delegate.pinch(pos, pixelDelta) + onSwipeLeft: contentwindow.delegate.swipeLeft() + onSwipeRight: contentwindow.delegate.swipeRight() + onSwipeUp: contentwindow.delegate.swipeUp() + onSwipeDown: contentwindow.delegate.swipeDown() } ContentWindowButton {