Revision control
++ // Copyright (C) 2016 The Qt Company Ltd.
++ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
++
++ #include "qdeclarativepinchgenerator_p.h"
++
++ #include <QtTest/QtTest>
++ #include <QtGui/QGuiApplication>
++ #include <QtGui/qpa/qwindowsysteminterface.h>
++ #include <QtGui/QStyleHints>
++
++ QT_BEGIN_NAMESPACE
++
++ QDeclarativePinchGenerator::QDeclarativePinchGenerator():
++ target_(0),
++ state_(Invalid),
++ window_(0),
++ activeSwipe_(0),
++ replayTimer_(-1),
++ replayBookmark_(-1),
++ masterSwipe_(-1),
++ replaySpeedFactor_(1.0),
++ enabled_(true)
++ {
++ setAcceptedMouseButtons(Qt::LeftButton | Qt::MiddleButton | Qt::RightButton);
++ swipeTimer_.invalidate();
++ device_ = new QPointingDevice("test", -1, QInputDevice::DeviceType::TouchScreen,
++ QPointingDevice::PointerType::Finger,
++ QInputDevice::Capability::Position, 1, 0);
++ QWindowSystemInterface::registerInputDevice(device_);
++ }
++
++ QDeclarativePinchGenerator::~QDeclarativePinchGenerator()
++ {
++ clear();
++ }
++
++ void QDeclarativePinchGenerator::componentComplete()
++ {
++ QQuickItem::componentComplete();
++ }
++
++ void QDeclarativePinchGenerator::mousePressEvent(QMouseEvent *event)
++ {
++ if (state_ != Idle || !enabled_) {
++ event->ignore();
++ return;
++ }
++ Q_ASSERT(!activeSwipe_);
++ Q_ASSERT(!swipeTimer_.isValid());
++ // Start recording a pinch gesture.
++ activeSwipe_ = new Swipe;
++ activeSwipe_->touchPoints << event->pos();
++ activeSwipe_->durations << 0;
++ swipeTimer_.start();
++ setState(Recording);
++ }
++
++ void QDeclarativePinchGenerator::mouseMoveEvent(QMouseEvent *event)
++ {
++ if (state_ != Recording || !enabled_) {
++ event->ignore();
++ return;
++ }
++ Q_ASSERT(activeSwipe_);
++ Q_ASSERT(swipeTimer_.isValid());
++
++ activeSwipe_->touchPoints << event->pos();
++ activeSwipe_->durations << swipeTimer_.elapsed();
++ swipeTimer_.start();
++ }
++
++ void QDeclarativePinchGenerator::mouseReleaseEvent(QMouseEvent *event)
++ {
++ if (state_ != Recording || !enabled_) {
++ event->ignore();
++ return;
++ }
++ Q_ASSERT(activeSwipe_);
++ Q_ASSERT(swipeTimer_.isValid());
++ activeSwipe_->touchPoints << event->pos();
++ activeSwipe_->durations << swipeTimer_.elapsed();
++
++ if (swipes_.count() == SWIPES_REQUIRED)
++ delete swipes_.takeFirst();
++ swipes_ << activeSwipe_;
++ activeSwipe_ = 0;
++ swipeTimer_.invalidate();
++ if (window_ && target_) setState(Idle); else setState(Invalid);
++ }
++
++ void QDeclarativePinchGenerator::mouseDoubleClickEvent(QMouseEvent *event)
++ {
++ Q_UNUSED(event);
++ if (!enabled_) {
++ event->ignore();
++ return;
++ }
++ stop();
++ clear();
++ if (window_ && target_) setState(Idle); else setState(Invalid);
++ }
++
++ void QDeclarativePinchGenerator::keyPressEvent(QKeyEvent *e)
++ {
++ if (!enabled_) {
++ e->ignore();
++ }
++
++ if (e->key() == Qt::Key_C) {
++ clear();
++ } else if (e->key() == Qt::Key_R) {
++ replay();
++ } else if (e->key() == Qt::Key_S) {
++ stop();
++ } else if (e->key() == Qt::Key_Plus) {
++ setReplaySpeedFactor(replaySpeedFactor() + 0.1);
++ } else if (e->key() == Qt::Key_Minus) {
++ setReplaySpeedFactor(replaySpeedFactor() - 0.1);
++ } else {
++ qDebug() << metaObject()->className() << "Unsupported key event.";
++ }
++ }
++
++ bool QDeclarativePinchGenerator::enabled() const
++ {
++ return enabled_;
++ }
++
++
++ void QDeclarativePinchGenerator::setEnabled(bool enabled)
++ {
++ if (enabled == enabled_)
++ return;
++ enabled_ = enabled;
++ if (!enabled_) {
++ stop();
++ clear();
++ }
++ emit enabledChanged();
++ }
++
++
++ qreal QDeclarativePinchGenerator::replaySpeedFactor() const
++ {
++ return replaySpeedFactor_;
++ }
++
++ void QDeclarativePinchGenerator::setReplaySpeedFactor(qreal factor)
++ {
++ if (factor == replaySpeedFactor_ || factor < 0.001)
++ return;
++ replaySpeedFactor_ = factor;
++ emit replaySpeedFactorChanged();
++ }
++
++
++ QString QDeclarativePinchGenerator::state() const
++ {
++ switch (state_) {
++ case Invalid:
++ return "Invalid";
++ case Idle:
++ return "Idle";
++ break;
++ case Recording:
++ return "Recording";
++ break;
++ case Replaying:
++ return "Replaying";
++ break;
++ default:
++ Q_ASSERT(false);
++ }
++ return "How emberassing";
++ }
++
++ void QDeclarativePinchGenerator::setState(GeneratorState state)
++ {
++ if (state == state_)
++ return;
++ state_ = state;
++ emit stateChanged();
++ }
++
++ void QDeclarativePinchGenerator::itemChange(ItemChange change, const ItemChangeData & data)
++ {
++ if (change == ItemSceneChange) {
++ window_ = data.window;
++ if (target_)
++ setState(Idle);
++ }
++ }
++
++ void QDeclarativePinchGenerator::timerEvent(QTimerEvent *event)
++ {
++ Q_ASSERT(replayTimer_ == event->timerId());
++ Q_UNUSED(event);
++ Q_ASSERT(state_ == Replaying);
++
++ int slaveSwipe = masterSwipe_ ^ 1;
++
++ int masterCount = swipes_.at(masterSwipe_)->touchPoints.count();
++ int slaveCount = swipes_.at(slaveSwipe)->touchPoints.count();
++
++ if (replayBookmark_ == 0) {
++ QTest::touchEvent(window_, device_)
++ .press(0, swipes_.at(masterSwipe_)->touchPoints.at(replayBookmark_))
++ .press(1, swipes_.at(slaveSwipe)->touchPoints.at(replayBookmark_));
++ } else if (replayBookmark_ == (slaveCount - 1)) {
++ if (masterCount != slaveCount) {
++ QTest::touchEvent(window_, device_)
++ .move(0, swipes_.at(masterSwipe_)->touchPoints.at(replayBookmark_))
++ .release(1, swipes_.at(slaveSwipe)->touchPoints.at(replayBookmark_));
++ } else {
++ QTest::touchEvent(window_, device_)
++ .release(0, swipes_.at(masterSwipe_)->touchPoints.at(replayBookmark_))
++ .release(1, swipes_.at(slaveSwipe)->touchPoints.at(replayBookmark_));
++ }
++ } else if (replayBookmark_ == (masterCount - 1)) {
++ QTest::touchEvent(window_, device_)
++ .release(0, swipes_.at(masterSwipe_)->touchPoints.at(replayBookmark_));
++ }
++ else {
++ QTest::touchEvent(window_, device_)
++ .move(0, swipes_.at(masterSwipe_)->touchPoints.at(replayBookmark_))
++ .move(1, swipes_.at(slaveSwipe)->touchPoints.at(replayBookmark_));
++ }
++
++ replayBookmark_++;
++ if (replayBookmark_ >= swipes_.at(masterSwipe_)->touchPoints.count())
++ stop();
++ else {
++ killTimer(replayTimer_);
++ replayTimer_ = startTimer((swipes_.at(masterSwipe_)->durations.at(replayBookmark_) + 5) / replaySpeedFactor_ );
++ }
++ }
++
++ QQuickItem* QDeclarativePinchGenerator::target() const
++ {
++ return target_;
++ }
++
++ void QDeclarativePinchGenerator::setTarget(QQuickItem* target)
++ {
++ if (target == target_)
++ return;
++ target_ = target;
++ stop();
++ clear();
++ if (window_)
++ setState(Idle);
++ else
++ setState(Invalid);
++ emit targetChanged();
++ }
++
++ void QDeclarativePinchGenerator::pinch(QPoint point1From,
++ QPoint point1To,
++ QPoint point2From,
++ QPoint point2To,
++ int interval1,
++ int interval2,
++ int samples1,
++ int samples2)
++ {
++ Q_ASSERT(interval1 > 10);
++ Q_ASSERT(interval2 > 10);
++ Q_ASSERT(samples1 >= 2); // we need press and release events at minimum
++ Q_ASSERT(samples2 >= 2);
++
++ clear();
++
++ Swipe* swipe1 = new Swipe;
++ Swipe* swipe2 = new Swipe;
++ for (int i = 0; i < samples1; ++i) {
++ swipe1->touchPoints << point1From + (point1To - point1From) / samples1 * i;
++ swipe1->durations << interval1;
++ }
++ for (int i = 0; i < samples2; ++i) {
++ swipe2->touchPoints << point2From + (point2To - point2From) / samples2 * i;
++ swipe2->durations << interval2;
++ }
++ swipes_ << swipe1 << swipe2;
++ Q_ASSERT(swipes_.at(0));
++ Q_ASSERT(swipes_.at(1));
++
++ masterSwipe_ = (samples1 >= samples2) ? 0 : 1;
++
++ replayTimer_ = startTimer(swipes_.at(masterSwipe_)->durations.at(0) / replaySpeedFactor_);
++ replayBookmark_ = 0;
++ setState(Replaying);
++ }
++
++ void QDeclarativePinchGenerator::pinchPress(QPoint point1From, QPoint point2From)
++ {
++ QTest::touchEvent(window_, device_).press(0, point1From).press(1, point2From);
++ }
++
++ void QDeclarativePinchGenerator::pinchMoveTo(QPoint point1To, QPoint point2To)
++ {
++ QTest::touchEvent(window_, device_).move(0, point1To).move(1, point2To);
++ }
++
++ void QDeclarativePinchGenerator::pinchRelease(QPoint point1To, QPoint point2To)
++ {
++ QTest::touchEvent(window_, device_).release(0, point1To).release(1, point2To);
++ }
++
++ void QDeclarativePinchGenerator::replay()
++ {
++ if (state_ != Idle) {
++ qDebug() << "Wrong state, will not replay pinch, state: " << state_;
++ return;
++ }
++ if (swipes_.count() < SWIPES_REQUIRED) {
++ qDebug() << "Too few swipes, cannot replay, amount: " << swipes_.count();
++ return;
++ }
++ if ((swipes_.at(0)->touchPoints.count() < 2) || (swipes_.at(1)->touchPoints.count() < 2)) {
++ qDebug() << "Too few touchpoints, won't replay, amount: " <<
++ swipes_.at(0)->touchPoints.count() << (swipes_.at(1)->touchPoints.count() < 2);
++ return;
++ }
++
++ masterSwipe_ = (swipes_.at(0)->touchPoints.count() >= swipes_.at(1)->touchPoints.count()) ? 0 : 1;
++
++ replayTimer_ = startTimer(swipes_.at(masterSwipe_)->touchPoints.count() / replaySpeedFactor_);
++ replayBookmark_ = 0;
++ setState(Replaying);
++ }
++
++ void QDeclarativePinchGenerator::clear()
++ {
++ stop();
++ delete activeSwipe_;
++ activeSwipe_ = 0;
++ if (!swipes_.isEmpty()) {
++ qDeleteAll(swipes_);
++ swipes_.clear();
++ }
++ }
++
++ void QDeclarativePinchGenerator::stop()
++ {
++ if (state_ != Replaying)
++ return;
++ // stop replay
++ Q_ASSERT(replayTimer_ != -1);
++ killTimer(replayTimer_);
++ replayTimer_ = -1;
++ setState(Idle);
++ }
++
++ int QDeclarativePinchGenerator::startDragDistance()
++ {
++ return qApp->styleHints()->startDragDistance();
++ }
++
++ QT_END_NAMESPACE