1 /*
2 This file is part of the KDE project
3 SPDX-FileCopyrightText: 2021 Steffen Hartleib <steffenhartleib@t-online.de>
4
5 SPDX-License-Identifier: LGPL-2.1-or-later
6 */
7
8 // Self
9 #include "ktwofingerswipe.h"
10
11 // Qt
12 #include <QGraphicsWidget>
13 #include <QLineF>
14 #include <QTouchEvent>
15 #include <QDebug>
16 class KTwoFingerSwipeRecognizerPrivate
17 {
18 public:
KTwoFingerSwipeRecognizerPrivate(KTwoFingerSwipeRecognizer * parent)19 KTwoFingerSwipeRecognizerPrivate(KTwoFingerSwipeRecognizer *parent)
20 : q(parent)
21 {
22 }
23 KTwoFingerSwipeRecognizer *const q;
24 qint64 mTouchBeginnTimestamp = 0;
25 bool mGestureAlreadyFinished = false;
26 int mMaxSwipeTime = 90;
27 int mMinSwipeDistance = 30;
28 };
29
KTwoFingerSwipeRecognizer()30 KTwoFingerSwipeRecognizer::KTwoFingerSwipeRecognizer()
31 : QGestureRecognizer()
32 , d(new KTwoFingerSwipeRecognizerPrivate(this))
33 {
34 }
35
~KTwoFingerSwipeRecognizer()36 KTwoFingerSwipeRecognizer::~KTwoFingerSwipeRecognizer()
37 {
38 }
39
create(QObject * target)40 QGesture* KTwoFingerSwipeRecognizer::create(QObject *target)
41 {
42 Q_UNUSED(target);
43 return static_cast<QGesture *>(new KTwoFingerSwipe());
44 }
45
recognize(QGesture * gesture,QObject * watched,QEvent * event)46 QGestureRecognizer::Result KTwoFingerSwipeRecognizer::recognize(QGesture *gesture, QObject *watched, QEvent *event)
47 {
48 Q_UNUSED(watched)
49
50 KTwoFingerSwipe *kTwoFingerSwipe = static_cast<KTwoFingerSwipe *>(gesture);
51 const QTouchEvent *touchEvent = static_cast<const QTouchEvent *>(event);
52
53 switch (event->type()) {
54 case QEvent::TouchBegin: {
55 d->mTouchBeginnTimestamp = touchEvent->timestamp();
56 d->mGestureAlreadyFinished = false;
57 const QTouchEvent::TouchPoint tp = touchEvent->touchPoints().first();
58 kTwoFingerSwipe->setHotSpot(tp.startScreenPos());
59 kTwoFingerSwipe->setPos(tp.startPos());
60 kTwoFingerSwipe->setScreenPos(tp.startScreenPos());
61 kTwoFingerSwipe->setScenePos(tp.startScenePos());
62 kTwoFingerSwipe->setSwipeAngle(0.0);
63 return MayBeGesture;
64 }
65
66 case QEvent::TouchUpdate: {
67 // The gesture was already canceled or finished, so we will ignore this event.
68 if (d->mGestureAlreadyFinished) {
69 return Ignore;
70 }
71
72 const qint64 now = touchEvent->timestamp();
73 const qint64 elapsedTime = now - d->mTouchBeginnTimestamp;
74 const QLineF ql = QLineF(touchEvent->touchPoints().first().startPos(), touchEvent->touchPoints().first().pos());
75 const qreal length = ql.length();
76 const int touchPointSize = touchEvent->touchPoints().size();
77
78 kTwoFingerSwipe->setSwipeAngle(ql.angle());
79
80 if (touchPointSize > 2) {
81 d->mGestureAlreadyFinished = true;
82 return CancelGesture;
83 }
84
85 if (touchPointSize == 2) {
86 if (elapsedTime > d->mMaxSwipeTime) {
87 d->mGestureAlreadyFinished = true;
88 return CancelGesture;
89 }
90 if (length >= d->mMinSwipeDistance && elapsedTime <= d->mMaxSwipeTime && !d->mGestureAlreadyFinished) {
91 d->mGestureAlreadyFinished = true;
92 return FinishGesture;
93 } else if (elapsedTime <= d->mMaxSwipeTime && !d->mGestureAlreadyFinished) {
94 return TriggerGesture;
95 }
96 }
97 break;
98 }
99
100 case QEvent::TouchEnd: {
101 if (gesture->state() == Qt::GestureUpdated || gesture->state() == Qt::GestureStarted) {
102 if (!d->mGestureAlreadyFinished) {
103 return CancelGesture;
104 }
105 }
106 break;
107 }
108
109 default:
110 return Ignore;
111 }
112 return Ignore;
113 }
114
maxSwipeTime() const115 int KTwoFingerSwipeRecognizer::maxSwipeTime() const
116 {
117 return d->mMaxSwipeTime;
118 }
119
setMaxSwipeTime(int i)120 void KTwoFingerSwipeRecognizer::setMaxSwipeTime(int i)
121 {
122 if (i < 0) {
123 i = 0;
124 }
125
126 d->mMaxSwipeTime = i;
127 }
128
minSswipeDistance() const129 int KTwoFingerSwipeRecognizer::minSswipeDistance() const
130 {
131 return d->mMinSwipeDistance;
132 }
133
setSwipeDistance(int i)134 void KTwoFingerSwipeRecognizer::setSwipeDistance(int i)
135 {
136 if (i < 0) {
137 i = 0;
138 }
139
140 d->mMinSwipeDistance = i;
141 }
142
143
144
145 class KTwoFingerSwipePrivate
146 {
147 public:
KTwoFingerSwipePrivate(KTwoFingerSwipe * parent)148 KTwoFingerSwipePrivate(KTwoFingerSwipe *parent)
149 : q(parent)
150 {
151 }
152 KTwoFingerSwipe *const q;
153 QPointF mPos = QPointF(-1, -1);
154 QPointF mScreenPos = QPointF(-1, -1);
155 QPointF mScenePos = QPointF(-1, -1);
156 qreal mSwipeAngle = 0.0;
157 };
158
KTwoFingerSwipe(QObject * parent)159 KTwoFingerSwipe::KTwoFingerSwipe(QObject *parent)
160 : QGesture(parent)
161 , d(new KTwoFingerSwipePrivate(this))
162 {
163 }
164
~KTwoFingerSwipe()165 KTwoFingerSwipe::~KTwoFingerSwipe()
166 {
167 }
168
pos() const169 QPointF KTwoFingerSwipe::pos() const
170 {
171 return d->mPos;
172 }
173
setPos(QPointF _pos)174 void KTwoFingerSwipe::setPos(QPointF _pos)
175 {
176 d->mPos = _pos;
177 }
178
screenPos() const179 QPointF KTwoFingerSwipe::screenPos() const
180 {
181 return d->mScreenPos;
182 }
183
setScreenPos(QPointF _screenPos)184 void KTwoFingerSwipe::setScreenPos(QPointF _screenPos)
185 {
186 d->mScreenPos = _screenPos;
187 }
188
scenePos() const189 QPointF KTwoFingerSwipe::scenePos() const
190 {
191 return d->mScenePos;
192 }
193
setScenePos(QPointF _scenePos)194 void KTwoFingerSwipe::setScenePos(QPointF _scenePos)
195 {
196 d->mScenePos = _scenePos;
197 }
198
swipeAngle() const199 qreal KTwoFingerSwipe::swipeAngle() const
200 {
201 return d->mSwipeAngle;
202 }
setSwipeAngle(qreal _swipeAngle)203 void KTwoFingerSwipe::setSwipeAngle(qreal _swipeAngle)
204 {
205 d->mSwipeAngle = _swipeAngle;
206 }
207