Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions doc/Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down
76 changes: 62 additions & 14 deletions tide/master/MultitouchArea.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,19 +45,22 @@
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;
}

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 )
Expand Down Expand Up @@ -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;
}
Expand All @@ -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;
Expand Down Expand Up @@ -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 );
Expand All @@ -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
}
}
}
}
11 changes: 10 additions & 1 deletion tide/master/MultitouchArea.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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 );

Expand All @@ -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;
Expand Down
4 changes: 4 additions & 0 deletions tide/master/resources/MasterContentWindow.qml
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down