6#include "QskPanGestureRecognizer.h"
12#include <qquickitem.h>
13#include <qguiapplication.h>
14#include <qstylehints.h>
16static inline bool qskIsInOrientation(
17 const QPointF& from,
const QPointF& to, Qt::Orientations orientations )
19 if ( orientations == ( Qt::Horizontal | Qt::Vertical ) )
22 const qreal dx = std::fabs( to.x() - from.x() );
23 const qreal dy = std::fabs( to.y() - from.y() );
25 const qreal ratio = 0.75;
27 if ( orientations == Qt::Horizontal )
28 return ( dx >= ratio * dy );
30 if ( orientations == Qt::Vertical )
31 return ( dy >= ratio * dx );
36static inline qreal qskDistance(
37 const QPointF& from,
const QPointF& to, Qt::Orientations orientations )
39 if ( orientations == Qt::Horizontal )
40 return std::fabs( to.x() - from.x() );
42 if ( orientations == Qt::Vertical )
43 return std::fabs( to.y() - from.y() );
45 const qreal dx = to.x() - from.x();
46 const qreal dy = to.y() - from.y();
48 return qSqrt( dx * dx + dy * dy );
51static inline qreal qskAngle(
52 const QPointF& from,
const QPointF& to, Qt::Orientations orientations )
54 if ( orientations == Qt::Horizontal )
55 return ( to.x() >= from.x() ) ? 0.0 : 180.0;
57 if ( orientations == Qt::Vertical )
58 return ( to.y() >= from.y() ) ? 270.0 : 90.0;
60 return QLineF( from, to ).angle();
63static void qskSendPanGestureEvent(
65 qreal velocity, qreal angle,
const QPointF& origin,
66 const QPointF& lastPosition,
const QPointF& position )
68 auto item = recognizer->targetItem();
69 if ( item ==
nullptr )
70 item = recognizer->watchedItem();
72 auto gesture = std::make_shared< QskPanGesture >();
73 gesture->setState( state );
75 gesture->setAngle( angle );
76 gesture->setVelocity( velocity );
78 gesture->setOrigin( origin );
79 gesture->setLastPosition( lastPosition );
80 gesture->setPosition( position );
83 QCoreApplication::sendEvent( item, &event );
96 void record(
int elapsed, qreal velocity )
98 if ( ( velocity != 0.0 ) && ( m_values[ m_pos ].velocity != 0.0 ) )
100 if ( ( velocity > 0.0 ) != ( m_values[ m_pos ].velocity > 0.0 ) )
104 m_values[ m_pos ].elapsed = elapsed;
105 m_values[ m_pos ].velocity = velocity;
107 m_pos = ( m_pos + 1 ) % Count;
112 for (
auto& v : m_values )
120 inline qreal velocity( ulong elapsed )
const
123 int numVelocities = 0;
125 for (
const auto& v : m_values )
128 if ( v.elapsed > 0 && ( elapsed - v.elapsed ) <= 500 )
135 return ( numVelocities > 0 ) ? ( sum / numVelocities ) : 0.0;
145 qreal velocity = 0.0;
150class QskPanGestureRecognizer::PrivateData
153 Qt::Orientations orientations = Qt::Horizontal | Qt::Vertical;
155 int minDistance = QGuiApplication::styleHints()->startDragDistance() + 5;
157 quint64 timestampVelocity = 0.0;
163 VelocityTracker velocityTracker;
166QskPanGestureRecognizer::QskPanGestureRecognizer( QObject* parent )
168 , m_data( new PrivateData() )
173QskPanGestureRecognizer::~QskPanGestureRecognizer()
177void QskPanGestureRecognizer::setOrientations( Qt::Orientations orientations )
179 m_data->orientations = orientations;
182Qt::Orientations QskPanGestureRecognizer::orientations()
const
184 return m_data->orientations;
187void QskPanGestureRecognizer::setMinDistance(
int pixels )
189 m_data->minDistance = qMax( pixels, 0 );
192int QskPanGestureRecognizer::minDistance()
const
194 return m_data->minDistance;
197void QskPanGestureRecognizer::processPress(
const QPointF& pos, quint64,
bool isFinal )
203 setRejectOnTimeout( !isFinal );
205 m_data->origin = m_data->pos = pos;
206 m_data->timestampVelocity = timestampStarted();
208 m_data->velocityTracker.reset();
211void QskPanGestureRecognizer::processMove(
const QPointF& pos, quint64 timestamp )
213 const ulong elapsed = timestamp - m_data->timestampVelocity;
214 const ulong elapsedTotal = timestamp - timestampStarted();
216 const QPointF oldPos = m_data->pos;
218 m_data->timestampVelocity = timestamp;
221 if ( elapsedTotal > 0 )
223 const qreal dist = qskDistance( oldPos, m_data->pos, m_data->orientations );
225 const qreal velocity = dist / ( elapsed / 1000.0 );
226 m_data->velocityTracker.record( elapsedTotal, velocity );
229 bool started =
false;
231 if ( state() != QskGestureRecognizer::Accepted )
233 const qreal dist = qskDistance(
234 m_data->origin, m_data->pos, m_data->orientations );
236 if ( ( qAbs( dist ) >= m_data->minDistance ) &&
237 qskIsInOrientation( m_data->origin, m_data->pos, m_data->orientations ) )
244 m_data->angle = qskAngle( oldPos, m_data->pos, m_data->orientations );
246 if ( state() == QskGestureRecognizer::Accepted )
248 const qreal velocity = m_data->velocityTracker.velocity( elapsedTotal );
252 qskSendPanGestureEvent(
this, QskGesture::Started,
253 velocity, m_data->angle, m_data->origin, m_data->origin, m_data->pos );
257 qskSendPanGestureEvent(
this, QskGesture::Updated,
258 velocity, m_data->angle, m_data->origin, oldPos, m_data->pos );
263void QskPanGestureRecognizer::processRelease(
const QPointF&, quint64 timestamp )
265 if ( state() == QskGestureRecognizer::Accepted )
267 const ulong elapsedTotal = timestamp - timestampStarted();
268 const qreal velocity = m_data->velocityTracker.velocity( elapsedTotal );
270 qskSendPanGestureEvent(
this, QskGesture::Finished,
271 velocity, m_data->angle, m_data->origin, m_data->pos, m_data->pos );