/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the test suite of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "qdeclarativepinchgenerator_p.h" #include #include #include #include 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 QTouchDevice; device_->setType(QTouchDevice::TouchScreen); QWindowSystemInterface::registerTouchDevice(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_.restart(); } 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