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