1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the test suite of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:GPL-EXCEPT$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21 ** included in the packaging of this file. Please review the following
22 ** information to ensure the GNU General Public License requirements will
23 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24 **
25 ** $QT_END_LICENSE$
26 **
27 ****************************************************************************/
28
29 #include "qdeclarativepinchgenerator_p.h"
30
31 #include <QtTest/QtTest>
32 #include <QtGui/QGuiApplication>
33 #include <QtGui/qpa/qwindowsysteminterface.h>
34 #include <QtGui/QStyleHints>
35
36 QT_BEGIN_NAMESPACE
37
QDeclarativePinchGenerator()38 QDeclarativePinchGenerator::QDeclarativePinchGenerator():
39 target_(0),
40 state_(Invalid),
41 window_(0),
42 activeSwipe_(0),
43 replayTimer_(-1),
44 replayBookmark_(-1),
45 masterSwipe_(-1),
46 replaySpeedFactor_(1.0),
47 enabled_(true)
48 {
49 setAcceptedMouseButtons(Qt::LeftButton | Qt::MiddleButton | Qt::RightButton);
50 swipeTimer_.invalidate();
51 device_ = new QTouchDevice;
52 device_->setType(QTouchDevice::TouchScreen);
53 QWindowSystemInterface::registerTouchDevice(device_);
54 }
55
~QDeclarativePinchGenerator()56 QDeclarativePinchGenerator::~QDeclarativePinchGenerator()
57 {
58 clear();
59 }
60
componentComplete()61 void QDeclarativePinchGenerator::componentComplete()
62 {
63 QQuickItem::componentComplete();
64 }
65
mousePressEvent(QMouseEvent * event)66 void QDeclarativePinchGenerator::mousePressEvent(QMouseEvent *event)
67 {
68 if (state_ != Idle || !enabled_) {
69 event->ignore();
70 return;
71 }
72 Q_ASSERT(!activeSwipe_);
73 Q_ASSERT(!swipeTimer_.isValid());
74 // Start recording a pinch gesture.
75 activeSwipe_ = new Swipe;
76 activeSwipe_->touchPoints << event->pos();
77 activeSwipe_->durations << 0;
78 swipeTimer_.start();
79 setState(Recording);
80 }
81
mouseMoveEvent(QMouseEvent * event)82 void QDeclarativePinchGenerator::mouseMoveEvent(QMouseEvent *event)
83 {
84 if (state_ != Recording || !enabled_) {
85 event->ignore();
86 return;
87 }
88 Q_ASSERT(activeSwipe_);
89 Q_ASSERT(swipeTimer_.isValid());
90
91 activeSwipe_->touchPoints << event->pos();
92 activeSwipe_->durations << swipeTimer_.elapsed();
93 swipeTimer_.restart();
94 }
95
mouseReleaseEvent(QMouseEvent * event)96 void QDeclarativePinchGenerator::mouseReleaseEvent(QMouseEvent *event)
97 {
98 if (state_ != Recording || !enabled_) {
99 event->ignore();
100 return;
101 }
102 Q_ASSERT(activeSwipe_);
103 Q_ASSERT(swipeTimer_.isValid());
104 activeSwipe_->touchPoints << event->pos();
105 activeSwipe_->durations << swipeTimer_.elapsed();
106
107 if (swipes_.count() == SWIPES_REQUIRED)
108 delete swipes_.takeFirst();
109 swipes_ << activeSwipe_;
110 activeSwipe_ = 0;
111 swipeTimer_.invalidate();
112 if (window_ && target_) setState(Idle); else setState(Invalid);
113 }
114
mouseDoubleClickEvent(QMouseEvent * event)115 void QDeclarativePinchGenerator::mouseDoubleClickEvent(QMouseEvent *event)
116 {
117 Q_UNUSED(event);
118 if (!enabled_) {
119 event->ignore();
120 return;
121 }
122 stop();
123 clear();
124 if (window_ && target_) setState(Idle); else setState(Invalid);
125 }
126
keyPressEvent(QKeyEvent * e)127 void QDeclarativePinchGenerator::keyPressEvent(QKeyEvent *e)
128 {
129 if (!enabled_) {
130 e->ignore();
131 }
132
133 if (e->key() == Qt::Key_C) {
134 clear();
135 } else if (e->key() == Qt::Key_R) {
136 replay();
137 } else if (e->key() == Qt::Key_S) {
138 stop();
139 } else if (e->key() == Qt::Key_Plus) {
140 setReplaySpeedFactor(replaySpeedFactor() + 0.1);
141 } else if (e->key() == Qt::Key_Minus) {
142 setReplaySpeedFactor(replaySpeedFactor() - 0.1);
143 } else {
144 qDebug() << metaObject()->className() << "Unsupported key event.";
145 }
146 }
147
enabled() const148 bool QDeclarativePinchGenerator::enabled() const
149 {
150 return enabled_;
151 }
152
153
setEnabled(bool enabled)154 void QDeclarativePinchGenerator::setEnabled(bool enabled)
155 {
156 if (enabled == enabled_)
157 return;
158 enabled_ = enabled;
159 if (!enabled_) {
160 stop();
161 clear();
162 }
163 emit enabledChanged();
164 }
165
166
replaySpeedFactor() const167 qreal QDeclarativePinchGenerator::replaySpeedFactor() const
168 {
169 return replaySpeedFactor_;
170 }
171
setReplaySpeedFactor(qreal factor)172 void QDeclarativePinchGenerator::setReplaySpeedFactor(qreal factor)
173 {
174 if (factor == replaySpeedFactor_ || factor < 0.001)
175 return;
176 replaySpeedFactor_ = factor;
177 emit replaySpeedFactorChanged();
178 }
179
180
state() const181 QString QDeclarativePinchGenerator::state() const
182 {
183 switch (state_) {
184 case Invalid:
185 return "Invalid";
186 case Idle:
187 return "Idle";
188 break;
189 case Recording:
190 return "Recording";
191 break;
192 case Replaying:
193 return "Replaying";
194 break;
195 default:
196 Q_ASSERT(false);
197 }
198 return "How emberassing";
199 }
200
setState(GeneratorState state)201 void QDeclarativePinchGenerator::setState(GeneratorState state)
202 {
203 if (state == state_)
204 return;
205 state_ = state;
206 emit stateChanged();
207 }
208
itemChange(ItemChange change,const ItemChangeData & data)209 void QDeclarativePinchGenerator::itemChange(ItemChange change, const ItemChangeData & data)
210 {
211 if (change == ItemSceneChange) {
212 window_ = data.window;
213 if (target_)
214 setState(Idle);
215 }
216 }
217
timerEvent(QTimerEvent * event)218 void QDeclarativePinchGenerator::timerEvent(QTimerEvent *event)
219 {
220 Q_ASSERT(replayTimer_ == event->timerId());
221 Q_UNUSED(event);
222 Q_ASSERT(state_ == Replaying);
223
224 int slaveSwipe = masterSwipe_ ^ 1;
225
226 int masterCount = swipes_.at(masterSwipe_)->touchPoints.count();
227 int slaveCount = swipes_.at(slaveSwipe)->touchPoints.count();
228
229 if (replayBookmark_ == 0) {
230 QTest::touchEvent(window_, device_)
231 .press(0, swipes_.at(masterSwipe_)->touchPoints.at(replayBookmark_))
232 .press(1, swipes_.at(slaveSwipe)->touchPoints.at(replayBookmark_));
233 } else if (replayBookmark_ == (slaveCount - 1)) {
234 if (masterCount != slaveCount) {
235 QTest::touchEvent(window_, device_)
236 .move(0, swipes_.at(masterSwipe_)->touchPoints.at(replayBookmark_))
237 .release(1, swipes_.at(slaveSwipe)->touchPoints.at(replayBookmark_));
238 } else {
239 QTest::touchEvent(window_, device_)
240 .release(0, swipes_.at(masterSwipe_)->touchPoints.at(replayBookmark_))
241 .release(1, swipes_.at(slaveSwipe)->touchPoints.at(replayBookmark_));
242 }
243 } else if (replayBookmark_ == (masterCount - 1)) {
244 QTest::touchEvent(window_, device_)
245 .release(0, swipes_.at(masterSwipe_)->touchPoints.at(replayBookmark_));
246 }
247 else {
248 QTest::touchEvent(window_, device_)
249 .move(0, swipes_.at(masterSwipe_)->touchPoints.at(replayBookmark_))
250 .move(1, swipes_.at(slaveSwipe)->touchPoints.at(replayBookmark_));
251 }
252
253 replayBookmark_++;
254 if (replayBookmark_ >= swipes_.at(masterSwipe_)->touchPoints.count())
255 stop();
256 else {
257 killTimer(replayTimer_);
258 replayTimer_ = startTimer((swipes_.at(masterSwipe_)->durations.at(replayBookmark_) + 5) / replaySpeedFactor_ );
259 }
260 }
261
target() const262 QQuickItem* QDeclarativePinchGenerator::target() const
263 {
264 return target_;
265 }
266
setTarget(QQuickItem * target)267 void QDeclarativePinchGenerator::setTarget(QQuickItem* target)
268 {
269 if (target == target_)
270 return;
271 target_ = target;
272 stop();
273 clear();
274 if (window_)
275 setState(Idle);
276 else
277 setState(Invalid);
278 emit targetChanged();
279 }
280
pinch(QPoint point1From,QPoint point1To,QPoint point2From,QPoint point2To,int interval1,int interval2,int samples1,int samples2)281 void QDeclarativePinchGenerator::pinch(QPoint point1From,
282 QPoint point1To,
283 QPoint point2From,
284 QPoint point2To,
285 int interval1,
286 int interval2,
287 int samples1,
288 int samples2)
289 {
290 Q_ASSERT(interval1 > 10);
291 Q_ASSERT(interval2 > 10);
292 Q_ASSERT(samples1 >= 2); // we need press and release events at minimum
293 Q_ASSERT(samples2 >= 2);
294
295 clear();
296
297 Swipe* swipe1 = new Swipe;
298 Swipe* swipe2 = new Swipe;
299 for (int i = 0; i < samples1; ++i) {
300 swipe1->touchPoints << point1From + (point1To - point1From) / samples1 * i;
301 swipe1->durations << interval1;
302 }
303 for (int i = 0; i < samples2; ++i) {
304 swipe2->touchPoints << point2From + (point2To - point2From) / samples2 * i;
305 swipe2->durations << interval2;
306 }
307 swipes_ << swipe1 << swipe2;
308 Q_ASSERT(swipes_.at(0));
309 Q_ASSERT(swipes_.at(1));
310
311 masterSwipe_ = (samples1 >= samples2) ? 0 : 1;
312
313 replayTimer_ = startTimer(swipes_.at(masterSwipe_)->durations.at(0) / replaySpeedFactor_);
314 replayBookmark_ = 0;
315 setState(Replaying);
316 }
317
pinchPress(QPoint point1From,QPoint point2From)318 void QDeclarativePinchGenerator::pinchPress(QPoint point1From, QPoint point2From)
319 {
320 QTest::touchEvent(window_, device_).press(0, point1From).press(1, point2From);
321 }
322
pinchMoveTo(QPoint point1To,QPoint point2To)323 void QDeclarativePinchGenerator::pinchMoveTo(QPoint point1To, QPoint point2To)
324 {
325 QTest::touchEvent(window_, device_).move(0, point1To).move(1, point2To);
326 }
327
pinchRelease(QPoint point1To,QPoint point2To)328 void QDeclarativePinchGenerator::pinchRelease(QPoint point1To, QPoint point2To)
329 {
330 QTest::touchEvent(window_, device_).release(0, point1To).release(1, point2To);
331 }
332
replay()333 void QDeclarativePinchGenerator::replay()
334 {
335 if (state_ != Idle) {
336 qDebug() << "Wrong state, will not replay pinch, state: " << state_;
337 return;
338 }
339 if (swipes_.count() < SWIPES_REQUIRED) {
340 qDebug() << "Too few swipes, cannot replay, amount: " << swipes_.count();
341 return;
342 }
343 if ((swipes_.at(0)->touchPoints.count() < 2) || (swipes_.at(1)->touchPoints.count() < 2)) {
344 qDebug() << "Too few touchpoints, won't replay, amount: " <<
345 swipes_.at(0)->touchPoints.count() << (swipes_.at(1)->touchPoints.count() < 2);
346 return;
347 }
348
349 masterSwipe_ = (swipes_.at(0)->touchPoints.count() >= swipes_.at(1)->touchPoints.count()) ? 0 : 1;
350
351 replayTimer_ = startTimer(swipes_.at(masterSwipe_)->touchPoints.count() / replaySpeedFactor_);
352 replayBookmark_ = 0;
353 setState(Replaying);
354 }
355
clear()356 void QDeclarativePinchGenerator::clear()
357 {
358 stop();
359 delete activeSwipe_;
360 activeSwipe_ = 0;
361 if (!swipes_.isEmpty()) {
362 qDeleteAll(swipes_);
363 swipes_.clear();
364 }
365 }
366
stop()367 void QDeclarativePinchGenerator::stop()
368 {
369 if (state_ != Replaying)
370 return;
371 // stop replay
372 Q_ASSERT(replayTimer_ != -1);
373 killTimer(replayTimer_);
374 replayTimer_ = -1;
375 setState(Idle);
376 }
377
startDragDistance()378 int QDeclarativePinchGenerator::startDragDistance()
379 {
380 return qApp->styleHints()->startDragDistance();
381 }
382
383 QT_END_NAMESPACE
384