diff --git a/autotests/CMakeLists.txt b/autotests/CMakeLists.txt --- a/autotests/CMakeLists.txt +++ b/autotests/CMakeLists.txt @@ -21,6 +21,7 @@ kpassworddialogautotest.cpp kpasswordlineedittest.cpp ksplittercollapserbuttontest.cpp + ktouchgestureautotest.cpp LINK_LIBRARIES Qt5::Test KF5::WidgetsAddons ) diff --git a/autotests/ktouchgestureautotest.h b/autotests/ktouchgestureautotest.h new file mode 100644 --- /dev/null +++ b/autotests/ktouchgestureautotest.h @@ -0,0 +1,69 @@ +/* + * KTouchGesture is a library for gestures and touch handling + * Copyright (C) 2019 Steffen Hartleib + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef KTOUCHGESTUREAUTOTEST_H +#define KTOUCHGESTUREAUTOTEST_H + +#include +#include + +class QGraphicsWidget; +class KTouchGesture; +class QMainWindow; + + +class ktouchautotest : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void initTestCase(); + void cleanupTestCase(); + + void testSetTouchSignals(); + void testSetRules_data(); + void testSetRules(); + void testSetSignals_data(); + void testSetSignals(); + void testSetHandleTouch(); + void testTouchSignals_data(); + void testTouchSignals(); + void testTapSignals(); + void testOneAndTwoFingerSwipeSignals(); + void testPinchSignals_data(); + void testPinchSignals(); + void testTapHoldAndMovingSignals(); + void testDoubleTapSignals(); + void testTwoFingerTapSignals(); + void testTwoFingerPanSignals(); + void testOneFingerPanSignals(); + +private: + KTouchGesture* ktw = nullptr; + KTouchGesture* ktgw = nullptr; + QMainWindow* qmw = nullptr; + QWidget* qw = nullptr; + QGraphicsWidget* qgw = nullptr; + QTouchDevice* dev = nullptr; + +}; + +Q_DECLARE_METATYPE(QList) + +#endif // KTOUCHGESTUREAUTOTEST_H diff --git a/autotests/ktouchgestureautotest.cpp b/autotests/ktouchgestureautotest.cpp new file mode 100644 --- /dev/null +++ b/autotests/ktouchgestureautotest.cpp @@ -0,0 +1,682 @@ +/* + * KTouchGesture is a library for gestures and touch handling + * Copyright (C) 2019 Steffen Hartleib + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "ktouchgestureautotest.h" +#include "ktouchgesture_helper.h" + +#include +#include "ktouchgesture.h" +#include +#include +#include +#include +#include + +QTEST_MAIN(ktouchautotest) + +void ktouchautotest::initTestCase() +{ + // Called before the first test function is executed + qRegisterMetaType(); + + qmw = new QMainWindow(); //QGestureManager need a QMainWindow + qmw->setGeometry(0, 0, 500, 500); + qmw->show(); + KTouchGesture* ktouch = new KTouchGesture (this, KTouchGesture::NoGesture); + QVERIFY (ktouch); + QVERIFY (!ktouch->isTouchTargetValid()); //No valid touch target + delete ktouch; + + qw = new QWidget (qmw); + QVERIFY (qw); + ktw = new KTouchGesture (qw, KTouchGesture::AllGesture); + QVERIFY (ktw); + QVERIFY (qw->testAttribute(Qt::WA_AcceptTouchEvents)); //test if target accept TouchEvents + QVERIFY (ktw->isTouchTargetValid()); //QWidget is valid touch target + + qgw = new QGraphicsWidget(); + QVERIFY (qgw); + ktgw = new KTouchGesture (qgw, KTouchGesture::AllGesture); + QVERIFY (ktgw); + QVERIFY (qgw->acceptTouchEvents()); //test if target accept TouchEvents + QVERIFY (ktgw->isTouchTargetValid()); //QGraphicsWidget is valid touch target + + dev = QTest::createTouchDevice(QTouchDevice::TouchScreen); + QVERIFY (dev); + + qw->setGeometry(0, 0, 500, 500); + qw->show(); + QVERIFY (QTest::qWaitForWindowExposed(qw)); +} + +void ktouchautotest::cleanupTestCase() +{ + // Called after the last test function was executed + delete ktgw; + delete ktw; + delete qgw; + delete qw; + delete qmw; +} + +void ktouchautotest::testSetTouchSignals() +{ + + QVERIFY (ktw->getTouchSignalFlags() == KTouchGesture::NoSignal); //default is KTouchGesture::NoSignal + QVERIFY (ktgw->getTouchSignalFlags() == KTouchGesture::NoSignal); //default is KTouchGesture::NoSignal + + ktw->setTouchSignalFlags(KTouchGesture::TouchBeginn | KTouchGesture::TouchEnd); + QVERIFY (ktw->getTouchSignalFlags() == (KTouchGesture::TouchBeginn | KTouchGesture::TouchEnd)); + + ktgw->setTouchSignalFlags(KTouchGesture::TouchBeginn | KTouchGesture::TouchEnd); + QVERIFY (ktgw->getTouchSignalFlags() == (KTouchGesture::TouchBeginn | KTouchGesture::TouchEnd)); +} + +void ktouchautotest::testSetRules_data() +{ + QTest::addColumn("gesture"); + + QTest::newRow("TapGesture") << KTouchGesture::TapGesture; + QTest::newRow("TapAndHoldGesture") << KTouchGesture::TapAndHoldGesture; + QTest::newRow("PanGesture") << KTouchGesture::PanGesture; + QTest::newRow("PinchGesture") << KTouchGesture::PinchGesture; + QTest::newRow("SwipeGesture") << KTouchGesture::SwipeGesture; + QTest::newRow("TwoFingerTap") << KTouchGesture::TwoFingerTap; + QTest::newRow("TwoFingerPan") << KTouchGesture::TwoFingerPan; + QTest::newRow("TapHoldAndMoving") << KTouchGesture::TapHoldAndMoving; + QTest::newRow("OneAndTwoFingerSwipe") << KTouchGesture::OneAndTwoFingerSwipe; + QTest::newRow("DoubleTap") << KTouchGesture::DoubleTap; + QTest::newRow("OneFingerPan") << KTouchGesture::OneFingerPan; +} + + +void ktouchautotest::testSetRules() +{ + QFETCH (KTouchGesture::GestureTypeFlags, gesture); + + ktw->setRulesTriggerIfNotActiv (gesture, KTouchGesture::TapAndHoldGesture | KTouchGesture::PinchGesture); + QVERIFY (ktw->getRulesTriggerIfNotActiv(gesture) == (KTouchGesture::TapAndHoldGesture | KTouchGesture::PinchGesture)); + ktgw->setRulesTriggerIfNotActiv (gesture, KTouchGesture::TapAndHoldGesture | KTouchGesture::PinchGesture); + QVERIFY (ktgw->getRulesTriggerIfNotActiv(gesture) == (KTouchGesture::TapAndHoldGesture | KTouchGesture::PinchGesture)); + + ktw->setRulesTriggerIfNotFinish (gesture, KTouchGesture::TapAndHoldGesture | KTouchGesture::PinchGesture); + QVERIFY (ktw->getRulesTriggerIfNotFinish(gesture) == (KTouchGesture::TapAndHoldGesture | KTouchGesture::PinchGesture)); + ktgw->setRulesTriggerIfNotFinish (gesture, KTouchGesture::TapAndHoldGesture | KTouchGesture::PinchGesture); + QVERIFY (ktgw->getRulesTriggerIfNotFinish(gesture) == (KTouchGesture::TapAndHoldGesture | KTouchGesture::PinchGesture)); +} + +void ktouchautotest::testSetSignals_data() +{ + QTest::addColumn("gesture"); + + QTest::newRow("TapGesture") << KTouchGesture::TapGesture; + QTest::newRow("TapAndHoldGesture") << KTouchGesture::TapAndHoldGesture; + QTest::newRow("PanGesture") << KTouchGesture::PanGesture; + QTest::newRow("PinchGesture") << KTouchGesture::PinchGesture; + QTest::newRow("SwipeGesture") << KTouchGesture::SwipeGesture; + QTest::newRow("TwoFingerTap") << KTouchGesture::TwoFingerTap; + QTest::newRow("TwoFingerPan") << KTouchGesture::TwoFingerPan; + QTest::newRow("TapHoldAndMoving") << KTouchGesture::TapHoldAndMoving; + QTest::newRow("OneAndTwoFingerSwipe") << KTouchGesture::OneAndTwoFingerSwipe; + QTest::newRow("DoubleTap") << KTouchGesture::DoubleTap; + QTest::newRow("OneFingerPan") << KTouchGesture::OneFingerPan; +} + +void ktouchautotest::testSetSignals() +{ + QFETCH (KTouchGesture::GestureTypeFlags, gesture); + + ktw->setGestureSignals (gesture, KTouchGesture::GestureFinished | KTouchGesture::GestureStarted); + QVERIFY (ktw->getGestureSignals(gesture) == (KTouchGesture::GestureFinished | KTouchGesture::GestureStarted)); + ktgw->setGestureSignals (gesture, KTouchGesture::GestureFinished | KTouchGesture::GestureStarted); + QVERIFY (ktgw->getGestureSignals(gesture) == (KTouchGesture::GestureFinished | KTouchGesture::GestureStarted)); + +} + +void ktouchautotest::testSetHandleTouch() +{ + QVERIFY (ktw->getHandleTouchEvents()); //default is true + QVERIFY (ktgw->getHandleTouchEvents()); //default is true + + ktw->setHandleTouchEvents(false); + QVERIFY (!ktw->getHandleTouchEvents()); + ktgw->setHandleTouchEvents(false); + QVERIFY (!ktgw->getHandleTouchEvents()); +} + +void ktouchautotest::testTouchSignals_data() +{ + QTest::addColumn("touchSignal"); + QTest::addColumn("countBeginn"); + QTest::addColumn("countUpdate"); + QTest::addColumn("countEnd"); + + QTest::newRow("beginn") << KTouchGesture::TouchBeginn << 1 << 0 << 0; + QTest::newRow("update") << KTouchGesture::TouchUpdate << 0 << 1 << 0; + QTest::newRow("end") << KTouchGesture::TouchEnd << 0 << 0 << 1; + QTest::newRow("all") << KTouchGesture::AllTouchSignals << 1 << 1 << 1; +} + + +void ktouchautotest::testTouchSignals() +{ + QFETCH (KTouchGesture::TouchSignalFlags, touchSignal); + QFETCH (int, countBeginn); + QFETCH (int, countUpdate); + QFETCH (int, countEnd); + + ktw->setTouchSignalFlags(touchSignal); + ktw->setHandleTouchEvents(true); + qRegisterMetaType>(); + + QSignalSpy touchBeginn( ktw, &KTouchGesture::touchBeginnTriggered); + QVERIFY( touchBeginn.isValid() ); + QCOMPARE( touchBeginn.count(), 0 ); + + QSignalSpy touchUpdate( ktw, &KTouchGesture::touchUpdateTriggered); + QVERIFY( touchUpdate.isValid() ); + QCOMPARE( touchUpdate.count(), 0 ); + + QSignalSpy touchEnd( ktw, &KTouchGesture::touchEndTriggered); + QVERIFY( touchEnd.isValid() ); + QCOMPARE( touchEnd.count(), 0 ); + + QPoint startPos = QPoint (10, 80); + QPoint endPos = QPoint (20, 50); + + QTest::touchEvent(qw, dev, true) + .press(0, startPos, qw); + QCOMPARE( touchBeginn.count(), countBeginn ); + QCOMPARE( touchUpdate.count(), 0 ); + QCOMPARE( touchEnd.count(), 0 ); + + QTest::touchEvent(qw, dev, true) + .move(0, endPos, qw); + QCOMPARE( touchBeginn.count(), countBeginn ); + QCOMPARE( touchUpdate.count(), countUpdate ); + QCOMPARE( touchEnd.count(), 0 ); + + QTest::touchEvent(qw, dev, true) + .release(0, endPos, qw); + QCOMPARE( touchBeginn.count(), countBeginn ); + QCOMPARE( touchUpdate.count(), countUpdate ); + QCOMPARE( touchEnd.count(), countEnd ); + + if (touchBeginn.size() > 0) { + QList touchBeginnArgs = touchBeginn.takeFirst(); + QList result = qvariant_cast>(touchBeginnArgs.at(0)); + qreal time = qvariant_cast(touchBeginnArgs.at(1)); + QVERIFY (time > 0); + QVERIFY (result.at(0).pos().toPoint() == startPos); + } + if (touchUpdate.size() > 0) { + QList touchUpdateArgs = touchUpdate.takeFirst(); + QList result = qvariant_cast>(touchUpdateArgs.at(0)); + qreal time = qvariant_cast(touchUpdateArgs.at(1)); + QVERIFY (time > 0); + QVERIFY (result.at(0).pos().toPoint() == endPos); + } + if (touchEnd.size() > 0) { + QList touchEndArgs = touchEnd.takeFirst(); + QList result = qvariant_cast>(touchEndArgs.at(0)); + qreal time = qvariant_cast(touchEndArgs.at(1)); + QVERIFY (time > 0); + QVERIFY (result.at(0).pos().toPoint() == endPos); + } +} + +void ktouchautotest::testTapSignals() +{ + + ktw->setGestureSignals(KTouchGesture::TapGesture, KTouchGesture::AllGestureSignals); + ktw->setGestureDefaultRules(KTouchGesture::TapGesture); + + QSignalSpy tapSignal( ktw, &KTouchGesture::tapTriggered); + QVERIFY( tapSignal.isValid()); + QCOMPARE( tapSignal.count(), 0); + + QPoint startPos = QPoint (15, 85); + + //valid Tap Gesture + QTest::touchEvent(qw, dev, true) + .press(0, startPos, qw); + QTest::touchEvent(qw, dev, true) + .release(0, startPos, qw); + QCOMPARE (tapSignal.count(), 2); + + if (tapSignal.size() > tapSignal.count() - 1) { + QList tapSignalArgs = tapSignal.takeFirst(); + KTouchGestureData gdata = qvariant_cast(tapSignalArgs.at(0)); + QCOMPARE (gdata.pos.toPoint(), startPos); + QCOMPARE (gdata.state, Qt::GestureStarted); + tapSignalArgs = tapSignal.takeFirst(); + gdata = qvariant_cast(tapSignalArgs.at(0)); + QCOMPARE (gdata.pos.toPoint(), startPos); + QCOMPARE (gdata.state, Qt::GestureFinished); + tapSignal.clear(); + } + + //invalid Tap Gesture (touchpoint is moving) + QTest::touchEvent(qw, dev, true) + .press(0, startPos, qw); + QTest::touchEvent(qw, dev, true) + .move(0, startPos + QPoint (30, 30), qw); + QTest::touchEvent(qw, dev, true) + .release(0, startPos + QPoint (30, 30), qw); + QCOMPARE (tapSignal.count(), 2); + if (tapSignal.size() > tapSignal.count() - 1) { + QList tapSignalArgs = tapSignal.takeLast(); + KTouchGestureData gdata = qvariant_cast(tapSignalArgs.at(0)); + QCOMPARE (gdata.state, Qt::GestureCanceled); + tapSignal.clear(); + } + + //invalid Tap Gesture (Tap time is to long, TapAndHoldGesture ist tapTriggered + //and default trigger rules are active, + //no signal should contain Qt::GestureFinished + QTest::touchEvent(qw, dev, true) + .press(0, startPos, qw); + QTest::qWait (800); + QTest::touchEvent(qw, dev, true) + .release(0, startPos, qw); + for (int i = 0; i(tapSignal.at(i).at(0)); + QVERIFY (gdata.state != Qt::GestureFinished); + } + tapSignal.clear(); + + //invalid Tap Gesture more like one touchpoint + QTest::touchEvent(qw, dev, true) + .press(0, startPos, qw); + QTest::touchEvent(qw, dev, true) + .press(1, startPos+startPos, qw); + QTest::touchEvent(qw, dev, true) + .release(0, startPos, qw) + .release(1, startPos+startPos, qw); + if (tapSignal.size() > tapSignal.count() - 1) { + QList tapSignalArgs = tapSignal.takeLast(); + KTouchGestureData gdata = qvariant_cast(tapSignalArgs.at(0)); + QCOMPARE (gdata.state, Qt::GestureCanceled); + tapSignal.clear(); + } +} + +void ktouchautotest::testOneAndTwoFingerSwipeSignals() +{ + ktw->setGestureSignals(KTouchGesture::OneAndTwoFingerSwipe, KTouchGesture::AllGestureSignals); + ktw->setGestureDefaultRules(KTouchGesture::OneAndTwoFingerSwipe); + + QSignalSpy swipeSignal( ktw, &KTouchGesture::oneAndTwoFingerSwipeTriggered); + QVERIFY( swipeSignal.isValid()); + QCOMPARE( swipeSignal.count(), 0); + + QPoint startPos = QPoint (10, 80); + QPoint endPos = QPoint (10 + KTouchGestureDefaults::minDistanceForSwipe, 80); + + //valid one finger swipe + QTest::touchEvent(qw, dev, true) + .press(0, startPos, qw); + QTest::touchEvent(qw, dev, true) + .move(0, endPos, qw); + QTest::touchEvent(qw, dev, true) + .release(0, endPos, qw); + if (swipeSignal.size() > swipeSignal.count() - 1) { + QList swipeSignalArgs = swipeSignal.takeLast(); + KTouchGestureData gdata = qvariant_cast(swipeSignalArgs.at(0)); + QCOMPARE (gdata.state, Qt::GestureFinished); + QCOMPARE (gdata.swipeAngel, (double) 0); + swipeSignal.clear(); + } + + //invalid one finger swipe (distance not far enough) + QTest::touchEvent(qw, dev, true) + .press(0, startPos, qw); + QTest::touchEvent(qw, dev, true) + .move(0, endPos - QPoint(20, 0), qw); + QTest::touchEvent(qw, dev, true) + .release(0, endPos - QPoint(20, 0), qw); + QCOMPARE( swipeSignal.count(), 0 ); + swipeSignal.clear(); + + //valid two finger swipe + QTest::touchEvent(qw, dev, true) + .press(0, startPos, qw) + .press(1, startPos, qw); + QTest::touchEvent(qw, dev, true) + .move(0, endPos, qw) + .move(1, endPos, qw); + QTest::touchEvent(qw, dev, true) + .release(0, endPos, qw) + .release(1, endPos, qw); + QVERIFY (swipeSignal.count() > 0); + QList swipeSignalArgs = swipeSignal.takeLast(); + KTouchGestureData gdata = qvariant_cast(swipeSignalArgs.at(0)); + QCOMPARE (gdata.state, Qt::GestureFinished); + QCOMPARE (gdata.swipeAngel, (double) 0); + swipeSignal.clear(); + + //invalid two finger swipe (distance not far enough) + QTest::touchEvent(qw, dev, true) + .press(0, startPos, qw) + .press(1, startPos, qw); + QTest::touchEvent(qw, dev, true) + .move(0, endPos - QPoint(20, 0), qw) + .move(1, endPos - QPoint(20, 0), qw); + QTest::touchEvent(qw, dev, true) + .release(0, endPos - QPoint(20, 0), qw) + .release(1, endPos - QPoint(20, 0), qw); + QCOMPARE( swipeSignal.count(), 0); + swipeSignal.clear(); + + //invalid swipe (three touchpoints) + QTest::touchEvent(qw, dev, true) + .press(0, startPos, qw) + .press(1, startPos, qw) + .press(2, startPos, qw); + QTest::touchEvent(qw, dev, true) + .move(0, endPos - QPoint(20, 0), qw) + .move(1, endPos - QPoint(20, 0), qw) + .move(2, endPos - QPoint(20, 0), qw); + QTest::touchEvent(qw, dev, true) + .release(0, endPos - QPoint(20, 0), qw) + .release(1, endPos - QPoint(20, 0), qw) + .release(2, endPos - QPoint(20, 0), qw); + QCOMPARE( swipeSignal.count(), 0); + swipeSignal.clear(); + +} + +void ktouchautotest::testPinchSignals_data() +{ + QTest::addColumn("startPos1"); + QTest::addColumn("startPos2"); + QTest::addColumn("movePos1"); + QTest::addColumn("movePos2"); + QTest::addColumn("endPos1"); + QTest::addColumn("endPos2"); + QTest::addColumn("state"); + + QTest::newRow("true pinch")<setGestureSignals(KTouchGesture::PinchGesture, KTouchGesture::AllGestureSignals); + ktw->setGestureDefaultRules(KTouchGesture::PinchGesture); + + QSignalSpy pinchSignal(ktw, &KTouchGesture::pinchTriggered); + QVERIFY( pinchSignal.isValid()); + QCOMPARE( pinchSignal.count(), 0); + QTest::touchEvent(qw, dev, true) + .press(0, startPos1, qw) + .press(1, startPos2, qw); + QTest::qWait(40); + QTest::touchEvent(qw, dev, true) + .move(0, (movePos1 - startPos1) / 2 + startPos1, qw) + .move(1, (movePos2 - startPos2) / 2 + startPos2, qw); + QTest::qWait(40); + QTest::touchEvent(qw, dev, true) + .move(0, movePos1, qw) + .move(1, movePos2, qw); + QTest::qWait(40); + QTest::touchEvent(qw, dev, true) + .move(0, (endPos1 - movePos1) / 2 + movePos1, qw) + .move(1, (endPos2 - movePos1) / 2 + movePos2, qw); + QTest::qWait(40); + QTest::touchEvent(qw, dev, true) + .release(0, endPos1, qw) + .release(1, endPos2, qw); + + QVERIFY (pinchSignal.count() > 0); + QList pinchSignalArgs = pinchSignal.first(); + KTouchGestureData gdata = qvariant_cast(pinchSignalArgs.at(0)); + QCOMPARE (gdata.state, Qt::GestureStarted); //first signal is Qt::GestureStarted + + pinchSignalArgs = pinchSignal.last(); + gdata = qvariant_cast(pinchSignalArgs.at(0)); + QCOMPARE (gdata.state, state); //last signal is Qt::GestureFinished (if valid gesture), + //or Qt::GestureStarted (if rules say invalid gesture) + pinchSignal.clear(); +} + +void ktouchautotest::testTapHoldAndMovingSignals() +{ + ktw->setGestureSignals(KTouchGesture::TapHoldAndMoving, KTouchGesture::AllGestureSignals); + ktw->setGestureDefaultRules(KTouchGesture::TapHoldAndMoving); + + QSignalSpy signal(ktw, &KTouchGesture::tapHoldAndMovingTriggered); + QVERIFY(signal.isValid()); + QCOMPARE(signal.count(), 0); + + QPoint startPos = QPoint (40, 40); + QPoint endPos = QPoint (80, 80); + //valid TapHoldAndMoving Gesture + QTest::touchEvent(qw, dev, true) + .press(0, startPos, qw); + QTest::qWait( KTouchGestureDefaults::durationForTapHold); + QTest::touchEvent(qw, dev, true) + .move(0, endPos, qw); + + QVERIFY (signal.count() > 0); + QList signalArgs = signal.first(); + KTouchGestureData gdata = qvariant_cast(signalArgs.at(0)); + QCOMPARE (gdata.state, Qt::GestureStarted); //first signal is Qt::GestureStarted + QCOMPARE (gdata.pos.toPoint(), startPos); + signal.clear(); + + //invalid TapHoldAndMoving Gesture (hold time too short) + QTest::touchEvent(qw, dev, true) + .press(0, startPos, qw); + QTest::qWait( KTouchGestureDefaults::durationForTapHold / 2); + QTest::touchEvent(qw, dev, true) + .move(0, endPos, qw); + QVERIFY (signal.count() == 0); +} + +void ktouchautotest::testDoubleTapSignals() +{ + ktw->setGestureSignals(KTouchGesture::DoubleTap, KTouchGesture::AllGestureSignals); + ktw->setGestureDefaultRules(KTouchGesture::DoubleTap); + + QSignalSpy signal(ktw, &KTouchGesture::doubleTapTriggered); + QVERIFY(signal.isValid()); + QCOMPARE(signal.count(), 0); + + QPoint startPos = QPoint (40, 40); + QPoint endPos = QPoint (80, 80); + + //valid DoubleTap Gesture + QTest::touchEvent(qw, dev, true) + .press(0, startPos, qw); + QTest::touchEvent(qw, dev, true) + .release(0, startPos, qw); + QTest::qWait( KTouchGestureDefaults::doubleTapInterval / 2); + QTest::touchEvent(qw, dev, true) + .press(0, endPos, qw); + QTest::touchEvent(qw, dev, true) + .release(0, endPos, qw); + + QVERIFY (signal.count() == 2); + QList signalArgs = signal.first(); + KTouchGestureData gdata = qvariant_cast(signalArgs.at(0)); + QCOMPARE (gdata.state, Qt::GestureStarted); //first signal is Qt::GestureStarted + QCOMPARE (gdata.pos.toPoint(), endPos); + QCOMPARE (gdata.screenPos.toPoint(), qw->mapToGlobal(endPos)); + QCOMPARE (gdata.hotSpot.toPoint(), qw->mapToGlobal(endPos)); + //scenePos is equal screenPos because target is not QGraphicsWidget + QCOMPARE (gdata.scenePos.toPoint(), qw->mapToGlobal(endPos)); + signal.clear(); + + //invalid DoubleTap Gesture first Tap time is too long + QTest::touchEvent(qw, dev, true) + .press(0, startPos, qw); + QTest::qWait( KTouchGestureDefaults::maxTimeForTap * 1.2); + QTest::touchEvent(qw, dev, true) + .release(0, startPos, qw); + QTest::qWait( KTouchGestureDefaults::doubleTapInterval / 2); + QTest::touchEvent(qw, dev, true) + .press(0, endPos, qw); + QTest::touchEvent(qw, dev, true) + .release(0, endPos, qw); + + QVERIFY (signal.count() == 0); + signal.clear(); + + //invalid DoubleTap Gesture second tap too late + QTest::touchEvent(qw, dev, true) + .press(0, startPos, qw); + QTest::touchEvent(qw, dev, true) + .release(0, startPos, qw); + QTest::qWait( KTouchGestureDefaults::doubleTapInterval * 1.2); + QTest::touchEvent(qw, dev, true) + .press(0, endPos, qw); + QTest::touchEvent(qw, dev, true) + .release(0, endPos, qw); + + QVERIFY (signal.count() == 0); + signal.clear(); +} + +void ktouchautotest::testTwoFingerTapSignals() +{ + ktw->setGestureSignals(KTouchGesture::TwoFingerTap, KTouchGesture::AllGestureSignals); + ktw->setGestureDefaultRules(KTouchGesture::TwoFingerTap); + + QSignalSpy signal(ktw, &KTouchGesture::twoFingerTapTriggered); + QVERIFY(signal.isValid()); + QCOMPARE(signal.count(), 0); + + QPoint startPos1 = QPoint (40, 40); + QPoint startPos2 = QPoint (45, 45); + + //valid TwoFingerTap Gesture + QTest::touchEvent(qw, dev, true) + .press(0, startPos1, qw); + QTest::touchEvent(qw, dev, true) + .move(0, startPos1, qw) + .press(1, startPos2, qw); + QTest::touchEvent(qw, dev, true) + .move(0, startPos1, qw) + .release(1, startPos2, qw); + QTest::touchEvent(qw, dev, true) + .release(0, startPos1, qw); + + QVERIFY (signal.count() == 2); + QList signalArgs = signal.first(); + KTouchGestureData gdata = qvariant_cast(signalArgs.at(0)); + QCOMPARE (gdata.state, Qt::GestureStarted); //first signal is Qt::GestureStarted + QCOMPARE (gdata.pos.toPoint(), startPos1); + QCOMPARE (gdata.screenPos.toPoint(), qw->mapToGlobal(startPos1)); + QCOMPARE (gdata.hotSpot.toPoint(), qw->mapToGlobal(startPos1)); + //scenePos is equal screenPos because target is not QGraphicsWidget + QCOMPARE (gdata.scenePos.toPoint(), qw->mapToGlobal(startPos1)); + signal.clear(); +} + +void ktouchautotest::testTwoFingerPanSignals() +{ + ktw->setGestureSignals(KTouchGesture::TwoFingerPan, KTouchGesture::AllGestureSignals); + ktw->setGestureDefaultRules(KTouchGesture::TwoFingerPan); + + QSignalSpy signal(ktw, &KTouchGesture::twoFingerPanTriggered); + QVERIFY(signal.isValid()); + QCOMPARE(signal.count(), 0); + + QPoint startPos1 = QPoint (40, 40); + QPoint startPos2 = QPoint (45, 45); + QPoint move1 = QPoint (5, 0); + //valid TwoFingerPan Gesture + QTest::touchEvent(qw, dev, true) + .press(0, startPos1, qw) + .press(1, startPos2, qw); + QTest::qWait( KTouchGestureDefaults::gestureDelay); + QTest::touchEvent(qw, dev, true) + .move(0, startPos1 + move1, qw) + .move(1, startPos2 + move1, qw); + QTest::qWait( KTouchGestureDefaults::gestureDelay * 0.25); + QTest::touchEvent(qw, dev, true) + .move(0, startPos1 + move1 * 2, qw) + .move(1, startPos2 + move1 * 2, qw); + QTest::touchEvent(qw, dev, true) + .release(0, startPos1 + move1 * 2, qw) + .release(1, startPos2 + move1 * 2, qw); + + QVERIFY (signal.count() >= 2); + QList signalArgs = signal.first(); + KTouchGestureData gdata = qvariant_cast(signalArgs.at(0)); + QCOMPARE (gdata.state, Qt::GestureStarted); //first signal is Qt::GestureStarted + QCOMPARE (gdata.pos.toPoint(), startPos1); + QCOMPARE (gdata.screenPos.toPoint(), qw->mapToGlobal(startPos1)); + QCOMPARE (gdata.hotSpot.toPoint(), qw->mapToGlobal(startPos1)); + //scenePos is equal screenPos because target is not QGraphicsWidget + QCOMPARE (gdata.scenePos.toPoint(), qw->mapToGlobal(startPos1)); + QCOMPARE (gdata.delta.toPoint(), move1); + + signalArgs = signal.at(1); + gdata = qvariant_cast(signalArgs.at(0)); + QCOMPARE (gdata.state, Qt::GestureUpdated); //second signal is Qt::GestureUpdated + QCOMPARE (gdata.delta.toPoint(), move1); + + signalArgs = signal.last(); + gdata = qvariant_cast(signalArgs.at(0)); + QCOMPARE (gdata.state, Qt::GestureFinished); //last signal is Qt::GestureFinished + signal.clear(); +} + +void ktouchautotest::testOneFingerPanSignals() +{ + ktw->setGestureSignals(KTouchGesture::OneFingerPan, KTouchGesture::AllGestureSignals); + ktw->setGestureDefaultRules(KTouchGesture::OneFingerPan); + + QSignalSpy signal(ktw, &KTouchGesture::oneFingerPanTriggered); + QVERIFY(signal.isValid()); + QCOMPARE(signal.count(), 0); + + QPoint startPos1 = QPoint (40, 40); + QPoint move1 = QPoint (5, 0); + //valid OneFingerPan Gesture + QTest::touchEvent(qw, dev, true) + .press(0, startPos1, qw); + QTest::touchEvent(qw, dev, true) + .move(0, startPos1 + move1, qw); + QTest::touchEvent(qw, dev, true) + .release(0, startPos1 + move1 * 2, qw); + + QVERIFY (signal.count() >= 1); + QList signalArgs = signal.first(); + KTouchGestureData gdata = qvariant_cast(signalArgs.at(0)); + QCOMPARE (gdata.state, Qt::GestureStarted); //first signal is Qt::GestureStarted + QCOMPARE (gdata.pos.toPoint(), startPos1); + QCOMPARE (gdata.screenPos.toPoint(), qw->mapToGlobal(startPos1)); + QCOMPARE (gdata.hotSpot.toPoint(), qw->mapToGlobal(startPos1)); + //scenePos is equal screenPos because target is not QGraphicsWidget + QCOMPARE (gdata.scenePos.toPoint(), qw->mapToGlobal(startPos1)); + QCOMPARE (gdata.delta.toPoint(), move1); + signal.clear(); +} diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -77,6 +77,13 @@ ksplittercollapserbutton.cpp kstyleextensions.cpp ktooltipwidget.cpp + ktouchgesture.cpp + kdoubletap.cpp + ktwofingertap.cpp + ktapholdandmoving.cpp + koneandtwofingerswipe.cpp + ktwofingerpan.cpp + konefingerpan.cpp ${kwidgetsaddons_QM_LOADER} ${kwidgetsaddons_ICON_SRCS} ) @@ -182,6 +189,7 @@ KSplitterCollapserButton KStyleExtensions KToolTipWidget + KTouchGesture REQUIRED_HEADERS KWidgetsAddons_HEADERS ) @@ -264,6 +272,7 @@ kmessageboxnotifyinterface.h ksplittercollapserbutton.h kstyleextensions.h + ktouchgesture.h ) endif() diff --git a/src/kdoubletap.h b/src/kdoubletap.h new file mode 100644 --- /dev/null +++ b/src/kdoubletap.h @@ -0,0 +1,65 @@ +/* + * KTouchGesture is a library for gestures and touch handling + * Copyright (C) 2019 Steffen Hartleib + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#ifndef KDOUBLETAP_H +#define KDOUBLETAP_H + +#include +// Qt +#include +#include + +// KDE + +// Local + +class KWIDGETSADDONS_EXPORT KDoubleTap : public QGesture +{ + Q_OBJECT + Q_PROPERTY(QPointF pos READ pos WRITE setPos) + Q_PROPERTY(QPointF screenPos READ screenPos WRITE setScreenPos) + Q_PROPERTY(QPointF scenePos READ scenePos WRITE setScenePos) + +public: + explicit KDoubleTap(QObject* parent = nullptr); + ~KDoubleTap(); + QPointF pos() const; + void setPos(QPointF pos); + QPointF screenPos() const; + void setScreenPos(QPointF screenPos); + QPointF scenePos() const; + void setScenePos(QPointF scenePos); +private: + class KDoubleTapPrivate* const d; +}; + +class KWIDGETSADDONS_EXPORT KDoubleTapRecognizer : public QGestureRecognizer +{ +public: + explicit KDoubleTapRecognizer(); + ~KDoubleTapRecognizer(); + + QGesture* create(QObject*) override; + Result recognize(QGesture*, QObject*, QEvent*) override; +private: + Q_DISABLE_COPY(KDoubleTapRecognizer) + class KDoubleTapRecognizerPrivate* const d; +}; + +#endif /* KDOUBLETAP_H */ + diff --git a/src/kdoubletap.cpp b/src/kdoubletap.cpp new file mode 100644 --- /dev/null +++ b/src/kdoubletap.cpp @@ -0,0 +1,200 @@ +/* + * KTouchGesture is a library for gestures and touch handling + * Copyright (C) 2019 Steffen Hartleib + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +// Self +#include "kdoubletap.h" + +// Qt +#include +#include + +// KDE + +// Local +#include "ktouchgesture_helper.h" + +class KDoubleTapPrivate +{ +public: + KDoubleTapPrivate() + { + } + ~KDoubleTapPrivate() + { + } + KDoubleTap* q; + QPointF m_pos; + QPointF m_screenPos; + QPointF m_scenePos; +}; + +class KDoubleTapRecognizerPrivate +{ +public: + KDoubleTapRecognizerPrivate() + { + } + ~KDoubleTapRecognizerPrivate() + { + } + void setGesturePositions (KDoubleTap* const gesture, QTouchEvent::TouchPoint tp) + { + gesture->setHotSpot(tp.startScreenPos()); + gesture->setPos(tp.startPos()); + gesture->setScreenPos(tp.startScreenPos()); + gesture->setScenePos(tp.startScenePos()); + } + bool isTouchStationary (const QTouchEvent* touchEvent) + { + const QPointF distance = touchEvent->touchPoints().first().startPos() - touchEvent->touchPoints().first().pos(); + if (distance.manhattanLength() <= KTouchGestureDefaults::wiggleRoomForTap) { + return true; + } + return false; + } + KDoubleTapRecognizer* q; + bool m_TargetIsGrapicsWidget = false; + qint64 m_TouchBeginnTimestamp; + bool m_IsOnlyTap; + qint64 m_LastTapTimestamp = 0; + qint64 m_LastDoupleTapTimestamp = 0; +}; + +KDoubleTapRecognizer::KDoubleTapRecognizer() + : QGestureRecognizer() + , d (new KDoubleTapRecognizerPrivate) +{ + d->q = this; +} + +KDoubleTapRecognizer::~KDoubleTapRecognizer() +{ + delete d; +} + +QGesture* KDoubleTapRecognizer::create(QObject*) +{ + return static_cast(new KDoubleTap()); +} + +QGestureRecognizer::Result KDoubleTapRecognizer::recognize(QGesture* gesture, QObject* watched, QEvent* event) +{ + //Because of a bug in Qt in a gesture event in a graphicsview, all gestures are trigger twice + //https://bugreports.qt.io/browse/QTBUG-13103 + if (qobject_cast(watched)) d->m_TargetIsGrapicsWidget = true; + if (d->m_TargetIsGrapicsWidget && watched->isWidgetType()) return Ignore; + + KDoubleTap* const kDoubleTap = static_cast(gesture); + const QTouchEvent* touchEvent = static_cast(event); + + switch (event->type()) { + case QEvent::TouchBegin: { + d->m_TouchBeginnTimestamp = touchEvent->timestamp(); + d->m_IsOnlyTap = true; + if (d->m_LastDoupleTapTimestamp == 0) d->m_LastDoupleTapTimestamp = touchEvent->timestamp() - KTouchGestureDefaults::doubleTapInterval; + d->setGesturePositions(kDoubleTap, touchEvent->touchPoints().first()); + return MayBeGesture; + } + + case QEvent::TouchUpdate: { + const qint64 now = touchEvent->timestamp(); + + if (touchEvent->touchPoints().size() > 1) { + d->m_IsOnlyTap = false; + d->setGesturePositions(kDoubleTap, touchEvent->touchPoints().first()); + return CancelGesture; + } + + if (d->m_IsOnlyTap && now - d->m_TouchBeginnTimestamp < KTouchGestureDefaults::maxTimeForTap && d->isTouchStationary(touchEvent)) { + d->m_IsOnlyTap = true; + d->setGesturePositions(kDoubleTap, touchEvent->touchPoints().first()); + return MayBeGesture; + } else { + d->m_IsOnlyTap = false; + d->setGesturePositions(kDoubleTap, touchEvent->touchPoints().first()); + return CancelGesture; + } + break; + } + + case QEvent::TouchEnd: { + const qint64 now = touchEvent->timestamp(); + + if (now - d->m_LastTapTimestamp <= KTouchGestureDefaults::doubleTapInterval && d->m_IsOnlyTap) { + //Interval between two double tap gesture need to be bigger than Touch_Helper::Touch::doupleTapIntervall, + //to suppress fast successively double tap gestures + if (now - d->m_LastDoupleTapTimestamp > KTouchGestureDefaults::doubleTapInterval) { + d->m_LastTapTimestamp = 0; + d->setGesturePositions(kDoubleTap, touchEvent->touchPoints().first()); + d->m_LastDoupleTapTimestamp = now; + return FinishGesture; + } + } + + if (d->m_IsOnlyTap) d->m_LastTapTimestamp = now; + + break; + } + + default: + return Ignore; + } + return Ignore; +} + +KDoubleTap::KDoubleTap(QObject* parent) + : QGesture(parent) + , d (new KDoubleTapPrivate) +{ + d->q = this; +} + +KDoubleTap::~KDoubleTap() +{ + delete d; +} + +QPointF KDoubleTap::pos() const +{ + return d->m_pos; +} + +void KDoubleTap::setPos(QPointF _pos) +{ + d->m_pos = _pos; +} + +QPointF KDoubleTap::screenPos() const +{ + return d->m_screenPos; +} + +void KDoubleTap::setScreenPos(QPointF _screenPos) +{ + d->m_screenPos = _screenPos; +} + +QPointF KDoubleTap::scenePos() const +{ + return d->m_scenePos; +} + +void KDoubleTap::setScenePos(QPointF _scenePos) +{ + d->m_scenePos = _scenePos; +} diff --git a/src/koneandtwofingerswipe.h b/src/koneandtwofingerswipe.h new file mode 100644 --- /dev/null +++ b/src/koneandtwofingerswipe.h @@ -0,0 +1,66 @@ +/* + * KTouchGesture is a library for gestures and touch handling + * Copyright (C) 2019 Steffen Hartleib + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#ifndef KONEANDTWOFINGERSWIPE_H +#define KONEANDTWOFINGERSWIPE_H + +#include +// Qt +#include +#include + +// KDE + +// Local + +class KWIDGETSADDONS_EXPORT KOneAndTwoFingerSwipe : public QGesture +{ + Q_OBJECT + Q_PROPERTY(QPointF pos READ pos WRITE setPos) + Q_PROPERTY(QPointF screenPos READ screenPos WRITE setScreenPos) + Q_PROPERTY(QPointF scenePos READ scenePos WRITE setScenePos) + Q_PROPERTY(qreal swipeAngle READ swipeAngle WRITE setSwipeAngle) +public: + explicit KOneAndTwoFingerSwipe (QObject* parent = nullptr); + ~KOneAndTwoFingerSwipe(); + QPointF pos() const; + void setPos(QPointF pos); + QPointF screenPos() const; + void setScreenPos(QPointF screenPos); + QPointF scenePos() const; + void setScenePos(QPointF scenePos); + qreal swipeAngle() const; + void setSwipeAngle(qreal swipeAngle); +private: + class KOneAndTwoFingerSwipePrivate* const d; +}; + +class KWIDGETSADDONS_EXPORT KOneAndTwoFingerSwipeRecognizer : public QGestureRecognizer +{ +public: + explicit KOneAndTwoFingerSwipeRecognizer(); + ~KOneAndTwoFingerSwipeRecognizer(); + QGesture* create(QObject*) override; + Result recognize(QGesture*, QObject*, QEvent*) override; +private: + Q_DISABLE_COPY(KOneAndTwoFingerSwipeRecognizer) + class KOneAndTwoFingerSwipeRecognizerPrivate* const d; +}; + +#endif /* KONEANDTWOFINGERSWIPE_H */ + diff --git a/src/koneandtwofingerswipe.cpp b/src/koneandtwofingerswipe.cpp new file mode 100644 --- /dev/null +++ b/src/koneandtwofingerswipe.cpp @@ -0,0 +1,185 @@ +/* + * KTouchGesture is a library for gestures and touch handling + * Copyright (C) 2019 Steffen Hartleib + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +// Self +#include "koneandtwofingerswipe.h" + +// Qt +#include +#include + +// KDE + +// Local +#include "ktouchgesture_helper.h" + +class KOneAndTwoFingerSwipePrivate +{ +public: + KOneAndTwoFingerSwipePrivate() + { + } + ~KOneAndTwoFingerSwipePrivate() + { + } + KOneAndTwoFingerSwipe* q; + QPointF m_pos; + QPointF m_screenPos; + QPointF m_scenePos; + qreal m_swipeAngle; +}; + +class KOneAndTwoFingerSwipeRecognizerPrivate +{ +public: + KOneAndTwoFingerSwipeRecognizerPrivate() + { + } + ~KOneAndTwoFingerSwipeRecognizerPrivate() + { + } + void setGesturePositions (KOneAndTwoFingerSwipe* const gesture, QTouchEvent::TouchPoint tp) + { + gesture->setHotSpot(tp.startScreenPos()); + gesture->setPos(tp.startPos()); + gesture->setScreenPos(tp.startScreenPos()); + gesture->setScenePos(tp.startScenePos()); + } + void setAngle (KOneAndTwoFingerSwipe* const gesture, QTouchEvent::TouchPoint tp) + { + const QLineF ql = QLineF (tp.startPos(), tp.pos()); + gesture->setSwipeAngle(ql.angle()); + } + KOneAndTwoFingerSwipeRecognizer* q; + bool m_TargetIsGrapicsWidget = false; + qint64 m_TouchBeginnTimestamp; + bool m_GestureAlreadyTriggered; +}; + +KOneAndTwoFingerSwipeRecognizer::KOneAndTwoFingerSwipeRecognizer() + : QGestureRecognizer() + , d (new KOneAndTwoFingerSwipeRecognizerPrivate) +{ + d->q = this; +} + +KOneAndTwoFingerSwipeRecognizer::~KOneAndTwoFingerSwipeRecognizer() +{ + delete d; +} + +QGesture* KOneAndTwoFingerSwipeRecognizer::create(QObject*) +{ + return static_cast(new KOneAndTwoFingerSwipe()); +} + +QGestureRecognizer::Result KOneAndTwoFingerSwipeRecognizer::recognize(QGesture* gesture, QObject* watched, QEvent* event) +{ + //Because of a bug in Qt in a gesture event in a graphicsview, all gestures are trigger twice + //https://bugreports.qt.io/browse/QTBUG-13103 + if (qobject_cast(watched)) d->m_TargetIsGrapicsWidget = true; + if (d->m_TargetIsGrapicsWidget && watched->isWidgetType()) return Ignore; + + KOneAndTwoFingerSwipe* const kOneAndTwoFingerSwipe = static_cast(gesture); + const QTouchEvent* touchEvent = static_cast(event); + + switch (event->type()) { + case QEvent::TouchBegin: { + d->m_TouchBeginnTimestamp = touchEvent->timestamp(); + d->m_GestureAlreadyTriggered = false; + d->setGesturePositions(kOneAndTwoFingerSwipe, touchEvent->touchPoints().first()); + return MayBeGesture; + } + + case QEvent::TouchUpdate: { + const qint64 now = touchEvent->timestamp(); + const QPointF distance = touchEvent->touchPoints().first().startPos() - touchEvent->touchPoints().first().pos(); + d->setGesturePositions(kOneAndTwoFingerSwipe, touchEvent->touchPoints().first()); + + if (touchEvent->touchPoints().size() >> 2) { + d->m_GestureAlreadyTriggered = false; + return CancelGesture; + } + + if (distance.manhattanLength() >= KTouchGestureDefaults::minDistanceForSwipe && + (now - d->m_TouchBeginnTimestamp ) <= KTouchGestureDefaults::maxTimeFrameForSwipe && !d->m_GestureAlreadyTriggered ) { + d->setAngle(kOneAndTwoFingerSwipe, touchEvent->touchPoints().first()); + d->m_GestureAlreadyTriggered = true; + return FinishGesture; + } + break; + } + + default: + return Ignore; + } + return Ignore; +} + +KOneAndTwoFingerSwipe::KOneAndTwoFingerSwipe (QObject* parent) + : QGesture(parent) + , d (new KOneAndTwoFingerSwipePrivate) +{ + d->q = this; +} + +KOneAndTwoFingerSwipe::~KOneAndTwoFingerSwipe() +{ + delete d; +} + + +QPointF KOneAndTwoFingerSwipe::pos() const +{ + return d->m_pos; +} + +void KOneAndTwoFingerSwipe::setPos(QPointF _pos) +{ + d->m_pos = _pos; +} + +QPointF KOneAndTwoFingerSwipe::screenPos() const +{ + return d->m_screenPos; +} + +void KOneAndTwoFingerSwipe::setScreenPos(QPointF _screenPos) +{ + d->m_screenPos = _screenPos; +} + +QPointF KOneAndTwoFingerSwipe::scenePos() const +{ + return d->m_scenePos; +} + +void KOneAndTwoFingerSwipe::setScenePos(QPointF _scenePos) +{ + d->m_scenePos = _scenePos; +} + +qreal KOneAndTwoFingerSwipe::swipeAngle() const +{ + return d->m_swipeAngle; +} + void KOneAndTwoFingerSwipe::setSwipeAngle(qreal _swipeAngle) +{ + d->m_swipeAngle = _swipeAngle; +} + diff --git a/src/konefingerpan.h b/src/konefingerpan.h new file mode 100644 --- /dev/null +++ b/src/konefingerpan.h @@ -0,0 +1,68 @@ +/* + * KTouchGesture is a library for gestures and touch handling + * Copyright (C) 2019 Steffen Hartleib + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#ifndef KONEFINGERPAN_H +#define KONEFINGERPAN_H + +#include +// Qt +#include +#include + +// KDE + +// Local + +class KWIDGETSADDONS_EXPORT KOneFingerPan : public QGesture +{ + Q_OBJECT + Q_PROPERTY(QPointF delta READ delta WRITE setDelta) + Q_PROPERTY(QPointF pos READ pos WRITE setPos) + Q_PROPERTY(QPointF screenPos READ screenPos WRITE setScreenPos) + Q_PROPERTY(QPointF scenePos READ scenePos WRITE setScenePos) + +public: + explicit KOneFingerPan(QObject* parent = nullptr); + ~KOneFingerPan(); + QPointF delta() const; + void setDelta(QPointF delta); + QPointF pos() const; + void setPos(QPointF pos); + QPointF screenPos() const; + void setScreenPos(QPointF screenPos); + QPointF scenePos() const; + void setScenePos(QPointF scenePos); +private: + class KOneFingerPanPrivate* const d; +}; + +class KWIDGETSADDONS_EXPORT KOneFingerPanRecognizer : public QGestureRecognizer +{ +public: + explicit KOneFingerPanRecognizer(); + ~KOneFingerPanRecognizer(); + QGesture* create(QObject*) override; + Result recognize(QGesture*, QObject*, QEvent*) override; +private: + Q_DISABLE_COPY (KOneFingerPanRecognizer) + class KOneFingerPanRecognizerPrivate* const d; +}; + +#endif /* KONEFINGERPAN_H */ + + diff --git a/src/konefingerpan.cpp b/src/konefingerpan.cpp new file mode 100644 --- /dev/null +++ b/src/konefingerpan.cpp @@ -0,0 +1,190 @@ +/* + * KTouchGesture is a library for gestures and touch handling + * Copyright (C) 2019 Steffen Hartleib + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +// Self +#include "konefingerpan.h" + +// Qt +#include +#include + +// KDE + +// Local +#include "ktouchgesture_helper.h" + +class KOneFingerPanPrivate +{ +public: + KOneFingerPanPrivate() + { + } + ~KOneFingerPanPrivate() + { + } + KOneFingerPan* q; + QPointF m_pos; + QPointF m_screenPos; + QPointF m_scenePos; + QPointF m_delta; +}; + +class KOneFingerPanRecognizerPrivate +{ +public: + KOneFingerPanRecognizerPrivate() + { + } + ~KOneFingerPanRecognizerPrivate() + { + } + void setGesturePositions (KOneFingerPan* const gesture, QTouchEvent::TouchPoint tp) + { + gesture->setHotSpot(tp.startScreenPos()); + gesture->setPos(tp.startPos()); + gesture->setScreenPos(tp.startScreenPos()); + gesture->setScenePos(tp.startScenePos()); + } + KOneFingerPanRecognizer* q; + bool m_TargetIsGrapicsWidget = false; + bool m_GestureTriggered; + bool m_GestureAlreadyCanceld; +}; + +KOneFingerPanRecognizer::KOneFingerPanRecognizer() : QGestureRecognizer() + , d (new KOneFingerPanRecognizerPrivate) +{ + d->q = this; +} + +KOneFingerPanRecognizer::~KOneFingerPanRecognizer() +{ + delete d; +} + +QGesture* KOneFingerPanRecognizer::create(QObject*) +{ + return static_cast(new KOneFingerPan()); +} + +QGestureRecognizer::Result KOneFingerPanRecognizer::recognize(QGesture* gesture, QObject* watched, QEvent* event) +{ + //Because of a bug in Qt in a gesture event in a graphicsview, all gestures are trigger twice + //https://bugreports.qt.io/browse/QTBUG-13103 + if (qobject_cast(watched)) d->m_TargetIsGrapicsWidget = true; + if (d->m_TargetIsGrapicsWidget && watched->isWidgetType()) return Ignore; + + KOneFingerPan* const kOneFingerPan = static_cast(gesture); + const QTouchEvent* touchEvent = static_cast(event); + + switch (event->type()) { + case QEvent::TouchBegin: { + d->m_GestureTriggered = false; + d->m_GestureAlreadyCanceld = false; + d->setGesturePositions(kOneFingerPan, touchEvent->touchPoints().first()); + return MayBeGesture; + } + + case QEvent::TouchUpdate: { + const QPointF pos = touchEvent->touchPoints().first().pos(); + d->setGesturePositions(kOneFingerPan, touchEvent->touchPoints().first()); + if (touchEvent->touchPoints().size() >> 1) { + if (d->m_GestureTriggered) { + d->m_GestureTriggered = false; + } + d->m_GestureAlreadyCanceld = true; + return CancelGesture; + } + + if (touchEvent->touchPoints().size() == 1 && !d->m_GestureAlreadyCanceld ) { + const QPointF diff = (pos - touchEvent->touchPoints().first().lastPos()); + kOneFingerPan->setDelta(diff); + d->m_GestureTriggered = true; + return TriggerGesture; + } + break; + } + + case QEvent::TouchEnd: { + if (d->m_GestureTriggered && !d->m_GestureAlreadyCanceld) { + d->m_GestureTriggered = false; + d->setGesturePositions(kOneFingerPan, touchEvent->touchPoints().first()); + return FinishGesture; + } + break; + } + + default: + return Ignore; + } + return Ignore; +} + +KOneFingerPan::KOneFingerPan(QObject* parent) + : QGesture(parent) + , d (new KOneFingerPanPrivate) +{ + d->q = this; +} + +KOneFingerPan::~KOneFingerPan() +{ + delete d; +} + +QPointF KOneFingerPan::pos() const +{ + return d->m_pos; +} + +void KOneFingerPan::setPos(QPointF _pos) +{ + d->m_pos = _pos; +} + +QPointF KOneFingerPan::screenPos() const +{ + return d->m_screenPos; +} + +void KOneFingerPan::setScreenPos(QPointF _screenPos) +{ + d->m_screenPos = _screenPos; +} + +QPointF KOneFingerPan::scenePos() const +{ + return d->m_scenePos; +} + +void KOneFingerPan::setScenePos(QPointF _scenePos) +{ + d->m_scenePos = _scenePos; +} + +QPointF KOneFingerPan::delta() const +{ + return d->m_delta; +} + +void KOneFingerPan::setDelta(QPointF _delta) +{ + d->m_delta = _delta; +} + + diff --git a/src/ktapholdandmoving.h b/src/ktapholdandmoving.h new file mode 100644 --- /dev/null +++ b/src/ktapholdandmoving.h @@ -0,0 +1,64 @@ +/* + * KTouchGesture is a library for gestures and touch handling + * Copyright (C) 2019 Steffen Hartleib + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#ifndef KTAPHOLDANDMOVING_H +#define KTAPHOLDANDMOVING_H + +#include +// Qt +#include +#include + +// KDE + +// Local + +class KWIDGETSADDONS_EXPORT KTapHoldAndMoving : public QGesture +{ + Q_OBJECT + Q_PROPERTY(QPointF pos READ pos WRITE setPos) + Q_PROPERTY(QPointF screenPos READ screenPos WRITE setScreenPos) + Q_PROPERTY(QPointF scenePos READ scenePos WRITE setScenePos) +public: + explicit KTapHoldAndMoving(QObject* parent = nullptr); + ~KTapHoldAndMoving(); + QPointF pos() const; + void setPos(QPointF pos); + QPointF screenPos() const; + void setScreenPos(QPointF screenPos); + QPointF scenePos() const; + void setScenePos(QPointF scenePos); +private: + class KTapHoldAndMovingPrivate* const d; +}; + +class KWIDGETSADDONS_EXPORT KTapHoldAndMovingRecognizer : public QGestureRecognizer +{ +public: + explicit KTapHoldAndMovingRecognizer(); + ~KTapHoldAndMovingRecognizer(); + QGesture* create(QObject*) override; + Result recognize(QGesture*, QObject*, QEvent*) override; + +private: + Q_DISABLE_COPY(KTapHoldAndMovingRecognizer) + class KTapHoldAndMovingRecognizerPrivate* const d; +}; + +#endif /* KTAPHOLDANDMOVING_H */ + diff --git a/src/ktapholdandmoving.cpp b/src/ktapholdandmoving.cpp new file mode 100644 --- /dev/null +++ b/src/ktapholdandmoving.cpp @@ -0,0 +1,197 @@ +/* + * KTouchGesture is a library for gestures and touch handling + * Copyright (C) 2019 Steffen Hartleib + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +// Self +#include "ktapholdandmoving.h" + +// Qt +#include +#include + +// KDE + +// Local +#include "ktouchgesture_helper.h" + +class KTapHoldAndMovingPrivate +{ +public: + KTapHoldAndMovingPrivate() + { + } + ~KTapHoldAndMovingPrivate() + { + } + KTapHoldAndMoving* q; + QPointF m_pos; + QPointF m_screenPos; + QPointF m_scenePos; +}; + +class KTapHoldAndMovingRecognizerPrivate +{ +public: + KTapHoldAndMovingRecognizerPrivate() + { + } + ~KTapHoldAndMovingRecognizerPrivate() + { + } + void setGesturePositions (KTapHoldAndMoving* const gesture, QTouchEvent::TouchPoint tp) + { + gesture->setHotSpot(tp.startScreenPos()); + gesture->setPos(tp.startPos()); + gesture->setScreenPos(tp.startScreenPos()); + gesture->setScenePos(tp.startScenePos()); + } + bool isTouchStationary (const QTouchEvent* touchEvent) + { + const QPointF distance = touchEvent->touchPoints().first().startPos() - touchEvent->touchPoints().first().pos(); + if (distance.manhattanLength() <= KTouchGestureDefaults::wiggleRoomForTap) { + return true; + } + return false; + } + KTapHoldAndMovingRecognizer* q; + bool m_TargetIsGrapicsWidget = false; + qint64 m_TouchBeginnTimestamp; + bool m_TouchPointStationary; + bool m_GestureTriggered; + Qt::GestureState m_LastGestureState = Qt::NoGesture; +}; + +KTapHoldAndMovingRecognizer::KTapHoldAndMovingRecognizer() + : QGestureRecognizer() + , d (new KTapHoldAndMovingRecognizerPrivate) +{ + d->q = this; +} + +KTapHoldAndMovingRecognizer::~KTapHoldAndMovingRecognizer() +{ + delete d; +} + +QGesture* KTapHoldAndMovingRecognizer::create(QObject*) +{ + return static_cast(new KTapHoldAndMoving()); +} + +QGestureRecognizer::Result KTapHoldAndMovingRecognizer::recognize(QGesture* gesture, QObject* watched, QEvent* event) +{ + //Because of a bug in Qt in a gesture event in a graphicsview, all gestures are trigger twice + //https://bugreports.qt.io/browse/QTBUG-13103 + if (qobject_cast(watched)) d->m_TargetIsGrapicsWidget = true; + if (d->m_TargetIsGrapicsWidget && watched->isWidgetType()) return Ignore; + + KTapHoldAndMoving* const kTapHoldAndMoving = static_cast(gesture); + const QTouchEvent* touchEvent = static_cast(event); + + switch (event->type()) { + case QEvent::TouchBegin: { + d->m_TouchBeginnTimestamp = touchEvent->timestamp(); + d->m_GestureTriggered = false; + d->m_TouchPointStationary = true; + d->setGesturePositions(kTapHoldAndMoving, touchEvent->touchPoints().first()); + d->m_LastGestureState = Qt::NoGesture; + return MayBeGesture; + } + + case QEvent::TouchUpdate: { + const qint64 now = touchEvent->timestamp(); + d->setGesturePositions(kTapHoldAndMoving, touchEvent->touchPoints().first()); + + if (touchEvent->touchPoints().size() >> 1) { + d->m_GestureTriggered = false; + d->m_LastGestureState = Qt::GestureCanceled; + return CancelGesture; + } + + if (touchEvent->touchPoints().size() == 1 && d->m_LastGestureState != Qt::GestureCanceled) { + if (!d->m_GestureTriggered && + d->m_TouchPointStationary && + now - d->m_TouchBeginnTimestamp >= KTouchGestureDefaults::durationForTapHold) { + d->m_GestureTriggered = true; + } + } + d->m_TouchPointStationary = d->isTouchStationary(touchEvent); + + if (d->m_GestureTriggered && d->m_LastGestureState != Qt::GestureCanceled) { + d->m_LastGestureState = Qt::GestureStarted; + return TriggerGesture; + } + break; + } + + case QEvent::TouchEnd: { + d->setGesturePositions(kTapHoldAndMoving, touchEvent->touchPoints().first()); + + if (d->m_GestureTriggered) { + d->m_LastGestureState = Qt::GestureFinished; + return FinishGesture; + } + break; + } + default: + return Ignore; + } + return Ignore; +} + +KTapHoldAndMoving::KTapHoldAndMoving(QObject* parent) + : QGesture(parent) + , d (new KTapHoldAndMovingPrivate) +{ + d->q = this; +} + +KTapHoldAndMoving::~KTapHoldAndMoving() +{ + delete d; +} + +QPointF KTapHoldAndMoving::pos() const +{ + return d->m_pos; +} + +void KTapHoldAndMoving::setPos(QPointF _pos) +{ + d->m_pos = _pos; +} + +QPointF KTapHoldAndMoving::screenPos() const +{ + return d->m_screenPos; +} + +void KTapHoldAndMoving::setScreenPos(QPointF _screenPos) +{ + d->m_screenPos = _screenPos; +} + +QPointF KTapHoldAndMoving::scenePos() const +{ + return d->m_scenePos; +} + +void KTapHoldAndMoving::setScenePos(QPointF _scenePos) +{ + d->m_scenePos = _scenePos; +} + diff --git a/src/ktouchgesture.h b/src/ktouchgesture.h new file mode 100644 --- /dev/null +++ b/src/ktouchgesture.h @@ -0,0 +1,445 @@ +/* + * KTouchGesture is a library for gestures and touch handling + * Copyright (C) 2019 Steffen Hartleib + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef KTOUCHGESTURE_H +#define KTOUCHGESTURE_H + +#include + +#include + +class QGestureEvent; + +/** +* \struct KTouchGestureData ktouchgesture.h KTouchGesture +* +* @brief contains information about a gesture event +* +* this struct contains information for a gesture event +* if a gesture doesn't support a specific information the value is nullptr or QPointF(-1,-1) +* if a gesture don't support centerPos the centerPos is equal to pos or hotSpot +*/ +struct KWIDGETSADDONS_EXPORT KTouchGestureData +{ + QPointF pos = QPointF (-1, -1); /**< position for the gesture,relative to the widget or QGraphicsItem*/ + QPointF centerPos = QPointF (-1, -1);/**< center point in screen coordinates*/ + QPointF screenPos = QPointF (-1, -1);/**< screen position for the gesture*/ + QPointF scenePos = QPointF (-1, -1); /**< scene position for the gesture*/ + QPointF hotSpot = QPointF (-1, -1); /**< position of the hot spot for the gesture*/ + QWidget* widgetEvent = nullptr; /**< widget on which the gesture occurred, but only in QGraphicsObjects*/ + QObject* objectEvent = nullptr; /**< QObject on which the gesture occurred*/ + qreal rotationsAngle = 0; /**< the angle covered by the gesture motion, see Qt:PinchGesture*/ + qreal totalRotationsAngle = 0; /**< the total angle covered by the gesture motion, see Qt:PinchGesture*/ + qreal scaleFactor = 0; /**< current scale factor, see Qt:PinchGesture*/ + qreal totalScaleFactor = 0; /**< the total scale factor, see Qt::PinchGesture*/ + QPointF delta = QPointF (-1, -1); /**< the difference between the current and last position*/ + qreal swipeAngel = 0; /**< the angle of the motion associated with the gesture*/ + Qt::GestureState state; /**< the current state of the gesture*/ +}; + + +/** +* @class KTouchGesture ktouchgesture.h KTouchGesture +* +* @brief a class for handling of touch and gesture events +* +*KTouchGesture is a class for handling of touch and gesture events, this class support all Qt gestures (TapGesture, TapAndHoldGesture, PinchGesture, SwipeGesture and PanGesture) and following own gestures: +* - TapHoldAndMoving (a one finger tap gesture, which is moving after a waiting time) +* - oneFingerPan (a one finger pan gesture) +* - twoFingerPan (a two finger pan gesture) +* - onAndTwoFingerSwipe (a swipe gesture with one or two fingers) +* - twoFingerTap (a two finger tap gesture) +* - doupleTap (two successive fast taps gestures) +* +*This class is watching over the gesture events and send corresponding signals. In with a case this class is sending a signal is depending of an attribute which is set with setGestureSignals(). Furthermore, two rules control the sending of signals (see setRulesTriggerIfNotActive() and setRulesTriggerIfNotFinish()). +* +*/ +class KWIDGETSADDONS_EXPORT KTouchGesture : public QObject +{ + Q_OBJECT +public: + ~KTouchGesture(); + + /** + * @enum TouchSignalFlags + * + * @brief define in which cases a touch event should trigger a signal + * + * see setTouchSignalFlags() and getTouchSignalFlags() + * the signals are touchBeginnTriggered(), touchUpdateTriggered(), touchEndTriggered() + * + * The KTouchSignals type is a typedef for QFlags. It stores an OR combination of TouchSignalFlags values. + */ + enum TouchSignalFlags { + NoSignal = 0x0, /**< no signal will triggered*/ + TouchBeginn = 0x1, /**< a signal will trigger at QEvent::TouchBegin*/ + TouchUpdate = 0x2, /**< a signal will trigger at QEvent::TouchUpdate*/ + TouchEnd = 0x4, /**< a signal will trigger at QEvent::TouchEnd*/ + AllTouchSignals = 0x7 /**< a signal will trigger at every touch events*/ + }; + Q_DECLARE_FLAGS(KTouchSignals, TouchSignalFlags) + + /** + * @enum GestureTypeFlags + * + * @brief define which gesture KTouchGesture will handle + * + * The KGestureType type is a typedef for QFlags. It stores an OR combination of GestureTypeFlags values. + */ + enum GestureTypeFlags { + NoGesture = 0x0, /**< handle no gesture*/ + TapGesture = 0x1, /**< Qt::TapGesture*/ + TapAndHoldGesture = 0x2, /**< Qt::TabAndHoldGesture*/ + PanGesture = 0x4, /**< Qt::PanGesture*/ + PinchGesture = 0x8, /**< Qt::PinchGesture*/ + SwipeGesture = 0x10, /**< Qt::SwipeGesture*/ + TwoFingerTap = 0x20, /**< a two finger tap gesture*/ + TwoFingerPan = 0x40, /**< a two finger pan gesture*/ + TapHoldAndMoving = 0x80, /**< a one finger tap hold and moving gesture*/ + OneAndTwoFingerSwipe= 0x100, /**< a one and two finger swipe gesture*/ + DoubleTap = 0x200, /**< a one finger double tap gesture*/ + OneFingerPan = 0x400, /**< a one finger pan gesture*/ + AllGesture = 0x7FF, /**< handle all gestures*/ + }; + Q_DECLARE_FLAGS(KGestureType, GestureTypeFlags) + + /** + * @enum GestureSignalFlags + * + * @brief define in which cases a gesture event should trigger a signal + * + * The KGestureSignals type is a typedef for QFlags. It stores an OR combination of GestureSignalFlags values. + */ + enum GestureSignalFlags { + NoGestureSignal = 0x0, /**< no signal will triggered*/ + GestureStarted = 0x1, /**< a signal will trigger at QGesture::GestureStarted*/ + GestureUpdated = 0x2, /**< a signal will trigger at QGesture::GestureUpdated*/ + GestureFinished = 0x4, /**< a signal will trigger at QGesture::GestureFinished*/ + GestureCanceled = 0x8, /**< a signal will trigger at QGesture::GestureCanceled*/ + AllGestureSignals = 0xF /**< a signal will trigger at every gesture events*/ + }; + Q_DECLARE_FLAGS(KGestureSignals, GestureSignalFlags) + + /** + * @brief returns true if target support gestures / touch events + * + * @return true if target support gestures and touch events + */ + bool isTouchTargetValid (); + + /** + * @brief set which touch events triggered a signal + * + * the signals are touchBeginnTriggered(), touchUpdateTriggered(), touchEndTriggered() + * + * @param s: a flag contains a OR combination of TouchSignalFlags + */ + void setTouchSignalFlags(const KTouchSignals s); + + /** + * @brief return the current touch signals + * + * @return QFlags KTouchGesture::KTouchSignals witch contains a OR combination of TouchSignalFlags + */ + KTouchSignals getTouchSignalFlags(); + + /** + * @brief set which gesture events triggered a signal + * + * see also setGestureSignals() + * + * @param gType define the gesture to set the signal flag + * @param gSignals a flag contains the gesture signals + */ + void setGestureSignals(const KGestureType gType, const KGestureSignals gSignals); + + /** + * @brief return the current gesture signals for the gesture @p gType + * + * see also setGestureSignals() + * + * @param gType the gesture + * @return KTouchGesture::KGestureSignals + */ + KGestureSignals getGestureSignals (const KGestureType gType); + + /** + * @brief define the active gesture, which block the trigger of the gesture @p gType + * + * exception is the GestureStarted signal, which will trigger every time. + * + * @param gType: the gesture for which to set the rules + * @param gBlock: a flag contains the gestures which block the trigger + */ + void setRulesTriggerIfNotActiv (const KGestureType gType, const KGestureType gBlock); + + /** + * @brief define the finished gesture, which block the trigger of the gesture @p gType + * + * exception is the GestureStarted signal, which will trigger every time. + * @param gType: the gesture for which to set the rules + * @param gBlock: a flag contains the gestures which block the trigger + */ + void setRulesTriggerIfNotFinish (const KGestureType gType, const KGestureType gBlock); + + /** + * @brief return the gestures, which block the trigger of gesture @p gType + * + * @param gType: the gesture for the rules + * @return KTouchGesture::KGestureType + */ + KGestureType getRulesTriggerIfNotActiv (const KGestureType gType); + + /** + * @brief return the gestures, which block the trigger of gesture @p gType + * + * @param gType: the gesture for the rules + * @return KTouchGesture::KGestureType + */ + KGestureType getRulesTriggerIfNotFinish (const KGestureType gType); + + /** + * @brief set the default rules for the gesture @p gType + * + * @param gType: the gesture + */ + void setGestureDefaultRules (const KGestureType gType); + + /** + * @brief Helper function to simulate a mouse button release event at @p point in @p obj + * + * @param point local position + * @param obj object for mouse event + */ + void touchToMouseRelease(QPoint point, QObject* obj); + + /** + * @brief Helper function to simulate a mouse move to @p point in @p obj + * + * @param point local position + * @param obj object for mouse event + * @param button mouse buttons for mouse event + */ + void touchToMouseMove(QPoint point, QObject* obj, Qt::MouseButton button); + + /** + * @brief Helper function to simulate a mouse click at @p point in @p obj + * + * @param point local position + * @param obj object for mouse event + */ + void touchToMouseClick(QPoint point, QObject* obj); + + /** + * @brief if @p b is true, KTouchGesture will handle touchBeginn events + * + * Qt synthetisiert a mouse click from unhandled touch events, to suppress this KTouchGesture need to handle the touch events, but + * if the user want to get TouchBeginn events (or want Qt synthetisiert mouse clicks), KTouchGesture should not handle touch events + * Attention if @p b is set to false you will not get TouchUpdate and TouchEnd signals + * @param b true if KTouchGesture should handle TouchBeginn events + */ + void setHandleTouchEvents (bool b); + + /** + * @brief get the current touchBegin event handling + * + * @see setHandleTouchEvents + * @return bool true if KTouchGesture handle TouchBeginn events + */ + bool getHandleTouchEvents (); + + /** + * @brief Constructor + * + * @param obj a QWidget or a QGraphicsObjects as target for the gestures + * @param t which gestures should KTouchGesture handle, a OR combination of GestureTypeFlags + */ + KTouchGesture(QObject* obj,const KGestureType t= NoGesture); + +public Q_SLOTS: + +Q_SIGNALS: + /** + * @brief this signal is triggered if a TouchBeginn event occurred + * + * KTouchGesture will send this signal if a TouchBeginn event occurred and the #TouchSignalFlags is set to TouchBeginn + * + * @param tpoints a QList wich contains the TouchPoints + * @param timestamp the time stamp of the event + */ + void touchBeginnTriggered (const QList& tpoints, qreal timestamp); + + /** + * @brief this signal is triggered if a TouchUpdate event occurred + * + * KTouchGesture will send this signal if a TouchUpdate event occurred and the #TouchSignalFlags is set to TouchUpdate + * + * @param tpoints a QList wich contains the TouchPoints + * @param timestamp the time stamp of the event + */ + void touchUpdateTriggered (const QList& tpoints, qreal timestamp); + + /** + * @brief this signal is triggered if a TouchEnd event occurred + * + * KTouchGesture will send this signal if a TouchEnd event occurred and the #TouchSignalFlags is set to TouchEnd + * + * @param tpoints a QList wich contains the TouchPoints + * @param timestamp the time stamp of the event + */ + void touchEndTriggered (const QList& tpoints, qreal timestamp); + + /** + * @brief this signal is triggered if a TapGesture event occurred + * + * the sending of this signals is depending of a attribute, see setGestureSignals() and depending of the + * rules see setRulesTriggerIfNotActiv() and setRulesTriggerIfNotFinish(). + * + * @param data contains parameters of the gesture event + */ + void tapTriggered (const KTouchGestureData& data); + + /** + * @brief this signal is triggered if a TapAndHoldGesture event occurred + * + * the sending of this signals is depending of a attribute, see setGestureSignals() and depending of the + * rules see setRulesTriggerIfNotActiv() and setRulesTriggerIfNotFinish(). + * + * @param data contains parameters of the gesture event + */ + void tapAndHoldTriggered (const KTouchGestureData& data); + + /** + * @brief this signal is triggered if a PinchGesture event occurred + * + * the sending of this signals is depending of a attribute, see setGestureSignals() and depending of the + * rules see setRulesTriggerIfNotActiv() and setRulesTriggerIfNotFinish(). + * + * @param data contains parameters of the gesture event + */ + void pinchTriggered (const KTouchGestureData& data); + + /** + * @brief this signal is triggered if a PanGesture event occurred + * + * the sending of this signals is depending of a attribute, see setGestureSignals() and depending of the + * rules see setRulesTriggerIfNotActiv() and setRulesTriggerIfNotFinish(). + * + * @param data contains parameters of the gesture event + */ + void panTriggered (const KTouchGestureData& data); + + /** + * @brief this signal is triggered if a SwipeGesture event occurred + * + * the sending of this signals is depending of a attribute, see setGestureSignals() and depending of the + * rules see setRulesTriggerIfNotActiv() and setRulesTriggerIfNotFinish(). + * + * @param data contains parameters of the gesture event + */ + void swipeTriggered (const KTouchGestureData& data); + + /** + * @brief this signal is triggered if a DoubleTapGesture event occurred + * + * the sending of this signals is depending of a attribute, see setGestureSignals() and depending of the + * rules see setRulesTriggerIfNotActiv() and setRulesTriggerIfNotFinish(). + * + * @param data contains parameters of the gesture event + */ + void doubleTapTriggered (const KTouchGestureData& data); + + /** + * @brief this signal is triggered if a TwoFingerTapGesture event occurred + * + * the sending of this signals is depending of a attribute, see setGestureSignals() and depending of the + * rules see setRulesTriggerIfNotActiv() and setRulesTriggerIfNotFinish(). + * + * @param data contains parameters of the gesture event + */ + void twoFingerTapTriggered (const KTouchGestureData& data); + + /** + * @brief this signal is triggered if a TapHoldAndMovingGesture event occurred + * + * the sending of this signals is depending of a attribute, see setGestureSignals() and depending of the + * rules see setRulesTriggerIfNotActiv() and setRulesTriggerIfNotFinish(). + * + * @param data contains parameters of the gesture event + */ + void tapHoldAndMovingTriggered (const KTouchGestureData& data); + + /** + * @brief this signal is triggered if a OneAndTwoFingerSwipeGesture event occurred + * + * the sending of this signals is depending of a attribute, see setGestureSignals() and depending of the + * rules see setRulesTriggerIfNotActiv() and setRulesTriggerIfNotFinish(). + * + * @param data contains parameters of the gesture event + */ + void oneAndTwoFingerSwipeTriggered (const KTouchGestureData& data); + + /** + * @brief this signal is triggered if a TwoFingerPanGesture event occurred + * + * the sending of this signals is depending of a attribute, see setGestureSignals() and depending of the + * rules see setRulesTriggerIfNotActiv() and setRulesTriggerIfNotFinish(). + * + * @param data contains parameters of the gesture event + */ + void twoFingerPanTriggered (const KTouchGestureData& data); + + /** + * @brief this signal is triggered if a OneFingerPanGesture event occurred + * + * the sending of this signals is depending of a attribute, see setGestureSignals() and depending of the + * rules see setRulesTriggerIfNotActiv() and setRulesTriggerIfNotFinish(). + * + * @param data contains parameters of the gesture event + */ + void oneFingerPanTriggered (const KTouchGestureData& data); + +protected: + bool eventFilter (QObject* watched, QEvent* event) override; + +private: + class KTouchGesturePrivate* const d; + + void checkTapGesture (QGestureEvent*, QObject*); + void checkTapAndHoldGesture (QGestureEvent*, QObject*); + void checkPinchGesture (QGestureEvent*, QObject*); + void checkPanGesture (QGestureEvent*, QObject*); + void checkSwipeGesture (QGestureEvent*, QObject*); + void checkDoubleTapGesture (QGestureEvent*, QObject*); + void checkTwoFingerTapGesture (QGestureEvent*, QObject*); + void checkTapHoldAndMovingGesture (QGestureEvent*, QObject*); + void checkOneAndTwoFingerSwipeGesture (QGestureEvent*, QObject*); + void checkTwoFingerPanGesture (QGestureEvent*, QObject*); + void checkOneFingerPanGesture (QGestureEvent*, QObject*); + void gestureEvent (QGestureEvent* event, QObject* obj); +}; +Q_DECLARE_OPERATORS_FOR_FLAGS(KTouchGesture::KTouchSignals) +Q_DECLARE_OPERATORS_FOR_FLAGS(KTouchGesture::KGestureType) +Q_DECLARE_OPERATORS_FOR_FLAGS(KTouchGesture::KGestureSignals) + +Q_DECLARE_METATYPE(KTouchGesture::GestureTypeFlags) +Q_DECLARE_METATYPE(KTouchGesture::TouchSignalFlags) +Q_DECLARE_METATYPE(KTouchGestureData) + +#endif // KTOUCHGESTURE_H diff --git a/src/ktouchgesture.cpp b/src/ktouchgesture.cpp new file mode 100644 --- /dev/null +++ b/src/ktouchgesture.cpp @@ -0,0 +1,1058 @@ +/* + * KTouchGesture is a library for gestures and touch handling + * Copyright (C) 2019 Steffen Hartleib + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "ktouchgesture.h" + +#include +#include +#include +#include + +#include "kdoubletap.h" +#include "ktwofingertap.h" +#include "ktapholdandmoving.h" +#include "koneandtwofingerswipe.h" +#include "ktwofingerpan.h" +#include "konefingerpan.h" + +class KTouchGesturePrivate +{ +public: + KTouchGesturePrivate() + { + } + ~KTouchGesturePrivate() + { + } + struct GestureAttribute { + KTouchGesture::KGestureSignals mGestureSignals; + Qt::GestureType mQtType; + + KTouchGesture::KGestureType mOnlyTriggerIfGestureNotActive = KTouchGesture::NoGesture; // only trigger gesture if the following gestures are not active (status finish, cancel or no gesture), exception gestures status is started + KTouchGesture::KGestureType mOnlyTriggerIfGestureNotFinished = KTouchGesture::NoGesture; // only trigger gesture if the following gestures are not finished, exception gestures status is started + + Qt::GestureState mLastGestureState = Qt::NoGesture; //save GestureState for tracking which gesture was active + QPointF mLastHotSpot; //save hotSpot in combination with mLastGestureState used to identify + //dublicate gesture event for Qt gestures + qreal mLastFactor; + QPointF mLastStartedHotSpot = QPointF (0, 0); + QPointF mLastUpdateHotSpot = QPointF (0, 0); + QPointF mLastFinishedHotSpot = QPointF (0, 0); + QPointF mLastCanceledHotSpot = QPointF (0, 0); +}; + void fillKGestureData(const QGesture* gesture, QObject* obj, QWidget* widget, KTouchGestureData* data) + { + //fill KTouchGestureData struct with default values + //gesture spezific values are set after call of this function + fillKGestureDataBase( gesture-> state(), obj, widget, data); + data->pos = gesture->property("pos").toPointF(); + data->centerPos = data->pos; + data->screenPos = gesture->property("screenPos").toPointF(); + data->scenePos = gesture->property("scenePos").toPointF(); + data->hotSpot = data->screenPos; + } + void fillKGestureDataBase(Qt::GestureState state, QObject* obj, QWidget* widget, KTouchGestureData* data) + { + data->widgetEvent = widget; + data->objectEvent = obj; + data->scaleFactor = 0; + data->totalScaleFactor = 0; + data->rotationsAngle = 0; + data->totalRotationsAngle = 0; + data->delta = QPointF (0, 0); + data->swipeAngel = 0; + data->state = state; + } + bool checkActivty(Qt::GestureState state) + { + if (state == Qt::GestureFinished || state == Qt::GestureCanceled || state == Qt::NoGesture) { + return false; + } + return true; + } + bool isGestureActive(const KTouchGesture::KGestureType type) + { + //Check activity state for gestures in type + if (!type) { + return false; + } + if (type & q->TapGesture) { + return checkActivty(TapGestureAttribute.mLastGestureState); + } + if (type & q->PinchGesture) { + return checkActivty(PinchGestureAttribute.mLastGestureState); + } + if (type & q->PanGesture) { + return checkActivty(PanGestureAttribute.mLastGestureState); + } + if (type & q->SwipeGesture) { + return checkActivty(SwipeGestureAttribute.mLastGestureState); + } + if (type & q->TapAndHoldGesture) { + return checkActivty(TapAndHoldGestureAttribute.mLastGestureState); + } + if (type & q->OneFingerPan) { + return checkActivty(OneFingerPanAttribute.mLastGestureState); + } + if (type & q->OneAndTwoFingerSwipe) { + return checkActivty(OneAndTwoFingerSwipeAttribute.mLastGestureState); + } + if (type & q->TwoFingerPan) { + return checkActivty(TwoFingerPanAttribute.mLastGestureState); + } + if (type & q->TapHoldAndMoving) { + return checkActivty(TapHoldAndMovingAttribute.mLastGestureState); + } + if (type & q->TwoFingerTap) { + return checkActivty(TwoFingerTapAttribute.mLastGestureState); + } + if (type & q->DoubleTap) { + return checkActivty(DoubleTapAttribute.mLastGestureState); + } + return false; + } + bool sendSignalKGestureTriggered(Qt::GestureState state, KTouchGesture::KGestureSignals signals) + { + if (state == Qt::GestureStarted && signals & q->GestureStarted) { + return true; + } + + if (state == Qt::GestureUpdated && signals & q->GestureUpdated) { + return true; + } + + if (state == Qt::GestureCanceled && signals & q->GestureCanceled) { + return true; + } + + if (state == Qt::GestureFinished && signals & q->GestureFinished) { + return true; + } + return false; + } + bool triggerGestureAllowed(GestureAttribute* gAttribute) + { + //check if other gesture, define in gesture attribute mOnlyTriggerIfGestureNotActive active + if (isGestureActive(gAttribute->mOnlyTriggerIfGestureNotActive) && gAttribute->mLastGestureState != Qt::GestureStarted) { + return false; + } + //check for already finished gesture + if ( mAllFinishedGestures & gAttribute->mOnlyTriggerIfGestureNotFinished && gAttribute->mLastGestureState != Qt::GestureStarted) { + return false; + } + return true; + } + bool handleGesture(Qt::GestureState state, KTouchGesture::KGestureType gTyp, GestureAttribute* gAttribute) + { + //save current gesture state, to track gesture state in KTouchGesture + gAttribute->mLastGestureState = state; + + //set flag d_ptr->mAllFinishedGestures if gesture finished, used for trigger rules + if (state == Qt::GestureFinished) { + mAllFinishedGestures = mAllFinishedGestures | gTyp; + } + + //check trigger rules + if (!triggerGestureAllowed(gAttribute)) { + return false; + } else { + } + + return sendSignalKGestureTriggered(state, gAttribute->mGestureSignals); + } + void fillKGestureDataPos(QGestureEvent* event, QPointF hotSpot, QPointF centerPos, KTouchGestureData* data) + { + const QWidget* widget = qobject_cast(mTouchTarget); + const QGraphicsObject* gwidget = qobject_cast(mTouchTarget); + + if (gwidget) { + data->pos = gwidget->mapFromScene(event->mapToGraphicsScene(hotSpot)); + data->centerPos = centerPos; + data->scenePos = event->mapToGraphicsScene(hotSpot); + data->screenPos = hotSpot; + data->hotSpot = hotSpot; + } else if (widget) { + data->pos = widget->mapFromGlobal(hotSpot.toPoint()); + data->centerPos = centerPos; + data->scenePos = hotSpot; + data->screenPos = hotSpot; + data->hotSpot = hotSpot; + } + } + void setGestureDefaultAttribute(KTouchGesture::KGestureType flags) + { + mGestureType = flags; + if (flags & q->TapGesture) { + TapGestureAttribute.mQtType = Qt::TapGesture; + TapGestureAttribute.mGestureSignals = KTouchGesture::KGestureSignals (q->GestureFinished); + } + if (flags & q->TapAndHoldGesture) { + TapAndHoldGestureAttribute.mQtType = Qt::TapAndHoldGesture; + TapAndHoldGestureAttribute.mGestureSignals = KTouchGesture::KGestureSignals (q->GestureFinished); + } + if (flags & q->PinchGesture) { + PinchGestureAttribute.mQtType = Qt::PinchGesture; + PinchGestureAttribute.mGestureSignals = KTouchGesture::KGestureSignals (q->GestureStarted | q->GestureUpdated); + } + if (flags & q->PanGesture) { + PanGestureAttribute.mQtType = Qt::PanGesture; + PanGestureAttribute.mGestureSignals = KTouchGesture::KGestureSignals (q->GestureStarted | q->GestureUpdated); + } + if (flags & q->SwipeGesture) { + SwipeGestureAttribute.mQtType = Qt::SwipeGesture; + SwipeGestureAttribute.mGestureSignals = KTouchGesture::KGestureSignals (q->GestureFinished); + } + if (flags & q->DoubleTap) { + DoubleTapAttribute.mQtType = Qt::CustomGesture; + DoubleTapAttribute.mGestureSignals = KTouchGesture::KGestureSignals (q->GestureFinished); + } + if (flags & q->TwoFingerTap) { + TwoFingerTapAttribute.mQtType = Qt::CustomGesture; + TwoFingerTapAttribute.mGestureSignals = KTouchGesture::KGestureSignals (q->GestureFinished); + } + if (flags & q->TapHoldAndMoving) { + TapHoldAndMovingAttribute.mQtType = Qt::CustomGesture; + TapHoldAndMovingAttribute.mGestureSignals = KTouchGesture::KGestureSignals (q->GestureFinished | q->GestureStarted | q->GestureUpdated); + } + if (flags & q->OneAndTwoFingerSwipe) { + OneAndTwoFingerSwipeAttribute.mQtType = Qt::CustomGesture; + OneAndTwoFingerSwipeAttribute.mGestureSignals = KTouchGesture::KTouchGesture::KGestureSignals (q->GestureFinished); + } + if (flags & q->TwoFingerPan) { + TwoFingerPanAttribute.mQtType = Qt::CustomGesture; + TwoFingerPanAttribute.mGestureSignals = KTouchGesture::KTouchGesture::KGestureSignals (q->GestureUpdated); + } + if (flags & q->OneFingerPan) { + OneFingerPanAttribute.mQtType = Qt::CustomGesture; + OneFingerPanAttribute.mGestureSignals = KTouchGesture::KGestureSignals (q->GestureUpdated); + } + q->setGestureDefaultRules (flags); + } + bool isDublicateGesture(Qt::GestureState state, QPointF hotSpot, GestureAttribute* gAttribute) + { + if (!mTargetIsGraphicsObject) { + return false; + } + + if (hotSpot != QPointF (-1, -1)) { + if (state == Qt::GestureStarted) { + gAttribute->mLastGestureState = state; + if (gAttribute->mLastStartedHotSpot == hotSpot) { + return true; + } + gAttribute->mLastStartedHotSpot = hotSpot; + return false; + } + if (state == Qt::GestureUpdated) { + gAttribute->mLastGestureState = state; + if (gAttribute->mLastUpdateHotSpot == hotSpot) { + return true; + } + gAttribute->mLastUpdateHotSpot = hotSpot; + return false; + } + if (state == Qt::GestureFinished) { + gAttribute->mLastGestureState = state; + if (gAttribute->mLastFinishedHotSpot == hotSpot) { + return true; + } + gAttribute->mLastFinishedHotSpot = hotSpot; + return false; + } + if (state == Qt::GestureCanceled) { + gAttribute->mLastGestureState = state; + if (gAttribute->mLastCanceledHotSpot == hotSpot) { + return true; + } + gAttribute->mLastCanceledHotSpot = hotSpot; + return false; + } + return false; + } + return false; + } + bool isDublicateGesturePinch(Qt::GestureState state, qreal factor, GestureAttribute* gAttribute) + { + //Every gesture should have only one Qt::GestureStarted, Qt::GestureFinished and Qt::GestureCanceled + //if the gAttribute->mLastGestureState the same as state it is duplicate gesture + if (gAttribute->mLastGestureState == state && state != Qt::GestureUpdated) { + return true; + } + gAttribute->mLastGestureState = state; + + //a gesture can have many Qt::GestureUpdate events, to check for duplicate gesture we need to + //check for equal factor + if (state == Qt::GestureUpdated) { + if (gAttribute->mLastFactor == factor) { + return true; + } + gAttribute->mLastFactor = factor; + return false; + } + return false; + } + void touchToMouseEvent (QPoint pos, QObject* receiver, QEvent::Type type, Qt::MouseButton button, Qt::MouseButtons buttons) + { + QMouseEvent* evt = new QMouseEvent(type, pos, button, buttons, Qt::NoModifier); + QCoreApplication::postEvent(receiver, evt); + } + + KTouchGesture* q = nullptr; + QObject* mTouchTarget = nullptr; + bool mTargetIsGraphicsObject = false; + bool mHandleTouchEvents = true; //set to false if you want handle touch events self + // attention if set to false you will get not touchupdate and touchend signals + KTouchGesture::KTouchSignals mTouchFlags = KTouchGesture::NoSignal; //which touchEvent should trigger a signal + //touchBeginnTriggered, touchUpdateTriggered, touchEndTriggered + KTouchGesture::KGestureType mGestureType; //which gestures should KTouch use + KTouchGesture::KGestureType mAllFinishedGestures = KTouchGesture::NoGesture; //all finished gestures between touchbeginn and touchend + + GestureAttribute TapGestureAttribute; + GestureAttribute TapAndHoldGestureAttribute; + GestureAttribute PinchGestureAttribute; + GestureAttribute PanGestureAttribute; + GestureAttribute SwipeGestureAttribute; + GestureAttribute DoubleTapAttribute; + GestureAttribute OneAndTwoFingerSwipeAttribute; + GestureAttribute TwoFingerTapAttribute; + GestureAttribute TapHoldAndMovingAttribute; + GestureAttribute TwoFingerPanAttribute; + GestureAttribute OneFingerPanAttribute; +}; + +KTouchGesture::KTouchGesture(QObject* touchTarget, const KGestureType type) + : QObject () + , d (new KTouchGesturePrivate) +{ + d->q = this; + d->mTouchTarget = touchTarget; + + if (!isTouchTargetValid()) { + qWarning()<<"Invalid target - Gestures can only be enabled for instances of QWidget and QGraphicsObject"; + return; + } + + d->setGestureDefaultAttribute(type); + + if (QGraphicsObject* GraphicsTarget = qobject_cast(touchTarget)) { + d->mTargetIsGraphicsObject = true; + GraphicsTarget->setAcceptTouchEvents(true); + if ( d->mGestureType & TapGesture) { + GraphicsTarget->grabGesture(Qt::TapGesture); + } + if ( d->mGestureType & TapAndHoldGesture) { + GraphicsTarget->grabGesture(Qt::TapAndHoldGesture); + } + if ( d->mGestureType & PinchGesture) { + GraphicsTarget->grabGesture(Qt::PinchGesture); + } + if ( d->mGestureType & PanGesture) { + GraphicsTarget->grabGesture(Qt::PanGesture); + } + if ( d->mGestureType & SwipeGesture) { + GraphicsTarget->grabGesture(Qt::SwipeGesture); + } + + if ( d->mGestureType & DoubleTap) { + d->DoubleTapAttribute.mQtType = QGestureRecognizer::registerRecognizer(new KDoubleTapRecognizer()); + GraphicsTarget->grabGesture( d->DoubleTapAttribute.mQtType); + } + if ( d->mGestureType & TwoFingerTap) { + d->TwoFingerTapAttribute.mQtType = QGestureRecognizer::registerRecognizer(new KTwoFingerTapRecognizer()); + GraphicsTarget->grabGesture( d->TwoFingerTapAttribute.mQtType); + } + if ( d->mGestureType & TapHoldAndMoving) { + d->TapHoldAndMovingAttribute.mQtType = QGestureRecognizer::registerRecognizer(new KTapHoldAndMovingRecognizer()); + GraphicsTarget->grabGesture( d->TapHoldAndMovingAttribute.mQtType); + } + if ( d->mGestureType & OneAndTwoFingerSwipe) { + d->OneAndTwoFingerSwipeAttribute.mQtType = QGestureRecognizer::registerRecognizer(new KOneAndTwoFingerSwipeRecognizer()); + GraphicsTarget->grabGesture( d->OneAndTwoFingerSwipeAttribute.mQtType); + } + if ( d->mGestureType & TwoFingerPan) { + d->TwoFingerPanAttribute.mQtType = QGestureRecognizer::registerRecognizer(new KTwoFingerPanRecognizer()); + GraphicsTarget->grabGesture( d->TwoFingerPanAttribute.mQtType); + } + if ( d->mGestureType & OneFingerPan) { + d->OneFingerPanAttribute.mQtType = QGestureRecognizer::registerRecognizer(new KOneFingerPanRecognizer()); + GraphicsTarget->grabGesture( d->OneFingerPanAttribute.mQtType); + } + + } else if (QWidget* widgetTarget = qobject_cast(touchTarget)) { + d->mTargetIsGraphicsObject = false; + widgetTarget->setAttribute(Qt::WA_AcceptTouchEvents); + if ( d->mGestureType & TapGesture) { + widgetTarget->grabGesture(Qt::TapGesture); + } + if ( d->mGestureType & TapAndHoldGesture) { + widgetTarget->grabGesture(Qt::TapAndHoldGesture); + } + if ( d->mGestureType & PinchGesture) { + widgetTarget->grabGesture(Qt::PinchGesture); + } + if ( d->mGestureType & PanGesture) { + widgetTarget->grabGesture(Qt::PanGesture); + } + if ( d->mGestureType & SwipeGesture) { + widgetTarget->grabGesture(Qt::SwipeGesture); + } + if ( d->mGestureType & DoubleTap) { + d->DoubleTapAttribute.mQtType = QGestureRecognizer::registerRecognizer(new KDoubleTapRecognizer()); + widgetTarget->grabGesture( d->DoubleTapAttribute.mQtType); + } + if ( d->mGestureType & TwoFingerTap) { + d->TwoFingerTapAttribute.mQtType = QGestureRecognizer::registerRecognizer(new KTwoFingerTapRecognizer()); + widgetTarget->grabGesture( d->TwoFingerTapAttribute.mQtType); + } + if ( d->mGestureType & TapHoldAndMoving) { + d->TapHoldAndMovingAttribute.mQtType = QGestureRecognizer::registerRecognizer(new KTapHoldAndMovingRecognizer()); + widgetTarget->grabGesture( d->TapHoldAndMovingAttribute.mQtType); + } + if ( d->mGestureType & OneAndTwoFingerSwipe) { + d->OneAndTwoFingerSwipeAttribute.mQtType = QGestureRecognizer::registerRecognizer(new KOneAndTwoFingerSwipeRecognizer()); + widgetTarget->grabGesture( d->OneAndTwoFingerSwipeAttribute.mQtType); + } + if ( d->mGestureType & TwoFingerPan) { + d->TwoFingerPanAttribute.mQtType = QGestureRecognizer::registerRecognizer(new KTwoFingerPanRecognizer()); + widgetTarget->grabGesture( d->TwoFingerPanAttribute.mQtType); + } + if ( d->mGestureType & OneFingerPan) { + d->OneFingerPanAttribute.mQtType = QGestureRecognizer::registerRecognizer(new KOneFingerPanRecognizer()); + widgetTarget->grabGesture( d->OneFingerPanAttribute.mQtType); + } + } + touchTarget->installEventFilter(this); +} + +KTouchGesture::~KTouchGesture() +{ + delete d; + +} + +bool KTouchGesture::isTouchTargetValid() +{ + if (qobject_cast( d->mTouchTarget) || qobject_cast( d->mTouchTarget)) { + return true; + } + return false; +} + +void KTouchGesture::setHandleTouchEvents(bool handle) +{ + d->mHandleTouchEvents = handle; +} + +bool KTouchGesture::getHandleTouchEvents() +{ + return d->mHandleTouchEvents; +} + +void KTouchGesture::setTouchSignalFlags(KTouchSignals flags) +{ + d->mTouchFlags = flags; + +} + +KTouchGesture::KTouchSignals KTouchGesture::getTouchSignalFlags() +{ + return d->mTouchFlags; +} + +void KTouchGesture::setGestureDefaultRules(const KGestureType flags) +{ + if (flags & TapGesture) { + d->TapGestureAttribute.mOnlyTriggerIfGestureNotActive = NoGesture; + d->TapGestureAttribute.mOnlyTriggerIfGestureNotFinished = TapAndHoldGesture; + } + if (flags & TapAndHoldGesture) { + d->TapAndHoldGestureAttribute.mOnlyTriggerIfGestureNotActive = NoGesture; + d->TapAndHoldGestureAttribute.mOnlyTriggerIfGestureNotFinished = NoGesture; + } + if (flags & PinchGesture) { + d->PinchGestureAttribute.mOnlyTriggerIfGestureNotActive = TwoFingerPan; + d->PinchGestureAttribute.mOnlyTriggerIfGestureNotFinished = NoGesture; + } + if (flags & PanGesture) { + d->PanGestureAttribute.mOnlyTriggerIfGestureNotFinished = OneAndTwoFingerSwipe; + d->PanGestureAttribute.mOnlyTriggerIfGestureNotActive = NoGesture; + } + if (flags & SwipeGesture) { + d->SwipeGestureAttribute.mOnlyTriggerIfGestureNotActive = NoGesture; + d->SwipeGestureAttribute.mOnlyTriggerIfGestureNotFinished = NoGesture; + } + if (flags & DoubleTap) { + d->DoubleTapAttribute.mOnlyTriggerIfGestureNotActive = NoGesture; + d->DoubleTapAttribute.mOnlyTriggerIfGestureNotFinished = NoGesture; + } + if (flags & TwoFingerTap) { + d->TwoFingerTapAttribute.mOnlyTriggerIfGestureNotActive = NoGesture; + d->TwoFingerTapAttribute.mOnlyTriggerIfGestureNotFinished = NoGesture; + } + if (flags & TapHoldAndMoving) { + d->TapHoldAndMovingAttribute.mOnlyTriggerIfGestureNotActive = NoGesture; + d->TapHoldAndMovingAttribute.mOnlyTriggerIfGestureNotFinished = NoGesture; + } + if (flags & OneAndTwoFingerSwipe) { + d->OneAndTwoFingerSwipeAttribute.mOnlyTriggerIfGestureNotActive = NoGesture; + d->OneAndTwoFingerSwipeAttribute.mOnlyTriggerIfGestureNotFinished = NoGesture; + } + if (flags & TwoFingerPan) { + d->TwoFingerPanAttribute.mOnlyTriggerIfGestureNotActive = NoGesture; + d->TwoFingerPanAttribute.mOnlyTriggerIfGestureNotFinished = OneAndTwoFingerSwipe; + + } + if (flags & OneFingerPan) { + d->OneFingerPanAttribute.mOnlyTriggerIfGestureNotActive = TapHoldAndMoving; + d->OneFingerPanAttribute.mOnlyTriggerIfGestureNotFinished = OneAndTwoFingerSwipe; + } +} + +void KTouchGesture::setRulesTriggerIfNotActiv(const KGestureType gType, const KGestureType notActive) +{ + if (gType & TapGesture) { + d->TapGestureAttribute.mOnlyTriggerIfGestureNotActive = notActive; + } + if (gType & TapAndHoldGesture) { + d->TapAndHoldGestureAttribute.mOnlyTriggerIfGestureNotActive = notActive; + } + if (gType & PinchGesture) { + d->PinchGestureAttribute.mOnlyTriggerIfGestureNotActive = notActive; + } + if (gType & PanGesture) { + d->PanGestureAttribute.mOnlyTriggerIfGestureNotActive = notActive; + } + if (gType & SwipeGesture) { + d->SwipeGestureAttribute.mOnlyTriggerIfGestureNotActive = notActive; + } + if (gType & DoubleTap) { + d->DoubleTapAttribute.mOnlyTriggerIfGestureNotActive = notActive; + } + if (gType & TwoFingerTap) { + d->TwoFingerTapAttribute.mOnlyTriggerIfGestureNotActive = notActive; + } + if (gType & TapHoldAndMoving) { + d->TapHoldAndMovingAttribute.mOnlyTriggerIfGestureNotActive = notActive; + } + if (gType & OneAndTwoFingerSwipe) { + d->OneAndTwoFingerSwipeAttribute.mOnlyTriggerIfGestureNotActive = notActive; + } + if (gType & TwoFingerPan) { + d->TwoFingerPanAttribute.mOnlyTriggerIfGestureNotActive = notActive; + } + if (gType & OneFingerPan) { + d->OneFingerPanAttribute.mOnlyTriggerIfGestureNotActive = notActive; + } +} + +void KTouchGesture::setRulesTriggerIfNotFinish(const KGestureType gType, const KGestureType notFinish) +{ + if (gType & TapGesture) { + d->TapGestureAttribute.mOnlyTriggerIfGestureNotFinished = notFinish; + } + if (gType & TapAndHoldGesture) { + d->TapAndHoldGestureAttribute.mOnlyTriggerIfGestureNotFinished = notFinish; + } + if (gType & PinchGesture) { + d->PinchGestureAttribute.mOnlyTriggerIfGestureNotFinished = notFinish; + } + if (gType & PanGesture) { + d->PanGestureAttribute.mOnlyTriggerIfGestureNotFinished = notFinish; + } + if (gType & SwipeGesture) { + d->SwipeGestureAttribute.mOnlyTriggerIfGestureNotFinished = notFinish; + } + if (gType & DoubleTap) { + d->DoubleTapAttribute.mOnlyTriggerIfGestureNotFinished = notFinish; + } + if (gType & TwoFingerTap) { + d->TwoFingerTapAttribute.mOnlyTriggerIfGestureNotFinished = notFinish; + } + if (gType & TapHoldAndMoving) { + d->TapHoldAndMovingAttribute.mOnlyTriggerIfGestureNotFinished = notFinish; + } + if (gType & OneAndTwoFingerSwipe) { + d->OneAndTwoFingerSwipeAttribute.mOnlyTriggerIfGestureNotFinished = notFinish; + } + if (gType & TwoFingerPan) { + d->TwoFingerPanAttribute.mOnlyTriggerIfGestureNotFinished = notFinish; + } + if (gType & OneFingerPan) { + d->OneFingerPanAttribute.mOnlyTriggerIfGestureNotFinished = notFinish; + } +} + +void KTouchGesture::setGestureSignals(const KGestureType gType, const KGestureSignals gSignals) +{ + if (gType & TapGesture) { + d->TapGestureAttribute.mGestureSignals = gSignals; + } + if (gType & TapAndHoldGesture) { + d->TapAndHoldGestureAttribute.mGestureSignals = gSignals; + } + if (gType & PinchGesture) { + d->PinchGestureAttribute.mGestureSignals = gSignals; + } + if (gType & PanGesture) { + d->PanGestureAttribute.mGestureSignals = gSignals; + } + if (gType & SwipeGesture) { + d->SwipeGestureAttribute.mGestureSignals = gSignals; + } + if (gType & DoubleTap) { + d->DoubleTapAttribute.mGestureSignals = gSignals; + } + if (gType & TwoFingerTap) { + d->TwoFingerTapAttribute.mGestureSignals = gSignals; + } + if (gType & TapHoldAndMoving) { + d->TapHoldAndMovingAttribute.mGestureSignals = gSignals; + } + if (gType & OneAndTwoFingerSwipe) { + d->OneAndTwoFingerSwipeAttribute.mGestureSignals = gSignals; + } + if (gType & TwoFingerPan) { + d->TwoFingerPanAttribute.mGestureSignals = gSignals; + } + if (gType & OneFingerPan) { + d->OneFingerPanAttribute.mGestureSignals = gSignals; + } +} + +KTouchGesture::KGestureType KTouchGesture::getRulesTriggerIfNotActiv(const KGestureType gType) +{ + if (gType & TapGesture) { + return d->TapGestureAttribute.mOnlyTriggerIfGestureNotActive; + } + if (gType & TapAndHoldGesture) { + return d->TapAndHoldGestureAttribute.mOnlyTriggerIfGestureNotActive; + } + if (gType & PinchGesture) { + return d->PinchGestureAttribute.mOnlyTriggerIfGestureNotActive; + } + if (gType & PanGesture) { + return d->PanGestureAttribute.mOnlyTriggerIfGestureNotActive; + } + if (gType & SwipeGesture) { + return d->SwipeGestureAttribute.mOnlyTriggerIfGestureNotActive; + } + if (gType & DoubleTap) { + return d->DoubleTapAttribute.mOnlyTriggerIfGestureNotActive; + } + if (gType & TwoFingerTap) { + return d->TwoFingerTapAttribute.mOnlyTriggerIfGestureNotActive; + } + if (gType & TapHoldAndMoving) { + return d->TapHoldAndMovingAttribute.mOnlyTriggerIfGestureNotActive; + } + if (gType & OneAndTwoFingerSwipe) { + return d->OneAndTwoFingerSwipeAttribute.mOnlyTriggerIfGestureNotActive; + } + if (gType & TwoFingerPan) { + return d->TwoFingerPanAttribute.mOnlyTriggerIfGestureNotActive; + } + if (gType & OneFingerPan) { + return d->OneFingerPanAttribute.mOnlyTriggerIfGestureNotActive; + } +return NoGesture; +} + +KTouchGesture::KGestureType KTouchGesture::getRulesTriggerIfNotFinish(const KGestureType gType) +{ + if (gType & TapGesture) { + return d->TapGestureAttribute.mOnlyTriggerIfGestureNotFinished; + } + if (gType & TapAndHoldGesture) { + return d->TapAndHoldGestureAttribute.mOnlyTriggerIfGestureNotFinished; + } + if (gType & PinchGesture) { + return d->PinchGestureAttribute.mOnlyTriggerIfGestureNotFinished; + } + if (gType & PanGesture) { + return d->PanGestureAttribute.mOnlyTriggerIfGestureNotFinished; + } + if (gType & SwipeGesture) { + return d->SwipeGestureAttribute.mOnlyTriggerIfGestureNotFinished; + } + if (gType & DoubleTap) { + return d->DoubleTapAttribute.mOnlyTriggerIfGestureNotFinished; + } + if (gType & TwoFingerTap) { + return d->TwoFingerTapAttribute.mOnlyTriggerIfGestureNotFinished; + } + if (gType & TapHoldAndMoving) { + return d->TapHoldAndMovingAttribute.mOnlyTriggerIfGestureNotFinished; + } + if (gType & OneAndTwoFingerSwipe) { + return d->OneAndTwoFingerSwipeAttribute.mOnlyTriggerIfGestureNotFinished; + } + if (gType & TwoFingerPan) { + return d->TwoFingerPanAttribute.mOnlyTriggerIfGestureNotFinished; + } + if (gType & OneFingerPan) { + return d->OneFingerPanAttribute.mOnlyTriggerIfGestureNotFinished; + } +return NoGesture; +} + +KTouchGesture::KGestureSignals KTouchGesture::getGestureSignals(const KTouchGesture::KGestureType gType) +{ + if (gType & TapGesture) { + return d->TapGestureAttribute.mGestureSignals; + } + if (gType & TapAndHoldGesture) { + return d->TapAndHoldGestureAttribute.mGestureSignals; + } + if (gType & PinchGesture) { + return d->PinchGestureAttribute.mGestureSignals; + } + if (gType & PanGesture) { + return d->PanGestureAttribute.mGestureSignals; + } + if (gType & SwipeGesture) { + return d->SwipeGestureAttribute.mGestureSignals; + } + if (gType & DoubleTap) { + return d->DoubleTapAttribute.mGestureSignals; + } + if (gType & TwoFingerTap) { + return d->TwoFingerTapAttribute.mGestureSignals; + } + if (gType & TapHoldAndMoving) { + return d->TapHoldAndMovingAttribute.mGestureSignals; + } + if (gType & OneAndTwoFingerSwipe) { + return d->OneAndTwoFingerSwipeAttribute.mGestureSignals; + } + if (gType & TwoFingerPan) { + return d->TwoFingerPanAttribute.mGestureSignals; + } + if (gType & OneFingerPan) { + return d->OneFingerPanAttribute.mGestureSignals; + } + + return NoGestureSignal; +} + +void KTouchGesture::checkDoubleTapGesture(QGestureEvent* event, QObject* obj) +{ + const QGesture* gesture = event->gesture( d->DoubleTapAttribute.mQtType); + + if (gesture) { + KTouchGestureData data; + event->accept(); + + d->fillKGestureData(gesture, obj, event->widget(), &data); + + if (d->handleGesture(gesture->state(), DoubleTap, &d->DoubleTapAttribute)) { + emit doubleTapTriggered(data); + } + } +} + +void KTouchGesture::checkTwoFingerTapGesture(QGestureEvent* event, QObject* obj) +{ + const QGesture* gesture = event->gesture( d->TwoFingerTapAttribute.mQtType); + + if (gesture) { + KTouchGestureData data; + event->accept(); + + d->fillKGestureData(gesture, obj, event->widget(), &data); + + if (d->handleGesture(gesture->state(), TwoFingerTap, &d->TwoFingerTapAttribute)) { + emit twoFingerTapTriggered(data); + } + } +} + +void KTouchGesture::checkTapHoldAndMovingGesture(QGestureEvent* event, QObject* obj) +{ + const QGesture* gesture = event->gesture( d->TapHoldAndMovingAttribute.mQtType); + + if (gesture) { + KTouchGestureData data; + event->accept(); + + d->fillKGestureData(gesture, obj, event->widget(), &data); + + if (d->handleGesture(gesture->state(), TapHoldAndMoving, &d->TapHoldAndMovingAttribute)) { + emit tapHoldAndMovingTriggered(data); + } + } +} + +void KTouchGesture::checkOneAndTwoFingerSwipeGesture(QGestureEvent* event, QObject* obj) +{ + const QGesture* gesture = event->gesture( d->OneAndTwoFingerSwipeAttribute.mQtType); + + if (gesture) { + KTouchGestureData data; + event->accept(); + + d->fillKGestureData(gesture, obj, event->widget(), &data); + data.swipeAngel = gesture->property("swipeAngle").toReal(); + + if (d->handleGesture(gesture->state(), OneAndTwoFingerSwipe, &d->OneAndTwoFingerSwipeAttribute)) { + emit oneAndTwoFingerSwipeTriggered(data); + } + } +} + +void KTouchGesture::checkTwoFingerPanGesture(QGestureEvent* event, QObject* obj) +{ + const QGesture* gesture = event->gesture( d->TwoFingerPanAttribute.mQtType); + + if (gesture) { + KTouchGestureData data; + event->accept(); + + d->fillKGestureData(gesture, obj, event->widget(), &data); + data.delta = gesture->property("delta").toPointF(); + + if (d->handleGesture(gesture->state(), TwoFingerPan, &d->TwoFingerPanAttribute)) { + emit twoFingerPanTriggered(data); + } + } +} + +void KTouchGesture::checkOneFingerPanGesture(QGestureEvent* event, QObject* obj) +{ + const QGesture* gesture = event->gesture( d->OneFingerPanAttribute.mQtType); + + if (gesture) { + KTouchGestureData data; + event->accept(); + + d->fillKGestureData(gesture, obj, event->widget(), &data); + data.delta = gesture->property("delta").toPointF(); + + if (d->handleGesture(gesture->state(), OneFingerPan, &d->OneFingerPanAttribute)) { + emit oneFingerPanTriggered(data); + } + } +} + +void KTouchGesture::checkSwipeGesture(QGestureEvent* event, QObject* obj) +{ + const QSwipeGesture* swipe = static_cast(event->gesture(Qt::SwipeGesture)); + + if (swipe) { + KTouchGestureData data; + + d->fillKGestureDataBase(swipe->state(), obj, event->widget(), &data); + event->accept(); + + if (d->isDublicateGesture(swipe->state(), swipe->hotSpot(), &d->SwipeGestureAttribute)) { + return; + }; + + d->fillKGestureDataPos(event, swipe->hotSpot(), swipe->hotSpot(), &data); + data.swipeAngel = swipe->swipeAngle(); + + if (d->handleGesture(swipe->state(), SwipeGesture, &d->SwipeGestureAttribute)) { + emit swipeTriggered(data); + } + } +} + +void KTouchGesture::checkPanGesture(QGestureEvent* event, QObject* obj) +{ + const QPanGesture* pan = static_cast(event->gesture(Qt::PanGesture)); + + if (pan) { + KTouchGestureData data; + + d->fillKGestureDataBase(pan->state(), obj, event->widget(), &data); + event->accept(); + + //use pan->delta to identify duplicate gesture, because pan->pos and pan->hotSpot is + //every time equal to start pos. + if (d->isDublicateGesture(pan->state(), pan->delta(), &d->PanGestureAttribute)) { + return; + }; + + d->fillKGestureDataPos(event, pan->hotSpot(), pan->hotSpot(), &data); + data.delta = pan->delta(); + + if (d->handleGesture(pan->state(), PanGesture, &d->PanGestureAttribute)) { + emit panTriggered(data); + } + } +} + +void KTouchGesture::checkPinchGesture(QGestureEvent* event, QObject* obj) +{ + const QPinchGesture* pinch = static_cast(event->gesture(Qt::PinchGesture)); + + if (pinch) { + KTouchGestureData data; + + d->fillKGestureDataBase(pinch->state(), obj, event->widget(), &data); + event->accept(); + + if (d->isDublicateGesturePinch(pinch->state(), pinch->scaleFactor(), &d->PinchGestureAttribute)) { + return; + }; + + d->fillKGestureDataPos(event, pinch->hotSpot(), pinch->centerPoint(), &data); + data.scaleFactor = pinch->scaleFactor(); + data.totalScaleFactor = pinch->totalScaleFactor(); + data.rotationsAngle = pinch->rotationAngle(); + data.totalRotationsAngle = pinch->totalRotationAngle(); + + if (d->handleGesture(pinch->state(), PinchGesture, &d->PinchGestureAttribute)) { + emit pinchTriggered(data); + } + } +} + +void KTouchGesture::checkTapAndHoldGesture(QGestureEvent* event, QObject* obj) +{ + const QTapAndHoldGesture* hold = static_cast(event->gesture(Qt::TapAndHoldGesture)); + + if (hold) { + KTouchGestureData data; + + d->fillKGestureDataBase(hold->state(), obj, event->widget(), &data); + event->accept(); + + if (d->isDublicateGesture(hold->state(), hold->hotSpot(), &d->TapAndHoldGestureAttribute)) { + return; + } + + d->fillKGestureDataPos(event, hold->hotSpot(), hold->position(), &data); + + if (d->handleGesture(hold->state(), TapAndHoldGesture, &d->TapAndHoldGestureAttribute)) { + emit tapAndHoldTriggered(data); + } + } +} + +void KTouchGesture::checkTapGesture(QGestureEvent* event, QObject* obj) +{ + const QTapGesture* tap = static_cast(event->gesture(Qt::TapGesture)); + + if (tap) { + KTouchGestureData data; + d->fillKGestureDataBase(tap->state(), obj, event->widget(), &data); + event->accept(); + + if (d->isDublicateGesture(tap->state(), tap->hotSpot(), &d->TapGestureAttribute)) { + return; + }; + + d->fillKGestureDataPos(event, tap->hotSpot(), tap->position(), &data); + + if (d->handleGesture(tap->state(), TapGesture, &d->TapGestureAttribute)) { + emit tapTriggered(data); + } + } +} + +bool KTouchGesture::eventFilter ( QObject* watched, QEvent* event ) +{ + switch (event->type()) { + case QEvent::TouchBegin: + d->mAllFinishedGestures = NoGesture; + if ( d->mTouchFlags & TouchBeginn) { + if (QTouchEvent* touchEvent = static_cast(event)) { + emit touchBeginnTriggered(touchEvent->touchPoints(), touchEvent->timestamp()); + } + } + return d->mHandleTouchEvents; + break; + case QEvent::TouchUpdate: + if ( d->mTouchFlags & TouchUpdate) { + if (QTouchEvent* touchEvent = static_cast(event)) { + emit touchUpdateTriggered(touchEvent->touchPoints(), touchEvent->timestamp()); + } + } + break; + case QEvent::TouchEnd: + if ( d->mTouchFlags & TouchEnd) { + if (QTouchEvent* touchEvent = static_cast(event)) { + emit touchEndTriggered(touchEvent->touchPoints(), touchEvent->timestamp()); + } + } + break; + case QEvent::Gesture: + gestureEvent(static_cast(event), watched); + break; + default: + break; + } + return false; +} + +void KTouchGesture::gestureEvent(QGestureEvent* event, QObject* obj) +{ + if ( d->mGestureType & TapGesture) { + checkTapGesture(event, obj); + } + if ( d->mGestureType & TapAndHoldGesture) { + checkTapAndHoldGesture(event, obj); + } + if ( d->mGestureType & PinchGesture) { + checkPinchGesture(event, obj); + } + if ( d->mGestureType & PanGesture) { + checkPanGesture(event, obj); + } + if ( d->mGestureType & SwipeGesture) { + checkSwipeGesture(event, obj); + } + if ( d->mGestureType & DoubleTap) { + checkDoubleTapGesture(event, obj); + } + if ( d->mGestureType & TwoFingerTap) { + checkTwoFingerTapGesture(event, obj); + } + if ( d->mGestureType & TapHoldAndMoving) { + checkTapHoldAndMovingGesture(event, obj); + } + if ( d->mGestureType & OneAndTwoFingerSwipe) { + checkOneAndTwoFingerSwipeGesture(event, obj); + } + if ( d->mGestureType & TwoFingerPan) { + checkTwoFingerPanGesture(event, obj); + } + if ( d->mGestureType & OneFingerPan) { + checkOneFingerPanGesture(event, obj); + } +} + +void KTouchGesture::touchToMouseRelease(QPoint pos, QObject* receiver) +{ + d->touchToMouseEvent(pos, receiver, QEvent::MouseButtonRelease, Qt::LeftButton, Qt::LeftButton); +} + +void KTouchGesture::touchToMouseMove(QPoint pos, QObject* receiver, Qt::MouseButton button) +{ + d->touchToMouseEvent(pos, receiver, QEvent::MouseMove, button, button); +} + +void KTouchGesture::touchToMouseClick (QPoint pos, QObject* receiver) +{ + d->touchToMouseEvent(pos, receiver, QEvent::MouseButtonPress, Qt::LeftButton, Qt::LeftButton); + d->touchToMouseEvent(pos, receiver, QEvent::MouseButtonRelease, Qt::LeftButton, Qt::LeftButton); +} + + +#include "moc_ktouchgesture.cpp" diff --git a/src/ktouchgesture_helper.h b/src/ktouchgesture_helper.h new file mode 100644 --- /dev/null +++ b/src/ktouchgesture_helper.h @@ -0,0 +1,43 @@ +/* + * KTouch is a library for gestures and touch handling + * Copyright (C) 2019 Steffen Hartleib + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#ifndef KTOUCHGESTURE_HELPER_H +#define KTOUCHGESTURE_HELPER_H + +//constant variables that define touch behavior +struct KTouchGestureDefaults +{ + //a little delay in the begin of the gesture, to get more data of the touch points moving so the recognizing + //of the pan gesture is better + static const int gestureDelay = 110; + //this defines how much a touch point can move, for a single tap gesture + static const int wiggleRoomForTap = 10; + //how long must a touch point be stationary, before he can move for a TabHoldAndMoving gesture + static const int durationForTapHold = 400; + //in what time and how far must the touch point moving to trigger a swipe gesture + static const int maxTimeFrameForSwipe = 100; + static const int minDistanceForSwipe = 70; + //How long is the duration for a simple tap gesture + static const int maxTimeForTap = 100; + //max interval for a double tap gesture + static const int doubleTapInterval = 400; + //max wiggle room before a pan gesture is canceled + static const int wiggleRoomForPan = 25; +}; + +#endif /* KTOUCHGESTURE_HELPER_H */ diff --git a/src/ktwofingerpan.h b/src/ktwofingerpan.h new file mode 100644 --- /dev/null +++ b/src/ktwofingerpan.h @@ -0,0 +1,70 @@ +/* + * KTouchGesture is a library for gestures and touch handling + * Copyright (C) 2019 Steffen Hartleib + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#ifndef KTWOFINGERPAN_H +#define KTWOFINGERPAN_H + +#include +// Qt +#include +#include + +// KDE + +// Local + +class KWIDGETSADDONS_EXPORT KTwoFingerPan : public QGesture +{ + Q_OBJECT + Q_PROPERTY(QPointF delta READ delta WRITE setDelta) + Q_PROPERTY(bool delayActive READ delayActive WRITE setDelayActive) + Q_PROPERTY(QPointF pos READ pos WRITE setPos) + Q_PROPERTY(QPointF screenPos READ screenPos WRITE setScreenPos) + Q_PROPERTY(QPointF scenePos READ scenePos WRITE setScenePos) + +public: + explicit KTwoFingerPan(QObject* parent = nullptr); + ~KTwoFingerPan(); + QPointF delta() const; + void setDelta(QPointF delta); + bool delayActive() const; + void setDelayActive (bool delayActive); + QPointF pos() const; + void setPos(QPointF pos); + QPointF screenPos() const; + void setScreenPos(QPointF screenPos); + QPointF scenePos() const; + void setScenePos(QPointF scenePos); +private: + class KTwoFingerPanPrivate* const d; +}; + +class KWIDGETSADDONS_EXPORT KTwoFingerPanRecognizer : public QGestureRecognizer +{ +public: + explicit KTwoFingerPanRecognizer(); + ~KTwoFingerPanRecognizer(); + QGesture* create(QObject*) override; + Result recognize(QGesture*, QObject*, QEvent*) override; +private: + Q_DISABLE_COPY (KTwoFingerPanRecognizer) + class KTwoFingerPanRecognizerPrivate* const d; +}; + +#endif /* KTWOFINGERPAN_H */ + diff --git a/src/ktwofingerpan.cpp b/src/ktwofingerpan.cpp new file mode 100644 --- /dev/null +++ b/src/ktwofingerpan.cpp @@ -0,0 +1,251 @@ +/* + * KTouchGesture is a library for gestures and touch handling + * Copyright (C) 2019 Steffen Hartleib + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +// Self +#include "ktwofingerpan.h" + +// Qt +#include +#include + +// KDE + +// Local +#include "ktouchgesture_helper.h" + +class KTwoFingerPanPrivate +{ +public: + KTwoFingerPanPrivate() + { + } + ~KTwoFingerPanPrivate() + { + } + KTwoFingerPan* q; + QPointF m_pos; + QPointF m_screenPos; + QPointF m_scenePos; + QPointF m_delta; + bool m_delayActive; +}; + +class KTwoFingerPanRecognizerPrivate +{ +public: + KTwoFingerPanRecognizerPrivate() + { + } + ~KTwoFingerPanRecognizerPrivate() + { + } + void setGesturePositions (KTwoFingerPan* const gesture, QTouchEvent::TouchPoint tp) + { + gesture->setHotSpot(tp.startScreenPos()); + gesture->setPos(tp.startPos()); + gesture->setScreenPos(tp.startScreenPos()); + gesture->setScenePos(tp.startScenePos()); + } + KTwoFingerPanRecognizer* q; + bool m_TargetIsGrapicsWidget = false; + qint64 m_TouchBeginnTimestamp; + bool m_GestureTriggered; +}; + +KTwoFingerPanRecognizer::KTwoFingerPanRecognizer() + : QGestureRecognizer() + , d (new KTwoFingerPanRecognizerPrivate) +{ + d->q = this; +} + +KTwoFingerPanRecognizer::~KTwoFingerPanRecognizer() +{ + delete d; +} + +QGesture* KTwoFingerPanRecognizer::create(QObject*) +{ + return static_cast(new KTwoFingerPan()); +} + +QGestureRecognizer::Result KTwoFingerPanRecognizer::recognize(QGesture* gesture, QObject* watched, QEvent* event) +{ + //Because of a bug in Qt in a gesture event in a graphicsview, all gestures are trigger twice + //https://bugreports.qt.io/browse/QTBUG-13103 + if (qobject_cast(watched)) d->m_TargetIsGrapicsWidget = true; + if (d->m_TargetIsGrapicsWidget && watched->isWidgetType()) return Ignore; + + KTwoFingerPan* const kTwoFingerPan = static_cast(gesture); + const QTouchEvent* touchEvent = static_cast(event); + + switch (event->type()) { + case QEvent::TouchBegin: { + d->m_TouchBeginnTimestamp = touchEvent->timestamp(); + d->m_GestureTriggered = false; + kTwoFingerPan->setDelayActive(true); + d->setGesturePositions(kTwoFingerPan, touchEvent->touchPoints().first()); + return MayBeGesture; //TriggerGesture; + } + + case QEvent::TouchUpdate: { + const qint64 now = touchEvent->timestamp(); + const QPointF pos = touchEvent->touchPoints().first().pos(); + d->setGesturePositions(kTwoFingerPan, touchEvent->touchPoints().first()); + + if (touchEvent->touchPoints().size() >> 2) { + if (d->m_GestureTriggered ) { + d->m_GestureTriggered = false; + } + return CancelGesture; + } + + if (touchEvent->touchPoints().size() == 2) { + if (touchEvent->touchPointStates() & Qt::TouchPointReleased) { + if (d->m_GestureTriggered ) { + d->m_GestureTriggered = false; + return FinishGesture; + } + } + + if (now - d->m_TouchBeginnTimestamp >= KTouchGestureDefaults::gestureDelay) { + kTwoFingerPan->setDelayActive(false); + + //Check if both touch points moving in the same direction + const QVector2D vectorTouchPoint1 = QVector2D (touchEvent->touchPoints().at(0).startPos() - touchEvent->touchPoints().at(0).pos()); + const QVector2D vectorTouchPoint2 = QVector2D (touchEvent->touchPoints().at(1).startPos() - touchEvent->touchPoints().at(1).pos()); + QVector2D dotProduct = vectorTouchPoint1 * vectorTouchPoint2; + + //The dot product is greater than zero if both touch points moving in the same direction + //special case if the touch point moving exact or almost exact in x or y axis + //one value of the dot product is zero or a little bit less than zero and + //the other value is bigger than zero + if (dotProduct.x() >= -500 && dotProduct.x() <= 0 && dotProduct.y() > 0) dotProduct.setX(1); + if (dotProduct.y() >= -500 && dotProduct.y() <= 0 && dotProduct.x() > 0) dotProduct.setY(1); + + if (dotProduct.x() > 0 && dotProduct.y() > 0) { + const QPointF diff = (pos - touchEvent->touchPoints().first().lastPos()); + kTwoFingerPan->setDelta(diff); + d->m_GestureTriggered = true; + //if diff QPointF (0, 0) dont trigger gesture, because touchpoints are moving + if (diff != QPointF (0, 0)) { + return TriggerGesture; + } + } else { + //special case if the user makes a very slow pan gesture, the vectors a very short. Sometimes the + //dot product is then zero, so we only want to cancel the gesture if the user makes a bigger wrong gesture + if (vectorTouchPoint1.toPoint().manhattanLength() > KTouchGestureDefaults::wiggleRoomForPan || + vectorTouchPoint2.toPoint().manhattanLength() > KTouchGestureDefaults::wiggleRoomForPan ) { + d->m_GestureTriggered = false; + return CancelGesture; + } else { + const QPointF diff = (pos - touchEvent->touchPoints().first().lastPos()); + kTwoFingerPan->setDelta(diff); + d->m_GestureTriggered = true; + if (diff != QPointF (0, 0)) { + return TriggerGesture; + } + } + } + } else { + kTwoFingerPan->setDelta(QPointF (0, 0)); + kTwoFingerPan->setDelayActive(true); + d->m_GestureTriggered = false; + return TriggerGesture; + } + } + break; + } + + case QEvent::TouchEnd: { + if (d->m_GestureTriggered ) { + d->m_GestureTriggered = false; + d->setGesturePositions(kTwoFingerPan, touchEvent->touchPoints().first()); + return FinishGesture; + } + break; + } + + default: + return Ignore; + } + return Ignore; +} + +KTwoFingerPan::KTwoFingerPan (QObject* parent) + : QGesture(parent) + , d (new KTwoFingerPanPrivate) +{ + d->q = this; +} + +KTwoFingerPan::~KTwoFingerPan() +{ + delete d; +} + +QPointF KTwoFingerPan::pos() const +{ + return d->m_pos; +} + +void KTwoFingerPan::setPos(QPointF _pos) +{ + d->m_pos = _pos; +} + +QPointF KTwoFingerPan::screenPos() const +{ + return d->m_screenPos; +} + +void KTwoFingerPan::setScreenPos(QPointF _screenPos) +{ + d->m_screenPos = _screenPos; +} + +QPointF KTwoFingerPan::scenePos() const +{ + return d->m_scenePos; +} + +void KTwoFingerPan::setScenePos(QPointF _scenePos) +{ + d->m_scenePos = _scenePos; +} + +QPointF KTwoFingerPan::delta() const +{ + return d->m_delta; +} + +void KTwoFingerPan::setDelta(QPointF _delta) +{ + d->m_delta = _delta; +} + +bool KTwoFingerPan::delayActive() const +{ + return d->m_delayActive; +} + +void KTwoFingerPan::setDelayActive(bool _delayActive) +{ + d->m_delayActive = _delayActive; +} + diff --git a/src/ktwofingertap.h b/src/ktwofingertap.h new file mode 100644 --- /dev/null +++ b/src/ktwofingertap.h @@ -0,0 +1,62 @@ +/* + * KTouchGesture is a library for gestures and touch handling + * Copyright (C) 2019 Steffen Hartleib + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#ifndef KTWOFINGERTAP_H +#define KTWOFINGERTAP_H + +#include +// Qt +#include +#include + +// KDE + +// Local + +class KWIDGETSADDONS_EXPORT KTwoFingerTap : public QGesture +{ + Q_OBJECT + Q_PROPERTY(QPointF pos READ pos WRITE setPos) + Q_PROPERTY(QPointF screenPos READ screenPos WRITE setScreenPos) + Q_PROPERTY(QPointF scenePos READ scenePos WRITE setScenePos) +public: + explicit KTwoFingerTap(QObject* parent = nullptr); + ~KTwoFingerTap(); + QPointF pos() const; + void setPos(QPointF pos); + QPointF screenPos() const; + void setScreenPos(QPointF screenPos); + QPointF scenePos() const; + void setScenePos(QPointF scenePos); +private: + class KTwoFingerTapPrivate* const d; +}; + +class KWIDGETSADDONS_EXPORT KTwoFingerTapRecognizer : public QGestureRecognizer +{ +public: + explicit KTwoFingerTapRecognizer(); + ~KTwoFingerTapRecognizer(); + QGesture* create(QObject*) override; + Result recognize(QGesture*, QObject*, QEvent*) override; +private: + Q_DISABLE_COPY(KTwoFingerTapRecognizer) + class KTwoFingerTapRecognizerPrivate* const d; +}; + +#endif /* KTWOFINGERTAP_H */ diff --git a/src/ktwofingertap.cpp b/src/ktwofingertap.cpp new file mode 100644 --- /dev/null +++ b/src/ktwofingertap.cpp @@ -0,0 +1,179 @@ +/* + * KTouchGesture is a library for gestures and touch handling + * Copyright (C) 2019 Steffen Hartleib + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +// Self +#include "ktwofingertap.h" + +// Qt +#include +#include +#include + +// KDE + +// Local +#include "ktouchgesture_helper.h" + +class KTwoFingerTapPrivate +{ +public: + KTwoFingerTapPrivate() + { + } + ~KTwoFingerTapPrivate() + { + } + KTwoFingerTap* q; + QPointF m_pos; + QPointF m_screenPos; + QPointF m_scenePos; +}; + +class KTwoFingerTapRecognizerPrivate +{ +public: + KTwoFingerTapRecognizerPrivate() + { + } + ~KTwoFingerTapRecognizerPrivate() + { + } + void setGesturePositions (KTwoFingerTap* const gesture, QTouchEvent::TouchPoint tp) + { + gesture->setHotSpot(tp.startScreenPos()); + gesture->setPos(tp.startPos()); + gesture->setScreenPos(tp.startScreenPos()); + gesture->setScenePos(tp.startScenePos()); + } + KTwoFingerTapRecognizer* q; + bool m_TargetIsGrapicsWidget = false; + qint64 m_TouchBeginnTimestamp; + bool m_GestureTriggered; +}; + +KTwoFingerTapRecognizer::KTwoFingerTapRecognizer() + : QGestureRecognizer() + , d (new KTwoFingerTapRecognizerPrivate) +{ + d->q = this; +} + +KTwoFingerTapRecognizer::~KTwoFingerTapRecognizer() +{ + delete d; +} + +QGesture* KTwoFingerTapRecognizer::create(QObject*) +{ + return static_cast(new KTwoFingerTap()); +} + +QGestureRecognizer::Result KTwoFingerTapRecognizer::recognize(QGesture* gesture, QObject* watched, QEvent* event) +{ + //Because of a bug in Qt in a gesture event in a graphicsview, all gestures are trigger twice + //https://bugreports.qt.io/browse/QTBUG-13103 + if (qobject_cast(watched)) d->m_TargetIsGrapicsWidget = true; + if (d->m_TargetIsGrapicsWidget && watched->isWidgetType()) return Ignore; + + KTwoFingerTap* const kTwoFingerTap = static_cast(gesture); + const QTouchEvent* touchEvent = static_cast(event); + + switch (event->type()) { + case QEvent::TouchBegin: { + d->m_TouchBeginnTimestamp = touchEvent->timestamp(); + d->setGesturePositions(kTwoFingerTap, touchEvent->touchPoints().first()); + d->m_GestureTriggered = false; + return MayBeGesture; + } + + case QEvent::TouchUpdate: { + d->setGesturePositions(kTwoFingerTap, touchEvent->touchPoints().first()); + + if (touchEvent->touchPoints().size() >> 2) { + d->m_GestureTriggered = false; + return CancelGesture; + } + + if (touchEvent->touchPoints().size() == 2) { + if ((touchEvent->touchPoints().first().startPos() - touchEvent->touchPoints().first().pos()).manhattanLength() > KTouchGestureDefaults::wiggleRoomForTap) { + d->m_GestureTriggered = false; + return CancelGesture; + } + if ((touchEvent->touchPoints().at(1).startPos() - touchEvent->touchPoints().at(1).pos()).manhattanLength() > KTouchGestureDefaults::wiggleRoomForTap) { + d->m_GestureTriggered = false; + return CancelGesture; + } + if (touchEvent->touchPointStates() & Qt::TouchPointPressed) { + d->m_GestureTriggered = true; + } + if (touchEvent->touchPointStates() & Qt::TouchPointReleased && d->m_GestureTriggered) { + d->m_GestureTriggered = false; + return FinishGesture; + } + } + break; + } + + default: + return Ignore; + } + return Ignore; +} + +KTwoFingerTap::KTwoFingerTap(QObject* parent) + : QGesture(parent) + , d (new KTwoFingerTapPrivate) +{ + d->q = this; +} + +KTwoFingerTap::~KTwoFingerTap() +{ + delete d; +} + +QPointF KTwoFingerTap::pos() const +{ + return d->m_pos; +} + +void KTwoFingerTap::setPos(QPointF _pos) +{ + d->m_pos = _pos; +} + +QPointF KTwoFingerTap::screenPos() const +{ + return d->m_screenPos; +} + +void KTwoFingerTap::setScreenPos(QPointF _screenPos) +{ + d->m_screenPos = _screenPos; +} + +QPointF KTwoFingerTap::scenePos() const +{ + return d->m_scenePos; +} + +void KTwoFingerTap::setScenePos(QPointF _scenePos) +{ + d->m_scenePos = _scenePos; +} + diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -43,6 +43,7 @@ ksplittercollapserbuttongui_test ktooltipwidget_test kpasswordlineedit_test + ktouchgesturetest ) add_executable(kdatetabletest kdatetabletest.cpp ../src/kdatetable.cpp) diff --git a/tests/ktouchgesturetest.cpp b/tests/ktouchgesturetest.cpp new file mode 100644 --- /dev/null +++ b/tests/ktouchgesturetest.cpp @@ -0,0 +1,670 @@ +/* + * + * Copyright (C) 2019 Steffen Hartleib + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +KTouchGesture* mKTouchGesture; +KTouchGesture* mGraphicsTouch; + +QString touchPointsToMsg (const QList &ts, qreal time) +{ + QString ret; + ret = (QString(QStringLiteral(" ---> touchpoints count=%1, touchpoint1 pos=(%2, %3), event timestamp=%4")). + arg(ts.count()). + arg(ts.first().pos().x()). + arg(ts.first().pos().y()). + arg(time)) + ; + ret += (QString(QStringLiteral(", screenPos=(%1, %2)")). + arg(ts.first().screenPos().x()). + arg(ts.first().screenPos().y())) + ; + ret += (QString(QStringLiteral(", scenePos=(%1, %2)")). + arg(ts.first().scenePos().x()). + arg(ts.first().scenePos().y())) + ; + return ret; +} + +QString gestureDataToMsg (const KTouchGestureData &data) +{ + QString ret; + ret = (QString(QStringLiteral(" ---> Gesture pos=(%1, %2), screenPos=(%3, %4), scenePos=(%5, %6), scaleFactor=%7, rotaionsAngle=%8, centerPos=(%9, %10), delta=(%11, %12), swipeAngle=%13 state:")). + arg(data.pos.x()). + arg(data.pos.y()). + arg(data.screenPos.x()). + arg(data.screenPos.y()). + arg(data.scenePos.x()). + arg(data.scenePos.y()). + arg(data.scaleFactor). + arg(data.rotationsAngle). + arg(data.centerPos.x()). + arg(data.centerPos.y()). + arg(data.delta.x()). + arg(data.delta.y()). + arg(data.swipeAngel) + ); + if (data.state == Qt::GestureStarted) { + ret += QString(QStringLiteral("Qt::GestureStarted")); + } + if (data.state == Qt::GestureUpdated) { + ret += QString(QStringLiteral("Qt::GestureUpdated")); + } + if (data.state == Qt::GestureFinished) { + ret += QString(QStringLiteral("Qt::GestureFinished")); + } + if (data.state == Qt::GestureCanceled) { + ret += QString(QStringLiteral("Qt::GestureCanceled")); + } + + return ret; +} + +void toggleTouchSignal (KTouchGesture::KTouchSignals signal, bool checked) +{ + KTouchGesture::KTouchSignals old = mKTouchGesture->getTouchSignalFlags(); + KTouchGesture::KTouchSignals oldg = mGraphicsTouch->getTouchSignalFlags(); + if (checked) { + mKTouchGesture->setTouchSignalFlags(old | signal); + mGraphicsTouch->setTouchSignalFlags(oldg | signal); + } + else { + mKTouchGesture->setTouchSignalFlags(old ^ signal); + mGraphicsTouch->setTouchSignalFlags(oldg ^ signal); + } +} + +void toggleGestureSignal (KTouchGesture::KGestureSignals signal, bool checked, KTouchGesture::KGestureType type) +{ + KTouchGesture::KGestureSignals old = mKTouchGesture->getGestureSignals(type); + KTouchGesture::KGestureSignals oldg = mGraphicsTouch->getGestureSignals(type); + if (checked) { + mKTouchGesture->setGestureSignals(type, old | signal); + mGraphicsTouch->setGestureSignals(type, oldg | signal); + } + else { + mKTouchGesture->setGestureSignals(type, old ^ signal); + mGraphicsTouch->setGestureSignals(type, oldg ^ signal); + } +} + +void connectGesture (KTouchGesture* obj, QPlainTextEdit* browser) +{ + QObject::connect(obj, &KTouchGesture::tapTriggered, browser, + [=](const KTouchGestureData& data) { + browser->appendPlainText(QStringLiteral("Tap Gesture Triggered")); + browser->appendPlainText(gestureDataToMsg(data)); + }); + QObject::connect(obj, &KTouchGesture::tapAndHoldTriggered, browser, + [=](const KTouchGestureData& data) { + browser->appendPlainText(QStringLiteral("TapAndHold Gesture Triggered")); + browser->appendPlainText(gestureDataToMsg(data)); + }); + QObject::connect(obj, &KTouchGesture::pinchTriggered, browser, + [=](const KTouchGestureData& data) { + browser->appendPlainText(QStringLiteral("Pinch Gesture Triggered")); + browser->appendPlainText(gestureDataToMsg(data)); + }); + + QObject::connect(obj, &KTouchGesture::panTriggered, browser, + [=](const KTouchGestureData& data) { + browser->appendPlainText(QStringLiteral("Pan Gesture Triggered")); + browser->appendPlainText(gestureDataToMsg(data)); + }); + + QObject::connect(obj, &KTouchGesture::swipeTriggered, browser, + [=](const KTouchGestureData& data) { + browser->appendPlainText(QStringLiteral("Swipe Gesture Triggered")); + browser->appendPlainText(gestureDataToMsg(data)); + }); + + QObject::connect(obj, &KTouchGesture::doubleTapTriggered, browser, + [=](const KTouchGestureData& data) { + browser->appendPlainText(QStringLiteral("DoubleTap Gesture Triggered")); + browser->appendPlainText(gestureDataToMsg(data)); + }); + + QObject::connect(obj, &KTouchGesture::twoFingerTapTriggered, browser, + [=](const KTouchGestureData& data) { + browser->appendPlainText(QStringLiteral("TwoFingerTap Gesture Triggered")); + browser->appendPlainText(gestureDataToMsg(data)); + }); + + QObject::connect(obj, &KTouchGesture::tapHoldAndMovingTriggered, browser, + [=](const KTouchGestureData& data) { + browser->appendPlainText(QStringLiteral("TapHoldAndMoving Gesture Triggered")); + browser->appendPlainText(gestureDataToMsg(data)); + }); + QObject::connect(obj, &KTouchGesture::oneAndTwoFingerSwipeTriggered, browser, + [=](const KTouchGestureData& data) { + browser->appendPlainText(QStringLiteral("OneAndTwoFingerSwipe Gesture Triggered")); + browser->appendPlainText(gestureDataToMsg(data)); + }); + + QObject::connect(obj, &KTouchGesture::twoFingerPanTriggered, browser, + [=](const KTouchGestureData& data) { + browser->appendPlainText(QStringLiteral("TwoFingerPan Gesture Triggered")); + browser->appendPlainText(gestureDataToMsg(data)); + }); + QObject::connect(obj, &KTouchGesture::oneFingerPanTriggered, browser, + [=](const KTouchGestureData& data) { + browser->appendPlainText(QStringLiteral("OneFingerPan Gesture Triggered")); + browser->appendPlainText(gestureDataToMsg(data)); + }); +} + + +int main(int argc, char* argv[]) +{ + QApplication app(argc, argv); + + QMainWindow* mainWindow = new QMainWindow(); + + QWidget* centralwidget = new QWidget(mainWindow); + QHBoxLayout* horizontalLayout = new QHBoxLayout(centralwidget); + + QTabWidget* tabWidget = new QTabWidget(centralwidget); + + QWidget* tab1 = new QWidget(); + QHBoxLayout* horizontalLayout_2 = new QHBoxLayout(tab1); + QPlainTextEdit* browser = new QPlainTextEdit(tab1); + browser->setReadOnly(true); + horizontalLayout_2->addWidget(browser); + + QWidget* tab2 = new QWidget(); + QHBoxLayout* horizontalLayout_tab2 = new QHBoxLayout(tab2); + QGraphicsScene scene(tab2); + scene.addText(QString(QStringLiteral("make touch gesture here"))); + QGraphicsView* graphicsView = new QGraphicsView(&scene); + QGraphicsWidget* graphicsW = new QGraphicsWidget(); + graphicsW->setGeometry(QRect(1, 1, 700, 600)); + graphicsW->setVisible(true); + graphicsW->setAutoFillBackground(true); + + QPlainTextEdit* browser2 = new QPlainTextEdit(tab1); + browser2->setReadOnly(true); + horizontalLayout_tab2->addWidget(graphicsView); + horizontalLayout_tab2->addWidget(browser2); + scene.addItem(graphicsW); + + QWidget* tab3 = new QWidget(); + + QVBoxLayout* vLayout = new QVBoxLayout(tab3); + + QGroupBox* gTouchBox = new QGroupBox(QString(QStringLiteral("Touch Signale")), tab3); + gTouchBox->setGeometry(QRect(50, 20, 771, 81)); + QWidget* widget = new QWidget(gTouchBox); + widget->setGeometry(QRect(30, 30, 762, 33)); + QHBoxLayout* horizontalLayout_4 = new QHBoxLayout(widget); + horizontalLayout_4->setContentsMargins(1, 1, 1, 1); + QCheckBox* cBTouchBeginn = new QCheckBox(QString(QStringLiteral("TouchBeginn")), widget); + cBTouchBeginn->setChecked(false); + horizontalLayout_4->addWidget(cBTouchBeginn); + QCheckBox* cBTouchUpdate = new QCheckBox(widget); + cBTouchUpdate->setText(QString(QStringLiteral("TouchUpdate"))); + cBTouchUpdate->setChecked(false); + horizontalLayout_4->addWidget(cBTouchUpdate); + QCheckBox* cBTouchEnd = new QCheckBox(widget); + cBTouchEnd->setText(QString(QStringLiteral("TouchEnd"))); + cBTouchEnd->setChecked(false); + horizontalLayout_4->addWidget(cBTouchEnd); + vLayout->addWidget(gTouchBox); + + QGroupBox* gTapBox = new QGroupBox(QString(QStringLiteral("Qt TapGesture Signale")), tab3); + QWidget* widgetTapBox = new QWidget(gTapBox); + widgetTapBox->setGeometry(QRect(30, 30, 762, 33)); + QHBoxLayout* horizontalLayout_gTap = new QHBoxLayout(widgetTapBox); + horizontalLayout_gTap->setContentsMargins(0, 0, 0, 0); + QCheckBox* cBTapBeginn = new QCheckBox(QString(QStringLiteral("TapBeginn")), widgetTapBox); + cBTapBeginn->setChecked(false); + horizontalLayout_gTap->addWidget(cBTapBeginn); + QCheckBox* cBTapUpdate = new QCheckBox(widgetTapBox); + cBTapUpdate->setText(QString(QStringLiteral("TapUpdate"))); + cBTapUpdate->setChecked(false); + horizontalLayout_gTap->addWidget(cBTapUpdate); + QCheckBox* cBTapEnd = new QCheckBox(widgetTapBox); + cBTapEnd->setText(QString(QStringLiteral("TapEnd"))); + cBTapEnd->setChecked(true); + horizontalLayout_gTap->addWidget(cBTapEnd); + QCheckBox* cBTapCancel = new QCheckBox(widgetTapBox); + cBTapCancel->setText(QString(QStringLiteral("TapCancel"))); + cBTapCancel->setChecked(false); + horizontalLayout_gTap->addWidget(cBTapCancel); + vLayout->addWidget(gTapBox); + + QGroupBox* gHoldBox = new QGroupBox(QString(QStringLiteral("Qt TapAndHoldGesture Signale")), tab3); + QWidget* widgetHoldBox = new QWidget(gHoldBox); + widgetHoldBox->setGeometry(QRect(30, 30, 762, 33)); + QHBoxLayout* horizontalLayout_gHold = new QHBoxLayout(widgetHoldBox); + horizontalLayout_gHold->setContentsMargins(0, 0, 0, 0); + QCheckBox* cBHoldBeginn = new QCheckBox(QString(QStringLiteral("TapAndHoldBeginn")), widgetHoldBox); + cBHoldBeginn->setChecked(false); + horizontalLayout_gHold->addWidget(cBHoldBeginn); + QCheckBox* cBHoldUpdate = new QCheckBox(widgetHoldBox); + cBHoldUpdate->setText(QString(QStringLiteral("TapAndHoldUpdate"))); + cBHoldUpdate->setChecked(false); + horizontalLayout_gHold->addWidget(cBHoldUpdate); + QCheckBox* cBHoldEnd = new QCheckBox(widgetHoldBox); + cBHoldEnd->setText(QString(QStringLiteral("TapAndHoldEnd"))); + cBHoldEnd->setChecked(true); + horizontalLayout_gHold->addWidget(cBHoldEnd); + QCheckBox* cBHoldCancel = new QCheckBox(widgetHoldBox); + cBHoldCancel->setText(QString(QStringLiteral("TapAndHoldCancel"))); + cBHoldCancel->setChecked(false); + horizontalLayout_gHold->addWidget(cBHoldCancel); + vLayout->addWidget(gHoldBox); + + QGroupBox* gPinchBox = new QGroupBox(QString(QStringLiteral("Qt PinchGesture Signale")), tab3); + QWidget* widgetPinchBox = new QWidget(gPinchBox); + widgetPinchBox->setGeometry(QRect(30, 30, 762, 33)); + QHBoxLayout* horizontalLayout_gPinch = new QHBoxLayout(widgetPinchBox); + horizontalLayout_gPinch->setContentsMargins(0, 0, 0, 0); + QCheckBox* cBPinchBeginn = new QCheckBox(QString(QStringLiteral("PinchBeginn")), widgetPinchBox); + cBPinchBeginn->setChecked(true); + horizontalLayout_gPinch->addWidget(cBPinchBeginn); + QCheckBox* cBPinchUpdate = new QCheckBox(widgetPinchBox); + cBPinchUpdate->setText(QString(QStringLiteral("PinchUpdate"))); + cBPinchUpdate->setChecked(true); + horizontalLayout_gPinch->addWidget(cBPinchUpdate); + QCheckBox* cBPinchEnd = new QCheckBox(widgetPinchBox); + cBPinchEnd->setText(QString(QStringLiteral("PinchEnd"))); + cBPinchEnd->setChecked(false); + horizontalLayout_gPinch->addWidget(cBPinchEnd); + QCheckBox* cBPinchCancel = new QCheckBox(widgetPinchBox); + cBPinchCancel->setText(QString(QStringLiteral("PinchCancel"))); + cBPinchCancel->setChecked(false); + horizontalLayout_gPinch->addWidget(cBPinchCancel); + vLayout->addWidget(gPinchBox); + + QGroupBox* gPanBox = new QGroupBox(QString(QStringLiteral("Qt PanGesture Signale")), tab3); + QWidget* widgetPanBox = new QWidget(gPanBox); + widgetPanBox->setGeometry(QRect(30, 30, 762, 33)); + QHBoxLayout* horizontalLayout_gPan = new QHBoxLayout(widgetPanBox); + horizontalLayout_gPan->setContentsMargins(0, 0, 0, 0); + QCheckBox* cBPanBeginn = new QCheckBox(QString(QStringLiteral("PanBeginn")), widgetPanBox); + cBPanBeginn->setChecked(true); + horizontalLayout_gPan->addWidget(cBPanBeginn); + QCheckBox* cBPanUpdate = new QCheckBox(widgetPanBox); + cBPanUpdate->setText(QString(QStringLiteral("PanUpdate"))); + cBPanUpdate->setChecked(true); + horizontalLayout_gPan->addWidget(cBPanUpdate); + QCheckBox* cBPanEnd = new QCheckBox(widgetPanBox); + cBPanEnd->setText(QString(QStringLiteral("PanEnd"))); + cBPanEnd->setChecked(false); + horizontalLayout_gPan->addWidget(cBPanEnd); + QCheckBox* cBPanCancel = new QCheckBox(widgetPanBox); + cBPanCancel->setText(QString(QStringLiteral("PanCancel"))); + cBPanCancel->setChecked(false); + horizontalLayout_gPan->addWidget(cBPanCancel); + vLayout->addWidget(gPanBox); + + QGroupBox* gSwipeBox = new QGroupBox(QString(QStringLiteral("Qt SwipeGesture Signale")), tab3); + QWidget* widgetSwipeBox = new QWidget(gSwipeBox); + widgetSwipeBox->setGeometry(QRect(30, 30, 762, 33)); + QHBoxLayout* horizontalLayout_gSwipe = new QHBoxLayout(widgetSwipeBox); + horizontalLayout_gSwipe->setContentsMargins(0, 0, 0, 0); + QCheckBox* cBSwipeBeginn = new QCheckBox(QString(QStringLiteral("SwipeBeginn")), widgetSwipeBox); + cBSwipeBeginn->setChecked(false); + horizontalLayout_gSwipe->addWidget(cBSwipeBeginn); + QCheckBox* cBSwipeUpdate = new QCheckBox(widgetSwipeBox); + cBSwipeUpdate->setText(QString(QStringLiteral("SwipeUpdate"))); + cBSwipeUpdate->setChecked(false); + horizontalLayout_gSwipe->addWidget(cBSwipeUpdate); + QCheckBox* cBSwipeEnd = new QCheckBox(widgetSwipeBox); + cBSwipeEnd->setText(QString(QStringLiteral("SwipeEnd"))); + cBSwipeEnd->setChecked(true); + horizontalLayout_gSwipe->addWidget(cBSwipeEnd); + QCheckBox* cBSwipeCancel = new QCheckBox(widgetSwipeBox); + cBSwipeCancel->setText(QString(QStringLiteral("SwipeCancel"))); + cBSwipeCancel->setChecked(false); + horizontalLayout_gSwipe->addWidget(cBSwipeCancel); + vLayout->addWidget(gSwipeBox); + + QGroupBox* gDoubleTapBox = new QGroupBox(QString(QStringLiteral("DoubleTapGesture Signale")), tab3); + QWidget* widgetDoubleTapBox = new QWidget(gDoubleTapBox); + widgetDoubleTapBox->setGeometry(QRect(30, 30, 762, 33)); + QHBoxLayout* horizontalLayout_gDoubleTap = new QHBoxLayout(widgetDoubleTapBox); + horizontalLayout_gDoubleTap->setContentsMargins(0, 0, 0, 0); + QCheckBox* cBDoubleTapBeginn = new QCheckBox(QString(QStringLiteral("DoubleTapBeginn")), widgetDoubleTapBox); + cBDoubleTapBeginn->setChecked(false); + horizontalLayout_gDoubleTap->addWidget(cBDoubleTapBeginn); + QCheckBox* cBDoubleTapUpdate = new QCheckBox(widgetDoubleTapBox); + cBDoubleTapUpdate->setText(QString(QStringLiteral("DoubleTapUpdate"))); + cBDoubleTapUpdate->setChecked(false); + horizontalLayout_gDoubleTap->addWidget(cBDoubleTapUpdate); + QCheckBox* cBDoubleTapEnd = new QCheckBox(widgetDoubleTapBox); + cBDoubleTapEnd->setText(QString(QStringLiteral("DoubleTapEnd"))); + cBDoubleTapEnd->setChecked(true); + horizontalLayout_gDoubleTap->addWidget(cBDoubleTapEnd); + QCheckBox* cBDoubleTapCancel = new QCheckBox(widgetDoubleTapBox); + cBDoubleTapCancel->setText(QString(QStringLiteral("DoubleTapCancel"))); + cBDoubleTapCancel->setChecked(false); + horizontalLayout_gDoubleTap->addWidget(cBDoubleTapCancel); + vLayout->addWidget(gDoubleTapBox); + + QGroupBox* gTwoFingerTapBox = new QGroupBox(QString(QStringLiteral("TwoFingerTapGesture Signale")), tab3); + QWidget* widgetTwoFingerTapBox = new QWidget(gTwoFingerTapBox); + widgetTwoFingerTapBox->setGeometry(QRect(30, 30, 762, 33)); + QHBoxLayout* horizontalLayout_gTwoFingerTap = new QHBoxLayout(widgetTwoFingerTapBox); + horizontalLayout_gTwoFingerTap->setContentsMargins(0, 0, 0, 0); + QCheckBox* cBTwoFingerTapBeginn = new QCheckBox(QString(QStringLiteral("TwoFingerTapBeginn")), widgetTwoFingerTapBox); + cBTwoFingerTapBeginn->setChecked(false); + horizontalLayout_gTwoFingerTap->addWidget(cBTwoFingerTapBeginn); + QCheckBox* cBTwoFingerTapUpdate = new QCheckBox(widgetTwoFingerTapBox); + cBTwoFingerTapUpdate->setText(QString(QStringLiteral("TwoFingerTapUpdate"))); + cBTwoFingerTapUpdate->setChecked(false); + horizontalLayout_gTwoFingerTap->addWidget(cBTwoFingerTapUpdate); + QCheckBox* cBTwoFingerTapEnd = new QCheckBox(widgetTwoFingerTapBox); + cBTwoFingerTapEnd->setText(QString(QStringLiteral("TwoFingerTapEnd"))); + cBTwoFingerTapEnd->setChecked(true); + horizontalLayout_gTwoFingerTap->addWidget(cBTwoFingerTapEnd); + QCheckBox* cBTwoFingerTapCancel = new QCheckBox(widgetTwoFingerTapBox); + cBTwoFingerTapCancel->setText(QString(QStringLiteral("TwoFingerTapCancel"))); + cBTwoFingerTapCancel->setChecked(false); + horizontalLayout_gTwoFingerTap->addWidget(cBTwoFingerTapCancel); + vLayout->addWidget(gTwoFingerTapBox); + + QGroupBox* gTapHoldAndMovingBox = new QGroupBox(QString(QStringLiteral("TapHoldAndMovingGesture Signale")), tab3); + QWidget* widgetTapHoldAndMovingBox = new QWidget(gTapHoldAndMovingBox); + widgetTapHoldAndMovingBox->setGeometry(QRect(30, 30, 762, 33)); + QHBoxLayout* horizontalLayout_gTapHoldAndMoving = new QHBoxLayout(widgetTapHoldAndMovingBox); + horizontalLayout_gTapHoldAndMoving->setContentsMargins(0, 0, 0, 0); + QCheckBox* cBTapHoldAndMovingBeginn = new QCheckBox(QString(QStringLiteral("TapHoldAndMovingBeginn")), widgetTapHoldAndMovingBox); + cBTapHoldAndMovingBeginn->setChecked(true); + horizontalLayout_gTapHoldAndMoving->addWidget(cBTapHoldAndMovingBeginn); + QCheckBox* cBTapHoldAndMovingUpdate = new QCheckBox(widgetTapHoldAndMovingBox); + cBTapHoldAndMovingUpdate->setText(QString(QStringLiteral("TapHoldAndMovingUpdate"))); + cBTapHoldAndMovingUpdate->setChecked(true); + horizontalLayout_gTapHoldAndMoving->addWidget(cBTapHoldAndMovingUpdate); + QCheckBox* cBTapHoldAndMovingEnd = new QCheckBox(widgetTapHoldAndMovingBox); + cBTapHoldAndMovingEnd->setText(QString(QStringLiteral("TapHoldAndMovingEnd"))); + cBTapHoldAndMovingEnd->setChecked(true); + horizontalLayout_gTapHoldAndMoving->addWidget(cBTapHoldAndMovingEnd); + QCheckBox* cBTapHoldAndMovingCancel = new QCheckBox(widgetTapHoldAndMovingBox); + cBTapHoldAndMovingCancel->setText(QString(QStringLiteral("TapHoldAndMovingCancel"))); + cBTapHoldAndMovingCancel->setChecked(false); + horizontalLayout_gTapHoldAndMoving->addWidget(cBTapHoldAndMovingCancel); + vLayout->addWidget(gTapHoldAndMovingBox); + + QGroupBox* gOneAndTwoFingerSwipeBox = new QGroupBox(QString(QStringLiteral("OneAndTwoFingerSwipeGesture Signale")), tab3); + QWidget* widgetOneAndTwoFingerSwipeBox = new QWidget(gOneAndTwoFingerSwipeBox); + widgetOneAndTwoFingerSwipeBox->setGeometry(QRect(30, 30, 762, 33)); + QHBoxLayout* horizontalLayout_gOneAndTwoFingerSwipe = new QHBoxLayout(widgetOneAndTwoFingerSwipeBox); + horizontalLayout_gOneAndTwoFingerSwipe->setContentsMargins(0, 0, 0, 0); + QCheckBox* cBOneAndTwoFingerSwipeBeginn = new QCheckBox(QString(QStringLiteral("OneAndTwoFingerSwipeBeginn")), widgetOneAndTwoFingerSwipeBox); + cBOneAndTwoFingerSwipeBeginn->setChecked(false); + horizontalLayout_gOneAndTwoFingerSwipe->addWidget(cBOneAndTwoFingerSwipeBeginn); + QCheckBox* cBOneAndTwoFingerSwipeUpdate = new QCheckBox(widgetOneAndTwoFingerSwipeBox); + cBOneAndTwoFingerSwipeUpdate->setText(QString(QStringLiteral("OneAndTwoFingerSwipeUpdate"))); + cBOneAndTwoFingerSwipeUpdate->setChecked(false); + horizontalLayout_gOneAndTwoFingerSwipe->addWidget(cBOneAndTwoFingerSwipeUpdate); + QCheckBox* cBOneAndTwoFingerSwipeEnd = new QCheckBox(widgetOneAndTwoFingerSwipeBox); + cBOneAndTwoFingerSwipeEnd->setText(QString(QStringLiteral("OneAndTwoFingerSwipeEnd"))); + cBOneAndTwoFingerSwipeEnd->setChecked(true); + horizontalLayout_gOneAndTwoFingerSwipe->addWidget(cBOneAndTwoFingerSwipeEnd); + QCheckBox* cBOneAndTwoFingerSwipeCancel = new QCheckBox(widgetOneAndTwoFingerSwipeBox); + cBOneAndTwoFingerSwipeCancel->setText(QString(QStringLiteral("OneAndTwoFingerSwipeCancel"))); + cBOneAndTwoFingerSwipeCancel->setChecked(false); + horizontalLayout_gOneAndTwoFingerSwipe->addWidget(cBOneAndTwoFingerSwipeCancel); + vLayout->addWidget(gOneAndTwoFingerSwipeBox); + + QGroupBox* gTwoFingerPanBox = new QGroupBox(QString(QStringLiteral("TwoFingerPanGesture Signale")), tab3); + QWidget* widgetTwoFingerPanBox = new QWidget(gTwoFingerPanBox); + widgetTwoFingerPanBox->setGeometry(QRect(30, 30, 762, 33)); + QHBoxLayout* horizontalLayout_gTwoFingerPan = new QHBoxLayout(widgetTwoFingerPanBox); + horizontalLayout_gTwoFingerPan->setContentsMargins(0, 0, 0, 0); + QCheckBox* cBTwoFingerPanBeginn = new QCheckBox(QString(QStringLiteral("TwoFingerPanBeginn")), widgetTwoFingerPanBox); + cBTwoFingerPanBeginn->setChecked(false); + horizontalLayout_gTwoFingerPan->addWidget(cBTwoFingerPanBeginn); + QCheckBox* cBTwoFingerPanUpdate = new QCheckBox(widgetTwoFingerPanBox); + cBTwoFingerPanUpdate->setText(QString(QStringLiteral("TwoFingerPanUpdate"))); + cBTwoFingerPanUpdate->setChecked(true); + horizontalLayout_gTwoFingerPan->addWidget(cBTwoFingerPanUpdate); + QCheckBox* cBTwoFingerPanEnd = new QCheckBox(widgetTwoFingerPanBox); + cBTwoFingerPanEnd->setText(QString(QStringLiteral("TwoFingerPanEnd"))); + cBTwoFingerPanEnd->setChecked(false); + horizontalLayout_gTwoFingerPan->addWidget(cBTwoFingerPanEnd); + QCheckBox* cBTwoFingerPanCancel = new QCheckBox(widgetTwoFingerPanBox); + cBTwoFingerPanCancel->setText(QString(QStringLiteral("TwoFingerPanCancel"))); + cBTwoFingerPanCancel->setChecked(false); + horizontalLayout_gTwoFingerPan->addWidget(cBTwoFingerPanCancel); + vLayout->addWidget(gTwoFingerPanBox); + + QGroupBox* gOneFingerPanBox = new QGroupBox(QString(QStringLiteral("OneFingerPanGesture Signale")), tab3); + QWidget* widgetOneFingerPanBox = new QWidget(gOneFingerPanBox); + widgetOneFingerPanBox->setGeometry(QRect(30, 30, 762, 33)); + QHBoxLayout* horizontalLayout_gOneFingerPan = new QHBoxLayout(widgetOneFingerPanBox); + horizontalLayout_gOneFingerPan->setContentsMargins(0, 0, 0, 0); + QCheckBox* cBOneFingerPanBeginn = new QCheckBox(QString(QStringLiteral("OneFingerPanBeginn")), widgetOneFingerPanBox); + cBOneFingerPanBeginn->setChecked(false); + horizontalLayout_gOneFingerPan->addWidget(cBOneFingerPanBeginn); + QCheckBox* cBOneFingerPanUpdate = new QCheckBox(widgetOneFingerPanBox); + cBOneFingerPanUpdate->setText(QString(QStringLiteral("OneFingerPanUpdate"))); + cBOneFingerPanUpdate->setChecked(true); + horizontalLayout_gOneFingerPan->addWidget(cBOneFingerPanUpdate); + QCheckBox* cBOneFingerPanEnd = new QCheckBox(widgetOneFingerPanBox); + cBOneFingerPanEnd->setText(QString(QStringLiteral("OneFingerPanEnd"))); + cBOneFingerPanEnd->setChecked(false); + horizontalLayout_gOneFingerPan->addWidget(cBOneFingerPanEnd); + QCheckBox* cBOneFingerPanCancel = new QCheckBox(widgetOneFingerPanBox); + cBOneFingerPanCancel->setText(QString(QStringLiteral("OneFingerPanCancel"))); + cBOneFingerPanCancel->setChecked(false); + horizontalLayout_gOneFingerPan->addWidget(cBOneFingerPanCancel); + vLayout->addWidget(gOneFingerPanBox); + + tabWidget->addTab(tab2, QString(QStringLiteral("QGraphicsView Class"))); + tabWidget->addTab(tab1, QString(QStringLiteral("QWidget Class"))); + tabWidget->addTab(tab3, QString(QStringLiteral("Settings"))); + horizontalLayout->addWidget(tabWidget); + mainWindow->setCentralWidget(centralwidget); + tabWidget->setCurrentIndex(0); + + mKTouchGesture = new KTouchGesture(browser->viewport(), KTouchGesture::AllGesture); + mKTouchGesture->setTouchSignalFlags(KTouchGesture::NoSignal); + + mGraphicsTouch = new KTouchGesture(graphicsW, KTouchGesture::AllGesture); + mGraphicsTouch->setTouchSignalFlags(KTouchGesture::NoSignal); + + QObject::connect(cBTouchBeginn, &QAbstractButton::toggled, + [=](const bool checked) {toggleTouchSignal(KTouchGesture::TouchBeginn, checked);}); + QObject::connect(cBTouchUpdate, &QAbstractButton::toggled, + [=](const bool checked) {toggleTouchSignal(KTouchGesture::TouchUpdate, checked);}); + QObject::connect(cBTouchEnd, &QAbstractButton::toggled, + [=](const bool checked) {toggleTouchSignal(KTouchGesture::TouchEnd, checked);}); + + QObject::connect(cBTapBeginn, &QAbstractButton::toggled, + [=](const bool checked) {toggleGestureSignal(KTouchGesture::GestureStarted, checked, KTouchGesture::TapGesture);}); + QObject::connect(cBTapUpdate, &QAbstractButton::toggled, + [=](const bool checked) {toggleGestureSignal(KTouchGesture::GestureUpdated, checked, KTouchGesture::TapGesture);}); + QObject::connect(cBTapEnd, &QAbstractButton::toggled, + [=](const bool checked) {toggleGestureSignal(KTouchGesture::GestureFinished, checked, KTouchGesture::TapGesture);}); + QObject::connect(cBTapCancel, &QAbstractButton::toggled, + [=](const bool checked) {toggleGestureSignal(KTouchGesture::GestureCanceled, checked, KTouchGesture::TapGesture);}); + + QObject::connect(cBHoldBeginn, &QAbstractButton::toggled, + [=](const bool checked) {toggleGestureSignal(KTouchGesture::GestureStarted, checked, KTouchGesture::TapAndHoldGesture);}); + QObject::connect(cBHoldUpdate, &QAbstractButton::toggled, + [=](const bool checked) {toggleGestureSignal(KTouchGesture::GestureUpdated, checked, KTouchGesture::TapAndHoldGesture);}); + QObject::connect(cBHoldEnd, &QAbstractButton::toggled, + [=](const bool checked) {toggleGestureSignal(KTouchGesture::GestureFinished, checked, KTouchGesture::TapAndHoldGesture);}); + QObject::connect(cBHoldCancel, &QAbstractButton::toggled, + [=](const bool checked) {toggleGestureSignal(KTouchGesture::GestureCanceled, checked, KTouchGesture::TapAndHoldGesture);}); + + QObject::connect(cBPinchBeginn, &QAbstractButton::toggled, + [=](const bool checked) {toggleGestureSignal(KTouchGesture::GestureStarted, checked, KTouchGesture::PinchGesture);}); + QObject::connect(cBPinchUpdate, &QAbstractButton::toggled, + [=](const bool checked) {toggleGestureSignal(KTouchGesture::GestureUpdated, checked, KTouchGesture::PinchGesture);}); + QObject::connect(cBPinchEnd, &QAbstractButton::toggled, + [=](const bool checked) {toggleGestureSignal(KTouchGesture::GestureFinished, checked, KTouchGesture::PinchGesture);}); + QObject::connect(cBPinchCancel, &QAbstractButton::toggled, + [=](const bool checked) {toggleGestureSignal(KTouchGesture::GestureCanceled, checked, KTouchGesture::PinchGesture);}); + + QObject::connect(cBPanBeginn, &QAbstractButton::toggled, + [=](const bool checked) {toggleGestureSignal(KTouchGesture::GestureStarted, checked, KTouchGesture::PanGesture);}); + QObject::connect(cBPanUpdate, &QAbstractButton::toggled, + [=](const bool checked) {toggleGestureSignal(KTouchGesture::GestureUpdated, checked, KTouchGesture::PanGesture);}); + QObject::connect(cBPanEnd, &QAbstractButton::toggled, + [=](const bool checked) {toggleGestureSignal(KTouchGesture::GestureFinished, checked, KTouchGesture::PanGesture);}); + QObject::connect(cBPanCancel, &QAbstractButton::toggled, + [=](const bool checked) {toggleGestureSignal(KTouchGesture::GestureCanceled, checked, KTouchGesture::PanGesture);}); + + + QObject::connect(cBSwipeBeginn, &QAbstractButton::toggled, + [=](const bool checked) {toggleGestureSignal(KTouchGesture::GestureStarted, checked, KTouchGesture::SwipeGesture);}); + QObject::connect(cBSwipeUpdate, &QAbstractButton::toggled, + [=](const bool checked) {toggleGestureSignal(KTouchGesture::GestureUpdated, checked, KTouchGesture::SwipeGesture);}); + QObject::connect(cBSwipeEnd, &QAbstractButton::toggled, + [=](const bool checked) {toggleGestureSignal(KTouchGesture::GestureFinished, checked, KTouchGesture::SwipeGesture);}); + QObject::connect(cBSwipeCancel, &QAbstractButton::toggled, + [=](const bool checked) {toggleGestureSignal(KTouchGesture::GestureCanceled, checked, KTouchGesture::SwipeGesture);}); + + QObject::connect(cBDoubleTapBeginn, &QAbstractButton::toggled, + [=](const bool checked) {toggleGestureSignal(KTouchGesture::GestureStarted, checked, KTouchGesture::DoubleTap);}); + QObject::connect(cBDoubleTapUpdate, &QAbstractButton::toggled, + [=](const bool checked) {toggleGestureSignal(KTouchGesture::GestureUpdated, checked, KTouchGesture::DoubleTap);}); + QObject::connect(cBDoubleTapEnd, &QAbstractButton::toggled, + [=](const bool checked) {toggleGestureSignal(KTouchGesture::GestureFinished, checked, KTouchGesture::DoubleTap);}); + QObject::connect(cBDoubleTapCancel, &QAbstractButton::toggled, + [=](const bool checked) {toggleGestureSignal(KTouchGesture::GestureCanceled, checked, KTouchGesture::DoubleTap);}); + + QObject::connect(cBTwoFingerTapBeginn, &QAbstractButton::toggled, + [=](const bool checked) {toggleGestureSignal(KTouchGesture::GestureStarted, checked, KTouchGesture::TwoFingerTap);}); + QObject::connect(cBTwoFingerTapUpdate, &QAbstractButton::toggled, + [=](const bool checked) {toggleGestureSignal(KTouchGesture::GestureUpdated, checked, KTouchGesture::TwoFingerTap);}); + QObject::connect(cBTwoFingerTapEnd, &QAbstractButton::toggled, + [=](const bool checked) {toggleGestureSignal(KTouchGesture::GestureFinished, checked, KTouchGesture::TwoFingerTap);}); + QObject::connect(cBTwoFingerTapCancel, &QAbstractButton::toggled, + [=](const bool checked) {toggleGestureSignal(KTouchGesture::GestureCanceled, checked, KTouchGesture::TwoFingerTap);}); + + QObject::connect(cBTapHoldAndMovingBeginn, &QAbstractButton::toggled, + [=](const bool checked) {toggleGestureSignal(KTouchGesture::GestureStarted, checked, KTouchGesture::TapHoldAndMoving);}); + QObject::connect(cBTapHoldAndMovingUpdate, &QAbstractButton::toggled, + [=](const bool checked) {toggleGestureSignal(KTouchGesture::GestureUpdated, checked, KTouchGesture::TapHoldAndMoving);}); + QObject::connect(cBTapHoldAndMovingEnd, &QAbstractButton::toggled, + [=](const bool checked) {toggleGestureSignal(KTouchGesture::GestureFinished, checked, KTouchGesture::TapHoldAndMoving);}); + QObject::connect(cBTapHoldAndMovingCancel, &QAbstractButton::toggled, + [=](const bool checked) {toggleGestureSignal(KTouchGesture::GestureCanceled, checked, KTouchGesture::TapHoldAndMoving);}); + + QObject::connect(cBOneAndTwoFingerSwipeBeginn, &QAbstractButton::toggled, + [=](const bool checked) {toggleGestureSignal(KTouchGesture::GestureStarted, checked, KTouchGesture::OneAndTwoFingerSwipe);}); + QObject::connect(cBOneAndTwoFingerSwipeUpdate, &QAbstractButton::toggled, + [=](const bool checked) {toggleGestureSignal(KTouchGesture::GestureUpdated, checked, KTouchGesture::OneAndTwoFingerSwipe);}); + QObject::connect(cBOneAndTwoFingerSwipeEnd, &QAbstractButton::toggled, + [=](const bool checked) {toggleGestureSignal(KTouchGesture::GestureFinished, checked, KTouchGesture::OneAndTwoFingerSwipe);}); + QObject::connect(cBOneAndTwoFingerSwipeCancel, &QAbstractButton::toggled, + [=](const bool checked) {toggleGestureSignal(KTouchGesture::GestureCanceled, checked, KTouchGesture::OneAndTwoFingerSwipe);}); + + QObject::connect(cBTwoFingerPanBeginn, &QAbstractButton::toggled, + [=](const bool checked) {toggleGestureSignal(KTouchGesture::GestureStarted, checked, KTouchGesture::TwoFingerPan);}); + QObject::connect(cBTwoFingerPanUpdate, &QAbstractButton::toggled, + [=](const bool checked) {toggleGestureSignal(KTouchGesture::GestureUpdated, checked, KTouchGesture::TwoFingerPan);}); + QObject::connect(cBTwoFingerPanEnd, &QAbstractButton::toggled, + [=](const bool checked) {toggleGestureSignal(KTouchGesture::GestureFinished, checked, KTouchGesture::TwoFingerPan);}); + QObject::connect(cBTwoFingerPanCancel, &QAbstractButton::toggled, + [=](const bool checked) {toggleGestureSignal(KTouchGesture::GestureCanceled, checked, KTouchGesture::TwoFingerPan);}); + + QObject::connect(cBOneFingerPanBeginn, &QAbstractButton::toggled, + [=](const bool checked) {toggleGestureSignal(KTouchGesture::GestureStarted, checked, KTouchGesture::OneFingerPan);}); + QObject::connect(cBOneFingerPanUpdate, &QAbstractButton::toggled, + [=](const bool checked) {toggleGestureSignal(KTouchGesture::GestureUpdated, checked, KTouchGesture::OneFingerPan);}); + QObject::connect(cBOneFingerPanEnd, &QAbstractButton::toggled, + [=](const bool checked) {toggleGestureSignal(KTouchGesture::GestureFinished, checked, KTouchGesture::OneFingerPan);}); + QObject::connect(cBOneFingerPanCancel, &QAbstractButton::toggled, + [=](const bool checked) {toggleGestureSignal(KTouchGesture::GestureCanceled, checked, KTouchGesture::OneFingerPan);}); + + QObject::connect(mKTouchGesture, &KTouchGesture::touchBeginnTriggered, browser, + [=](const QList&ts, qreal time){ + browser->appendPlainText(QStringLiteral("touchBeginnTriggered")); + browser->appendPlainText(touchPointsToMsg(ts, time)); + }); + QObject::connect(mKTouchGesture, &KTouchGesture::touchUpdateTriggered, browser, + [=](const QList&ts, qreal time){ + browser->appendPlainText(QStringLiteral("touchUpdateTriggered")); + browser->appendPlainText(touchPointsToMsg(ts, time)); + }); + QObject::connect(mKTouchGesture, &KTouchGesture::touchEndTriggered, browser, + [=](const QList&ts, qreal time){ + browser->appendPlainText(QStringLiteral("touchEndTriggered")); + browser->appendPlainText(touchPointsToMsg(ts, time)); + }); + QObject::connect(mGraphicsTouch, &KTouchGesture::touchBeginnTriggered, browser2, + [=](const QList&ts, qreal time){ + browser2->appendPlainText(QStringLiteral("touchBeginnTriggered")); + browser2->appendPlainText(touchPointsToMsg(ts, time)); + }); + QObject::connect(mGraphicsTouch, &KTouchGesture::touchUpdateTriggered, browser2, + [=](const QList&ts, qreal time){ + browser2->appendPlainText(QStringLiteral("touchUpdateTriggered")); + browser2->appendPlainText(touchPointsToMsg(ts, time)); + }); + QObject::connect(mGraphicsTouch, &KTouchGesture::touchEndTriggered, browser2, + [=](const QList&ts, qreal time){ + browser2->appendPlainText(QStringLiteral("touchEndTriggered")); + browser2->appendPlainText(touchPointsToMsg(ts, time)); + }); + + connectGesture(mKTouchGesture, browser); + connectGesture(mGraphicsTouch, browser2); + + if (mKTouchGesture) { + browser->appendPlainText(QStringLiteral("KTouchGesture Class gefunden")); + } else { + browser->appendPlainText(QStringLiteral("KTouchGesture nicht gefunden")); + } + if (mKTouchGesture->isTouchTargetValid()) { + browser->appendPlainText(QStringLiteral("Touch target is valid")); + } else { + browser->appendPlainText(QStringLiteral("Touch target is not valid - Gestures can be enabled for instances of QWidget and QGraphicsObject subclasses")); + } + + if (mGraphicsTouch) { + browser2->appendPlainText(QStringLiteral("KTouchGesture Class gefunden")); + } else { + browser2->appendPlainText(QStringLiteral("KTouchGesture nicht gefunden")); + } + if (mGraphicsTouch->isTouchTargetValid()) { + browser2->appendPlainText(QStringLiteral("Touch target is valid")); + } else { + browser2->appendPlainText(QStringLiteral("Touch target is not valid - Gestures can be enabled for instances of QWidget and QGraphicsObject subclasses")); + } + + mainWindow->resize(1200, 900); + mainWindow->show(); + + return app.exec(); + +} +