blob: b8866b482e8cbef7a216924c60ae70510d950714 [file] [log] [blame]
/****************************************************************************
**
** 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 <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::MidButton | 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