mirror of
https://github.com/xiaoyifang/goldendict-ng.git
synced 2024-11-25 01:14:07 +00:00
391 lines
12 KiB
C++
391 lines
12 KiB
C++
/* This file is (c) 2014 Abs62
|
|
* Part of GoldenDict. Licensed under GPLv3 or later, see the LICENSE file */
|
|
|
|
#include <QTouchEvent>
|
|
#include <QSwipeGesture>
|
|
#include <QVariant>
|
|
#include <math.h>
|
|
#include "articleview.hh"
|
|
#include "gestures.hh"
|
|
|
|
namespace Gestures
|
|
{
|
|
|
|
Qt::GestureType GDPinchGestureType;
|
|
Qt::GestureType GDSwipeGestureType;
|
|
static bool fewTouchPointsPresented;
|
|
|
|
bool isFewTouchPointsPresented()
|
|
{
|
|
return fewTouchPointsPresented;
|
|
}
|
|
|
|
QSwipeGesture::SwipeDirection getHorizontalDirection( qreal angle )
|
|
{
|
|
if ( ( 0 <= angle && angle <= 45 )
|
|
|| ( 315 <= angle && angle <= 360 ) )
|
|
return QSwipeGesture::Right;
|
|
|
|
if ( 135 <= angle && angle <= 225 )
|
|
return QSwipeGesture::Left;
|
|
|
|
return QSwipeGesture::NoDirection;
|
|
}
|
|
|
|
QSwipeGesture::SwipeDirection getVerticalDirection( qreal angle )
|
|
{
|
|
if ( 45 < angle && angle < 135 )
|
|
return QSwipeGesture::Up;
|
|
|
|
if ( 225 < angle && angle < 315 )
|
|
return QSwipeGesture::Down;
|
|
|
|
return QSwipeGesture::NoDirection;
|
|
}
|
|
|
|
GDPinchGesture::GDPinchGesture( QObject * parent ) :
|
|
QGesture( parent ),
|
|
isNewSequence( true )
|
|
{
|
|
}
|
|
|
|
QGesture * GDPinchGestureRecognizer::create( QObject * pTarget )
|
|
{
|
|
if ( pTarget && pTarget->isWidgetType()) {
|
|
static_cast< QWidget * >( pTarget )->setAttribute( Qt::WA_AcceptTouchEvents );
|
|
}
|
|
QGesture *pGesture = new GDPinchGesture( pTarget );
|
|
return pGesture;
|
|
}
|
|
|
|
void GDPinchGestureRecognizer::reset( QGesture * pGesture )
|
|
{
|
|
QGestureRecognizer::reset( pGesture );
|
|
}
|
|
|
|
QGestureRecognizer::Result GDPinchGestureRecognizer::recognize( QGesture * state,
|
|
QObject *,
|
|
QEvent * event)
|
|
{
|
|
QGestureRecognizer::Result result = QGestureRecognizer::Ignore;
|
|
GDPinchGesture * gest = static_cast< GDPinchGesture * >( state );
|
|
|
|
switch ( event->type() )
|
|
{
|
|
case QEvent::TouchBegin:
|
|
{
|
|
result = QGestureRecognizer::MayBeGesture;
|
|
gest->isNewSequence = true;
|
|
break;
|
|
}
|
|
case QEvent::TouchCancel:
|
|
case QEvent::TouchEnd:
|
|
{
|
|
result = QGestureRecognizer::CancelGesture;
|
|
fewTouchPointsPresented = false;
|
|
break;
|
|
}
|
|
case QEvent::TouchUpdate:
|
|
{
|
|
gest->scaleChanged = false;
|
|
const QTouchEvent * const ev = static_cast< const QTouchEvent * >( event );
|
|
fewTouchPointsPresented = ( ev->touchPoints().size() > 1 );
|
|
if ( ev->touchPoints().size() == 2 )
|
|
{
|
|
QTouchEvent::TouchPoint p1 = ev->touchPoints().at( 0 );
|
|
QTouchEvent::TouchPoint p2 = ev->touchPoints().at( 1 );
|
|
|
|
QPointF centerPoint = ( p1.screenPos() + p2.screenPos() ) / 2.0;
|
|
gest->setHotSpot( centerPoint );
|
|
if ( gest->isNewSequence )
|
|
{
|
|
gest->startPosition[ 0 ] = p1.screenPos();
|
|
gest->startPosition[ 1 ] = p2.screenPos();
|
|
gest->lastCenterPoint = centerPoint;
|
|
}
|
|
else
|
|
{
|
|
gest->lastCenterPoint = gest->centerPoint;
|
|
}
|
|
gest->centerPoint = centerPoint;
|
|
|
|
if ( gest->isNewSequence )
|
|
{
|
|
gest->scaleFactor = 1.0;
|
|
gest->lastScaleFactor = 1.0;
|
|
gest->totalScaleFactor = 1.0;
|
|
}
|
|
else
|
|
{
|
|
gest->lastScaleFactor = gest->scaleFactor;
|
|
QLineF line( p1.screenPos(), p2.screenPos() );
|
|
QLineF lastLine( p1.lastScreenPos(), p2.lastScreenPos() );
|
|
gest->scaleFactor = line.length() / lastLine.length();
|
|
}
|
|
|
|
gest->totalScaleFactor = gest->totalScaleFactor * gest->scaleFactor;
|
|
gest->scaleChanged = true;
|
|
|
|
gest->isNewSequence = false;
|
|
if( gest->totalScaleFactor <= OUT_SCALE_LIMIT || gest->totalScaleFactor >= IN_SCALE_LIMIT )
|
|
{
|
|
result = QGestureRecognizer::TriggerGesture;
|
|
gest->isNewSequence = true;
|
|
}
|
|
else
|
|
result = QGestureRecognizer::MayBeGesture;
|
|
}
|
|
else
|
|
{
|
|
gest->isNewSequence = true;
|
|
if ( gest->state() == Qt::NoGesture )
|
|
result = QGestureRecognizer::Ignore;
|
|
else
|
|
result = QGestureRecognizer::FinishGesture;
|
|
}
|
|
break;
|
|
}
|
|
case QEvent::MouseButtonPress:
|
|
case QEvent::MouseMove:
|
|
case QEvent::MouseButtonRelease:
|
|
result = QGestureRecognizer::Ignore;
|
|
break;
|
|
default:
|
|
result = QGestureRecognizer::Ignore;
|
|
break;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
|
|
GDSwipeGesture::GDSwipeGesture( QObject * parent ) :
|
|
QGesture( parent ),
|
|
vertDirection( QSwipeGesture::NoDirection ),
|
|
horizDirection( QSwipeGesture::NoDirection ),
|
|
started( false )
|
|
{
|
|
}
|
|
|
|
QGesture * GDSwipeGestureRecognizer::create( QObject * pTarget )
|
|
{
|
|
if ( pTarget && pTarget->isWidgetType() ) {
|
|
static_cast< QWidget * >( pTarget )->setAttribute( Qt::WA_AcceptTouchEvents );
|
|
}
|
|
QGesture *pGesture = new GDSwipeGesture( pTarget );
|
|
return pGesture;
|
|
}
|
|
|
|
void GDSwipeGestureRecognizer::reset( QGesture * pGesture )
|
|
{
|
|
GDSwipeGesture * gest = static_cast< GDSwipeGesture * >( pGesture );
|
|
gest->vertDirection = QSwipeGesture::NoDirection;
|
|
gest->horizDirection = QSwipeGesture::NoDirection;
|
|
gest->lastPositions[ 0 ] = QPoint();
|
|
gest->lastPositions[ 1 ] = QPoint();
|
|
|
|
QGestureRecognizer::reset( pGesture );
|
|
}
|
|
|
|
qreal GDSwipeGestureRecognizer::computeAngle( int dx, int dy )
|
|
{
|
|
double PI = 3.14159265;
|
|
|
|
// Need to convert from screen coordinates direction
|
|
// into classical coordinates direction.
|
|
dy = -dy;
|
|
|
|
double result = atan2( (double)dy, (double)dx ) ;
|
|
result = ( result * 180 ) / PI;
|
|
|
|
// Always return positive angle.
|
|
if ( result < 0 )
|
|
result += 360;
|
|
|
|
return result;
|
|
}
|
|
|
|
QGestureRecognizer::Result GDSwipeGestureRecognizer::recognize( QGesture * state,
|
|
QObject *,
|
|
QEvent * event)
|
|
{
|
|
GDSwipeGesture * swipe = static_cast< GDSwipeGesture * >( state );
|
|
QGestureRecognizer::Result result = QGestureRecognizer::Ignore;
|
|
|
|
switch( event->type() )
|
|
{
|
|
case QEvent::TouchBegin:
|
|
{
|
|
swipe->unsetHotSpot();
|
|
swipe->lastPositions[ 0 ] = QPoint();
|
|
swipe->started = true;
|
|
result = QGestureRecognizer::MayBeGesture;
|
|
break;
|
|
}
|
|
case QEvent::TouchCancel:
|
|
case QEvent::TouchEnd:
|
|
{
|
|
fewTouchPointsPresented = false;
|
|
result = QGestureRecognizer::CancelGesture;
|
|
break;
|
|
}
|
|
case QEvent::TouchUpdate:
|
|
{
|
|
const QTouchEvent * const ev = static_cast< const QTouchEvent * >( event );
|
|
fewTouchPointsPresented = ( ev->touchPoints().size() > 1 );
|
|
if( !swipe->started )
|
|
result = QGestureRecognizer::CancelGesture;
|
|
else
|
|
if( ev->touchPoints().size() == 2 )
|
|
{
|
|
//2-point gesture
|
|
|
|
QTouchEvent::TouchPoint p1 = ev->touchPoints().at( 0 );
|
|
QTouchEvent::TouchPoint p2 = ev->touchPoints().at( 1 );
|
|
|
|
if (swipe->lastPositions[0].isNull()) {
|
|
swipe->lastPositions[ 0 ] = p1.startScreenPos().toPoint();
|
|
swipe->lastPositions[ 1 ] = p2.startScreenPos().toPoint();
|
|
}
|
|
|
|
if( !swipe->hasHotSpot() )
|
|
{
|
|
swipe->setHotSpot( ( p1.startScreenPos() + p2.startScreenPos() ) / 2 );
|
|
}
|
|
|
|
int dx1 = p1.screenPos().toPoint().x() - swipe->lastPositions[ 0 ].x();
|
|
int dx2 = p2.screenPos().toPoint().x() - swipe->lastPositions[ 1 ].x();
|
|
int dy1 = p1.screenPos().toPoint().y() - swipe->lastPositions[ 0 ].y();
|
|
int dy2 = p2.screenPos().toPoint().y() - swipe->lastPositions[ 1 ].y();
|
|
|
|
if( qAbs( ( dx1 + dx2 ) / 2.0 ) >= MOVE_X_TRESHOLD ||
|
|
qAbs( ( dy1 + dy2 ) / 2.0 ) >= MOVE_Y_TRESHOLD )
|
|
{
|
|
qreal angle1 = computeAngle( dx1, dy1 );
|
|
qreal angle2 = computeAngle( dx2, dy2 );
|
|
QSwipeGesture::SwipeDirection vertDir = getVerticalDirection( angle1 );
|
|
QSwipeGesture::SwipeDirection horizDir = getHorizontalDirection( angle1 );
|
|
|
|
if( vertDir != getVerticalDirection( angle2 ) ||
|
|
horizDir != getHorizontalDirection( angle2 ) )
|
|
{
|
|
// It seems it is no swipe gesture
|
|
result = QGestureRecognizer::CancelGesture;
|
|
break;
|
|
}
|
|
|
|
if( ( swipe->vertDirection != QSwipeGesture::NoDirection && horizDir != QSwipeGesture::NoDirection ) ||
|
|
( swipe->horizDirection != QSwipeGesture::NoDirection && vertDir != QSwipeGesture::NoDirection ) )
|
|
{
|
|
// Gesture direction changed
|
|
result = QGestureRecognizer::CancelGesture;
|
|
break;
|
|
}
|
|
|
|
swipe->vertDirection = vertDir;
|
|
swipe->horizDirection = horizDir;
|
|
|
|
swipe->lastPositions[ 0 ] = p1.screenPos().toPoint();
|
|
swipe->lastPositions[ 1 ] = p2.screenPos().toPoint();
|
|
|
|
result = QGestureRecognizer::TriggerGesture;
|
|
}
|
|
else
|
|
result = QGestureRecognizer::MayBeGesture;
|
|
}
|
|
else // No 2-point gesture
|
|
result = QGestureRecognizer::CancelGesture;
|
|
break;
|
|
}
|
|
case QEvent::MouseButtonPress:
|
|
case QEvent::MouseMove:
|
|
case QEvent::MouseButtonRelease:
|
|
result = QGestureRecognizer::Ignore;
|
|
break;
|
|
default:
|
|
result = QGestureRecognizer::Ignore;
|
|
break;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
const qreal GDPinchGestureRecognizer::OUT_SCALE_LIMIT = 0.5;
|
|
const qreal GDPinchGestureRecognizer::IN_SCALE_LIMIT = 2;
|
|
|
|
bool handleGestureEvent( QObject * obj, QEvent * event, GestureResult & result,
|
|
QPoint & point )
|
|
{
|
|
result = NOT_HANLDED;
|
|
|
|
if( event->type() != QEvent::Gesture || !obj->isWidgetType() )
|
|
return false;
|
|
|
|
QGestureEvent * gev = static_cast<QGestureEvent *>( event );
|
|
|
|
gev->accept( Qt::PanGesture );
|
|
|
|
QGesture * gesture = gev->gesture( GDSwipeGestureType );
|
|
if( gesture )
|
|
{
|
|
GDSwipeGesture * swipe = static_cast< GDSwipeGesture * >( gesture );
|
|
point = swipe->hotSpot().toPoint();
|
|
|
|
if( swipe->getHorizDirection() != QSwipeGesture::NoDirection )
|
|
result = swipe->getHorizDirection() == QSwipeGesture::Left ?
|
|
SWIPE_LEFT : SWIPE_RIGHT;
|
|
|
|
if( swipe->getVertDirection() != QSwipeGesture::NoDirection )
|
|
result = swipe->getVertDirection() == QSwipeGesture::Up ?
|
|
SWIPE_UP : SWIPE_DOWN;
|
|
|
|
gev->setAccepted( true );
|
|
return true;
|
|
}
|
|
|
|
gesture = gev->gesture( GDPinchGestureType );
|
|
if( gesture )
|
|
{
|
|
GDPinchGesture * pinch = static_cast< GDPinchGesture * >( gesture );
|
|
point = pinch->getCenterPoint().toPoint();
|
|
|
|
if( pinch->isScaleChanged() )
|
|
{
|
|
if( pinch->getTotalScaleFactor() <= GDPinchGestureRecognizer::OUT_SCALE_LIMIT )
|
|
result = ZOOM_OUT;
|
|
if( pinch->getTotalScaleFactor() >= GDPinchGestureRecognizer::IN_SCALE_LIMIT )
|
|
result = ZOOM_IN;
|
|
}
|
|
gev->setAccepted( true );
|
|
return true;
|
|
}
|
|
|
|
gesture = gev->gesture( Qt::PanGesture );
|
|
if( gesture )
|
|
{
|
|
gev->setAccepted( true );
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void registerRecognizers()
|
|
{
|
|
QGestureRecognizer * pRecognizer = new Gestures::GDPinchGestureRecognizer();
|
|
GDPinchGestureType = QGestureRecognizer::registerRecognizer( pRecognizer );
|
|
|
|
pRecognizer = new Gestures::GDSwipeGestureRecognizer();
|
|
GDSwipeGestureType = QGestureRecognizer::registerRecognizer( pRecognizer );
|
|
}
|
|
|
|
void unregisterRecognizers()
|
|
{
|
|
if( GDPinchGestureType )
|
|
QGestureRecognizer::unregisterRecognizer( GDPinchGestureType );
|
|
|
|
if( GDSwipeGestureType )
|
|
QGestureRecognizer::unregisterRecognizer( GDSwipeGestureType );
|
|
}
|
|
|
|
} // namespace
|
|
|