File indexing completed on 2024-04-28 15:32:16

0001 /*
0002     This file is part of the KDE libraries
0003     SPDX-FileCopyrightText: 2021 Steffen Hartleib <steffenhartleib@t-online.de>
0004 
0005     SPDX-License-Identifier: LGPL-2.1-or-later
0006 */
0007 
0008 // Self
0009 #include "ktwofingertap.h"
0010 
0011 // Qt
0012 #include <QApplication>
0013 #include <QGraphicsWidget>
0014 #include <QTouchEvent>
0015 
0016 class KTwoFingerTapRecognizerPrivate
0017 {
0018 public:
0019     KTwoFingerTapRecognizerPrivate(KTwoFingerTapRecognizer *parent)
0020         : q(parent)
0021     {
0022     }
0023     KTwoFingerTapRecognizer *const q;
0024     bool mGestureTriggered = false;
0025     int mTapRadius = 40;  // same as Qt::TapGesture
0026     Qt::GestureState mLastState = Qt::NoGesture;
0027 };
0028 
0029 KTwoFingerTapRecognizer::KTwoFingerTapRecognizer()
0030     : QGestureRecognizer()
0031     , d(new KTwoFingerTapRecognizerPrivate(this))
0032 {
0033 }
0034 
0035 KTwoFingerTapRecognizer::~KTwoFingerTapRecognizer()
0036 {
0037 }
0038 
0039 QGesture* KTwoFingerTapRecognizer::create(QObject *target)
0040 {
0041     Q_UNUSED(target)
0042     return static_cast<QGesture *>(new KTwoFingerTap());
0043 }
0044 
0045 QGestureRecognizer::Result KTwoFingerTapRecognizer::recognize(QGesture *gesture, QObject *watched, QEvent *event)
0046 {
0047     Q_UNUSED(watched)
0048 
0049     KTwoFingerTap *ktwoFingerTap = static_cast<KTwoFingerTap *>(gesture);
0050     const QTouchEvent *touchEvent = static_cast<const QTouchEvent *>(event);
0051 
0052     switch (event->type()) {
0053     case QEvent::TouchBegin: {
0054         const QTouchEvent::TouchPoint tp = touchEvent->touchPoints().first();
0055         ktwoFingerTap->setHotSpot(tp.startScreenPos());
0056         ktwoFingerTap->setPos(tp.startPos());
0057         ktwoFingerTap->setScreenPos(tp.startScreenPos());
0058         ktwoFingerTap->setScenePos(tp.startScenePos());
0059         d->mLastState = Qt::NoGesture;
0060         return MayBeGesture;
0061     }
0062 
0063     case QEvent::TouchUpdate: {
0064         // The gesture was already canceled or finished, so we will ignore this event.
0065         if (d->mLastState == Qt::GestureCanceled || d->mLastState == Qt::GestureFinished) {
0066             return Ignore;
0067         }
0068 
0069         const int touchPointSize = touchEvent->touchPoints().size();
0070 
0071         if (touchPointSize > 2) {
0072             d->mLastState = Qt::GestureCanceled;
0073             return CancelGesture;
0074         }
0075 
0076         if (touchPointSize == 2) {
0077             if ((touchEvent->touchPoints().first().startPos() - touchEvent->touchPoints().first().pos()).manhattanLength() > d->mTapRadius) {
0078                 d->mLastState = Qt::GestureCanceled;
0079                 return CancelGesture;
0080             }
0081             if ((touchEvent->touchPoints().at(1).startPos() - touchEvent->touchPoints().at(1).pos()).manhattanLength() > d->mTapRadius) {
0082                 d->mLastState = Qt::GestureCanceled;
0083                 return CancelGesture;
0084             }
0085             if (touchEvent->touchPointStates() & Qt::TouchPointPressed) {
0086                 d->mLastState = gesture->state() == Qt::NoGesture ? Qt::GestureStarted : Qt::GestureUpdated;
0087                 return TriggerGesture;
0088             }
0089             if (touchEvent->touchPointStates() & Qt::TouchPointMoved) {
0090                 d->mLastState = gesture->state() == Qt::NoGesture ? Qt::GestureStarted : Qt::GestureUpdated;
0091                 return TriggerGesture;
0092             }
0093             if (touchEvent->touchPointStates() & Qt::TouchPointReleased) {
0094                 d->mLastState = Qt::GestureFinished;
0095                 return FinishGesture;
0096             }
0097         }
0098         break;
0099     }
0100 
0101     case QEvent::TouchEnd: {
0102         if (d->mLastState == Qt::GestureStarted || d->mLastState == Qt::GestureUpdated) {
0103             return FinishGesture;
0104         }
0105         break;
0106     }
0107 
0108     default:
0109         return Ignore;
0110     }
0111     return Ignore;
0112 }
0113 
0114 void KTwoFingerTapRecognizer::setTapRadius(int i)
0115 {
0116     if (i < 0) {
0117         i = 0;
0118     }
0119 
0120     d->mTapRadius = i;
0121 }
0122 
0123 int KTwoFingerTapRecognizer::tapRadius() const
0124 {
0125     return d->mTapRadius;
0126 }
0127 
0128 class KTwoFingerTapPrivate
0129 {
0130 public:
0131     KTwoFingerTapPrivate(KTwoFingerTap *parent)
0132         : q(parent)
0133     {
0134     }
0135     KTwoFingerTap *const q;
0136     QPointF mPos = QPointF(-1, -1);
0137     QPointF mScreenPos = QPointF(-1, -1);
0138     QPointF mScenePos = QPointF(-1, -1);
0139 };
0140 
0141 KTwoFingerTap::KTwoFingerTap(QObject *parent)
0142     : QGesture(parent)
0143     , d(new KTwoFingerTapPrivate(this))
0144 {
0145 }
0146 
0147 KTwoFingerTap::~KTwoFingerTap()
0148 {
0149 }
0150 
0151 QPointF KTwoFingerTap::pos() const
0152 {
0153     return d->mPos;
0154 }
0155 
0156 void KTwoFingerTap::setPos(QPointF _pos)
0157 {
0158     d->mPos = _pos;
0159 }
0160 
0161 QPointF KTwoFingerTap::screenPos() const
0162 {
0163     return d->mScreenPos;
0164 }
0165 
0166 void KTwoFingerTap::setScreenPos(QPointF _screenPos)
0167 {
0168     d->mScreenPos = _screenPos;
0169 }
0170 
0171 QPointF KTwoFingerTap::scenePos() const
0172 {
0173     return d->mScenePos;
0174 }
0175 
0176 void KTwoFingerTap::setScenePos(QPointF _scenePos)
0177 {
0178     d->mScenePos = _scenePos;
0179 }
0180 
0181 #include "moc_ktwofingertap.cpp"