on xenial help sign in
Remove DirectionalDragArea and libs/UbuntuGestures and port to SDK equivalents

Approved by: Daniel d'Andrada

commiteacc6becb8a81516f93abf562d615fd1110ea586 authorDaniel d'Andrada <> dateFri 27 May 2016, 13:49 (10 years ago) parent64d3f31c80ec92
79 files changed+354−6258
CMakeLists.txt+12−1 debian/control+2 debian/unity8-private.install−1 libs/CMakeLists.txt−1 libs/UbuntuGestures/CMakeLists.txt−41 libs/UbuntuGestures/CandidateInactivityTimer.cpp−46 libs/UbuntuGestures/CandidateInactivityTimer.h−51 libs/UbuntuGestures/DebugHelpers.cpp−95 libs/UbuntuGestures/DebugHelpers.h−31 libs/UbuntuGestures/Pool.h−124 libs/UbuntuGestures/TimeSource.cpp−49 libs/UbuntuGestures/TimeSource.h−64 libs/UbuntuGestures/Timer.cpp−152 libs/UbuntuGestures/Timer.h−122 libs/UbuntuGestures/TouchOwnershipEvent.cpp−35 libs/UbuntuGestures/TouchOwnershipEvent.h−50 libs/UbuntuGestures/TouchRegistry.cpp−553 libs/UbuntuGestures/TouchRegistry.h−201 libs/UbuntuGestures/UbuntuGesturesGlobal.h−23 libs/UbuntuGestures/UnownedTouchEvent.cpp−39 libs/UbuntuGestures/UnownedTouchEvent.h−45 plugins/Ubuntu/Gestures/AxisVelocityCalculator.h+1−1 plugins/Ubuntu/Gestures/CMakeLists.txt+5−5 plugins/Ubuntu/Gestures/Damper.cpp−24 plugins/Ubuntu/Gestures/Damper.h−89 plugins/Ubuntu/Gestures/Direction.h+1 plugins/Ubuntu/Gestures/DirectionalDragArea.cpp−932 plugins/Ubuntu/Gestures/DirectionalDragArea.h−143 plugins/Ubuntu/Gestures/DirectionalDragArea_p.h−169 plugins/Ubuntu/Gestures/FloatingFlickable.cpp−150 plugins/Ubuntu/Gestures/FloatingFlickable.h−86 plugins/Ubuntu/Gestures/Gestures.qmltypes−132 plugins/Ubuntu/Gestures/MouseEventGenerator.cpp+64 plugins/Ubuntu/Gestures/MouseEventGenerator.h+48 plugins/Ubuntu/Gestures/PressedOutsideNotifier.h+1−1 plugins/Ubuntu/Gestures/TouchGate.cpp+2−2 plugins/Ubuntu/Gestures/TouchGestureArea.cpp+9−6 plugins/Ubuntu/Gestures/TouchGestureArea.h+1−2 plugins/Ubuntu/Gestures/plugin.cpp+3−5 qml/Components/DragHandle.qml+16−18 qml/Components/FloatingFlickable.qml+59 qml/Dash/Dash.qml+3−3 qml/Launcher/Launcher.qml+4−4 qml/Panel/IndicatorsMenu.qml+17−13 qml/Stages/DesktopStage.qml+1−1 qml/Stages/PhoneStage.qml+4−4 qml/Stages/TabletStage.qml+4−4 qml/Tutorial/TutorialBottom.qml+3−3 src/CMakeLists.txt−4 tests/CMakeLists.txt−1 tests/libs/CMakeLists.txt−1 tests/libs/UbuntuGestures/CMakeLists.txt−16 tests/libs/UbuntuGestures/tst_TouchRegistry.cpp−974 tests/plugins/Ubuntu/Gestures/CMakeLists.txt+4−4 tests/plugins/Ubuntu/Gestures/DownwardsLauncher.qml−72 tests/plugins/Ubuntu/Gestures/GestureTest.cpp+2−2 tests/plugins/Ubuntu/Gestures/LeftwardsLauncher.qml−76 tests/plugins/Ubuntu/Gestures/RightwardsLauncher.qml−76 tests/plugins/Ubuntu/Gestures/UpwardsLauncher.qml−76 tests/plugins/Ubuntu/Gestures/tst_Damper.cpp−40 tests/plugins/Ubuntu/Gestures/tst_DirectionalDragArea.cpp−1250 tests/plugins/Ubuntu/Gestures/tst_DirectionalDragArea.qml−76 tests/plugins/Ubuntu/Gestures/tst_FloatingFlickable.cpp+25−18 tests/plugins/Ubuntu/Gestures/tst_FloatingFlickable.qml+1 tests/plugins/Ubuntu/Gestures/tst_TouchGate.cpp+1−1 tests/qmltests/Components/CMakeLists.txt+6−3 tests/qmltests/Components/tst_DragHandle.cpp+25−21 tests/qmltests/Components/tst_EdgeDragEvaluator.cpp+1−1 tests/qmltests/Greeter/tst_Greeter.qml+1−1 tests/qmltests/Greeter/tst_NarrowView.qml+1−1 tests/qmltests/Greeter/tst_WideView.qml+1−1 tests/qmltests/Launcher/tst_Launcher.qml+1−1 tests/qmltests/Tutorial/tst_Tutorial.qml+2−2 tests/qmltests/tst_OrientedShell.qml+1−1 tests/qmltests/tst_Shell.qml+7−5 tests/qmltests/tst_ShellWithPin.qml+1−1 tests/utils/modules/Unity/Test/CMakeLists.txt+4−2 tests/utils/modules/Unity/Test/UnityTestCase.qml+8−8 tests/utils/modules/Unity/Test/testutil.cpp+2−2
CMakeLists.txt+12−1
@@ -63,6 +63,18 @@ pkg_check_modules(GIO REQUIRED gio-2.0>=2.32)
6363pkg_check_modules(GLIB REQUIRED glib-2.0>=2.32)
6464pkg_check_modules(QMENUMODEL REQUIRED qmenumodel)
6565
66+pkg_check_modules(UBUNTUGESTURES REQUIRED UbuntuGestures)
67+
68+### Check UbuntuGestures private headers. No pkg-config (.pc) file is provided for them
69+find_path(UBUNTUGESTUREPRIV
70+ NAMES UbuntuGestures/private/damper_p.h UbuntuGestures/private/ucswipearea_p.h UbuntuGestures/private/ucswipearea_p_p.h
71+ PATHS ${UBUNTUGESTURES_INCLUDEDIR}/UbuntuGestures/${UBUNTUGESTURES_VERSION}
72+ NO_DEFAULT_PATH)
73+if (${UBUNTUGESTUREPRIV} STREQUAL UBUNTUGESTUREPRIV-NOTFOUND)
74+ message(FATAL_ERROR "UbuntuGestures private headers not found.")
75+endif()
76+# end of UbuntuGesture private headers check
77+
6678# Standard install paths
6779include(GNUInstallDirs)
6880
@@ -144,7 +156,6 @@ endif()
144156
145157# add subdirectories to build
146158add_subdirectory(include)
147−add_subdirectory(libs)
148159add_subdirectory(src)
149160add_subdirectory(tools)
150161add_subdirectory(qml)
debian/control+2
@@ -29,6 +29,8 @@ Build-Depends: cmake,
2929 libqt5svg5-dev,
3030 libqt5xmlpatterns5-dev,
3131 libsystemsettings-dev,
32+ libubuntugestures5-dev,
33+ libubuntugestures5-private-dev,
3234 libudev-dev,
3335 libunity-api-dev (>= 7.112),
3436 libusermetricsoutput1-dev,
debian/unity8-private.install−1
@@ -1,5 +1,4 @@
11usr/lib/*/libunity8-private.*
2−usr/lib/*/unity8/libUbuntuGestures*
32usr/lib/*/unity8/qml/AccountsService
43usr/lib/*/unity8/qml/Cursor
54usr/lib/*/unity8/qml/Dash
libs/CMakeLists.txtdeleted−1
@@ -1 +0,0 @@
1−add_subdirectory(UbuntuGestures)
libs/UbuntuGestures/CMakeLists.txtdeleted−41
@@ -1,41 +0,0 @@
1−# in order to include Qt's private headers
2−remove_definitions(-DQT_NO_KEYWORDS)
3−
4−set(UbuntuGestures_SOURCES
5− CandidateInactivityTimer.cpp
6− DebugHelpers.cpp
7− Timer.cpp
8− TimeSource.cpp
9− TouchOwnershipEvent.cpp
10− TouchRegistry.cpp
11− UnownedTouchEvent.cpp
12−)
13−
14−add_definitions(-DUBUNTUGESTURES_LIBRARY)
15−
16−add_library(UbuntuGestures SHARED ${UbuntuGestures_SOURCES})
17−
18−qt5_use_modules(UbuntuGestures Core Quick)
19−
20−# So that Foo.cpp can #include "Foo.moc"
21−include_directories(${CMAKE_CURRENT_BINARY_DIR})
22−
23−install(TARGETS UbuntuGestures
24− DESTINATION ${SHELL_PRIVATE_LIBDIR})
25−
26−
27−# There's no cmake var for v8 include path :-/ so create one
28−LIST(GET Qt5Core_INCLUDE_DIRS 0 QtCoreDir0)
29−if(${Qt5Core_VERSION_STRING} VERSION_LESS "5.1.0")
30− SET(Qt5V8_PRIVATE_INCLUDE_DIR ${QtCoreDir0}/../QtV8/${Qt5Core_VERSION_STRING}/QtV8)
31−else()
32− SET(Qt5V8_PRIVATE_INCLUDE_DIR ${QtCoreDir0}/QtV8/${Qt5Core_VERSION_STRING}/QtV8)
33−endif()
34−
35−# DANGER! DANGER! Using Qt's private API!
36−include_directories(
37− ${Qt5Qml_PRIVATE_INCLUDE_DIRS}
38− ${Qt5Quick_INCLUDE_DIRS}
39− ${Qt5Quick_PRIVATE_INCLUDE_DIRS}
40− ${Qt5V8_PRIVATE_INCLUDE_DIR}
41−)
libs/UbuntuGestures/CandidateInactivityTimer.cppdeleted−46
@@ -1,46 +0,0 @@
1−/*
2− * Copyright (C) 2014 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−#include "CandidateInactivityTimer.h"
18−
19−namespace UbuntuGestures {
20−
21−CandidateInactivityTimer::CandidateInactivityTimer(int touchId, QQuickItem *candidate,
22− AbstractTimer *timer, QObject *parent)
23− : QObject(parent)
24− , m_timer(timer)
25− , m_touchId(touchId)
26− , m_candidate(candidate)
27−{
28− connect(m_timer, &AbstractTimer::timeout,
29− this, &CandidateInactivityTimer::onTimeout);
30− m_timer->setInterval(durationMs);
31− m_timer->setSingleShot(true);
32− m_timer->start();
33−}
34−
35−CandidateInactivityTimer::~CandidateInactivityTimer()
36−{
37− delete m_timer;
38−}
39−
40−void CandidateInactivityTimer::onTimeout()
41−{
42− qWarning("[TouchRegistry] Candidate for touch %d defaulted!", m_touchId);
43− Q_EMIT candidateDefaulted(m_touchId, m_candidate);
44−}
45−
46−} // namespace UbuntuGestures
libs/UbuntuGestures/CandidateInactivityTimer.hdeleted−51
@@ -1,51 +0,0 @@
1−/*
2− * Copyright (C) 2014 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−#ifndef UBUNTUGESTURES_CANDIDATE_INACTIVITY_TIMER_H
18−#define UBUNTUGESTURES_CANDIDATE_INACTIVITY_TIMER_H
19−
20−#include <QObject>
21−
22−class QQuickItem;
23−
24−#include "Timer.h"
25−
26−namespace UbuntuGestures {
27−
28−class UBUNTUGESTURES_EXPORT CandidateInactivityTimer : public QObject {
29− Q_OBJECT
30−public:
31− CandidateInactivityTimer(int touchId, QQuickItem *candidate,
32− AbstractTimer *timer,
33− QObject *parent = nullptr);
34−
35− virtual ~CandidateInactivityTimer();
36−
37− const int durationMs = 1000;
38−
39−Q_SIGNALS:
40− void candidateDefaulted(int touchId, QQuickItem *candidate);
41−private Q_SLOTS:
42− void onTimeout();
43−private:
44− AbstractTimer *m_timer;
45− int m_touchId;
46− QQuickItem *m_candidate;
47−};
48−
49−} // namespace UbuntuGestures
50−
51−#endif // UBUNTUGESTURES_CANDIDATE_INACTIVITY_TIMER_H
libs/UbuntuGestures/DebugHelpers.cppdeleted−95
@@ -1,95 +0,0 @@
1−/*
2− * Copyright (C) 2014 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−#include "DebugHelpers.h"
18−#include <QTouchEvent>
19−#include <QMouseEvent>
20−
21−QString touchPointStateToString(Qt::TouchPointState state)
22−{
23− switch (state) {
24− case Qt::TouchPointPressed:
25− return QStringLiteral("pressed");
26− case Qt::TouchPointMoved:
27− return QStringLiteral("moved");
28− case Qt::TouchPointStationary:
29− return QStringLiteral("stationary");
30− case Qt::TouchPointReleased:
31− return QStringLiteral("released");
32− default:
33− return QStringLiteral("INVALID_STATE");
34− }
35−}
36−
37−QString touchEventToString(const QTouchEvent *ev)
38−{
39− QString message;
40−
41− switch (ev->type()) {
42− case QEvent::TouchBegin:
43− message.append("TouchBegin ");
44− break;
45− case QEvent::TouchUpdate:
46− message.append("TouchUpdate ");
47− break;
48− case QEvent::TouchEnd:
49− message.append("TouchEnd ");
50− break;
51− case QEvent::TouchCancel:
52− message.append("TouchCancel ");
53− break;
54− default:
55− message.append("INVALID_TOUCH_EVENT_TYPE ");
56− }
57−
58− foreach(const QTouchEvent::TouchPoint& touchPoint, ev->touchPoints()) {
59− message.append(
60− QStringLiteral("(id:%1, state:%2, scenePos:(%3,%4)) ")
61− .arg(touchPoint.id())
62− .arg(touchPointStateToString(touchPoint.state()))
63− .arg(touchPoint.scenePos().x())
64− .arg(touchPoint.scenePos().y())
65− );
66− }
67−
68− return message;
69−}
70−
71−QString mouseEventToString(const QMouseEvent *ev)
72−{
73− QString message;
74−
75− switch (ev->type()) {
76− case QEvent::MouseButtonPress:
77− message.append("MouseButtonPress ");
78− break;
79− case QEvent::MouseButtonRelease:
80− message.append("MouseButtonRelease ");
81− break;
82− case QEvent::MouseButtonDblClick:
83− message.append("MouseButtonDblClick ");
84− break;
85− case QEvent::MouseMove:
86− message.append("MouseMove ");
87− break;
88− default:
89− message.append("INVALID_MOUSE_EVENT_TYPE ");
90− }
91−
92− message.append(QStringLiteral("pos(%1, %2)").arg(ev->x()).arg(ev->y()));
93−
94− return message;
95−}
libs/UbuntuGestures/DebugHelpers.hdeleted−31
@@ -1,31 +0,0 @@
1−/*
2− * Copyright (C) 2014 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−#ifndef UBUNTUGESTURES_DEBUG_HELPER_H
18−#define UBUNTUGESTURES_DEBUG_HELPER_H
19−
20−#include <QString>
21−
22−#include "UbuntuGesturesGlobal.h"
23−
24−class QMouseEvent;
25−class QTouchEvent;
26−
27−UBUNTUGESTURES_EXPORT QString touchPointStateToString(Qt::TouchPointState state);
28−UBUNTUGESTURES_EXPORT QString touchEventToString(const QTouchEvent *ev);
29−UBUNTUGESTURES_EXPORT QString mouseEventToString(const QMouseEvent *ev);
30−
31−#endif // UBUNTUGESTURES_DEBUG_HELPER_H
libs/UbuntuGestures/Pool.hdeleted−124
@@ -1,124 +0,0 @@
1−/*
2− * Copyright (C) 2014 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−#ifndef UBUNTUGESTURES_POOL_H
18−#define UBUNTUGESTURES_POOL_H
19−
20−#include <QVector>
21−
22−#include "UbuntuGesturesGlobal.h"
23−
24−/*
25− An object pool.
26− Avoids unnecessary creations/initializations and deletions/destructions of items. Useful
27− in a scenario where items are created and destroyed very frequently but the total number
28− of items at any given time remains small. They're stored in a unordered fashion.
29−
30− To be used in Pool, ItemType needs to have the following methods:
31−
32− - ItemType();
33−
34− A constructor that takes no parameters. An object contructed with it must return false if
35− isValid() is called.
36−
37− - bool isValid() const;
38−
39− Returns wheter the object holds a valid , "filled" state or is empty.
40− Used by Pool to check if the slot occupied by this object is actually available.
41−
42− - void reset();
43−
44− Resets the object to its initial, empty, state. After calling this method, isValid() must
45− return false.
46− */
47−template <class ItemType> class Pool
48−{
49−public:
50− Pool() : m_lastUsedIndex(-1) {
51− }
52−
53− class Iterator {
54− public:
55− Iterator() : index(-1), item(nullptr) {}
56− Iterator(int index, ItemType *item)
57− : index(index), item(item) {}
58−
59− ItemType *operator->() const { return item; }
60− ItemType &operator*() const { return *item; }
61− ItemType &value() const { return *item; }
62−
63− operator bool() const { return item != nullptr; }
64−
65− int index;
66− ItemType *item;
67− };
68−
69− ItemType &getEmptySlot() {
70− Q_ASSERT(m_lastUsedIndex < m_slots.size());
71−
72− // Look for an in-between vacancy first
73− for (int i = 0; i < m_lastUsedIndex; ++i) {
74− ItemType &item = m_slots[i];
75− if (!item.isValid()) {
76− return item;
77− }
78− }
79−
80− ++m_lastUsedIndex;
81− if (m_lastUsedIndex >= m_slots.size()) {
82− m_slots.resize(m_lastUsedIndex + 1);
83− }
84−
85− return m_slots[m_lastUsedIndex];
86− }
87−
88− void freeSlot(Iterator &iterator) {
89− m_slots[iterator.index].reset();
90− if (iterator.index == m_lastUsedIndex) {
91− do {
92− --m_lastUsedIndex;
93− } while (m_lastUsedIndex >= 0 && !m_slots.at(m_lastUsedIndex).isValid());
94− }
95− }
96−
97− // Iterates through all valid items (i.e. the occupied slots)
98− // calling the given function, with the option of ending the loop early.
99− //
100− // bool Func(Iterator& item)
101− //
102− // Returning true means it wants to continue the "for" loop, false
103− // terminates the loop.
104− template<typename Func> void forEach(Func func) {
105− Iterator it;
106− for (it.index = 0; it.index <= m_lastUsedIndex; ++it.index) {
107− it.item = &m_slots[it.index];
108− if (!it.item->isValid())
109− continue;
110−
111− if (!func(it))
112− break;
113− }
114− }
115−
116− bool isEmpty() const { return m_lastUsedIndex == -1; }
117−
118−
119−private:
120− QVector<ItemType> m_slots;
121− int m_lastUsedIndex;
122−};
123−
124−#endif // UBUNTUGESTURES_POOL_H
libs/UbuntuGestures/TimeSource.cppdeleted−49
@@ -1,49 +0,0 @@
1−/*
2− * Copyright (C) 2013 - Canonical Ltd.
3− *
4− * This program is free software: you can redistribute it and/or modify it
5− * under the terms of the GNU Lesser General Public License, as
6− * published by the Free Software Foundation; either version 2.1 or 3.0
7− * of the License.
8− *
9− * This program is distributed in the hope that it will be useful, but
10− * WITHOUT ANY WARRANTY; without even the implied warranties of
11− * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
12− * PURPOSE. See the applicable version of the GNU Lesser General Public
13− * License for more details.
14− *
15− * You should have received a copy of both the GNU Lesser General Public
16− * License along with this program. If not, see <http://www.gnu.org/licenses/>
17− *
18− * Authored by: Daniel d'Andrada <daniel.dandrada@canonical.com>
19− */
20−
21−#include "TimeSource.h"
22−
23−#include <QElapsedTimer>
24−
25−namespace UbuntuGestures {
26−class RealTimeSourcePrivate {
27−public:
28− QElapsedTimer timer;
29−};
30−}
31−
32−using namespace UbuntuGestures;
33−
34−RealTimeSource::RealTimeSource()
35− : UbuntuGestures::TimeSource()
36− , d(new RealTimeSourcePrivate)
37−{
38− d->timer.start();
39−}
40−
41−RealTimeSource::~RealTimeSource()
42−{
43− delete d;
44−}
45−
46−qint64 RealTimeSource::msecsSinceReference()
47−{
48− return d->timer.elapsed();
49−}
libs/UbuntuGestures/TimeSource.hdeleted−64
@@ -1,64 +0,0 @@
1−/*
2− * Copyright (C) 2013,2015 Canonical Ltd.
3− *
4− * This program is free software: you can redistribute it and/or modify it
5− * under the terms of the GNU Lesser General Public License, as
6− * published by the Free Software Foundation; either version 2.1 or 3.0
7− * of the License.
8− *
9− * This program is distributed in the hope that it will be useful, but
10− * WITHOUT ANY WARRANTY; without even the implied warranties of
11− * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
12− * PURPOSE. See the applicable version of the GNU Lesser General Public
13− * License for more details.
14− *
15− * You should have received a copy of both the GNU Lesser General Public
16− * License along with this program. If not, see <http://www.gnu.org/licenses/>
17− *
18− * Authored by: Daniel d'Andrada <daniel.dandrada@canonical.com>
19− */
20−
21−#ifndef UBUNTUGESTURES_TIMESOURCE_H
22−#define UBUNTUGESTURES_TIMESOURCE_H
23−
24−#include "UbuntuGesturesGlobal.h"
25−#include <QSharedPointer>
26−
27−namespace UbuntuGestures {
28−/*
29− Interface for a time source.
30− */
31−class UBUNTUGESTURES_EXPORT TimeSource {
32−public:
33− virtual ~TimeSource() {}
34− /* Returns the current time in milliseconds since some reference time in the past. */
35− virtual qint64 msecsSinceReference() = 0;
36−};
37−typedef QSharedPointer<TimeSource> SharedTimeSource;
38−
39−/*
40− Implementation of a time source
41− */
42−class RealTimeSourcePrivate;
43−class UBUNTUGESTURES_EXPORT RealTimeSource : public TimeSource {
44−public:
45− RealTimeSource();
46− virtual ~RealTimeSource();
47− qint64 msecsSinceReference() override;
48−private:
49− RealTimeSourcePrivate *d;
50−};
51−
52−/*
53− A fake time source, useful for tests
54− */
55−class FakeTimeSource : public TimeSource {
56−public:
57− FakeTimeSource() { m_msecsSinceReference = 0; }
58− qint64 msecsSinceReference() override { return m_msecsSinceReference; }
59− qint64 m_msecsSinceReference;
60−};
61−
62−} // namespace UbuntuGestures
63−
64−#endif // UBUNTUGESTURES_TIMESOURCE_H
libs/UbuntuGestures/Timer.cppdeleted−152
@@ -1,152 +0,0 @@
1−/*
2− * Copyright (C) 2014-2015 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−#include "Timer.h"
18−
19−namespace UbuntuGestures {
20−
21−Timer::Timer(QObject *parent) : AbstractTimer(parent)
22−{
23− m_timer.setSingleShot(false);
24− connect(&m_timer, &QTimer::timeout, this, &AbstractTimer::timeout);
25−}
26−
27−int Timer::interval() const
28−{
29− return m_timer.interval();
30−}
31−
32−void Timer::setInterval(int msecs)
33−{
34− m_timer.setInterval(msecs);
35−}
36−
37−void Timer::start()
38−{
39− m_timer.start();
40− AbstractTimer::start();
41−}
42−
43−void Timer::stop()
44−{
45− m_timer.stop();
46− AbstractTimer::stop();
47−}
48−
49−bool Timer::isSingleShot() const
50−{
51− return m_timer.isSingleShot();
52−}
53−
54−void Timer::setSingleShot(bool value)
55−{
56− m_timer.setSingleShot(value);
57−}
58−
59−/////////////////////////////////// FakeTimer //////////////////////////////////
60−
61−FakeTimer::FakeTimer(const SharedTimeSource &timeSource, QObject *parent)
62− : UbuntuGestures::AbstractTimer(parent)
63− , m_interval(0)
64− , m_singleShot(false)
65− , m_timeSource(timeSource)
66−{
67−}
68−
69−void FakeTimer::update()
70−{
71− if (!isRunning()) {
72− return;
73− }
74−
75− if (m_nextTimeoutTime <= m_timeSource->msecsSinceReference()) {
76− if (isSingleShot()) {
77− stop();
78− } else {
79− m_nextTimeoutTime += interval();
80− }
81− Q_EMIT timeout();
82− }
83−}
84−
85−void FakeTimer::start()
86−{
87− AbstractTimer::start();
88− m_nextTimeoutTime = m_timeSource->msecsSinceReference() + (qint64)interval();
89−}
90−
91−int FakeTimer::interval() const
92−{
93− return m_interval;
94−}
95−
96−void FakeTimer::setInterval(int msecs)
97−{
98− m_interval = msecs;
99−}
100−
101−bool FakeTimer::isSingleShot() const
102−{
103− return m_singleShot;
104−}
105−
106−void FakeTimer::setSingleShot(bool value)
107−{
108− m_singleShot = value;
109−}
110−
111−/////////////////////////////////// FakeTimerFactory //////////////////////////////////
112−
113−FakeTimerFactory::FakeTimerFactory()
114−{
115− m_timeSource.reset(new FakeTimeSource);
116−}
117−
118−void FakeTimerFactory::updateTime(qint64 targetTime)
119−{
120− qint64 minTimeoutTime = targetTime;
121−
122− for (int i = 0; i < timers.count(); ++i) {
123− FakeTimer *timer = timers[i].data();
124− if (timer && timer->isRunning() && timer->nextTimeoutTime() < minTimeoutTime) {
125− minTimeoutTime = timer->nextTimeoutTime();
126− }
127− }
128−
129− m_timeSource->m_msecsSinceReference = minTimeoutTime;
130−
131− for (int i = 0; i < timers.count(); ++i) {
132− FakeTimer *timer = timers[i].data();
133− if (timer) {
134− timer->update();
135− }
136− }
137−
138− if (m_timeSource->msecsSinceReference() < targetTime) {
139− updateTime(targetTime);
140− }
141−}
142−
143−AbstractTimer *FakeTimerFactory::createTimer(QObject *parent)
144−{
145− FakeTimer *fakeTimer = new FakeTimer(m_timeSource, parent);
146−
147− timers.append(fakeTimer);
148−
149− return fakeTimer;
150−}
151−
152−} // namespace UbuntuGestures
libs/UbuntuGestures/Timer.hdeleted−122
@@ -1,122 +0,0 @@
1−/*
2− * Copyright (C) 2014 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−#ifndef UBUNTUGESTURES_TIMER_H
18−#define UBUNTUGESTURES_TIMER_H
19−
20−#include "UbuntuGesturesGlobal.h"
21−#include "TimeSource.h"
22−
23−#include <QObject>
24−#include <QPointer>
25−#include <QTimer>
26−
27−namespace UbuntuGestures {
28−
29−/* Defines an interface for a Timer. Useful for tests. */
30−class UBUNTUGESTURES_EXPORT AbstractTimer : public QObject
31−{
32− Q_OBJECT
33−public:
34− AbstractTimer(QObject *parent) : QObject(parent), m_isRunning(false) {}
35− virtual int interval() const = 0;
36− virtual void setInterval(int msecs) = 0;
37− virtual void start() { m_isRunning = true; }
38− virtual void start(int msecs)
39− {
40− setInterval(msecs);
41− start();
42− }
43− virtual void stop() { m_isRunning = false; }
44− bool isRunning() const { return m_isRunning; }
45− virtual bool isSingleShot() const = 0;
46− virtual void setSingleShot(bool value) = 0;
47−Q_SIGNALS:
48− void timeout();
49−private:
50− bool m_isRunning;
51−};
52−
53−/* Essentially a QTimer wrapper */
54−class UBUNTUGESTURES_EXPORT Timer : public AbstractTimer
55−{
56− Q_OBJECT
57−public:
58− Timer(QObject *parent = nullptr);
59−
60− int interval() const override;
61− void setInterval(int msecs) override;
62− void start() override;
63− void stop() override;
64− bool isSingleShot() const override;
65− void setSingleShot(bool value) override;
66−private:
67− QTimer m_timer;
68−};
69−
70−/* For tests */
71−class UBUNTUGESTURES_EXPORT FakeTimer : public AbstractTimer
72−{
73− Q_OBJECT
74−public:
75− FakeTimer(const SharedTimeSource &timeSource, QObject *parent = nullptr);
76−
77− void update();
78− qint64 nextTimeoutTime() const { return m_nextTimeoutTime; }
79−
80− int interval() const override;
81− void setInterval(int msecs) override;
82− void start() override;
83− bool isSingleShot() const override;
84− void setSingleShot(bool value) override;
85−private:
86− int m_interval;
87− bool m_singleShot;
88− SharedTimeSource m_timeSource;
89− qint64 m_nextTimeoutTime;
90−};
91−
92−class UBUNTUGESTURES_EXPORT AbstractTimerFactory
93−{
94−public:
95− virtual ~AbstractTimerFactory() {}
96− virtual AbstractTimer *createTimer(QObject *parent = nullptr) = 0;
97−};
98−
99−class UBUNTUGESTURES_EXPORT TimerFactory : public AbstractTimerFactory
100−{
101−public:
102− AbstractTimer *createTimer(QObject *parent = nullptr) override { return new Timer(parent); }
103−};
104−
105−class UBUNTUGESTURES_EXPORT FakeTimerFactory : public AbstractTimerFactory
106−{
107−public:
108− FakeTimerFactory();
109− virtual ~FakeTimerFactory() {}
110−
111− void updateTime(qint64 msecsSinceReference);
112− QSharedPointer<TimeSource> timeSource() { return m_timeSource; }
113−
114− AbstractTimer *createTimer(QObject *parent = nullptr) override;
115− QList<QPointer<FakeTimer>> timers;
116−private:
117− QSharedPointer<FakeTimeSource> m_timeSource;
118−};
119−
120−} // namespace UbuntuGestures
121−
122−#endif // UBUNTUGESTURES_TIMER_H
libs/UbuntuGestures/TouchOwnershipEvent.cppdeleted−35
@@ -1,35 +0,0 @@
1−/*
2− * Copyright (C) 2014 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−#include "TouchOwnershipEvent.h"
18−
19−QEvent::Type TouchOwnershipEvent::m_touchOwnershipType = (QEvent::Type)-1;
20−
21−TouchOwnershipEvent::TouchOwnershipEvent(int touchId, bool gained)
22− : QEvent(touchOwnershipEventType())
23− , m_touchId(touchId)
24− , m_gained(gained)
25−{
26−}
27−
28−QEvent::Type TouchOwnershipEvent::touchOwnershipEventType()
29−{
30− if (m_touchOwnershipType == (QEvent::Type)-1) {
31− m_touchOwnershipType = (QEvent::Type)registerEventType();
32− }
33−
34− return m_touchOwnershipType;
35−}
libs/UbuntuGestures/TouchOwnershipEvent.hdeleted−50
@@ -1,50 +0,0 @@
1−/*
2− * Copyright (C) 2014 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−#ifndef UBUNTU_TOUCHOWNERSHIPEVENT_H
18−#define UBUNTU_TOUCHOWNERSHIPEVENT_H
19−
20−#include <QEvent>
21−#include "UbuntuGesturesGlobal.h"
22−
23−/*
24− When an item get an ownership event for a touch it can grab/steal that touch
25− with a clean conscience.
26− */
27−class UBUNTUGESTURES_EXPORT TouchOwnershipEvent : public QEvent
28−{
29−public:
30− TouchOwnershipEvent(int touchId, bool gained);
31−
32− static Type touchOwnershipEventType();
33−
34− /*
35− Whether ownership was gained (true) or lost (false)
36− */
37− bool gained() const { return m_gained; }
38−
39− /*
40− Id of the touch whose ownership was granted.
41− */
42− int touchId() const { return m_touchId; }
43−
44−private:
45− static Type m_touchOwnershipType;
46− int m_touchId;
47− bool m_gained;
48−};
49−
50−#endif // UBUNTU_TOUCHOWNERSHIPEVENT_H
libs/UbuntuGestures/TouchRegistry.cppdeleted−553
@@ -1,553 +0,0 @@
1−/*
2− * Copyright (C) 2014-2015 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−#include "TouchRegistry.h"
18−
19−#include <QCoreApplication>
20−#include <QDebug>
21−
22−#pragma GCC diagnostic push
23−#pragma GCC diagnostic ignored "-pedantic"
24−#include <private/qquickitem_p.h>
25−#pragma GCC diagnostic pop
26−
27−#include "CandidateInactivityTimer.h"
28−#include "Timer.h"
29−#include "TouchOwnershipEvent.h"
30−#include "UnownedTouchEvent.h"
31−
32−#define TOUCHREGISTRY_DEBUG 0
33−
34−#if TOUCHREGISTRY_DEBUG
35− #include "DebugHelpers.h"
36− #define UG_DEBUG qDebug() << "[TouchRegistry]"
37−#endif // TOUCHREGISTRY_DEBUG
38−
39−using namespace UbuntuGestures;
40−
41−TouchRegistry *TouchRegistry::m_instance = nullptr;
42−
43−TouchRegistry::TouchRegistry(QObject *parent)
44− : QObject(parent)
45− , m_inDispatchLoop(false)
46− , m_timerFactory(new TimerFactory)
47−{
48−}
49−
50−TouchRegistry::~TouchRegistry()
51−{
52− Q_ASSERT(m_instance != nullptr);
53− m_instance = nullptr;
54− delete m_timerFactory;
55−}
56−
57−TouchRegistry *TouchRegistry::instance()
58−{
59− if (m_instance == nullptr) {
60− m_instance = new TouchRegistry;
61− }
62− return m_instance;
63−}
64−
65−void TouchRegistry::setTimerFactory(AbstractTimerFactory *timerFactory)
66−{
67− delete m_timerFactory;
68− m_timerFactory = timerFactory;
69−}
70−
71−void TouchRegistry::update(const QTouchEvent *event)
72−{
73− #if TOUCHREGISTRY_DEBUG
74− UG_DEBUG << "got" << qPrintable(touchEventToString(event));
75− #endif
76−
77− const QList<QTouchEvent::TouchPoint> &touchPoints = event->touchPoints();
78− for (int i = 0; i < touchPoints.count(); ++i) {
79− const QTouchEvent::TouchPoint &touchPoint = touchPoints.at(i);
80− if (touchPoint.state() == Qt::TouchPointPressed) {
81− TouchInfo &touchInfo = m_touchInfoPool.getEmptySlot();
82− touchInfo.init(touchPoint.id());
83− } else if (touchPoint.state() == Qt::TouchPointReleased) {
84− Pool<TouchInfo>::Iterator touchInfo = findTouchInfo(touchPoint.id());
85−
86− touchInfo->physicallyEnded = true;
87− }
88− }
89−
90− deliverTouchUpdatesToUndecidedCandidatesAndWatchers(event);
91−
92− freeEndedTouchInfos();
93−}
94−
95−void TouchRegistry::deliverTouchUpdatesToUndecidedCandidatesAndWatchers(const QTouchEvent *event)
96−{
97− // TODO: Look into how we could optimize this whole thing.
98− // Although it's not really a problem as we should have at most two candidates
99− // for each point and there should not be many active points at any given moment.
100− // But having three nested for-loops does scare.
101−
102− const QList<QTouchEvent::TouchPoint> &updatedTouchPoints = event->touchPoints();
103−
104− // Maps an item to the touches in this event he should be informed about.
105− // E.g.: a QTouchEvent might have three touches but a given item might be interested in only
106− // one of them. So he will get a UnownedTouchEvent from this QTouchEvent containing only that
107− // touch point.
108− QHash<QQuickItem*, QList<int>> touchIdsForItems;
109−
110− // Build touchIdsForItems
111− m_touchInfoPool.forEach([&](Pool<TouchInfo>::Iterator &touchInfo) {
112− if (touchInfo->isOwned() && touchInfo->watchers.isEmpty())
113− return true;
114−
115− for (int j = 0; j < updatedTouchPoints.count(); ++j) {
116− if (updatedTouchPoints[j].id() == touchInfo->id) {
117− if (!touchInfo->isOwned()) {
118− for (int i = 0; i < touchInfo->candidates.count(); ++i) {
119− CandidateInfo &candidate = touchInfo->candidates[i];
120− Q_ASSERT(!candidate.item.isNull());
121− if (candidate.state != CandidateInfo::InterimOwner) {
122− touchIdsForItems[candidate.item.data()].append(touchInfo->id);
123− }
124− }
125− }
126−
127− const QList<QPointer<QQuickItem>> &watchers = touchInfo->watchers;
128− for (int i = 0; i < watchers.count(); ++i) {
129− if (!watchers[i].isNull()) {
130− touchIdsForItems[watchers[i].data()].append(touchInfo->id);
131− }
132− }
133−
134− return true;
135− }
136− }
137−
138− return true;
139− });
140−
141− // TODO: Consider what happens if an item calls any of TouchRegistry's public methods
142− // from the event handler callback.
143− m_inDispatchLoop = true;
144− auto it = touchIdsForItems.constBegin();
145− while (it != touchIdsForItems.constEnd()) {
146− QQuickItem *item = it.key();
147− const QList<int> &touchIds = it.value();
148− dispatchPointsToItem(event, touchIds, item);
149− ++it;
150− };
151− m_inDispatchLoop = false;
152−}
153−
154−void TouchRegistry::freeEndedTouchInfos()
155−{
156− m_touchInfoPool.forEach([&](Pool<TouchInfo>::Iterator &touchInfo) {
157− if (touchInfo->ended()) {
158− m_touchInfoPool.freeSlot(touchInfo);
159− }
160− return true;
161− });
162−}
163−
164−/*
165− Extracts the touches with the given touchIds from event and send them in a
166− UnownedTouchEvent to the given item
167− */
168−void TouchRegistry::dispatchPointsToItem(const QTouchEvent *event, const QList<int> &touchIds,
169− QQuickItem *item)
170−{
171− Qt::TouchPointStates touchPointStates = 0;
172− QList<QTouchEvent::TouchPoint> touchPoints;
173−
174− const QList<QTouchEvent::TouchPoint> &allTouchPoints = event->touchPoints();
175−
176− QTransform windowToCandidateTransform = QQuickItemPrivate::get(item)->windowToItemTransform();
177− QMatrix4x4 windowToCandidateMatrix(windowToCandidateTransform);
178−
179− for (int i = 0; i < allTouchPoints.count(); ++i) {
180− const QTouchEvent::TouchPoint &originalTouchPoint = allTouchPoints[i];
181− if (touchIds.contains(originalTouchPoint.id())) {
182− QTouchEvent::TouchPoint touchPoint = originalTouchPoint;
183−
184− translateTouchPointFromScreenToWindowCoords(touchPoint);
185−
186− // Set the point's local coordinates to that of the item
187− touchPoint.setRect(windowToCandidateTransform.mapRect(touchPoint.sceneRect()));
188− touchPoint.setStartPos(windowToCandidateTransform.map(touchPoint.startScenePos()));
189− touchPoint.setLastPos(windowToCandidateTransform.map(touchPoint.lastScenePos()));
190− touchPoint.setVelocity(windowToCandidateMatrix.mapVector(touchPoint.velocity()).toVector2D());
191−
192− touchPoints.append(touchPoint);
193− touchPointStates |= touchPoint.state();
194− }
195− }
196−
197− QTouchEvent *eventForItem = new QTouchEvent(event->type(),
198− event->device(),
199− event->modifiers(),
200− touchPointStates,
201− touchPoints);
202− eventForItem->setWindow(event->window());
203− eventForItem->setTimestamp(event->timestamp());
204− eventForItem->setTarget(event->target());
205−
206− UnownedTouchEvent unownedTouchEvent(eventForItem);
207−
208− #if TOUCHREGISTRY_DEBUG
209− UG_DEBUG << "Sending unowned" << qPrintable(touchEventToString(eventForItem))
210− << "to" << item;
211− #endif
212−
213− QCoreApplication::sendEvent(item, &unownedTouchEvent);
214−}
215−
216−void TouchRegistry::translateTouchPointFromScreenToWindowCoords(QTouchEvent::TouchPoint &touchPoint)
217−{
218− touchPoint.setScreenRect(touchPoint.sceneRect());
219− touchPoint.setStartScreenPos(touchPoint.startScenePos());
220− touchPoint.setLastScreenPos(touchPoint.lastScenePos());
221−
222− touchPoint.setSceneRect(touchPoint.rect());
223− touchPoint.setStartScenePos(touchPoint.startPos());
224− touchPoint.setLastScenePos(touchPoint.lastPos());
225−}
226−
227−bool TouchRegistry::eventFilter(QObject *watched, QEvent *event)
228−{
229− Q_UNUSED(watched);
230−
231− switch (event->type()) {
232− case QEvent::TouchBegin:
233− case QEvent::TouchUpdate:
234− case QEvent::TouchEnd:
235− case QEvent::TouchCancel:
236− update(static_cast<QTouchEvent*>(event));
237− break;
238− default:
239− // do nothing
240− break;
241− }
242−
243− // Do not filter out the event. i.e., let it be handled further as
244− // we're just monitoring events
245− return false;
246−}
247−
248−void TouchRegistry::addCandidateOwnerForTouch(int id, QQuickItem *candidate)
249−{
250− #if TOUCHREGISTRY_DEBUG
251− UG_DEBUG << "addCandidateOwnerForTouch id" << id << "candidate" << candidate;
252− #endif
253−
254− Pool<TouchInfo>::Iterator touchInfo = findTouchInfo(id);
255− if (!touchInfo) { qFatal("TouchRegistry: Failed to find TouchInfo"); }
256−
257− if (touchInfo->isOwned()) {
258− qWarning("TouchRegistry: trying to add candidate owner for a touch that's already owned");
259− return;
260− }
261−
262− // TODO: Check if candidate already exists
263−
264− CandidateInfo candidateInfo;
265− candidateInfo.state = CandidateInfo::Undecided;
266− candidateInfo.item = candidate;
267− candidateInfo.inactivityTimer = new CandidateInactivityTimer(id, candidate,
268− m_timerFactory->createTimer(),
269− this);
270− connect(candidateInfo.inactivityTimer, &CandidateInactivityTimer::candidateDefaulted,
271− this, &TouchRegistry::rejectCandidateOwnerForTouch);
272−
273− touchInfo->candidates.append(candidateInfo);
274−
275− connect(candidate, &QObject::destroyed, this, [=](){ pruneNullCandidatesForTouch(id); });
276−}
277−
278−void TouchRegistry::addTouchWatcher(int touchId, QQuickItem *watcher)
279−{
280− #if TOUCHREGISTRY_DEBUG
281− UG_DEBUG << "addTouchWatcher id" << touchId << "watcher" << watcher;
282− #endif
283−
284− Pool<TouchInfo>::Iterator touchInfo = findTouchInfo(touchId);
285− if (!touchInfo) { qFatal("TouchRegistry: Failed to find TouchInfo"); }
286−
287− // TODO: Check if watcher already exists
288−
289− touchInfo->watchers.append(watcher);
290−}
291−
292−void TouchRegistry::removeCandidateOwnerForTouch(int id, QQuickItem *candidate)
293−{
294− #if TOUCHREGISTRY_DEBUG
295− UG_DEBUG << "removeCandidateOwnerForTouch id" << id << "candidate" << candidate;
296− #endif
297−
298− Pool<TouchInfo>::Iterator touchInfo = findTouchInfo(id);
299− if (!touchInfo) { qFatal("TouchRegistry: Failed to find TouchInfo"); }
300−
301−
302− // TODO: check if the candidate is in fact the owner of the touch
303−
304− bool removed = false;
305− for (int i = 0; i < touchInfo->candidates.count() && !removed; ++i) {
306− if (touchInfo->candidates[i].item == candidate) {
307− removeCandidateOwnerForTouchByIndex(touchInfo, i);
308− removed = true;
309− }
310− }
311−}
312−
313−void TouchRegistry::pruneNullCandidatesForTouch(int touchId)
314−{
315− #if TOUCHREGISTRY_DEBUG
316− UG_DEBUG << "pruneNullCandidatesForTouch touchId" << touchId;
317− #endif
318−
319− Pool<TouchInfo>::Iterator touchInfo = findTouchInfo(touchId);
320− if (!touchInfo) {
321− // doesn't matter as touch is already gone.
322− return;
323− }
324−
325− int i = 0;
326− while (i < touchInfo->candidates.count()) {
327− if (touchInfo->candidates[i].item.isNull()) {
328− removeCandidateOwnerForTouchByIndex(touchInfo, i);
329− } else {
330− ++i;
331− }
332− }
333−}
334−
335−void TouchRegistry::removeCandidateOwnerForTouchByIndex(Pool<TouchRegistry::TouchInfo>::Iterator &touchInfo,
336− int candidateIndex)
337−{
338− // TODO: check if the candidate is in fact the owner of the touch
339−
340− Q_ASSERT(candidateIndex < touchInfo->candidates.count());
341−
342− if (candidateIndex == 0 && touchInfo->candidates[candidateIndex].state != CandidateInfo::Undecided) {
343− qCritical("TouchRegistry: touch owner is being removed.");
344− }
345− removeCandidateHelper(touchInfo, candidateIndex);
346−
347− if (candidateIndex == 0) {
348− // the top candidate has been removed. if the new top candidate
349− // wants the touch let him know he's now the owner.
350− if (touchInfo->isOwned()) {
351− touchInfo->notifyCandidatesOfOwnershipResolution();
352− }
353− }
354−
355− if (!m_inDispatchLoop && touchInfo->ended()) {
356− m_touchInfoPool.freeSlot(touchInfo);
357− }
358−}
359−
360−void TouchRegistry::requestTouchOwnership(int id, QQuickItem *candidate)
361−{
362− Pool<TouchInfo>::Iterator touchInfo = findTouchInfo(id);
363− if (!touchInfo) { qFatal("TouchRegistry: Failed to find TouchInfo"); }
364−
365− Q_ASSERT(!touchInfo->isOwned());
366−
367− int candidateIndex = -1;
368− for (int i = 0; i < touchInfo->candidates.count(); ++i) {
369− CandidateInfo &candidateInfo = touchInfo->candidates[i];
370− if (candidateInfo.item == candidate) {
371− candidateInfo.state = CandidateInfo::Requested;
372− delete candidateInfo.inactivityTimer;
373− candidateInfo.inactivityTimer = nullptr;
374− candidateIndex = i;
375− break;
376− }
377− }
378− #if TOUCHREGISTRY_DEBUG
379− UG_DEBUG << "requestTouchOwnership id " << id << "candidate" << candidate << "index: " << candidateIndex;
380− #endif
381−
382− // add it as a candidate if not present yet
383− if (candidateIndex < 0) {
384− CandidateInfo candidateInfo;
385− candidateInfo.state = CandidateInfo::InterimOwner;
386− candidateInfo.item = candidate;
387− candidateInfo.inactivityTimer = nullptr;
388− touchInfo->candidates.append(candidateInfo);
389− // it's the last one
390− candidateIndex = touchInfo->candidates.count() - 1;
391− connect(candidate, &QObject::destroyed, this, [=](){ pruneNullCandidatesForTouch(id); });
392− }
393−
394− // If it's the top candidate it means it's now the owner. Let
395− // it know about it.
396− if (candidateIndex == 0) {
397− touchInfo->notifyCandidatesOfOwnershipResolution();
398− }
399−}
400−
401−Pool<TouchRegistry::TouchInfo>::Iterator TouchRegistry::findTouchInfo(int id)
402−{
403− Pool<TouchInfo>::Iterator touchInfo;
404−
405− m_touchInfoPool.forEach([&](Pool<TouchInfo>::Iterator &someTouchInfo) -> bool {
406− if (someTouchInfo->id == id) {
407− touchInfo = someTouchInfo;
408− return false;
409− } else {
410− return true;
411− }
412− });
413−
414− return touchInfo;
415−}
416−
417−
418−void TouchRegistry::rejectCandidateOwnerForTouch(int id, QQuickItem *candidate)
419−{
420− // NB: It's technically possible that candidate is a dangling pointer at this point.
421− // Although that would most likely be due to a bug in our code.
422− // In any case, only dereference it after it's confirmed that it indeed exists.
423−
424− #if TOUCHREGISTRY_DEBUG
425− UG_DEBUG << "rejectCandidateOwnerForTouch id" << id << "candidate" << (void*)candidate;
426− #endif
427−
428− Pool<TouchInfo>::Iterator touchInfo = findTouchInfo(id);
429− if (!touchInfo) {
430− #if TOUCHREGISTRY_DEBUG
431− UG_DEBUG << "Failed to find TouchInfo for id" << id;
432− #endif
433− return;
434− }
435−
436− int rejectedCandidateIndex = -1;
437−
438− // Check if the given candidate is valid and still undecided
439− for (int i = 0; i < touchInfo->candidates.count() && rejectedCandidateIndex == -1; ++i) {
440− CandidateInfo &candidateInfo = touchInfo->candidates[i];
441− if (candidateInfo.item == candidate) {
442− Q_ASSERT(i > 0 || candidateInfo.state == CandidateInfo::Undecided);
443− if (i == 0 && candidateInfo.state != CandidateInfo::Undecided) {
444− qCritical() << "TouchRegistry: Can't reject item (" << (void*)candidate
445− << ") as it already owns touch" << id;
446− return;
447− } else {
448− // we found the guy and it's all fine.
449− rejectedCandidateIndex = i;
450− }
451− }
452− }
453−
454− // If we reached this point it's because the given candidate exists and is indeed undecided.
455−
456− Q_ASSERT(rejectedCandidateIndex >= 0 && rejectedCandidateIndex < touchInfo->candidates.size());
457−
458− {
459− TouchOwnershipEvent lostOwnershipEvent(id, false /*gained*/);
460− QCoreApplication::sendEvent(candidate, &lostOwnershipEvent);
461− }
462−
463− removeCandidateHelper(touchInfo, rejectedCandidateIndex);
464−
465− if (rejectedCandidateIndex == 0) {
466− // the top candidate has been removed. if the new top candidate
467− // wants the touch let him know he's now the owner.
468− if (touchInfo->isOwned()) {
469− touchInfo->notifyCandidatesOfOwnershipResolution();
470− }
471− }
472−}
473−
474−void TouchRegistry::removeCandidateHelper(Pool<TouchInfo>::Iterator &touchInfo, int candidateIndex)
475−{
476− {
477− CandidateInfo &candidateInfo = touchInfo->candidates[candidateIndex];
478−
479− delete candidateInfo.inactivityTimer;
480− candidateInfo.inactivityTimer = nullptr;
481−
482− if (candidateInfo.item) {
483− disconnect(candidateInfo.item.data(), nullptr, this, nullptr);
484− }
485− }
486− touchInfo->candidates.removeAt(candidateIndex);
487−}
488−
489−////////////////////////////////////// TouchRegistry::TouchInfo ////////////////////////////////////
490−
491−TouchRegistry::TouchInfo::TouchInfo(int id)
492−{
493− init(id);
494−}
495−
496−void TouchRegistry::TouchInfo::reset()
497−{
498− id = -1;
499−
500− for (int i = 0; i < candidates.count(); ++i) {
501− CandidateInfo &candidate = candidates[i];
502− delete candidate.inactivityTimer;
503− candidate.inactivityTimer.clear(); // shoundn't be needed but anyway...
504− }
505−}
506−
507−void TouchRegistry::TouchInfo::init(int id)
508−{
509− this->id = id;
510− physicallyEnded = false;
511− candidates.clear();
512− watchers.clear();
513−}
514−
515−bool TouchRegistry::TouchInfo::isOwned() const
516−{
517− return !candidates.isEmpty() && candidates.first().state != CandidateInfo::Undecided;
518−}
519−
520−bool TouchRegistry::TouchInfo::ended() const
521−{
522− Q_ASSERT(isValid());
523− return physicallyEnded && (isOwned() || candidates.isEmpty());
524−}
525−
526−void TouchRegistry::TouchInfo::notifyCandidatesOfOwnershipResolution()
527−{
528− Q_ASSERT(isOwned());
529−
530− #if TOUCHREGISTRY_DEBUG
531− UG_DEBUG << "sending TouchOwnershipEvent(id =" << id
532− << " gained) to candidate" << candidates[0].item;
533− #endif
534−
535− // need to take a copy of the item list in case
536− // we call back in to remove candidate during the lost ownership event.
537− QList<QPointer<QQuickItem>> items;
538− Q_FOREACH(const CandidateInfo& info, candidates) {
539− items << info.item;
540− }
541−
542− TouchOwnershipEvent gainedOwnershipEvent(id, true /*gained*/);
543− QCoreApplication::sendEvent(items[0], &gainedOwnershipEvent);
544−
545− TouchOwnershipEvent lostOwnershipEvent(id, false /*gained*/);
546− for (int i = 1; i < items.count(); ++i) {
547− #if TOUCHREGISTRY_DEBUG
548− UG_DEBUG << "sending TouchOwnershipEvent(id =" << id << " lost) to candidate"
549− << items[i];
550− #endif
551− QCoreApplication::sendEvent(items[i], &lostOwnershipEvent);
552− }
553−}
libs/UbuntuGestures/TouchRegistry.hdeleted−201
@@ -1,201 +0,0 @@
1−/*
2− * Copyright (C) 2014 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−#ifndef UNITY_TOUCHREGISTRY_H
18−#define UNITY_TOUCHREGISTRY_H
19−
20−#include <QQuickItem>
21−#include <QObject>
22−#include <QPointer>
23−#include <QTouchEvent>
24−#include <QVector>
25−
26−#include "UbuntuGesturesGlobal.h"
27−#include "CandidateInactivityTimer.h"
28−#include "Timer.h"
29−#include "Pool.h"
30−
31−namespace UbuntuGestures {
32− class AbstractTimerFactory;
33−}
34−
35−/*
36− Where the ownership of touches is registered.
37−
38− Singleton used for adding a touch point ownership model analogous to the one
39− described in the XInput 2.2 protocol[1] on top of the existing input dispatch logic in QQuickWindow.
40−
41− It provides a much more flexible and powerful way of dealing with pointer ownership than the existing
42− mechanisms in Qt. Namely QQuickItem::grabTouchPoints, QuickItem::keepTouchGrab,
43− QQuickItem::setFiltersChildMouseEvents, QQuickItem::ungrabTouchPoints and QQuickItem::touchUngrabEvent.
44−
45− Usage:
46−
47− 1- An item receives a a new touch point. If he's not sure whether he wants it yet, he calls:
48− TouchRegistry::instance()->addCandidateOwnerForTouch(touchId, this);
49− touchEvent->ignore();
50− Ignoring the event is crucial so that it can be seen by other interested parties, which will
51− behave similarly.
52−
53− 2- That item will then start receiving UnownedTouchEvents for that touch from step 1. Once he's
54− made a decision he calls either:
55− TouchRegistry::instance()->requestTouchOwnership(touchId, this);
56− If he wants the touch point or:
57− TouchRegistry::instance()->removeCandidateOwnerForTouch(touchId, this);
58−  if he does not want it.
59−
60− Candidates are put in a priority queue. The first one to call addCandidateOwnerForTouch() will
61− take precedence over the others for receiving ownership over the touch point (from now on called
62− simply top-candidate).
63−
64− If the top-candidate calls requestTouchOwnership() he will immediately receive a
65− TouchOwnershipEvent(gained=true) for that touch point. He can then safely call
66− QQuickItem::grabTouchPoints to actually get the owned touch points. The other candidates
67− will receive TouchOwnershipEvent(gained=false) and will no longer receive UnownedTouchEvents
68− for that touch point. They will have to undo whatever action they were performing with that
69− touch point.
70−
71− But if the top-candidate calls removeCandidateOwnerForTouch() instead, he's popped from the
72− candidacy queue and ownership is given to the new top-most candidate if he has already
73− made his decision, that is.
74−
75− The TouchRegistry cannot enforce the results of this pointer ownership negotiation (i.e.,
76− who gets to grab the touch points) as that would clash with QQuickWindow's input event
77− dispatching logic. The candidates have to respect the decision and grab the touch points
78− themselves.
79−
80− If an item wants ownership over touches as soon as he receives the TouchBegin for them, his step 1
81− would be instead:
82− TouchRegistry::instance()->requestTouchOwnership(touchId, this);
83− touchEvent->accept();
84− He won't get any UnownedTouchEvent for that touch as he is already the interim owner (ie, QQuickWindow
85− will keep sending touch updates to him already). Eventually he will be notified once ownership has
86− been granted to him (from TouchRegistry perspective), from which point onwards he could safely assume
87− other TouchRegistry users wouldn't snatch this touch away from him.
88−
89− Items oblivious to TouchRegistry will lose their touch points without warning, just like in plain Qt.
90−
91− [1] - http://www.x.org/releases/X11R7.7/doc/inputproto/XI2proto.txt (see multitouch-ownership)
92− */
93−class UBUNTUGESTURES_EXPORT TouchRegistry : public QObject
94−{
95− Q_OBJECT
96−public:
97− virtual ~TouchRegistry();
98−
99− // Returns a pointer to the application's TouchRegistry instance.
100− static TouchRegistry *instance();
101−
102− void update(const QTouchEvent *event);
103−
104− // Calls update() if the given event is a QTouchEvent
105− bool eventFilter(QObject *watched, QEvent *event) override;
106−
107− // An item that might later request ownership over the given touch point.
108− // He will be kept informed about that touch point through UnownedTouchEvents
109− // All candidates must eventually decide whether they want to own the touch point
110− // or not. That decision is informed through requestTouchOwnership() or
111− // removeCandidateOwnerForTouch()
112− void addCandidateOwnerForTouch(int id, QQuickItem *candidate);
113−
114− // The same as rejecting ownership of a touch
115− void removeCandidateOwnerForTouch(int id, QQuickItem *candidate);
116−
117− // The candidate object wants to be the owner of the touch with the given id.
118− // If he's currently the oldest/top-most candidate, he will get an ownership
119− // event immediately. If not, he will get ownership if (or once) he becomes the
120− // top-most candidate.
121− void requestTouchOwnership(int id, QQuickItem *candidate);
122−
123− // An item that has no interest (effective or potential) in owning a touch point
124− // but would nonetheless like to be kept up-to-date on its state.
125− void addTouchWatcher(int touchId, QQuickItem *watcherItem);
126−
127− // Useful for tests, where you should use fake timers
128− void setTimerFactory(UbuntuGestures::AbstractTimerFactory *timerFactory);
129−
130−private Q_SLOTS:
131− void rejectCandidateOwnerForTouch(int id, QQuickItem *candidate);
132−
133−private:
134− // Only instance() can cronstruct one
135− TouchRegistry(QObject *parent = nullptr);
136−
137− class CandidateInfo {
138− public:
139− enum {
140− // A candidate owner that doesn't yet know for sure whether he wants the touch point
141− // (gesture recognition is stilll going on)
142− Undecided = 0,
143− // A candidate owner that wants the touch but hasn't been granted it yet,
144− // most likely because there's an undecided candidate with higher priority
145− Requested = 1,
146− // An item that is the interim owner of the touch, receiving QTouchEvents of it
147− // from QQuickWindow. Ie, it's the actual touch owner from Qt's point of view.
148− // It wants to keep its touch ownership but hasn't been granted it by TouchRegistry
149− // yet because of undecided candidates higher up.
150− InterimOwner = 2
151− } state;
152− QPointer<QQuickItem> item;
153− QPointer<UbuntuGestures::CandidateInactivityTimer> inactivityTimer;
154− };
155−
156− class TouchInfo {
157− public:
158− TouchInfo() : id(-1) {}
159− TouchInfo(int id);
160− bool isValid() const { return id >= 0; }
161− void reset();
162− void init(int id);
163− int id;
164− bool physicallyEnded;
165− bool isOwned() const;
166− bool ended() const;
167− void notifyCandidatesOfOwnershipResolution();
168−
169− // TODO optimize storage (s/QList/Pool)
170− QList<CandidateInfo> candidates;
171− QList<QPointer<QQuickItem>> watchers;
172− };
173−
174− void pruneNullCandidatesForTouch(int touchId);
175− void removeCandidateOwnerForTouchByIndex(Pool<TouchInfo>::Iterator &touchInfo, int candidateIndex);
176− void removeCandidateHelper(Pool<TouchInfo>::Iterator &touchInfo, int candidateIndex);
177−
178− Pool<TouchInfo>::Iterator findTouchInfo(int id);
179−
180− void deliverTouchUpdatesToUndecidedCandidatesAndWatchers(const QTouchEvent *event);
181−
182− static void translateTouchPointFromScreenToWindowCoords(QTouchEvent::TouchPoint &touchPoint);
183−
184− static void dispatchPointsToItem(const QTouchEvent *event, const QList<int> &touchIds,
185− QQuickItem *item);
186− void freeEndedTouchInfos();
187−
188− Pool<TouchInfo> m_touchInfoPool;
189−
190− // the singleton instance
191− static TouchRegistry *m_instance;
192−
193− bool m_inDispatchLoop;
194−
195− UbuntuGestures::AbstractTimerFactory *m_timerFactory;
196−
197− friend class tst_TouchRegistry;
198− friend class tst_DirectionalDragArea;
199−};
200−
201−#endif // UNITY_TOUCHREGISTRY_H
libs/UbuntuGestures/UbuntuGesturesGlobal.hdeleted−23
@@ -1,23 +0,0 @@
1−/*
2− * Copyright (C) 2014 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−#include <QtCore/QtGlobal>
18−
19−#if defined(UBUNTUGESTURES_LIBRARY)
20−# define UBUNTUGESTURES_EXPORT Q_DECL_EXPORT
21−#else
22−# define UBUNTUGESTURES_EXPORT Q_DECL_IMPORT
23−#endif
libs/UbuntuGestures/UnownedTouchEvent.cppdeleted−39
@@ -1,39 +0,0 @@
1−/*
2− * Copyright (C) 2014 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−#include "UnownedTouchEvent.h"
18−
19−QEvent::Type UnownedTouchEvent::m_unownedTouchEventType = (QEvent::Type)-1;
20−
21−UnownedTouchEvent::UnownedTouchEvent(QTouchEvent *touchEvent)
22− : QEvent(unownedTouchEventType())
23− , m_touchEvent(touchEvent)
24−{
25−}
26−
27−QEvent::Type UnownedTouchEvent::unownedTouchEventType()
28−{
29− if (m_unownedTouchEventType == (QEvent::Type)-1) {
30− m_unownedTouchEventType = (QEvent::Type)registerEventType();
31− }
32−
33− return m_unownedTouchEventType;
34−}
35−
36−QTouchEvent *UnownedTouchEvent::touchEvent()
37−{
38− return m_touchEvent.data();
39−}
libs/UbuntuGestures/UnownedTouchEvent.hdeleted−45
@@ -1,45 +0,0 @@
1−/*
2− * Copyright (C) 2014 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−#ifndef UBUNTU_UNOWNEDTOUCHEVENT_H
18−#define UBUNTU_UNOWNEDTOUCHEVENT_H
19−
20−#include <QTouchEvent>
21−#include <QScopedPointer>
22−#include "UbuntuGesturesGlobal.h"
23−
24−/*
25− A touch event with touch points that do not belong the item receiving it.
26−
27− See TouchRegistry::addCandidateOwnerForTouch and TouchRegistry::addTouchWatcher
28− */
29−class UBUNTUGESTURES_EXPORT UnownedTouchEvent : public QEvent
30−{
31−public:
32− UnownedTouchEvent(QTouchEvent *touchEvent);
33− static Type unownedTouchEventType();
34−
35− // TODO: It might be cleaner to store the information directly in UnownedTouchEvent
36− // instead of carrying around a synthesized QTouchEvent. But the latter option
37− // is very convenient.
38− QTouchEvent *touchEvent();
39−
40−private:
41− static Type m_unownedTouchEventType;
42− QScopedPointer<QTouchEvent> m_touchEvent;
43−};
44−
45−#endif // UBUNTU_UNOWNEDTOUCHEVENT_H
plugins/Ubuntu/Gestures/AxisVelocityCalculator.h+1−1
@@ -24,7 +24,7 @@
2424#include "UbuntuGesturesQmlGlobal.h"
2525#include <stdint.h>
2626#include <QtCore/QObject>
27−#include "TimeSource.h"
27+#include <TimeSource>
2828
2929/*
3030 Estimates the current velocity of a finger based on recent movement along an axis
plugins/Ubuntu/Gestures/CMakeLists.txt+5−5
@@ -4,27 +4,27 @@ remove_definitions(-DQT_NO_KEYWORDS)
44set(UbuntuGesturesQml_SOURCES
55 plugin.cpp
66 AxisVelocityCalculator.cpp
7− Damper.cpp
87 Direction.cpp
9− DirectionalDragArea.cpp
10− FloatingFlickable.cpp
8+ MouseEventGenerator.cpp
119 PressedOutsideNotifier.cpp
1210 TouchDispatcher.cpp
1311 TouchGate.cpp
1412 TouchGestureArea.cpp
1513)
1614
15+pkg_check_modules(UBUNTUGESTURES REQUIRED UbuntuGestures)
16+
1717add_definitions(-DUBUNTUGESTURESQML_LIBRARY)
1818
1919add_library(UbuntuGesturesQml MODULE ${UbuntuGesturesQml_SOURCES})
20−target_link_libraries(UbuntuGesturesQml UbuntuGestures)
20+target_link_libraries(UbuntuGesturesQml ${UBUNTUGESTURES_LIBRARIES})
2121
2222qt5_use_modules(UbuntuGesturesQml Core Quick)
2323
2424# So that Foo.cpp can #include "Foo.moc"
2525include_directories(${CMAKE_CURRENT_BINARY_DIR})
2626
27−include_directories(${CMAKE_SOURCE_DIR}/libs/UbuntuGestures)
27+include_directories(${UBUNTUGESTURES_INCLUDE_DIRS})
2828
2929# There's no cmake var for v8 include path :-/ so create one
3030LIST(GET Qt5Core_INCLUDE_DIRS 0 QtCoreDir0)
plugins/Ubuntu/Gestures/Damper.cppdeleted−24
@@ -1,24 +0,0 @@
1−/*
2− * Copyright (C) 2015 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−#include "Damper.h"
18−#include <QDebug>
19−
20−QDebug operator<<(QDebug dbg, const DampedPointF &p)
21−{
22− dbg.nospace() << "(" << p.x() << ", " << p.y() << ")";
23− return dbg.space();
24−}
plugins/Ubuntu/Gestures/Damper.hdeleted−89
@@ -1,89 +0,0 @@
1−/*
2− * Copyright (C) 2013 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−#ifndef UBUNTU_GESTURES_DAMPER_H
18−#define UBUNTU_GESTURES_DAMPER_H
19−
20−#include <QtCore/QPointF>
21−
22−/*
23− Decreases the oscillations of a value along an axis.
24− */
25−template <class Type> class Damper {
26−public:
27− Damper() : m_value(0), m_maxDelta(0) { }
28−
29− // Maximum delta between the raw value and its dampened counterpart.
30− void setMaxDelta(Type maxDelta) {
31− if (maxDelta < 0) qFatal("Damper::maxDelta must be a positive number.");
32− m_maxDelta = maxDelta;
33− }
34− Type maxDelta() const { return m_maxDelta; }
35−
36− void reset(Type value) {
37− m_value = value;
38− }
39−
40− Type update(Type value) {
41− Type delta = value - m_value;
42− if (delta > 0 && delta > m_maxDelta) {
43− m_value += delta - m_maxDelta;
44− } else if (delta < 0 && delta < -m_maxDelta) {
45− m_value += delta + m_maxDelta;
46− }
47−
48− return m_value;
49− }
50−
51− Type value() const { return m_value; }
52−
53−private:
54− Type m_value;
55− Type m_maxDelta;
56−};
57−
58−/*
59− A point that has its movement dampened.
60− */
61−class DampedPointF {
62−public:
63− void setMaxDelta(qreal maxDelta) {
64− m_x.setMaxDelta(maxDelta);
65− m_y.setMaxDelta(maxDelta);
66− }
67−
68− qreal maxDelta() const { return m_x.maxDelta(); }
69−
70− void reset(const QPointF point) {
71− m_x.reset(point.x());
72− m_y.reset(point.y());
73− }
74−
75− void update(const QPointF point) {
76− m_x.update(point.x());
77− m_y.update(point.y());
78− }
79−
80− qreal x() const { return m_x.value(); }
81− qreal y() const { return m_y.value(); }
82−private:
83− Damper<qreal> m_x;
84− Damper<qreal> m_y;
85−};
86−
87−QDebug operator<<(QDebug dbg, const DampedPointF &p);
88−
89−#endif // UBUNTU_GESTURES_DAMPER_H
plugins/Ubuntu/Gestures/Direction.h+1
@@ -29,6 +29,7 @@ class UBUNTUGESTURESQML_EXPORT Direction : public QObject {
2929 Q_ENUMS(Type)
3030
3131public:
32+ // Make sure it is kept synchronized with SDK UCSwipeArea::Direction
3233 enum Type {
3334 Rightwards, // Along the positive direction of the X axis
3435 Leftwards, // Along the negative direction of the X axis
plugins/Ubuntu/Gestures/DirectionalDragArea.cppdeleted−932
@@ -1,932 +0,0 @@
1−/*
2− * Copyright (C) 2013-2015 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−#define ACTIVETOUCHESINFO_DEBUG 0
18−#define DIRECTIONALDRAGAREA_DEBUG 0
19−
20−#include "DirectionalDragArea.h"
21−
22−#include <QQuickWindow>
23−#include <QtCore/qmath.h>
24−#include <QScreen>
25−#include <QDebug>
26−
27−#pragma GCC diagnostic push
28−#pragma GCC diagnostic ignored "-pedantic"
29−#include <private/qquickwindow_p.h>
30−#pragma GCC diagnostic pop
31−
32−// local
33−#include "TouchOwnershipEvent.h"
34−#include "TouchRegistry.h"
35−#include "UnownedTouchEvent.h"
36−
37−#include "DirectionalDragArea_p.h"
38−
39−using namespace UbuntuGestures;
40−
41−#if DIRECTIONALDRAGAREA_DEBUG
42−#define ddaDebug(params) qDebug().nospace() << "[DDA(" << qPrintable(objectName()) << ")] " << params
43−#include "DebugHelpers.h"
44−
45−namespace {
46−const char *statusToString(DirectionalDragAreaPrivate::Status status)
47−{
48− if (status == DirectionalDragAreaPrivate::WaitingForTouch) {
49− return "WaitingForTouch";
50− } else if (status == DirectionalDragAreaPrivate::Undecided) {
51− return "Undecided";
52− } else {
53− return "Recognized";
54− }
55−}
56−
57−} // namespace {
58−#else // DIRECTIONALDRAGAREA_DEBUG
59−#define ddaDebug(params) ((void)0)
60−#endif // DIRECTIONALDRAGAREA_DEBUG
61−
62−DirectionalDragArea::DirectionalDragArea(QQuickItem *parent)
63− : QQuickItem(parent)
64− , d(new DirectionalDragAreaPrivate(this))
65−{
66− d->setRecognitionTimer(new Timer(this));
67− d->recognitionTimer->setInterval(d->maxTime);
68− d->recognitionTimer->setSingleShot(true);
69−
70− connect(this, &QQuickItem::enabledChanged, d, &DirectionalDragAreaPrivate::giveUpIfDisabledOrInvisible);
71− connect(this, &QQuickItem::visibleChanged, d, &DirectionalDragAreaPrivate::giveUpIfDisabledOrInvisible);
72−}
73−
74−Direction::Type DirectionalDragArea::direction() const
75−{
76− return d->direction;
77−}
78−
79−void DirectionalDragArea::setDirection(Direction::Type direction)
80−{
81− if (direction != d->direction) {
82− d->direction = direction;
83− Q_EMIT directionChanged(d->direction);
84− }
85−}
86−
87−void DirectionalDragAreaPrivate::setDistanceThreshold(qreal value)
88−{
89− if (distanceThreshold != value) {
90− distanceThreshold = value;
91− distanceThresholdSquared = distanceThreshold * distanceThreshold;
92− }
93−}
94−
95−void DirectionalDragAreaPrivate::setMaxTime(int value)
96−{
97− if (maxTime != value) {
98− maxTime = value;
99− recognitionTimer->setInterval(maxTime);
100− }
101−}
102−
103−void DirectionalDragAreaPrivate::setRecognitionTimer(UbuntuGestures::AbstractTimer *timer)
104−{
105− int interval = 0;
106− bool timerWasRunning = false;
107− bool wasSingleShot = false;
108−
109− // can be null when called from the constructor
110− if (recognitionTimer) {
111− interval = recognitionTimer->interval();
112− timerWasRunning = recognitionTimer->isRunning();
113− if (recognitionTimer->parent() == this) {
114− delete recognitionTimer;
115− }
116− }
117−
118− recognitionTimer = timer;
119− timer->setInterval(interval);
120− timer->setSingleShot(wasSingleShot);
121− connect(timer, &UbuntuGestures::AbstractTimer::timeout,
122− this, &DirectionalDragAreaPrivate::rejectGesture);
123− if (timerWasRunning) {
124− recognitionTimer->start();
125− }
126−}
127−
128−void DirectionalDragAreaPrivate::setTimeSource(const SharedTimeSource &timeSource)
129−{
130− this->timeSource = timeSource;
131− activeTouches.m_timeSource = timeSource;
132−}
133−
134−qreal DirectionalDragArea::distance() const
135−{
136− if (Direction::isHorizontal(d->direction)) {
137− return d->publicPos.x() - d->startPos.x();
138− } else {
139− return d->publicPos.y() - d->startPos.y();
140− }
141−}
142−
143−void DirectionalDragAreaPrivate::updateSceneDistance()
144−{
145− QPointF totalMovement = publicScenePos - startScenePos;
146− sceneDistance = projectOntoDirectionVector(totalMovement);
147−}
148−
149−qreal DirectionalDragArea::sceneDistance() const
150−{
151− return d->sceneDistance;
152−}
153−
154−qreal DirectionalDragArea::touchX() const
155−{
156− return d->publicPos.x();
157−}
158−
159−qreal DirectionalDragArea::touchY() const
160−{
161− return d->publicPos.y();
162−}
163−
164−qreal DirectionalDragArea::touchSceneX() const
165−{
166− return d->publicScenePos.x();
167−}
168−
169−qreal DirectionalDragArea::touchSceneY() const
170−{
171− return d->publicScenePos.y();
172−}
173−
174−bool DirectionalDragArea::dragging() const
175−{
176− return d->status == DirectionalDragAreaPrivate::Recognized;
177−}
178−
179−bool DirectionalDragArea::pressed() const
180−{
181− return d->status != DirectionalDragAreaPrivate::WaitingForTouch;
182−}
183−
184−bool DirectionalDragArea::immediateRecognition() const
185−{
186− return d->immediateRecognition;
187−}
188−
189−void DirectionalDragArea::setImmediateRecognition(bool enabled)
190−{
191− if (d->immediateRecognition != enabled) {
192− d->immediateRecognition = enabled;
193− Q_EMIT immediateRecognitionChanged(enabled);
194− }
195−}
196−
197−bool DirectionalDragArea::monitorOnly() const
198−{
199− return d->monitorOnly;
200−}
201−
202−void DirectionalDragArea::setMonitorOnly(bool monitorOnly)
203−{
204− if (d->monitorOnly != monitorOnly) {
205− d->monitorOnly = monitorOnly;
206−
207− if (monitorOnly && d->status == DirectionalDragAreaPrivate::Undecided) {
208− TouchRegistry::instance()->removeCandidateOwnerForTouch(d->touchId, this);
209− // We still wanna know when it ends for keeping the composition time window up-to-date
210− TouchRegistry::instance()->addTouchWatcher(d->touchId, this);
211− }
212−
213− Q_EMIT monitorOnlyChanged(monitorOnly);
214− }
215−}
216−
217−void DirectionalDragArea::removeTimeConstraints()
218−{
219− d->setMaxTime(60 * 60 * 1000);
220− d->compositionTime = 0;
221− ddaDebug("removed time constraints");
222−}
223−
224−bool DirectionalDragArea::event(QEvent *event)
225−{
226− if (event->type() == TouchOwnershipEvent::touchOwnershipEventType()) {
227− d->touchOwnershipEvent(static_cast<TouchOwnershipEvent *>(event));
228− return true;
229− } else if (event->type() == UnownedTouchEvent::unownedTouchEventType()) {
230− d->unownedTouchEvent(static_cast<UnownedTouchEvent *>(event));
231− return true;
232− } else {
233− return QQuickItem::event(event);
234− }
235−}
236−
237−void DirectionalDragAreaPrivate::touchOwnershipEvent(TouchOwnershipEvent *event)
238−{
239− if (event->gained()) {
240− QVector<int> ids;
241− ids.append(event->touchId());
242− ddaDebug("grabbing touch");
243− q->grabTouchPoints(ids);
244−
245− // Work around for Qt bug. If we grab a touch that is being used for mouse pointer
246− // emulation it will cause the emulation logic to go nuts.
247− // Thus we have to also grab the mouse in this case.
248− //
249− // The fix for this bug has landed in Qt 5.4 (https://codereview.qt-project.org/96887)
250− // TODO: Remove this workaround once we start using Qt 5.4
251− if (q->window()) {
252− QQuickWindowPrivate *windowPrivate = QQuickWindowPrivate::get(q->window());
253− if (windowPrivate->touchMouseId == event->touchId() && q->window()->mouseGrabberItem()) {
254− ddaDebug("removing mouse grabber");
255− q->window()->mouseGrabberItem()->ungrabMouse();
256− }
257− }
258− } else {
259− // We still wanna know when it ends for keeping the composition time window up-to-date
260− TouchRegistry::instance()->addTouchWatcher(touchId, q);
261−
262− setStatus(WaitingForTouch);
263− }
264−}
265−
266−void DirectionalDragAreaPrivate::unownedTouchEvent(UnownedTouchEvent *unownedTouchEvent)
267−{
268− QTouchEvent *event = unownedTouchEvent->touchEvent();
269−
270− Q_ASSERT(!event->touchPointStates().testFlag(Qt::TouchPointPressed));
271−
272− ddaDebug("Unowned " << timeSource->msecsSinceReference() << " " << qPrintable(touchEventToString(event)));
273−
274− switch (status) {
275− case WaitingForTouch:
276− // do nothing
277− break;
278− case Undecided:
279− Q_ASSERT(q->isEnabled() && q->isVisible());
280− unownedTouchEvent_undecided(unownedTouchEvent);
281− break;
282− default: // Recognized:
283− if (monitorOnly) {
284− // Treat unowned event as if we owned it, but we are really just watching it
285− touchEvent_recognized(event);
286− }
287− break;
288− }
289−
290− activeTouches.update(event);
291−}
292−
293−void DirectionalDragAreaPrivate::unownedTouchEvent_undecided(UnownedTouchEvent *unownedTouchEvent)
294−{
295− const QTouchEvent::TouchPoint *touchPoint = fetchTargetTouchPoint(unownedTouchEvent->touchEvent());
296− if (!touchPoint) {
297− qCritical() << "DirectionalDragArea[status=Undecided]: touch " << touchId
298− << "missing from UnownedTouchEvent without first reaching state Qt::TouchPointReleased. "
299− "Considering it as released.";
300−
301− TouchRegistry::instance()->removeCandidateOwnerForTouch(touchId, q);
302− setStatus(WaitingForTouch);
303− return;
304− }
305−
306− const QPointF &touchScenePos = touchPoint->scenePos();
307−
308− if (touchPoint->state() == Qt::TouchPointReleased) {
309− // touch has ended before recognition concluded
310− ddaDebug("Touch has ended before recognition concluded");
311− TouchRegistry::instance()->removeCandidateOwnerForTouch(touchId, q);
312− setStatus(WaitingForTouch);
313− return;
314− }
315−
316− previousDampedScenePos.setX(dampedScenePos.x());
317− previousDampedScenePos.setY(dampedScenePos.y());
318− dampedScenePos.update(touchScenePos);
319−
320− if (!movingInRightDirection()) {
321− ddaDebug("Rejecting gesture because touch point is moving in the wrong direction.");
322− TouchRegistry::instance()->removeCandidateOwnerForTouch(touchId, q);
323− // We still wanna know when it ends for keeping the composition time window up-to-date
324− TouchRegistry::instance()->addTouchWatcher(touchId, q);
325− setStatus(WaitingForTouch);
326− return;
327− }
328−
329− if (isWithinTouchCompositionWindow()) {
330− // There's still time for some new touch to appear and ruin our party as it would be combined
331− // with our touchId one and therefore deny the possibility of a single-finger gesture.
332− ddaDebug("Sill within composition window. Let's wait more.");
333− return;
334− }
335−
336− if (movedFarEnoughAlongGestureAxis()) {
337− if (!monitorOnly) {
338− TouchRegistry::instance()->requestTouchOwnership(touchId, q);
339− }
340− setStatus(Recognized);
341− setPublicPos(touchPoint->pos());
342− setPublicScenePos(touchScenePos);
343− } else if (isPastMaxDistance()) {
344− ddaDebug("Rejecting gesture because it went farther than maxDistance without getting recognized.");
345− TouchRegistry::instance()->removeCandidateOwnerForTouch(touchId, q);
346− // We still wanna know when it ends for keeping the composition time window up-to-date
347− TouchRegistry::instance()->addTouchWatcher(touchId, q);
348− setStatus(WaitingForTouch);
349− } else {
350− ddaDebug("Didn't move far enough yet. Let's wait more.");
351− }
352−}
353−
354−void DirectionalDragArea::touchEvent(QTouchEvent *event)
355−{
356− // TODO: Consider when more than one touch starts in the same event (although it's not possible
357− // with Mir's android-input). Have to track them all. Consider it a plus/bonus.
358−
359− ddaDebug(d->timeSource->msecsSinceReference() << " " << qPrintable(touchEventToString(event)));
360−
361− if (!isEnabled() || !isVisible()) {
362− QQuickItem::touchEvent(event);
363− return;
364− }
365−
366− switch (d->status) {
367− case DirectionalDragAreaPrivate::WaitingForTouch:
368− d->touchEvent_absent(event);
369− break;
370− case DirectionalDragAreaPrivate::Undecided:
371− d->touchEvent_undecided(event);
372− break;
373− default: // Recognized:
374− d->touchEvent_recognized(event);
375− break;
376− }
377−
378− d->activeTouches.update(event);
379−}
380−
381−void DirectionalDragAreaPrivate::touchEvent_absent(QTouchEvent *event)
382−{
383− // TODO: accept/reject is for the whole event, not per touch id. See how that affects us.
384−
385− if (!event->touchPointStates().testFlag(Qt::TouchPointPressed)) {
386− // Nothing to see here. No touch starting in this event.
387− return;
388− }
389−
390− // to be proven wrong, if that's the case
391− bool allGood = true;
392−
393− if (isWithinTouchCompositionWindow()) {
394− // too close to the last touch start. So we consider them as starting roughly at the same time.
395− // Can't be a single-touch gesture.
396− ddaDebug("A new touch point came in but we're still within time composition window. Ignoring it.");
397− allGood = false;
398− }
399−
400− const QList<QTouchEvent::TouchPoint> &touchPoints = event->touchPoints();
401−
402− const QTouchEvent::TouchPoint *newTouchPoint = nullptr;
403− for (int i = 0; i < touchPoints.count() && allGood; ++i) {
404− const QTouchEvent::TouchPoint &touchPoint = touchPoints.at(i);
405− if (touchPoint.state() == Qt::TouchPointPressed) {
406− if (newTouchPoint) {
407− // more than one touch starting in this QTouchEvent. Can't be a single-touch gesture
408− allGood = false;
409− } else {
410− // that's our candidate
411− newTouchPoint = &touchPoint;
412− }
413− }
414− }
415−
416− if (allGood) {
417− allGood = sanityCheckRecognitionProperties();
418− if (!allGood) {
419− qWarning("DirectionalDragArea: recognition properties are wrongly set. Gesture recognition"
420− " is impossible");
421− }
422− }
423−
424− if (allGood) {
425− Q_ASSERT(newTouchPoint);
426−
427− startPos = newTouchPoint->pos();
428− startScenePos = newTouchPoint->scenePos();
429− touchId = newTouchPoint->id();
430− dampedScenePos.reset(startScenePos);
431− setPublicPos(startPos);
432−
433− setPublicScenePos(startScenePos);
434− updateSceneDirectionVector();
435−
436− if (recognitionIsDisabled()) {
437− // Behave like a dumb TouchArea
438− ddaDebug("Gesture recognition is disabled. Requesting touch ownership immediately.");
439− setStatus(Recognized);
440− if (monitorOnly) {
441− watchPressedTouchPoints(touchPoints);
442− event->ignore();
443− } else {
444− TouchRegistry::instance()->requestTouchOwnership(touchId, q);
445− event->accept();
446− }
447− } else {
448− // just monitor the touch points for now.
449− if (monitorOnly) {
450− watchPressedTouchPoints(touchPoints);
451− } else {
452− TouchRegistry::instance()->addCandidateOwnerForTouch(touchId, q);
453− }
454−
455− setStatus(Undecided);
456− // Let the item below have it. We will monitor it and grab it later if a gesture
457− // gets recognized.
458− event->ignore();
459− }
460− } else {
461− watchPressedTouchPoints(touchPoints);
462− event->ignore();
463− }
464−}
465−
466−void DirectionalDragAreaPrivate::touchEvent_undecided(QTouchEvent *event)
467−{
468− Q_ASSERT(fetchTargetTouchPoint(event) == nullptr);
469−
470− // We're not interested in new touch points. We already have our candidate (touchId).
471− // But we do want to know when those new touches end for keeping the composition time
472− // window up-to-date
473− event->ignore();
474− watchPressedTouchPoints(event->touchPoints());
475−
476− if (event->touchPointStates().testFlag(Qt::TouchPointPressed) && isWithinTouchCompositionWindow()) {
477− // multi-finger drags are not accepted
478− ddaDebug("Multi-finger drags are not accepted");
479−
480− TouchRegistry::instance()->removeCandidateOwnerForTouch(touchId, q);
481− // We still wanna know when it ends for keeping the composition time window up-to-date
482− TouchRegistry::instance()->addTouchWatcher(touchId, q);
483−
484− setStatus(WaitingForTouch);
485− }
486−}
487−
488−void DirectionalDragAreaPrivate::touchEvent_recognized(QTouchEvent *event)
489−{
490− const QTouchEvent::TouchPoint *touchPoint = fetchTargetTouchPoint(event);
491−
492− if (!touchPoint) {
493− qCritical() << "DirectionalDragArea[status=Recognized]: touch " << touchId
494− << "missing from QTouchEvent without first reaching state Qt::TouchPointReleased. "
495− "Considering it as released.";
496− setStatus(WaitingForTouch);
497− } else {
498− setPublicPos(touchPoint->pos());
499− setPublicScenePos(touchPoint->scenePos());
500−
501− if (touchPoint->state() == Qt::TouchPointReleased) {
502− setStatus(WaitingForTouch);
503− }
504− }
505−}
506−
507−void DirectionalDragAreaPrivate::watchPressedTouchPoints(const QList<QTouchEvent::TouchPoint> &touchPoints)
508−{
509− for (int i = 0; i < touchPoints.count(); ++i) {
510− const QTouchEvent::TouchPoint &touchPoint = touchPoints.at(i);
511− if (touchPoint.state() == Qt::TouchPointPressed) {
512− TouchRegistry::instance()->addTouchWatcher(touchPoint.id(), q);
513− }
514− }
515−}
516−
517−bool DirectionalDragAreaPrivate::recognitionIsDisabled() const
518−{
519− return immediateRecognition || (distanceThreshold <= 0 && compositionTime <= 0);
520−}
521−
522−bool DirectionalDragAreaPrivate::sanityCheckRecognitionProperties()
523−{
524− return recognitionIsDisabled()
525− || (distanceThreshold < maxDistance && compositionTime < maxTime);
526−}
527−
528−const QTouchEvent::TouchPoint *DirectionalDragAreaPrivate::fetchTargetTouchPoint(QTouchEvent *event)
529−{
530− const QList<QTouchEvent::TouchPoint> &touchPoints = event->touchPoints();
531− const QTouchEvent::TouchPoint *touchPoint = 0;
532− for (int i = 0; i < touchPoints.size(); ++i) {
533− if (touchPoints.at(i).id() == touchId) {
534− touchPoint = &touchPoints.at(i);
535− break;
536− }
537− }
538− return touchPoint;
539−}
540−
541−bool DirectionalDragAreaPrivate::movingInRightDirection() const
542−{
543− if (direction == Direction::Horizontal || direction == Direction::Vertical) {
544− return true;
545− } else {
546− QPointF movementVector(dampedScenePos.x() - previousDampedScenePos.x(),
547− dampedScenePos.y() - previousDampedScenePos.y());
548−
549− qreal scalarProjection = projectOntoDirectionVector(movementVector);
550−
551− return scalarProjection >= 0.;
552− }
553−}
554−
555−bool DirectionalDragAreaPrivate::movedFarEnoughAlongGestureAxis() const
556−{
557− if (distanceThreshold <= 0.) {
558− // distance threshold check is disabled
559− return true;
560− } else {
561− QPointF totalMovement(dampedScenePos.x() - startScenePos.x(),
562− dampedScenePos.y() - startScenePos.y());
563−
564− qreal scalarProjection = projectOntoDirectionVector(totalMovement);
565−
566− ddaDebug(" movedFarEnoughAlongGestureAxis: scalarProjection=" << scalarProjection
567− << ", distanceThreshold=" << distanceThreshold);
568−
569− if (direction == Direction::Horizontal || direction == Direction::Vertical) {
570− return qAbs(scalarProjection) > distanceThreshold;
571− } else {
572− return scalarProjection > distanceThreshold;
573− }
574− }
575−}
576−
577−bool DirectionalDragAreaPrivate::isPastMaxDistance() const
578−{
579− QPointF totalMovement(dampedScenePos.x() - startScenePos.x(),
580− dampedScenePos.y() - startScenePos.y());
581−
582− qreal squaredDistance = totalMovement.x()*totalMovement.x() + totalMovement.y()*totalMovement.y();
583− return squaredDistance > maxDistance*maxDistance;
584−}
585−
586−void DirectionalDragAreaPrivate::giveUpIfDisabledOrInvisible()
587−{
588− if (!q->isEnabled() || !q->isVisible()) {
589− if (status == Undecided) {
590− TouchRegistry::instance()->removeCandidateOwnerForTouch(touchId, q);
591− // We still wanna know when it ends for keeping the composition time window up-to-date
592− TouchRegistry::instance()->addTouchWatcher(touchId, q);
593− }
594−
595− if (status != WaitingForTouch) {
596− ddaDebug("Resetting status because got disabled or made invisible");
597− setStatus(WaitingForTouch);
598− }
599− }
600−}
601−
602−void DirectionalDragAreaPrivate::rejectGesture()
603−{
604− if (status == Undecided) {
605− ddaDebug("Rejecting gesture because it's taking too long to drag beyond the threshold.");
606−
607− TouchRegistry::instance()->removeCandidateOwnerForTouch(touchId, q);
608− // We still wanna know when it ends for keeping the composition time window up-to-date
609− TouchRegistry::instance()->addTouchWatcher(touchId, q);
610−
611− setStatus(WaitingForTouch);
612− }
613−}
614−
615−void DirectionalDragAreaPrivate::setStatus(Status newStatus)
616−{
617− if (newStatus == status)
618− return;
619−
620− Status oldStatus = status;
621−
622− if (oldStatus == Undecided) {
623− recognitionTimer->stop();
624− }
625−
626− status = newStatus;
627− Q_EMIT statusChanged(status);
628−
629− ddaDebug(statusToString(oldStatus) << " -> " << statusToString(newStatus));
630−
631− switch (newStatus) {
632− case WaitingForTouch:
633− if (oldStatus == Recognized) {
634− Q_EMIT q->draggingChanged(false);
635− }
636− Q_EMIT q->pressedChanged(false);
637− break;
638− case Undecided:
639− recognitionTimer->start();
640− Q_EMIT q->pressedChanged(true);
641− break;
642− case Recognized:
643− if (oldStatus == WaitingForTouch) { // for immediate recognition
644− Q_EMIT q->pressedChanged(true);
645− }
646− Q_EMIT q->draggingChanged(true);
647− break;
648− default:
649− // no-op
650− break;
651− }
652−}
653−
654−void DirectionalDragAreaPrivate::setPublicPos(const QPointF point)
655−{
656− bool xChanged = publicPos.x() != point.x();
657− bool yChanged = publicPos.y() != point.y();
658−
659− // Public position should not get updated while the gesture is still being recognized
660− // (ie, Undecided status).
661− Q_ASSERT(status == WaitingForTouch || status == Recognized);
662−
663− if (status == Recognized && !recognitionIsDisabled()) {
664− // When the gesture finally gets recognized, the finger will likely be
665− // reasonably far from the edge. If we made the contentX immediately
666− // follow the finger position it would be visually unpleasant as it
667− // would appear right next to the user's finger out of nowhere (ie,
668− // it would jump). Instead, we make contentX go towards the user's
669− // finger in several steps. ie., in an animated way.
670− QPointF delta = point - publicPos;
671− // the trick is not to go all the way (1.0) as it would cause a sudden jump
672− publicPos.rx() += 0.4 * delta.x();
673− publicPos.ry() += 0.4 * delta.y();
674− } else {
675− // no smoothing when initializing or if gesture recognition was immediate as there will
676− // be no jump.
677− publicPos = point;
678− }
679−
680− if (xChanged) {
681− Q_EMIT q->touchXChanged(publicPos.x());
682− if (Direction::isHorizontal(direction))
683− Q_EMIT q->distanceChanged(q->distance());
684− }
685−
686− if (yChanged) {
687− Q_EMIT q->touchYChanged(publicPos.y());
688− if (Direction::isVertical(direction))
689− Q_EMIT q->distanceChanged(q->distance());
690− }
691−}
692−
693−void DirectionalDragAreaPrivate::setPublicScenePos(const QPointF point)
694−{
695− bool xChanged = publicScenePos.x() != point.x();
696− bool yChanged = publicScenePos.y() != point.y();
697−
698− if (!xChanged && !yChanged)
699− return;
700−
701− // Public position should not get updated while the gesture is still being recognized
702− // (ie, Undecided status).
703− Q_ASSERT(status == WaitingForTouch || status == Recognized);
704−
705− qreal oldSceneDistance = sceneDistance;
706−
707− if (status == Recognized && !recognitionIsDisabled()) {
708− // When the gesture finally gets recognized, the finger will likely be
709− // reasonably far from the edge. If we made the contentX immediately
710− // follow the finger position it would be visually unpleasant as it
711− // would appear right next to the user's finger out of nowhere (ie,
712− // it would jump). Instead, we make contentX go towards the user's
713− // finger in several steps. ie., in an animated way.
714− QPointF delta = point - publicScenePos;
715− // the trick is not to go all the way (1.0) as it would cause a sudden jump
716− publicScenePos.rx() += 0.4 * delta.x();
717− publicScenePos.ry() += 0.4 * delta.y();
718− } else {
719− // no smoothing when initializing or if gesture recognition was immediate as there will
720− // be no jump.
721− publicScenePos = point;
722− }
723−
724− updateSceneDistance();
725−
726− if (oldSceneDistance != sceneDistance) {
727− Q_EMIT q->sceneDistanceChanged(sceneDistance);
728− }
729−
730− if (xChanged) {
731− Q_EMIT q->touchSceneXChanged(publicScenePos.x());
732− }
733−
734− if (yChanged) {
735− Q_EMIT q->touchSceneYChanged(publicScenePos.y());
736− }
737−}
738−
739−bool DirectionalDragAreaPrivate::isWithinTouchCompositionWindow()
740−{
741− return
742− compositionTime > 0 &&
743− !activeTouches.isEmpty() &&
744− timeSource->msecsSinceReference() <=
745− activeTouches.mostRecentStartTime() + (qint64)compositionTime;
746−}
747−
748−void DirectionalDragArea::itemChange(ItemChange change, const ItemChangeData &value)
749−{
750− if (change == QQuickItem::ItemSceneChange) {
751− if (value.window != nullptr) {
752− value.window->installEventFilter(TouchRegistry::instance());
753−
754− // TODO: Handle window->screen() changes (ie window changing screens)
755−
756− qreal pixelsPerInch = value.window->screen()->physicalDotsPerInch();
757− if (pixelsPerInch < 0) {
758− // It can return garbage when run in a XVFB server (Virtual Framebuffer 'fake' X server)
759− pixelsPerInch = 72;
760− }
761−
762− d->setPixelsPerMm(pixelsPerInch / 25.4);
763− }
764− }
765−}
766−
767−void DirectionalDragAreaPrivate::setPixelsPerMm(qreal pixelsPerMm)
768−{
769− dampedScenePos.setMaxDelta(1. * pixelsPerMm);
770− setDistanceThreshold(4. * pixelsPerMm);
771− maxDistance = 10. * pixelsPerMm;
772−}
773−
774−//************************** ActiveTouchesInfo **************************
775−
776−ActiveTouchesInfo::ActiveTouchesInfo(const SharedTimeSource &timeSource)
777− : m_timeSource(timeSource)
778−{
779−}
780−
781−void ActiveTouchesInfo::update(QTouchEvent *event)
782−{
783− if (!(event->touchPointStates() & (Qt::TouchPointPressed | Qt::TouchPointReleased))) {
784− // nothing to update
785− #if ACTIVETOUCHESINFO_DEBUG
786− qDebug("[DDA::ActiveTouchesInfo] Nothing to Update");
787− #endif
788− return;
789− }
790−
791− const QList<QTouchEvent::TouchPoint> &touchPoints = event->touchPoints();
792− for (int i = 0; i < touchPoints.count(); ++i) {
793− const QTouchEvent::TouchPoint &touchPoint = touchPoints.at(i);
794− if (touchPoint.state() == Qt::TouchPointPressed) {
795− addTouchPoint(touchPoint.id());
796− } else if (touchPoint.state() == Qt::TouchPointReleased) {
797− removeTouchPoint(touchPoint.id());
798− }
799− }
800−}
801−
802−#if ACTIVETOUCHESINFO_DEBUG
803−QString ActiveTouchesInfo::toString()
804−{
805− QString string = "(";
806−
807− {
808− QTextStream stream(&string);
809− m_touchInfoPool.forEach([&](Pool<ActiveTouchInfo>::Iterator &touchInfo) {
810− stream << "(id=" << touchInfo->id << ",startTime=" << touchInfo->startTime << ")";
811− return true;
812− });
813− }
814−
815− string.append(")");
816−
817− return string;
818−}
819−#endif // ACTIVETOUCHESINFO_DEBUG
820−
821−void ActiveTouchesInfo::addTouchPoint(int touchId)
822−{
823− ActiveTouchInfo &activeTouchInfo = m_touchInfoPool.getEmptySlot();
824− activeTouchInfo.id = touchId;
825− activeTouchInfo.startTime = m_timeSource->msecsSinceReference();
826−
827− #if ACTIVETOUCHESINFO_DEBUG
828− qDebug() << "[DDA::ActiveTouchesInfo]" << qPrintable(toString());
829− #endif
830−}
831−
832−qint64 ActiveTouchesInfo::touchStartTime(int touchId)
833−{
834− qint64 result = -1;
835−
836− m_touchInfoPool.forEach([&](Pool<ActiveTouchInfo>::Iterator &touchInfo) {
837− if (touchId == touchInfo->id) {
838− result = touchInfo->startTime;
839− return false;
840− } else {
841− return true;
842− }
843− });
844−
845− Q_ASSERT(result != -1);
846− return result;
847−}
848−
849−void ActiveTouchesInfo::removeTouchPoint(int touchId)
850−{
851− m_touchInfoPool.forEach([&](Pool<ActiveTouchInfo>::Iterator &touchInfo) {
852− if (touchId == touchInfo->id) {
853− m_touchInfoPool.freeSlot(touchInfo);
854− return false;
855− } else {
856− return true;
857− }
858− });
859−
860− #if ACTIVETOUCHESINFO_DEBUG
861− qDebug() << "[DDA::ActiveTouchesInfo]" << qPrintable(toString());
862− #endif
863−}
864−
865−qint64 ActiveTouchesInfo::mostRecentStartTime()
866−{
867− Q_ASSERT(!m_touchInfoPool.isEmpty());
868−
869− qint64 highestStartTime = -1;
870−
871− m_touchInfoPool.forEach([&](Pool<ActiveTouchInfo>::Iterator &activeTouchInfo) {
872− if (activeTouchInfo->startTime > highestStartTime) {
873− highestStartTime = activeTouchInfo->startTime;
874− }
875− return true;
876− });
877−
878− return highestStartTime;
879−}
880−
881−void DirectionalDragAreaPrivate::updateSceneDirectionVector()
882−{
883− QPointF localOrigin(0., 0.);
884− QPointF localDirection;
885− switch (direction) {
886− case Direction::Upwards:
887− localDirection.rx() = 0.;
888− localDirection.ry() = -1.;
889− break;
890− case Direction::Downwards:
891− case Direction::Vertical:
892− localDirection.rx() = 0.;
893− localDirection.ry() = 1;
894− break;
895− case Direction::Leftwards:
896− localDirection.rx() = -1.;
897− localDirection.ry() = 0.;
898− break;
899− default: // Direction::Rightwards || Direction.Horizontal
900− localDirection.rx() = 1.;
901− localDirection.ry() = 0.;
902− break;
903− }
904− QPointF sceneOrigin = q->mapToScene(localOrigin);
905− QPointF sceneDirection = q->mapToScene(localDirection);
906− sceneDirectionVector = sceneDirection - sceneOrigin;
907−}
908−
909−qreal DirectionalDragAreaPrivate::projectOntoDirectionVector(const QPointF sceneVector) const
910−{
911− // same as dot product as sceneDirectionVector is a unit vector
912− return sceneVector.x() * sceneDirectionVector.x() +
913− sceneVector.y() * sceneDirectionVector.y();
914−}
915−
916−DirectionalDragAreaPrivate::DirectionalDragAreaPrivate(DirectionalDragArea *q)
917− : q(q)
918− , status(WaitingForTouch)
919− , sceneDistance(0)
920− , touchId(-1)
921− , direction(Direction::Rightwards)
922− , distanceThreshold(0)
923− , distanceThresholdSquared(0.)
924− , maxTime(400)
925− , compositionTime(60)
926− , immediateRecognition(false)
927− , recognitionTimer(nullptr)
928− , timeSource(new RealTimeSource)
929− , activeTouches(timeSource)
930− , monitorOnly(false)
931−{
932−}
plugins/Ubuntu/Gestures/DirectionalDragArea.hdeleted−143
@@ -1,143 +0,0 @@
1−/*
2− * Copyright (C) 2013,2014 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−#ifndef DIRECTIONAL_DRAG_AREA_H
18−#define DIRECTIONAL_DRAG_AREA_H
19−
20−#include <QtQuick/QQuickItem>
21−#include "UbuntuGesturesQmlGlobal.h"
22−#include "Damper.h"
23−#include "Direction.h"
24−
25−// lib UbuntuGestures
26−#include <Pool.h>
27−#include <Timer.h>
28−
29−class TouchOwnershipEvent;
30−class UnownedTouchEvent;
31−class DirectionalDragAreaPrivate;
32−
33−/*
34− An area that detects axis-aligned single-finger drag gestures
35−
36− If a drag deviates too much from the components' direction recognition will
37− fail. It will also fail if the drag or flick is too short. E.g. a noisy or
38− fidgety click
39−
40− See doc/DirectionalDragArea.svg
41− */
42−class UBUNTUGESTURESQML_EXPORT DirectionalDragArea : public QQuickItem {
43− Q_OBJECT
44−
45− // The direction in which the gesture should move in order to be recognized.
46− Q_PROPERTY(Direction::Type direction READ direction WRITE setDirection NOTIFY directionChanged)
47−
48− // The distance travelled by the finger along the axis specified by
49− // DirectionalDragArea's direction.
50− Q_PROPERTY(qreal distance READ distance NOTIFY distanceChanged)
51−
52− // The distance travelled by the finger along the axis specified by
53− // DirectionalDragArea's direction in scene coordinates
54− Q_PROPERTY(qreal sceneDistance READ sceneDistance NOTIFY sceneDistanceChanged)
55−
56− // Position of the touch point performing the drag relative to this item.
57− Q_PROPERTY(qreal touchX READ touchX NOTIFY touchXChanged)
58− Q_PROPERTY(qreal touchY READ touchY NOTIFY touchYChanged)
59−
60− // Position of the touch point performing the drag, in scene's coordinate system
61− Q_PROPERTY(qreal touchSceneX READ touchSceneX NOTIFY touchSceneXChanged)
62− Q_PROPERTY(qreal touchSceneY READ touchSceneY NOTIFY touchSceneYChanged)
63−
64− // Whether a drag gesture is taking place
65− Q_PROPERTY(bool dragging READ dragging NOTIFY draggingChanged)
66−
67− // Whether the drag area is pressed.
68− Q_PROPERTY(bool pressed READ pressed NOTIFY pressedChanged)
69−
70− // Whether a gesture should be Recognized as soon a touch lands on the area.
71− // With this property enabled it will work pretty much like a MultiPointTouchArea,
72− // just with a different API.
73− //
74− // It's false by default. In most cases you will not want that enabled.
75− Q_PROPERTY(bool immediateRecognition
76− READ immediateRecognition
77− WRITE setImmediateRecognition
78− NOTIFY immediateRecognitionChanged)
79−
80− // Whether we are merely monitoring touch events (in which case, we don't
81− // claim ownership of the touch).
82− Q_PROPERTY(bool monitorOnly READ monitorOnly WRITE setMonitorOnly NOTIFY monitorOnlyChanged)
83−
84− Q_ENUMS(Direction)
85−public:
86− DirectionalDragArea(QQuickItem *parent = 0);
87−
88− Direction::Type direction() const;
89− void setDirection(Direction::Type);
90−
91− qreal distance() const;
92− qreal sceneDistance() const;
93−
94− qreal touchX() const;
95− qreal touchY() const;
96−
97− qreal touchSceneX() const;
98− qreal touchSceneY() const;
99−
100− bool dragging() const;
101−
102− bool pressed() const;
103−
104− bool immediateRecognition() const;
105− void setImmediateRecognition(bool enabled);
106−
107− bool monitorOnly() const;
108− void setMonitorOnly(bool monitorOnly);
109−
110− bool event(QEvent *e) override;
111−
112− /*
113− In qmltests, sequences of touch events are sent all at once, unlike in "real life".
114− Also qmltests might run really slowly, e.g. when run from inside virtual machines.
115− Thus to remove a variable that qmltests cannot really control, namely time, this
116− function removes all constraints that are sensible to elapsed time.
117−
118− This effectively makes the DirectionalDragArea easier to fool.
119− */
120− Q_INVOKABLE void removeTimeConstraints();
121−
122−Q_SIGNALS:
123− void directionChanged(Direction::Type direction);
124− void draggingChanged(bool value);
125− void pressedChanged(bool value);
126− void distanceChanged(qreal value);
127− void sceneDistanceChanged(qreal value);
128− void touchXChanged(qreal value);
129− void touchYChanged(qreal value);
130− void touchSceneXChanged(qreal value);
131− void touchSceneYChanged(qreal value);
132− void immediateRecognitionChanged(bool value);
133− void monitorOnlyChanged(bool value);
134−
135−protected:
136− void touchEvent(QTouchEvent *event) override;
137− void itemChange(ItemChange change, const ItemChangeData &value) override;
138−
139−public: // so tests can access it
140− DirectionalDragAreaPrivate *d;
141−};
142−
143−#endif // DIRECTIONAL_DRAG_AREA_H
plugins/Ubuntu/Gestures/DirectionalDragArea_p.hdeleted−169
@@ -1,169 +0,0 @@
1−/*
2− * Copyright (C) 2015 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−#ifndef DIRECTIONAL_DRAG_AREA_PRIV_H
18−#define DIRECTIONAL_DRAG_AREA_PRIV_H
19−
20−// Information about an active touch point
21−struct UBUNTUGESTURESQML_EXPORT ActiveTouchInfo {
22− ActiveTouchInfo() : id(-1), startTime(-1) {}
23− bool isValid() const { return id != -1; }
24− void reset() { id = -1; }
25− int id;
26− qint64 startTime;
27−};
28−class UBUNTUGESTURESQML_EXPORT ActiveTouchesInfo {
29−public:
30− ActiveTouchesInfo(const UbuntuGestures::SharedTimeSource &timeSource);
31− void update(QTouchEvent *event);
32− qint64 touchStartTime(int id);
33− bool isEmpty() const { return m_touchInfoPool.isEmpty(); }
34− qint64 mostRecentStartTime();
35− UbuntuGestures::SharedTimeSource m_timeSource;
36−private:
37− void addTouchPoint(int touchId);
38− void removeTouchPoint(int touchId);
39− #if ACTIVETOUCHESINFO_DEBUG
40− QString toString();
41− #endif
42−
43− Pool<ActiveTouchInfo> m_touchInfoPool;
44−};
45−
46−class UBUNTUGESTURESQML_EXPORT DirectionalDragAreaPrivate : public QObject {
47− Q_OBJECT
48−
49− Q_ENUMS(Status)
50−public:
51− DirectionalDragAreaPrivate(DirectionalDragArea *q);
52−
53−public Q_SLOTS:
54− void giveUpIfDisabledOrInvisible();
55− void rejectGesture();
56−
57−public:
58− // Describes the state of the directional drag gesture.
59− enum Status {
60− // Waiting for a new touch point to land on this area. No gesture is being processed
61− // or tracked.
62− WaitingForTouch,
63−
64− // A touch point has landed on this area but it's not know yet whether it is
65− // performing a drag in the correct direction.
66− // If it's decided that the touch point is not performing a directional drag gesture,
67− // it will be rejected/ignored and status will return to WaitingForTouch.
68− Undecided, //Recognizing,
69−
70− // There's a touch point in this area and it performed a drag in the correct
71− // direction.
72− //
73− // Once recognized, the gesture state will move back to WaitingForTouch only once
74− // that touch point ends. The gesture will remain in the Recognized state even if
75− // the touch point starts moving in other directions or halts.
76− Recognized,
77− };
78−
79− void touchEvent_absent(QTouchEvent *event);
80− void touchEvent_undecided(QTouchEvent *event);
81− void touchEvent_recognized(QTouchEvent *event);
82− bool movingInRightDirection() const;
83− bool movedFarEnoughAlongGestureAxis() const;
84− bool isPastMaxDistance() const;
85− const QTouchEvent::TouchPoint *fetchTargetTouchPoint(QTouchEvent *event);
86− void setStatus(Status newStatus);
87− void setPublicPos(const QPointF point);
88− void setPublicScenePos(const QPointF point);
89− bool isWithinTouchCompositionWindow();
90− void updateSceneDirectionVector();
91− // returns the scalar projection between the given vector (in scene coordinates)
92− // and m_sceneDirectionVector
93− qreal projectOntoDirectionVector(const QPointF sceneVector) const;
94− void touchOwnershipEvent(TouchOwnershipEvent *event);
95− void unownedTouchEvent(UnownedTouchEvent *event);
96− void unownedTouchEvent_undecided(UnownedTouchEvent *unownedTouchEvent);
97− void watchPressedTouchPoints(const QList<QTouchEvent::TouchPoint> &touchPoints);
98− bool recognitionIsDisabled() const;
99− bool sanityCheckRecognitionProperties();
100− void updateSceneDistance();
101− void setMaxTime(int value);
102− void setDistanceThreshold(qreal value);
103− void setPixelsPerMm(qreal pixelsPerMm);
104− QString objectName() const { return q->objectName(); }
105−
106− // Replaces the existing Timer with the given one.
107− //
108− // Useful for providing a fake timer when testing.
109− void setRecognitionTimer(UbuntuGestures::AbstractTimer *timer);
110−
111− // Useful for testing, where a fake time source can be supplied
112− void setTimeSource(const UbuntuGestures::SharedTimeSource &timeSource);
113−
114− DirectionalDragArea *q;
115−
116− // The current status of the directional drag gesture area.
117− Status status;
118−
119− QPointF startPos;
120− QPointF startScenePos;
121− qreal sceneDistance;
122− int touchId;
123−
124− // The touch position exposed in the public API.
125− // It only starts to move once the gesture gets recognized.
126− QPointF publicPos;
127− QPointF publicScenePos;
128−
129− // A movement damper is used in some of the gesture recognition calculations
130− // to get rid of noise or small oscillations in the touch position.
131− DampedPointF dampedScenePos;
132− QPointF previousDampedScenePos;
133−
134− // Unit vector in scene coordinates describing the direction of the gesture recognition
135− QPointF sceneDirectionVector;
136−
137− Direction::Type direction;
138−
139− // How far a touch point has to move from its initial position along the gesture axis in order
140− // for it to be recognized as a directional drag.
141− qreal distanceThreshold;
142− qreal distanceThresholdSquared; // it's pow(distanceThreshold, 2)
143−
144− // Maximum time (in milliseconds) the gesture can take to go beyond the distance threshold
145− int maxTime;
146−
147− // Maximum distance the gesture can go without crossing the axis-aligned distance threshold
148− qreal maxDistance;
149−
150− // Maximum time (in milliseconds) after the start of a given touch point where
151− // subsequent touch starts are grouped with the first one into an N-touches gesture
152− // (e.g. a two-fingers tap or drag).
153− int compositionTime;
154−
155− bool immediateRecognition;
156−
157− UbuntuGestures::AbstractTimer *recognitionTimer;
158−
159− UbuntuGestures::SharedTimeSource timeSource;
160−
161− ActiveTouchesInfo activeTouches;
162−
163− bool monitorOnly;
164−
165−Q_SIGNALS:
166− void statusChanged(Status value);
167−};
168−
169−#endif // DIRECTIONAL_DRAG_AREA_PRIV_H
plugins/Ubuntu/Gestures/FloatingFlickable.cppdeleted−150
@@ -1,150 +0,0 @@
1−/*
2− * Copyright (C) 2015 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−#include "FloatingFlickable.h"
18−
19−#include <private/qquickflickable_p.h>
20−#include "DirectionalDragArea.h"
21−
22−#include <QDebug>
23−
24−FloatingFlickable::FloatingFlickable(QQuickItem *parent)
25− : QQuickItem(parent)
26− , m_mousePressed(false)
27−{
28− m_dragArea = new DirectionalDragArea(this);
29− m_dragArea->setWidth(width());
30− m_dragArea->setHeight(height());
31− m_dragArea->setDirection(Direction::Horizontal);
32− connect(m_dragArea, &DirectionalDragArea::touchXChanged,
33− this, &FloatingFlickable::onDragAreaTouchPosChanged);
34− connect(m_dragArea, &DirectionalDragArea::touchYChanged,
35− this, &FloatingFlickable::onDragAreaTouchPosChanged);
36− connect(m_dragArea, &DirectionalDragArea::draggingChanged,
37− this, &FloatingFlickable::onDragAreaDraggingChanged);
38− connect(m_dragArea, &DirectionalDragArea::directionChanged, this, &FloatingFlickable::directionChanged);
39−
40− m_flickable = new QQuickFlickable(this);
41− m_flickable->setEnabled(false);
42− m_flickable->setWidth(width());
43− m_flickable->setHeight(height());
44− connect(m_flickable, &QQuickFlickable::contentWidthChanged, this, &FloatingFlickable::contentWidthChanged);
45− connect(m_flickable, &QQuickFlickable::contentHeightChanged, this, &FloatingFlickable::contentHeightChanged);
46− connect(m_flickable, &QQuickFlickable::contentXChanged, this, &FloatingFlickable::contentXChanged);
47− connect(m_flickable, &QQuickFlickable::contentYChanged, this, &FloatingFlickable::contentYChanged);
48−
49− connect(this, &QQuickItem::widthChanged, this, &FloatingFlickable::updateChildrenWidth);
50− connect(this, &QQuickItem::heightChanged, this, &FloatingFlickable::updateChildrenHeight);
51−}
52−
53−qreal FloatingFlickable::contentWidth() const
54−{
55− return m_flickable->contentWidth();
56−}
57−
58−void FloatingFlickable::setContentWidth(qreal contentWidth)
59−{
60− m_flickable->setContentWidth(contentWidth);
61−}
62−
63−qreal FloatingFlickable::contentHeight() const
64−{
65− return m_flickable->contentHeight();
66−}
67−
68−void FloatingFlickable::setContentHeight(qreal contentHeight)
69−{
70− m_flickable->setContentHeight(contentHeight);
71−}
72−
73−qreal FloatingFlickable::contentX() const
74−{
75− return m_flickable->contentX();
76−}
77−
78−void FloatingFlickable::setContentX(qreal contentX)
79−{
80− m_flickable->setContentX(contentX);
81−}
82−
83−qreal FloatingFlickable::contentY() const
84−{
85− return m_flickable->contentY();
86−}
87−
88−void FloatingFlickable::setContentY(qreal contentY)
89−{
90− m_flickable->setContentY(contentY);
91−}
92−
93−Direction::Type FloatingFlickable::direction() const
94−{
95− return m_dragArea->direction();
96−}
97−
98−void FloatingFlickable::setDirection(Direction::Type direction)
99−{
100− m_dragArea->setDirection(direction);
101− if (Direction::isHorizontal(direction)) {
102− m_flickable->setFlickableDirection(QQuickFlickable::HorizontalFlick);
103− } else {
104− m_flickable->setFlickableDirection(QQuickFlickable::VerticalFlick);
105− }
106−}
107−
108−void FloatingFlickable::updateChildrenWidth()
109−{
110− m_dragArea->setWidth(width());
111− m_flickable->setWidth(width());
112−}
113−
114−void FloatingFlickable::updateChildrenHeight()
115−{
116− m_dragArea->setHeight(height());
117− m_flickable->setHeight(height());
118−}
119−
120−void FloatingFlickable::onDragAreaTouchPosChanged(qreal)
121−{
122− if (m_mousePressed) {
123− QMouseEvent mouseEvent(QEvent::MouseMove,
124− QPointF(m_dragArea->touchX(),m_dragArea->touchY()),
125− Qt::NoButton, Qt::LeftButton, Qt::NoModifier);
126−
127− QCoreApplication::sendEvent(m_flickable, &mouseEvent);
128−
129− }
130−}
131−
132−void FloatingFlickable::onDragAreaDraggingChanged(bool dragging)
133−{
134− if (dragging && !m_mousePressed) {
135− QMouseEvent mouseEvent(QEvent::MouseButtonPress,
136− QPointF(m_dragArea->touchX(),m_dragArea->touchY()),
137− Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
138−
139− QCoreApplication::sendEvent(m_flickable, &mouseEvent);
140− m_mousePressed = true;
141−
142− } else if (!dragging && m_mousePressed) {
143− QMouseEvent mouseEvent(QEvent::MouseButtonRelease,
144− QPointF(m_dragArea->touchX(),m_dragArea->touchY()),
145− Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
146−
147− QCoreApplication::sendEvent(m_flickable, &mouseEvent);
148− m_mousePressed = false;
149− }
150−}
plugins/Ubuntu/Gestures/FloatingFlickable.hdeleted−86
@@ -1,86 +0,0 @@
1−/*
2− * Copyright (C) 2015 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−#ifndef FLOATING_FLICKABLE_H
18−#define FLOATING_FLICKABLE_H
19−
20−#include <QQuickItem>
21−#include "UbuntuGesturesQmlGlobal.h"
22−#include "Direction.h"
23−
24−class DirectionalDragArea;
25−class QQuickFlickable;
26−
27−/*
28− A Flickable that can be put in front of the item to be flicked and
29− still have the item-to-be-flicked receive input events that are not flicks.
30−
31− Ie, it's a Flickable that, input-wise, is transparent to non-flick gestures.
32−
33− With a regular Flickable you would have to make the item-to-be-flicked a child
34− of Flicakble to achieve the same result. FloatingFlickable has no such requirement
35− or limitation.
36− */
37−class UBUNTUGESTURESQML_EXPORT FloatingFlickable : public QQuickItem {
38− Q_OBJECT
39−
40− Q_PROPERTY(qreal contentWidth READ contentWidth WRITE setContentWidth NOTIFY contentWidthChanged)
41− Q_PROPERTY(qreal contentHeight READ contentHeight WRITE setContentHeight NOTIFY contentHeightChanged)
42− Q_PROPERTY(qreal contentX READ contentX WRITE setContentX NOTIFY contentXChanged)
43− Q_PROPERTY(qreal contentY READ contentY WRITE setContentY NOTIFY contentYChanged)
44−
45− Q_PROPERTY(Direction::Type direction READ direction WRITE setDirection NOTIFY directionChanged)
46−
47−Q_SIGNALS:
48− void contentWidthChanged();
49− void contentHeightChanged();
50− void contentXChanged();
51− void contentYChanged();
52− void directionChanged();
53−
54−public:
55− FloatingFlickable(QQuickItem *parent = nullptr);
56−
57− qreal contentWidth() const;
58− void setContentWidth(qreal contentWidth);
59−
60− qreal contentHeight() const;
61− void setContentHeight(qreal contentHeight);
62−
63− qreal contentX() const;
64− void setContentX(qreal contentX);
65−
66− qreal contentY() const;
67− void setContentY(qreal contentY);
68−
69− Direction::Type direction() const;
70− void setDirection(Direction::Type);
71−
72−private Q_SLOTS:
73− void updateChildrenWidth();
74− void updateChildrenHeight();
75− void onDragAreaTouchPosChanged(qreal);
76− void onDragAreaDraggingChanged(bool value);
77−
78−private:
79− DirectionalDragArea *m_dragArea;
80− QQuickFlickable *m_flickable;
81− bool m_mousePressed;
82−
83− friend class tst_FloatingFlickable;
84−};
85−
86−#endif // FLOATING_FLICKABLE_H
plugins/Ubuntu/Gestures/Gestures.qmltypes−132
@@ -54,88 +54,6 @@ Module {
5454 Parameter { name: "type"; type: "Direction::Type" }
5555 }
5656 }
57− Component {
58− name: "DirectionalDragArea"
59− defaultProperty: "data"
60− prototype: "QQuickItem"
61− exports: ["Ubuntu.Gestures/DirectionalDragArea 0.1"]
62− exportMetaObjectRevisions: [0]
63− Property { name: "direction"; type: "Direction::Type" }
64− Property { name: "distance"; type: "double"; isReadonly: true }
65− Property { name: "sceneDistance"; type: "double"; isReadonly: true }
66− Property { name: "touchX"; type: "double"; isReadonly: true }
67− Property { name: "touchY"; type: "double"; isReadonly: true }
68− Property { name: "touchSceneX"; type: "double"; isReadonly: true }
69− Property { name: "touchSceneY"; type: "double"; isReadonly: true }
70− Property { name: "dragging"; type: "bool"; isReadonly: true }
71− Property { name: "pressed"; type: "bool"; isReadonly: true }
72− Property { name: "immediateRecognition"; type: "bool" }
73− Signal {
74− name: "directionChanged"
75− Parameter { name: "direction"; type: "Direction::Type" }
76− }
77− Signal {
78− name: "draggingChanged"
79− Parameter { name: "value"; type: "bool" }
80− }
81− Signal {
82− name: "pressedChanged"
83− Parameter { name: "value"; type: "bool" }
84− }
85− Signal {
86− name: "distanceChanged"
87− Parameter { name: "value"; type: "double" }
88− }
89− Signal {
90− name: "sceneDistanceChanged"
91− Parameter { name: "value"; type: "double" }
92− }
93− Signal {
94− name: "touchXChanged"
95− Parameter { name: "value"; type: "double" }
96− }
97− Signal {
98− name: "touchYChanged"
99− Parameter { name: "value"; type: "double" }
100− }
101− Signal {
102− name: "touchSceneXChanged"
103− Parameter { name: "value"; type: "double" }
104− }
105− Signal {
106− name: "touchSceneYChanged"
107− Parameter { name: "value"; type: "double" }
108− }
109− Signal {
110− name: "immediateRecognitionChanged"
111− Parameter { name: "value"; type: "bool" }
112− }
113− Method { name: "removeTimeConstraints" }
114− }
115− Component {
116− name: "FloatingFlickable"
117− defaultProperty: "data"
118− prototype: "QQuickItem"
119− exports: ["Ubuntu.Gestures/FloatingFlickable 0.1"]
120− exportMetaObjectRevisions: [0]
121− Property { name: "contentWidth"; type: "double" }
122− Property { name: "contentHeight"; type: "double" }
123− Property { name: "contentX"; type: "double" }
124− Property { name: "contentY"; type: "double" }
125− Property { name: "direction"; type: "Direction::Type" }
126− }
127− Component {
128− name: "GestureTouchPoint"
129− prototype: "QObject"
130− exports: ["Ubuntu.Gestures/GestureTouchPoint 0.1"]
131− isCreatable: false
132− exportMetaObjectRevisions: [0]
133− Property { name: "pointId"; type: "int"; isReadonly: true }
134− Property { name: "pressed"; type: "bool"; isReadonly: true }
135− Property { name: "x"; type: "double"; isReadonly: true }
136− Property { name: "y"; type: "double"; isReadonly: true }
137− Property { name: "dragging"; type: "bool"; isReadonly: true }
138− }
13957 Component {
14058 name: "PressedOutsideNotifier"
14159 defaultProperty: "data"
@@ -156,54 +74,4 @@ Module {
15674 Parameter { name: "item"; type: "QQuickItem"; isPointer: true }
15775 }
15876 }
159− Component {
160− name: "TouchGestureArea"
161− defaultProperty: "data"
162− prototype: "QQuickItem"
163− exports: ["Ubuntu.Gestures/TouchGestureArea 0.1"]
164− exportMetaObjectRevisions: [0]
165− Enum {
166− name: "Status"
167− values: {
168− "WaitingForTouch": 0,
169− "Undecided": 1,
170− "Recognized": 2,
171− "Rejected": 3
172− }
173− }
174− Property { name: "touchPoints"; type: "GestureTouchPoint"; isList: true; isReadonly: true }
175− Property { name: "dragging"; type: "bool"; isReadonly: true }
176− Property { name: "minimumTouchPoints"; type: "int" }
177− Property { name: "maximumTouchPoints"; type: "int" }
178− Signal {
179− name: "statusChanged"
180− Parameter { name: "status"; type: "Status" }
181− }
182− Signal { name: "touchPointsUpdated" }
183− Signal {
184− name: "draggingChanged"
185− Parameter { name: "dragging"; type: "bool" }
186− }
187− Signal {
188− name: "minimumTouchPointsChanged"
189− Parameter { name: "value"; type: "bool" }
190− }
191− Signal {
192− name: "maximumTouchPointsChanged"
193− Parameter { name: "value"; type: "bool" }
194− }
195− Signal {
196− name: "pressed"
197− Parameter { name: "points"; type: "QList<QObject*>" }
198− }
199− Signal {
200− name: "released"
201− Parameter { name: "points"; type: "QList<QObject*>" }
202− }
203− Signal {
204− name: "updated"
205− Parameter { name: "points"; type: "QList<QObject*>" }
206− }
207− Signal { name: "clicked" }
208− }
20977}
plugins/Ubuntu/Gestures/MouseEventGenerator.cppnew file+64
@@ -0,0 +1,64 @@
1+/*
2+ * Copyright (C) 2015-2016 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#include "MouseEventGenerator.h"
18+
19+#include <QCoreApplication>
20+#include <QMouseEvent>
21+#include <QQuickItem>
22+
23+MouseEventGenerator::MouseEventGenerator(QObject *parent)
24+ : QObject(parent)
25+{
26+}
27+
28+void MouseEventGenerator::move(const QPointF position)
29+{
30+ if (!m_mousePressed || !m_targetItem) {
31+ return;
32+ }
33+
34+ QMouseEvent mouseEvent(QEvent::MouseMove,
35+ QPointF(position.x(), position.y()), Qt::NoButton, Qt::LeftButton, Qt::NoModifier);
36+
37+ QCoreApplication::sendEvent(m_targetItem, &mouseEvent);
38+}
39+
40+void MouseEventGenerator::press(const QPointF position)
41+{
42+ if (m_mousePressed || !m_targetItem) {
43+ return;
44+ }
45+
46+ QMouseEvent mouseEvent(QEvent::MouseButtonPress,
47+ QPointF(position.x(), position.y()), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
48+
49+ QCoreApplication::sendEvent(m_targetItem, &mouseEvent);
50+ m_mousePressed = true;
51+}
52+
53+void MouseEventGenerator::release(const QPointF position)
54+{
55+ if (!m_mousePressed || !m_targetItem) {
56+ return;
57+ }
58+
59+ QMouseEvent mouseEvent(QEvent::MouseButtonRelease,
60+ QPointF(position.x(), position.y()), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
61+
62+ QCoreApplication::sendEvent(m_targetItem, &mouseEvent);
63+ m_mousePressed = false;
64+}
plugins/Ubuntu/Gestures/MouseEventGenerator.hnew file+48
@@ -0,0 +1,48 @@
1+/*
2+ * Copyright (C) 2015-2016 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#ifndef MOUSEEVENTGENERATOR_H
18+#define MOUSEEVENTGENERATOR_H
19+
20+#include <QObject>
21+#include <QPointF>
22+
23+#include "UbuntuGesturesQmlGlobal.h"
24+
25+class QQuickItem;
26+
27+class UBUNTUGESTURESQML_EXPORT MouseEventGenerator : public QObject {
28+ Q_OBJECT
29+ Q_PROPERTY(QQuickItem* targetItem MEMBER m_targetItem NOTIFY targetItemChanged)
30+
31+public:
32+ MouseEventGenerator(QObject *parent = nullptr);
33+
34+ Q_INVOKABLE void move(const QPointF position);
35+ Q_INVOKABLE void press(const QPointF position);
36+ Q_INVOKABLE void release(const QPointF position);
37+
38+Q_SIGNALS:
39+ void targetItemChanged(QQuickItem *);
40+
41+private:
42+ bool m_mousePressed {false};
43+ QQuickItem *m_targetItem {nullptr};
44+
45+ friend class tst_FloatingFlickable;
46+};
47+
48+#endif // MOUSEEVENTGENERATOR_H
plugins/Ubuntu/Gestures/PressedOutsideNotifier.h+1−1
@@ -23,7 +23,7 @@
2323#include <QPointer>
2424#include <QTimer>
2525
26−#include "UbuntuGesturesGlobal.h"
26+#include <ubuntugesturesglobal.h>
2727
2828/*
2929 Notifies when a point, mouse or touch, is pressed outside its area.
plugins/Ubuntu/Gestures/TouchGate.cpp+2−2
@@ -20,8 +20,8 @@
2020#include <QDebug>
2121#include <QQuickWindow>
2222
23−#include <TouchOwnershipEvent.h>
24−#include <TouchRegistry.h>
23+#include <TouchOwnershipEvent>
24+#include <TouchRegistry>
2525
2626#if TOUCHGATE_DEBUG
2727#define ugDebug(params) qDebug().nospace() << "[TouchGate(" << (void*)this << ")] " << params
plugins/Ubuntu/Gestures/TouchGestureArea.cpp+9−6
@@ -16,10 +16,11 @@
1616
1717#include "TouchGestureArea.h"
1818
19−// local
20−#include "TouchOwnershipEvent.h"
21−#include "TouchRegistry.h"
22−#include "UnownedTouchEvent.h"
19+#include <UbuntuGestures/TouchOwnershipEvent>
20+#include <UbuntuGestures/TouchRegistry>
21+#include <UbuntuGestures/UnownedTouchEvent>
22+// #include "TouchRegistry.h"
23+// #include "UnownedTouchEvent.h"
2324
2425#include <QGuiApplication>
2526#include <QStyleHints>
@@ -588,13 +589,15 @@ void TouchGestureArea::setInternalStatus(uint newStatus)
588589 resyncCachedTouchPoints();
589590 break;
590591 case InternalStatus::WaitingForMoreTouches:
591− m_recognitionTimer->start(m_recognitionPeriod);
592+ m_recognitionTimer->setInterval(m_recognitionPeriod);
593+ m_recognitionTimer->start();
592594 break;
593595 case InternalStatus::Recognized:
594596 resyncCachedTouchPoints();
595597 break;
596598 case InternalStatus::WaitingForRejection:
597− m_recognitionTimer->start(m_releaseRejectPeriod);
599+ m_recognitionTimer->setInterval(m_releaseRejectPeriod);
600+ m_recognitionTimer->start();
598601 break;
599602 case InternalStatus::Rejected:
600603 resyncCachedTouchPoints();
plugins/Ubuntu/Gestures/TouchGestureArea.h+1−2
@@ -21,8 +21,7 @@
2121
2222#include <QQuickItem>
2323
24−// lib UbuntuGestures
25−#include <Timer.h>
24+#include <UbuntuGestures/Timer>
2625
2726class TouchOwnershipEvent;
2827class UnownedTouchEvent;
plugins/Ubuntu/Gestures/plugin.cpp+3−5
@@ -1,5 +1,5 @@
11/*
2− * Copyright (C) 2013,2015 Canonical, Ltd.
2+ * Copyright (C) 2013,2015,2016 Canonical, Ltd.
33 *
44 * This program is free software; you can redistribute it and/or modify
55 * it under the terms of the GNU General Public License as published by
@@ -17,8 +17,7 @@
1717#include "plugin.h"
1818#include "AxisVelocityCalculator.h"
1919#include "Direction.h"
20−#include "DirectionalDragArea.h"
21−#include "FloatingFlickable.h"
20+#include "MouseEventGenerator.h"
2221#include "PressedOutsideNotifier.h"
2322#include "TouchGate.h"
2423#include "TouchGestureArea.h"
@@ -34,9 +33,8 @@ static QObject* directionSingleton(QQmlEngine* engine, QJSEngine* scriptEngine)
3433void UbuntuGesturesQmlPlugin::registerTypes(const char *uri)
3534{
3635 qmlRegisterSingletonType<Direction>(uri, 0, 1, "Direction", directionSingleton);
37− qmlRegisterType<DirectionalDragArea>(uri, 0, 1, "DirectionalDragArea");
3836 qmlRegisterType<AxisVelocityCalculator>(uri, 0, 1, "AxisVelocityCalculator");
39− qmlRegisterType<FloatingFlickable>(uri, 0, 1, "FloatingFlickable");
37+ qmlRegisterType<MouseEventGenerator>(uri, 0, 1, "MouseEventGenerator");
4038 qmlRegisterType<PressedOutsideNotifier>(uri, 0, 1, "PressedOutsideNotifier");
4139 qmlRegisterType<TouchGate>(uri, 0, 1, "TouchGate");
4240 qmlRegisterType<TouchGestureArea>(uri, 0, 1, "TouchGestureArea");
qml/Components/DragHandle.qml+16−18
@@ -38,12 +38,12 @@ import Ubuntu.Gestures 0.1
3838 anchors.bottom: parent.bottom
3939 width: units.gu(2)
4040
41− direction: DirectionalDragArea::Leftwards
41+ direction: SwipeArea::Leftwards
4242 }
4343 }
4444
4545 */
46−DirectionalDragArea {
46+SwipeArea {
4747 id: dragArea
4848
4949 property bool stretch: false
@@ -118,26 +118,26 @@ DirectionalDragArea {
118118 }
119119 }
120120
121− function limitMovement(inputStep) {
122− var targetValue = MathUtils.clamp(dragParent[targetProp] + inputStep, minValue, maxValue);
123− var step = targetValue - dragParent[targetProp];
121+ function limitMovement(distance) {
122+ var targetValue = MathUtils.clamp(d.startValue + distance, minValue, maxValue);
123+ var diff = targetValue - d.startValue;
124124
125125 if (hintDisplacement == 0) {
126− return step;
126+ return diff;
127127 }
128128
129129 // we should not go behind hintingAnimation's current value
130130 if (Direction.isPositive(direction)) {
131− if (dragParent[targetProp] + step < hintingAnimation.targetValue) {
132− step = hintingAnimation.targetValue - dragParent[targetProp];
131+ if (d.startValue + diff < hintingAnimation.targetValue) {
132+ diff = hintingAnimation.targetValue - d.startValue;
133133 }
134134 } else {
135− if (dragParent[targetProp] + step > hintingAnimation.targetValue) {
136− step = hintingAnimation.targetValue - dragParent[targetProp];
135+ if (d.startValue + diff > hintingAnimation.targetValue) {
136+ diff = hintingAnimation.targetValue - d.startValue;
137137 }
138138 }
139139
140− return step;
140+ return diff;
141141 }
142142
143143 function onFinishedRecognizedGesture() {
@@ -171,19 +171,17 @@ DirectionalDragArea {
171171 objectName: "edgeDragEvaluator"
172172 id: dragEvaluator
173173 // Effectively convert distance into the drag position projected onto the gesture direction axis
174− trackedPosition: Direction.isPositive(dragArea.direction) ? sceneDistance : -sceneDistance
174+ trackedPosition: Direction.isPositive(dragArea.direction) ? distance : -distance
175175 maxDragDistance: maxTotalDragDistance
176176 direction: dragArea.direction
177177 }
178178
179179 onDistanceChanged: {
180180 if (dragging) {
181− // don't go the whole distance in order to smooth out the movement
182− var step = distance * 0.3;
183−
184− step = d.limitMovement(step);
185−
186− parent[d.targetProp] += step;
181+ if (!Direction.isPositive(direction))
182+ distance = -distance;
183+ var toAdd = d.limitMovement(distance);
184+ parent[d.targetProp] = d.startValue + toAdd;
187185 }
188186 }
189187
qml/Components/FloatingFlickable.qmlnew file+59
@@ -0,0 +1,59 @@
1+/*
2+ * Copyright (C) 2015-2016 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.4
18+import Ubuntu.Components 1.3
19+import Ubuntu.Gestures 0.1
20+
21+/*
22+ A Flickable that can be put in front of the item to be flicked and
23+ still have the item-to-be-flicked receive input events that are not flicks.
24+
25+ Ie, it's a Flickable that, input-wise, is transparent to non-flick gestures.
26+
27+ With a regular Flickable you would have to make the item-to-be-flicked a child
28+ of Flicakble to achieve the same result. FloatingFlickable has no such requirement
29+ or limitation.
30+ */
31+Item {
32+ property alias contentWidth: flickable.contentWidth
33+ property alias contentHeight: flickable.contentHeight
34+ property alias contentX: flickable.contentX
35+ property alias contentY: flickable.contentY
36+ property alias direction: swipeArea.direction
37+
38+ MouseEventGenerator {
39+ id: mouseEventGenerator
40+ targetItem: flickable
41+ }
42+
43+ Flickable {
44+ id: flickable
45+ enabled: false
46+ anchors.fill: parent
47+ flickableDirection: Direction.isHorizontal(swipeArea.direction) ? Flickable.HorizontalFlick : Flickable.VerticalFlick
48+ }
49+
50+ SwipeArea {
51+ id: swipeArea
52+ anchors.fill: parent
53+ direction: Direction.Horizontal
54+
55+ onTouchPositionChanged: mouseEventGenerator.move(touchPosition);
56+ onDraggingChanged: dragging ? mouseEventGenerator.press(touchPosition)
57+ : mouseEventGenerator.release(touchPosition)
58+ }
59+}
qml/Dash/Dash.qml+3−3
@@ -349,7 +349,7 @@ Showable {
349349 }
350350 }
351351
352− DirectionalDragArea {
352+ SwipeArea {
353353 id: overviewDragHandle
354354 objectName: "overviewDragHandle"
355355 z: 1
@@ -364,10 +364,10 @@ Showable {
364364 anchors { left: parent.left; right: parent.right; bottom: parent.bottom }
365365 height: units.gu(2)
366366
367− onSceneDistanceChanged: {
367+ onDistanceChanged: {
368368 if (dragging) {
369369 bottomEdgeController.enableAnimation = false;
370− bottomEdgeController.progress = Math.max(0, Math.min(1, sceneDistance / fullMovement));
370+ bottomEdgeController.progress = Math.max(0, Math.min(1, distance / fullMovement));
371371 }
372372 }
373373
qml/Launcher/Launcher.qml+4−4
@@ -31,14 +31,14 @@ FocusScope {
3131 property int panelWidth: units.gu(10)
3232 property int dragAreaWidth: units.gu(1)
3333 property int minimizeDistance: units.gu(26)
34− property real progress: dragArea.dragging && dragArea.touchX > panelWidth ?
35− (width * (dragArea.touchX-panelWidth) / (width - panelWidth)) : 0
34+ property real progress: dragArea.dragging && dragArea.touchPosition.x > panelWidth ?
35+ (width * (dragArea.touchPosition.x-panelWidth) / (width - panelWidth)) : 0
3636
3737 property bool superPressed: false
3838 property bool superTabPressed: false
3939
4040 readonly property bool dragging: dragArea.dragging
41− readonly property real dragDistance: dragArea.dragging ? dragArea.touchX : 0
41+ readonly property real dragDistance: dragArea.dragging ? dragArea.touchPosition.x : 0
4242 readonly property real visibleWidth: panel.width + panel.x
4343
4444 readonly property bool shown: panel.x > -panel.width
@@ -400,7 +400,7 @@ FocusScope {
400400 }
401401 }
402402
403− DirectionalDragArea {
403+ SwipeArea {
404404 id: dragArea
405405 objectName: "launcherDragArea"
406406
qml/Panel/IndicatorsMenu.qml+17−13
@@ -39,7 +39,7 @@ Showable {
3939 property bool showOnClick: true
4040 property color panelColor: theme.palette.normal.background
4141
42− signal showTapped(point position)
42+ signal showTapped()
4343
4444 // TODO: Perhaps we need a animation standard for showing/hiding? Each showable seems to
4545 // use its own values. Need to ask design about this.
@@ -204,7 +204,7 @@ Showable {
204204 } else {
205205 var touchReleaseTime = new Date().getTime();
206206 if (touchReleaseTime - touchPressTime <= 300) {
207− root.showTapped(Qt.point(touchSceneX, touchSceneY));
207+ root.showTapped();
208208 }
209209 }
210210 }
@@ -233,10 +233,10 @@ Showable {
233233 stretch: true
234234 maxTotalDragDistance: openedHeight - expandedPanelHeight - handle.height
235235
236− onTouchSceneXChanged: {
236+ onTouchPositionChanged: {
237237 if (root.state === "locked") {
238− d.xDisplacementSinceLock += (touchSceneX - d.lastHideTouchSceneX)
239− d.lastHideTouchSceneX = touchSceneX;
238+ d.xDisplacementSinceLock += (touchPosition.x - d.lastHideTouchX)
239+ d.lastHideTouchX = touchPosition.x;
240240 }
241241 }
242242 }
@@ -244,7 +244,11 @@ Showable {
244244 PanelVelocityCalculator {
245245 id: yVelocityCalculator
246246 velocityThreshold: d.hasCommitted ? 0.1 : 0.3
247− trackedValue: d.activeDragHandle ? d.activeDragHandle.touchSceneY : 0
247+ trackedValue: d.activeDragHandle ?
248+ (Direction.isPositive(d.activeDragHandle.direction) ?
249+ d.activeDragHandle.distance :
250+ -d.activeDragHandle.distance)
251+ : 0
248252
249253 onVelocityAboveThresholdChanged: d.updateState()
250254 }
@@ -271,13 +275,13 @@ Showable {
271275 id: d
272276 property var activeDragHandle: showDragHandle.dragging ? showDragHandle : hideDragHandle.dragging ? hideDragHandle : null
273277 property bool hasCommitted: false
274− property real lastHideTouchSceneX: 0
278+ property real lastHideTouchX: 0
275279 property real xDisplacementSinceLock: 0
276280 onXDisplacementSinceLockChanged: d.updateState()
277281
278282 property real rowMappedLateralPosition: {
279283 if (!d.activeDragHandle) return -1;
280− return d.activeDragHandle.mapToItem(bar, d.activeDragHandle.touchX, 0).x;
284+ return d.activeDragHandle.mapToItem(bar, d.activeDragHandle.touchPosition.x, 0).x;
281285 }
282286
283287 function updateState() {
@@ -305,7 +309,7 @@ Showable {
305309 script: {
306310 yVelocityCalculator.reset();
307311 // initial item selection
308− if (!d.hasCommitted) bar.selectItemAt(d.activeDragHandle ? d.activeDragHandle.touchX : -1);
312+ if (!d.hasCommitted) bar.selectItemAt(d.activeDragHandle ? d.activeDragHandle.touchPosition.x : -1);
309313 d.hasCommitted = false;
310314 }
311315 }
@@ -323,7 +327,7 @@ Showable {
323327 target: leftScroller
324328 lateralPosition: {
325329 if (!d.activeDragHandle) return -1;
326− var mapped = d.activeDragHandle.mapToItem(leftScroller, d.activeDragHandle.touchX, 0);
330+ var mapped = d.activeDragHandle.mapToItem(leftScroller, d.activeDragHandle.touchPosition.x, 0);
327331 return mapped.x;
328332 }
329333 }
@@ -332,7 +336,7 @@ Showable {
332336 target: rightScroller
333337 lateralPosition: {
334338 if (!d.activeDragHandle) return -1;
335− var mapped = d.activeDragHandle.mapToItem(rightScroller, d.activeDragHandle.touchX, 0);
339+ var mapped = d.activeDragHandle.mapToItem(rightScroller, d.activeDragHandle.touchPosition.x, 0);
336340 return mapped.x;
337341 }
338342 }
@@ -342,7 +346,7 @@ Showable {
342346 StateChangeScript {
343347 script: {
344348 d.xDisplacementSinceLock = 0;
345− d.lastHideTouchSceneX = hideDragHandle.touchSceneX;
349+ d.lastHideTouchX = hideDragHandle.touchPosition.x;
346350 }
347351 }
348352 PropertyChanges { target: bar; expanded: true }
@@ -354,7 +358,7 @@ Showable {
354358 PropertyChanges {
355359 target: d;
356360 hasCommitted: true
357− lastHideTouchSceneX: 0
361+ lastHideTouchX: 0
358362 xDisplacementSinceLock: 0
359363 restoreEntryValues: false
360364 }
qml/Stages/DesktopStage.qml+1−1
@@ -650,7 +650,7 @@ AbstractStage {
650650 }
651651 }
652652
653− DirectionalDragArea {
653+ SwipeArea {
654654 direction: Direction.Leftwards
655655 anchors { top: parent.top; right: parent.right; bottom: parent.bottom }
656656 width: units.gu(1)
qml/Stages/PhoneStage.qml+4−4
@@ -713,7 +713,7 @@ AbstractStage {
713713 enabled: spreadDragArea.dragging
714714 }
715715
716− DirectionalDragArea {
716+ SwipeArea {
717717 id: spreadDragArea
718718 objectName: "spreadDragArea"
719719 direction: Direction.Leftwards
@@ -724,10 +724,10 @@ AbstractStage {
724724
725725 property var gesturePoints: new Array()
726726
727− onTouchXChanged: {
727+ onTouchPositionChanged: {
728728 if (dragging) {
729729 // Gesture recognized. Let's move the spreadView with the finger
730− var dragX = Math.min(touchX + width, width); // Prevent dragging rightwards
730+ var dragX = Math.min(touchPosition.x + width, width); // Prevent dragging rightwards
731731 dragX = -dragX + spreadDragArea.width - spreadView.shift;
732732 // Don't allow dragging further than the animation crossing with phase2's animation
733733 var maxMovement = spreadView.width * spreadView.positionMarker4 - spreadView.shift;
@@ -739,7 +739,7 @@ AbstractStage {
739739 spreadView.contentX = -spreadView.shift;
740740 }
741741
742− gesturePoints.push(touchX);
742+ gesturePoints.push(touchPosition.x);
743743 }
744744
745745 onDraggingChanged: {
qml/Stages/TabletStage.qml+4−4
@@ -1106,7 +1106,7 @@ AbstractStage {
11061106 enabled: spreadDragArea.dragging
11071107 }
11081108
1109− DirectionalDragArea {
1109+ SwipeArea {
11101110 id: spreadDragArea
11111111 objectName: "spreadDragArea"
11121112 x: parent.width - root.dragAreaWidth
@@ -1117,18 +1117,18 @@ AbstractStage {
11171117
11181118 property var gesturePoints: new Array()
11191119
1120− onTouchXChanged: {
1120+ onTouchPositionChanged: {
11211121 if (!dragging) {
11221122 spreadView.phase = 0;
11231123 spreadView.contentX = -spreadView.shift;
11241124 }
11251125
11261126 if (dragging) {
1127− var dragX = -touchX + spreadDragArea.width - spreadView.shift;
1127+ var dragX = -touchPosition.x + spreadDragArea.width - spreadView.shift;
11281128 var maxDrag = spreadView.width * spreadView.positionMarker4 - spreadView.shift;
11291129 spreadView.contentX = Math.min(dragX, maxDrag);
11301130 }
1131− gesturePoints.push(touchX);
1131+ gesturePoints.push(touchPosition.x);
11321132 }
11331133
11341134 onDraggingChanged: {
qml/Tutorial/TutorialBottom.qml+3−3
@@ -51,7 +51,7 @@ TutorialPage {
5151 readonly property real dragAreaHeight: units.gu(3) // based on PageWithBottomEdge.qml
5252 readonly property real targetDistance: height * 0.2 + dragAreaHeight // based on PageWithBottomEdge.qml
5353
54− opacityOverride: dragArea.dragging ? 1 - (-dragArea.distance / targetDistance) : 1
54+ opacityOverride: dragArea.dragging ? 1 - (dragArea.distance / targetDistance) : 1
5555
5656 mouseArea {
5757 anchors.bottomMargin: root.dragAreaHeight
@@ -95,9 +95,9 @@ TutorialPage {
9595
9696 // Watches drag events but does not intercept them, so that the app beneath
9797 // will still drag the bottom edge up.
98− DirectionalDragArea {
98+ SwipeArea {
9999 id: dragArea
100− monitorOnly: true
100+ grabGesture: false
101101 direction: Direction.Upwards
102102 anchors.left: parent.left
103103 anchors.right: parent.right
src/CMakeLists.txt−4
@@ -2,7 +2,6 @@ pkg_check_modules(CONNECTIVITY REQUIRED connectivity-qt1)
22
33include_directories(
44 ${Qt5Gui_PRIVATE_INCLUDE_DIRS}
5− ${CMAKE_SOURCE_DIR}/libs/UbuntuGestures
65 ${CONNECTIVITY_INCLUDE_DIRS}
76)
87
@@ -44,9 +43,6 @@ if (ENABLE_TOUCH_EMULATION)
4443 target_link_libraries(${SHELL_APP} ${MOUSETOUCHADAPTOR_LIBS_LDFLAGS})
4544endif()
4645
47−# For it to find libUbuntuGestures.so
48−set_target_properties(${SHELL_APP} PROPERTIES INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${SHELL_PRIVATE_LIBDIR}")
49−
5046# install binaries
5147install(TARGETS ${SHELL_APP}
5248 RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
tests/CMakeLists.txt−1
@@ -128,7 +128,6 @@ endfunction()
128128
129129
130130# Actual test definitions
131−add_subdirectory(libs)
132131add_subdirectory(plugins)
133132add_subdirectory(qmltests)
134133add_subdirectory(whitespace)
tests/libs/CMakeLists.txtdeleted−1
@@ -1 +0,0 @@
1−add_subdirectory(UbuntuGestures)
tests/libs/UbuntuGestures/CMakeLists.txtdeleted−16
@@ -1,16 +0,0 @@
1−include_directories(
2− ${CMAKE_SOURCE_DIR}/libs/UbuntuGestures
3− ${CMAKE_CURRENT_BINARY_DIR}
4− )
5−
6−macro(add_gesture_test CLASSNAME)
7− add_executable(${CLASSNAME}TestExec tst_${CLASSNAME}.cpp)
8− qt5_use_modules(${CLASSNAME}TestExec Test Core Gui Quick)
9− target_link_libraries(${CLASSNAME}TestExec UbuntuGestures)
10−
11− add_unity8_unittest(${CLASSNAME} ${CLASSNAME}TestExec
12− ENVIRONMENT LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/libs/UbuntuGestures
13− )
14−endmacro(add_gesture_test)
15−
16−add_gesture_test(TouchRegistry)
tests/libs/UbuntuGestures/tst_TouchRegistry.cppdeleted−974
@@ -1,974 +0,0 @@
1−/*
2− * Copyright (C) 2014-2015 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−#include <QtTest>
18−#include <QSet>
19−#include <QTouchEvent>
20−
21−#include <Timer.h>
22−#include <TouchOwnershipEvent.h>
23−#include <TouchRegistry.h>
24−#include <UnownedTouchEvent.h>
25−
26−using namespace UbuntuGestures;
27−
28−class TouchMemento {
29−public:
30− TouchMemento(const QTouchEvent *touchEvent);
31− Qt::TouchPointStates touchPointStates;
32− QList<QTouchEvent::TouchPoint> touchPoints;
33−
34− bool containsTouchWithId(int touchId) const;
35−};
36−
37−class DummyCandidate : public QQuickItem
38−{
39− Q_OBJECT
40−public:
41− bool event(QEvent *e) override;
42− QSet<int> ownedTouches;
43− QSet<int> lostTouches;
44− QList<TouchMemento> unownedTouchEvents;
45−
46−Q_SIGNALS:
47− void gainedOwnership();
48− void lostOwnership();
49−};
50−
51−class tst_TouchRegistry : public QObject
52−{
53− Q_OBJECT
54−public:
55− tst_TouchRegistry() : QObject(0) { }
56−private Q_SLOTS:
57− void initTestCase() {} // will be called before the first test function is executed
58− void cleanupTestCase() {} // will be called after the last test function was executed.
59−
60− void init(); // called right before each and every test function is executed
61− void cleanup(); // called right after each and every test function is executed
62−
63− void requestWithNoCandidates();
64− void lateCandidateRequestGetsNothing();
65− void lateCandidateGestOwnershipOnceEarlyCandidateQuits();
66− void dispatchesTouchEventsToCandidates();
67− void dispatchesTouchEventsToWatchers();
68− void keepDispatchingToWatchersAfterLastCandidateGivesUp();
69− void candidatesAndWatchers_1();
70− void candidatesAndWatchers_2();
71− void rejectingTouchfterItsEnd();
72− void removeOldUndecidedCandidates();
73− void interimOwnerWontGetUnownedTouchEvents();
74− void candidateVanishes();
75− void candicateOwnershipReentrace();
76−
77−private:
78− TouchRegistry *touchRegistry;
79−};
80−
81−void tst_TouchRegistry::init()
82−{
83− touchRegistry = TouchRegistry::instance();
84−}
85−
86−void tst_TouchRegistry::cleanup()
87−{
88− delete touchRegistry;
89−}
90−
91−void tst_TouchRegistry::requestWithNoCandidates()
92−{
93− DummyCandidate candidate;
94−
95− {
96− QList<QTouchEvent::TouchPoint> touchPoints;
97− touchPoints.append(QTouchEvent::TouchPoint(0));
98− touchPoints[0].setState(Qt::TouchPointPressed);
99− QTouchEvent touchEvent(QEvent::TouchBegin,
100− 0 /* device */,
101− Qt::NoModifier,
102− Qt::TouchPointPressed,
103− touchPoints);
104− touchRegistry->update(&touchEvent);
105− }
106−
107− touchRegistry->requestTouchOwnership(0, &candidate);
108−
109− QVERIFY(candidate.ownedTouches.contains(0));
110−}
111−
112−void tst_TouchRegistry::lateCandidateRequestGetsNothing()
113−{
114− DummyCandidate earlyCandidate;
115− earlyCandidate.setObjectName("early");
116− DummyCandidate lateCandidate;
117− lateCandidate.setObjectName("late");
118−
119− {
120− QList<QTouchEvent::TouchPoint> touchPoints;
121− touchPoints.append(QTouchEvent::TouchPoint(0));
122− touchPoints[0].setState(Qt::TouchPointPressed);
123− QTouchEvent touchEvent(QEvent::TouchBegin,
124− 0 /* device */,
125− Qt::NoModifier,
126− Qt::TouchPointPressed,
127− touchPoints);
128− touchRegistry->update(&touchEvent);
129− }
130−
131− touchRegistry->addCandidateOwnerForTouch(0, &earlyCandidate);
132− touchRegistry->addCandidateOwnerForTouch(0, &lateCandidate);
133−
134− QVERIFY(earlyCandidate.ownedTouches.isEmpty());
135− QVERIFY(lateCandidate.ownedTouches.isEmpty());
136−
137− touchRegistry->requestTouchOwnership(0, &lateCandidate);
138−
139− QVERIFY(earlyCandidate.ownedTouches.isEmpty());
140− QVERIFY(lateCandidate.ownedTouches.isEmpty());
141−
142− touchRegistry->requestTouchOwnership(0, &earlyCandidate);
143−
144− QVERIFY(earlyCandidate.ownedTouches.contains(0));
145− QVERIFY(lateCandidate.ownedTouches.isEmpty());
146−}
147−
148−void tst_TouchRegistry::lateCandidateGestOwnershipOnceEarlyCandidateQuits()
149−{
150− DummyCandidate earlyCandidate;
151− DummyCandidate lateCandidate;
152−
153− {
154− QList<QTouchEvent::TouchPoint> touchPoints;
155− touchPoints.append(QTouchEvent::TouchPoint(0));
156− touchPoints[0].setState(Qt::TouchPointPressed);
157− QTouchEvent touchEvent(QEvent::TouchBegin,
158− 0 /* device */,
159− Qt::NoModifier,
160− Qt::TouchPointPressed,
161− touchPoints);
162− touchRegistry->update(&touchEvent);
163− }
164−
165− touchRegistry->addCandidateOwnerForTouch(0, &earlyCandidate);
166− touchRegistry->addCandidateOwnerForTouch(0, &lateCandidate);
167−
168− QVERIFY(earlyCandidate.ownedTouches.isEmpty());
169− QVERIFY(lateCandidate.ownedTouches.isEmpty());
170−
171− touchRegistry->requestTouchOwnership(0, &lateCandidate);
172−
173− QVERIFY(earlyCandidate.ownedTouches.isEmpty());
174− QVERIFY(lateCandidate.ownedTouches.isEmpty());
175−
176− touchRegistry->removeCandidateOwnerForTouch(0, &earlyCandidate);
177−
178− QVERIFY(earlyCandidate.ownedTouches.isEmpty());
179− QVERIFY(lateCandidate.ownedTouches.contains(0));
180−}
181−
182−void tst_TouchRegistry::dispatchesTouchEventsToCandidates()
183−{
184− QQuickItem rootItem;
185−
186− DummyCandidate candidate0;
187− candidate0.setObjectName("0");
188− candidate0.setParentItem(&rootItem);
189− candidate0.setX(1);
190− candidate0.setY(2);
191−
192− DummyCandidate candidate1;
193− candidate1.setObjectName("1");
194− candidate0.setParentItem(&rootItem);
195− candidate1.setX(3);
196− candidate1.setY(4);
197−
198− {
199− QList<QTouchEvent::TouchPoint> touchPoints;
200− touchPoints.append(QTouchEvent::TouchPoint(0));
201− touchPoints[0].setState(Qt::TouchPointPressed);
202− touchPoints[0].setRect(QRect(10, 10, 0, 0));
203− QTouchEvent touchEvent(QEvent::TouchBegin,
204− 0 /* device */,
205− Qt::NoModifier,
206− Qt::TouchPointPressed,
207− touchPoints);
208− touchRegistry->update(&touchEvent);
209− }
210−
211− touchRegistry->addCandidateOwnerForTouch(0, &candidate0);
212−
213− {
214− QList<QTouchEvent::TouchPoint> touchPoints;
215− touchPoints.append(QTouchEvent::TouchPoint(0));
216− touchPoints[0].setState(Qt::TouchPointMoved);
217− touchPoints[0].setRect(QRect(11, 11, 0, 0));
218− touchPoints.append(QTouchEvent::TouchPoint(1));
219− touchPoints[1].setState(Qt::TouchPointPressed);
220− touchPoints[1].setRect(QRect(20, 20, 0, 0));
221− QTouchEvent touchEvent(QEvent::TouchUpdate,
222− 0 /* device */,
223− Qt::NoModifier,
224− Qt::TouchPointPressed | Qt::TouchPointMoved,
225− touchPoints);
226− touchRegistry->update(&touchEvent);
227− }
228−
229− // candidate0 should have received an update on the touch he's interested on.
230− QCOMPARE(candidate0.unownedTouchEvents.count(), 1);
231− // make sure only touch 0 is there (i.e. no mention of touch 1)
232− QCOMPARE(candidate0.unownedTouchEvents[0].touchPoints.count(), 1);
233− QCOMPARE(candidate0.unownedTouchEvents[0].touchPoints[0].id(), 0);
234− // Check that the points local coordinates have been mapped to candidate0's coordinate system.
235− QCOMPARE(candidate0.unownedTouchEvents[0].touchPoints[0].rect().x(), 11 - candidate0.x());
236− QCOMPARE(candidate0.unownedTouchEvents[0].touchPoints[0].rect().y(), 11 - candidate0.y());
237−
238− touchRegistry->addCandidateOwnerForTouch(1, &candidate1);
239−
240− {
241− QList<QTouchEvent::TouchPoint> touchPoints;
242− touchPoints.append(QTouchEvent::TouchPoint(0));
243− touchPoints[0].setState(Qt::TouchPointMoved);
244− touchPoints[0].setRect(QRect(12, 12, 0, 0));
245− touchPoints.append(QTouchEvent::TouchPoint(1));
246− touchPoints[1].setState(Qt::TouchPointMoved);
247− touchPoints[1].setRect(QRect(21, 21, 0, 0));
248− QTouchEvent touchEvent(QEvent::TouchUpdate,
249− 0 /* device */,
250− Qt::NoModifier,
251− Qt::TouchPointPressed | Qt::TouchPointMoved,
252− touchPoints);
253− touchRegistry->update(&touchEvent);
254− }
255−
256− // candidate0 gets updates only for touch 0 and
257− // candidate1 gets updates only for touch 1
258−
259− QCOMPARE(candidate0.unownedTouchEvents.count(), 2);
260− QCOMPARE(candidate0.unownedTouchEvents[1].touchPoints.count(), 1);
261− QCOMPARE(candidate0.unownedTouchEvents[1].touchPoints[0].id(), 0);
262−
263− QCOMPARE(candidate1.unownedTouchEvents.count(), 1);
264− QCOMPARE(candidate1.unownedTouchEvents[0].touchPoints.count(), 1);
265− QCOMPARE(candidate1.unownedTouchEvents[0].touchPoints[0].id(), 1);
266−}
267−
268−void tst_TouchRegistry::dispatchesTouchEventsToWatchers()
269−{
270− QQuickItem rootItem;
271−
272− DummyCandidate watcher;
273− watcher.setObjectName("watcher");
274− watcher.setParentItem(&rootItem);
275− watcher.setX(1);
276− watcher.setY(2);
277−
278− {
279− QList<QTouchEvent::TouchPoint> touchPoints;
280− touchPoints.append(QTouchEvent::TouchPoint(0));
281− touchPoints[0].setState(Qt::TouchPointPressed);
282− touchPoints[0].setRect(QRect(10, 10, 0, 0));
283− QTouchEvent touchEvent(QEvent::TouchBegin,
284− 0 /* device */,
285− Qt::NoModifier,
286− Qt::TouchPointPressed,
287− touchPoints);
288− touchRegistry->update(&touchEvent);
289− }
290−
291− touchRegistry->addTouchWatcher(0, &watcher);
292−
293− {
294− QList<QTouchEvent::TouchPoint> touchPoints;
295− touchPoints.append(QTouchEvent::TouchPoint(0));
296− touchPoints[0].setState(Qt::TouchPointMoved);
297− touchPoints[0].setRect(QRect(11, 11, 0, 0));
298− touchPoints.append(QTouchEvent::TouchPoint(1));
299− touchPoints[1].setState(Qt::TouchPointPressed);
300− touchPoints[1].setRect(QRect(20, 20, 0, 0));
301− QTouchEvent touchEvent(QEvent::TouchUpdate,
302− 0 /* device */,
303− Qt::NoModifier,
304− Qt::TouchPointPressed | Qt::TouchPointMoved,
305− touchPoints);
306− touchRegistry->update(&touchEvent);
307− }
308−
309− // watcher should have received an update on the touch he's interested on.
310− QCOMPARE(watcher.unownedTouchEvents.count(), 1);
311− // make sure only touch 0 is there (i.e. no mention of touch 1)
312− QCOMPARE(watcher.unownedTouchEvents[0].touchPoints.count(), 1);
313− QCOMPARE(watcher.unownedTouchEvents[0].touchPoints[0].id(), 0);
314− // Check that the points local coordinates have been mapped to watcher's coordinate system.
315− QCOMPARE(watcher.unownedTouchEvents[0].touchPoints[0].rect().x(), 11 - watcher.x());
316− QCOMPARE(watcher.unownedTouchEvents[0].touchPoints[0].rect().y(), 11 - watcher.y());
317−
318− {
319− QList<QTouchEvent::TouchPoint> touchPoints;
320− touchPoints.append(QTouchEvent::TouchPoint(0));
321− touchPoints[0].setState(Qt::TouchPointMoved);
322− touchPoints[0].setRect(QRect(12, 12, 0, 0));
323− touchPoints.append(QTouchEvent::TouchPoint(1));
324− touchPoints[1].setState(Qt::TouchPointMoved);
325− touchPoints[1].setRect(QRect(21, 21, 0, 0));
326− QTouchEvent touchEvent(QEvent::TouchUpdate,
327− 0 /* device */,
328− Qt::NoModifier,
329− Qt::TouchPointPressed | Qt::TouchPointMoved,
330− touchPoints);
331− touchRegistry->update(&touchEvent);
332− }
333−
334− // watcher gets updates only for touch 0
335−
336− QCOMPARE(watcher.unownedTouchEvents.count(), 2);
337− QCOMPARE(watcher.unownedTouchEvents[1].touchPoints.count(), 1);
338− QCOMPARE(watcher.unownedTouchEvents[1].touchPoints[0].id(), 0);
339−}
340−
341−void tst_TouchRegistry::keepDispatchingToWatchersAfterLastCandidateGivesUp()
342−{
343− DummyCandidate item;
344−
345− {
346− QList<QTouchEvent::TouchPoint> touchPoints;
347− touchPoints.append(QTouchEvent::TouchPoint(0));
348− touchPoints[0].setState(Qt::TouchPointPressed);
349− QTouchEvent touchEvent(QEvent::TouchBegin,
350− 0 /* device */,
351− Qt::NoModifier,
352− Qt::TouchPointPressed,
353− touchPoints);
354− touchRegistry->update(&touchEvent);
355− }
356−
357− touchRegistry->addCandidateOwnerForTouch(0, &item);
358−
359− {
360− QList<QTouchEvent::TouchPoint> touchPoints;
361− touchPoints.append(QTouchEvent::TouchPoint(0));
362− touchPoints[0].setState(Qt::TouchPointMoved);
363− touchPoints.append(QTouchEvent::TouchPoint(1));
364− touchPoints[1].setState(Qt::TouchPointPressed);
365− QTouchEvent touchEvent(QEvent::TouchUpdate,
366− 0 /* device */,
367− Qt::NoModifier,
368− Qt::TouchPointPressed | Qt::TouchPointMoved,
369− touchPoints);
370− touchRegistry->update(&touchEvent);
371− }
372−
373− QCOMPARE(item.unownedTouchEvents.count(), 1);
374− QCOMPARE(item.unownedTouchEvents[0].touchPoints.count(), 1);
375− QCOMPARE(item.unownedTouchEvents[0].touchPoints[0].id(), 0);
376− item.unownedTouchEvents.clear();
377−
378− touchRegistry->addTouchWatcher(1, &item);
379−
380− {
381− QList<QTouchEvent::TouchPoint> touchPoints;
382− touchPoints.append(QTouchEvent::TouchPoint(0));
383− touchPoints[0].setState(Qt::TouchPointMoved);
384− touchPoints.append(QTouchEvent::TouchPoint(1));
385− touchPoints[1].setState(Qt::TouchPointMoved);
386− QTouchEvent touchEvent(QEvent::TouchUpdate,
387− 0 /* device */,
388− Qt::NoModifier,
389− Qt::TouchPointMoved,
390− touchPoints);
391− touchRegistry->update(&touchEvent);
392− }
393−
394− QCOMPARE(item.unownedTouchEvents.count(), 1);
395− QCOMPARE(item.unownedTouchEvents[0].touchPoints.count(), 2);
396− QVERIFY(item.unownedTouchEvents[0].containsTouchWithId(0));
397− QVERIFY(item.unownedTouchEvents[0].containsTouchWithId(1));
398− item.unownedTouchEvents.clear();
399−
400− {
401− QList<QTouchEvent::TouchPoint> touchPoints;
402− touchPoints.append(QTouchEvent::TouchPoint(0));
403− touchPoints[0].setState(Qt::TouchPointReleased);
404− touchPoints.append(QTouchEvent::TouchPoint(1));
405− touchPoints[1].setState(Qt::TouchPointMoved);
406− QTouchEvent touchEvent(QEvent::TouchUpdate,
407− 0 /* device */,
408− Qt::NoModifier,
409− Qt::TouchPointReleased | Qt::TouchPointMoved,
410− touchPoints);
411− touchRegistry->update(&touchEvent);
412− }
413−
414− QCOMPARE(item.unownedTouchEvents.count(), 1);
415− QCOMPARE(item.unownedTouchEvents[0].touchPoints.count(), 2);
416− QVERIFY(item.unownedTouchEvents[0].containsTouchWithId(0));
417− QVERIFY(item.unownedTouchEvents[0].containsTouchWithId(1));
418− item.unownedTouchEvents.clear();
419−
420− touchRegistry->removeCandidateOwnerForTouch(0, &item);
421−
422− {
423− QList<QTouchEvent::TouchPoint> touchPoints;
424− touchPoints.append(QTouchEvent::TouchPoint(1));
425− touchPoints[0].setState(Qt::TouchPointReleased);
426− QTouchEvent touchEvent(QEvent::TouchEnd,
427− 0 /* device */,
428− Qt::NoModifier,
429− Qt::TouchPointReleased,
430− touchPoints);
431− touchRegistry->update(&touchEvent);
432− }
433−
434− QCOMPARE(item.unownedTouchEvents.count(), 1);
435− QCOMPARE(item.unownedTouchEvents[0].touchPoints.count(), 1);
436− QVERIFY(item.unownedTouchEvents[0].containsTouchWithId(1));
437− item.unownedTouchEvents.clear();
438−
439− QVERIFY(touchRegistry->m_touchInfoPool.isEmpty());
440−}
441−
442−/*
443− Regression test that reproduces a problematic scenario that came up during manual testing.
444− It reproduces the interaction between TouchRegistry and a DirectionalDragArea
445− */
446−void tst_TouchRegistry::candidatesAndWatchers_1()
447−{
448− DummyCandidate item;
449−
450− {
451− QList<QTouchEvent::TouchPoint> touchPoints;
452− touchPoints.append(QTouchEvent::TouchPoint(0));
453− touchPoints[0].setState(Qt::TouchPointPressed);
454− QTouchEvent touchEvent(QEvent::TouchBegin,
455− 0 /* device */,
456− Qt::NoModifier,
457− Qt::TouchPointPressed,
458− touchPoints);
459− touchRegistry->update(&touchEvent);
460− }
461−
462− touchRegistry->addCandidateOwnerForTouch(0, &item);
463−
464− {
465− QList<QTouchEvent::TouchPoint> touchPoints;
466− touchPoints.append(QTouchEvent::TouchPoint(0));
467− touchPoints[0].setState(Qt::TouchPointMoved);
468− touchPoints.append(QTouchEvent::TouchPoint(1));
469− touchPoints[1].setState(Qt::TouchPointPressed);
470− QTouchEvent touchEvent(QEvent::TouchUpdate,
471− 0 /* device */,
472− Qt::NoModifier,
473− Qt::TouchPointPressed | Qt::TouchPointMoved,
474− touchPoints);
475− touchRegistry->update(&touchEvent);
476− }
477−
478− touchRegistry->addTouchWatcher(1, &item);
479−
480− touchRegistry->removeCandidateOwnerForTouch(0, &item);
481−
482− touchRegistry->addTouchWatcher(0, &item);
483−
484− {
485− QList<QTouchEvent::TouchPoint> touchPoints;
486− touchPoints.append(QTouchEvent::TouchPoint(0));
487− touchPoints[0].setState(Qt::TouchPointReleased);
488− touchPoints.append(QTouchEvent::TouchPoint(1));
489− touchPoints[1].setState(Qt::TouchPointMoved);
490− QTouchEvent touchEvent(QEvent::TouchUpdate,
491− 0 /* device */,
492− Qt::NoModifier,
493− Qt::TouchPointReleased | Qt::TouchPointMoved,
494− touchPoints);
495− touchRegistry->update(&touchEvent);
496− }
497−
498− {
499− QList<QTouchEvent::TouchPoint> touchPoints;
500− touchPoints.append(QTouchEvent::TouchPoint(1));
501− touchPoints[0].setState(Qt::TouchPointReleased);
502− QTouchEvent touchEvent(QEvent::TouchEnd,
503− 0 /* device */,
504− Qt::NoModifier,
505− Qt::TouchPointReleased,
506− touchPoints);
507− touchRegistry->update(&touchEvent);
508− }
509−
510− QVERIFY(touchRegistry->m_touchInfoPool.isEmpty());
511−
512− item.unownedTouchEvents.clear();
513−
514− {
515− QList<QTouchEvent::TouchPoint> touchPoints;
516− touchPoints.append(QTouchEvent::TouchPoint(0));
517− touchPoints[0].setState(Qt::TouchPointPressed);
518− QTouchEvent touchEvent(QEvent::TouchBegin,
519− 0 /* device */,
520− Qt::NoModifier,
521− Qt::TouchPointPressed,
522− touchPoints);
523− touchRegistry->update(&touchEvent);
524− }
525−
526− // Haven't made any subscription for that new touch 0.
527− QCOMPARE(item.unownedTouchEvents.count(), 0);
528−}
529−
530−/*
531− Regression test that reproduces a problematic scenario that came up during manual testing.
532− It reproduces the interaction between TouchRegistry, DirectionalDragArea and a TouchGate.
533− */
534−void tst_TouchRegistry::candidatesAndWatchers_2()
535−{
536− DummyCandidate directionalDragArea;
537− directionalDragArea.setObjectName("DirectionalDragArea");
538−
539− DummyCandidate touchGate;
540− touchGate.setObjectName("TouchGate");
541−
542− // [DDA] 1298 TouchBegin (id:0, state:pressed, scenePos:(147,1023))
543− {
544− QList<QTouchEvent::TouchPoint> touchPoints;
545− touchPoints.append(QTouchEvent::TouchPoint(0));
546− touchPoints[0].setState(Qt::TouchPointPressed);
547− QTouchEvent touchEvent(QEvent::TouchBegin,
548− 0 /* device */,
549− Qt::NoModifier,
550− Qt::TouchPointPressed,
551− touchPoints);
552− touchRegistry->update(&touchEvent);
553− }
554−
555− // [TouchRegistry] addCandidateOwnerForTouch id 0 candidate DirectionalDragArea
556− touchRegistry->addCandidateOwnerForTouch(0, &directionalDragArea);
557−
558− // [TouchRegistry] requestTouchOwnership id 0 candidate TouchGate
559− touchRegistry->requestTouchOwnership(0, &touchGate);
560−
561− //[TouchRegistry] got TouchUpdate (id:0, state:moved, scenePos:(147,1023)) (id:1, state:pressed, scenePos:(327,792))
562− {
563− QList<QTouchEvent::TouchPoint> touchPoints;
564− touchPoints.append(QTouchEvent::TouchPoint(0));
565− touchPoints[0].setState(Qt::TouchPointMoved);
566− touchPoints.append(QTouchEvent::TouchPoint(1));
567− touchPoints[1].setState(Qt::TouchPointPressed);
568− QTouchEvent touchEvent(QEvent::TouchUpdate,
569− 0 /* device */,
570− Qt::NoModifier,
571− Qt::TouchPointPressed | Qt::TouchPointMoved,
572− touchPoints);
573− touchRegistry->update(&touchEvent);
574− }
575−
576− // [TouchRegistry] addTouchWatcher id 1 watcher DirectionalDragArea
577− touchRegistry->addTouchWatcher(1, &directionalDragArea);
578−
579− // [TouchRegistry] removeCandidateOwnerForTouch id 0 candidate DirectionalDragArea
580− touchRegistry->removeCandidateOwnerForTouch(0, &directionalDragArea);
581−
582− //[TouchRegistry] sending TouchWonershipEvent(id = 0 gained) to candidate TouchGate
583− QCOMPARE(touchGate.ownedTouches.count(), 1);
584− QVERIFY(touchGate.ownedTouches.contains(0));
585−
586− // [TouchRegistry] addTouchWatcher id 0 watcher DirectionalDragArea
587− touchRegistry->addTouchWatcher(0, &directionalDragArea);
588−
589− // [TouchRegistry] requestTouchOwnership id 1 candidate TouchGate
590− touchRegistry->requestTouchOwnership(1, &touchGate);
591−
592− //[TouchRegistry] sending TouchWonershipEvent(id = 1 gained) to candidate TouchGate
593− QCOMPARE(touchGate.ownedTouches.count(), 2);
594− QVERIFY(touchGate.ownedTouches.contains(1));
595−
596− directionalDragArea.unownedTouchEvents.clear();
597− touchGate.unownedTouchEvents.clear();
598−
599− //[TouchRegistry] got TouchUpdate (id:0, state:moved, scenePos:(148,1025)) (id:1, state:moved, scenePos:(329,795))
600− {
601− QList<QTouchEvent::TouchPoint> touchPoints;
602− touchPoints.append(QTouchEvent::TouchPoint(0));
603− touchPoints[0].setState(Qt::TouchPointMoved);
604− touchPoints.append(QTouchEvent::TouchPoint(1));
605− touchPoints[1].setState(Qt::TouchPointMoved);
606− QTouchEvent touchEvent(QEvent::TouchUpdate,
607− 0 /* device */,
608− Qt::NoModifier,
609− Qt::TouchPointMoved,
610− touchPoints);
611− touchRegistry->update(&touchEvent);
612− }
613−
614− //vvvvv DDA Watchers are being ignored from now on vvvvvvv
615−
616− QCOMPARE(directionalDragArea.unownedTouchEvents.count(), 1);
617− QCOMPARE(directionalDragArea.unownedTouchEvents.first().touchPoints.count(), 2);
618− QVERIFY(directionalDragArea.unownedTouchEvents.first().containsTouchWithId(0));
619− QVERIFY(directionalDragArea.unownedTouchEvents.first().containsTouchWithId(1));
620−
621− QVERIFY(touchGate.unownedTouchEvents.isEmpty());
622−
623− directionalDragArea.unownedTouchEvents.clear();
624−
625− //[TouchRegistry] got TouchUpdate (id:0, state:moved, scenePos:(151,1029)) (id:1, state:released, scenePos:(329,795))
626− {
627− QList<QTouchEvent::TouchPoint> touchPoints;
628− touchPoints.append(QTouchEvent::TouchPoint(0));
629− touchPoints[0].setState(Qt::TouchPointMoved);
630− touchPoints.append(QTouchEvent::TouchPoint(1));
631− touchPoints[1].setState(Qt::TouchPointReleased);
632− QTouchEvent touchEvent(QEvent::TouchUpdate,
633− 0 /* device */,
634− Qt::NoModifier,
635− Qt::TouchPointMoved | Qt::TouchPointReleased,
636− touchPoints);
637− touchRegistry->update(&touchEvent);
638− }
639−
640− QCOMPARE(directionalDragArea.unownedTouchEvents.count(), 1);
641− QCOMPARE(directionalDragArea.unownedTouchEvents.first().touchPoints.count(), 2);
642− QVERIFY(directionalDragArea.unownedTouchEvents.first().containsTouchWithId(0));
643− QVERIFY(directionalDragArea.unownedTouchEvents.first().containsTouchWithId(1));
644−
645− QVERIFY(touchGate.unownedTouchEvents.isEmpty());
646−
647− directionalDragArea.unownedTouchEvents.clear();
648−
649− //[TouchRegistry] got TouchEnd (id:0, state:released, scenePos:(157,1034))
650− {
651− QList<QTouchEvent::TouchPoint> touchPoints;
652− touchPoints.append(QTouchEvent::TouchPoint(0));
653− touchPoints[0].setState(Qt::TouchPointReleased);
654− QTouchEvent touchEvent(QEvent::TouchEnd,
655− 0 /* device */,
656− Qt::NoModifier,
657− Qt::TouchPointReleased,
658− touchPoints);
659− touchRegistry->update(&touchEvent);
660− }
661−
662− QCOMPARE(directionalDragArea.unownedTouchEvents.count(), 1);
663− QCOMPARE(directionalDragArea.unownedTouchEvents.first().touchPoints.count(), 1);
664− QVERIFY(directionalDragArea.unownedTouchEvents.first().containsTouchWithId(0));
665−
666− QVERIFY(touchGate.unownedTouchEvents.isEmpty());
667−}
668−
669−void tst_TouchRegistry::rejectingTouchfterItsEnd()
670−{
671− DummyCandidate earlyCandidate;
672− DummyCandidate lateCandidate;
673−
674− {
675− QList<QTouchEvent::TouchPoint> touchPoints;
676− touchPoints.append(QTouchEvent::TouchPoint(0));
677− touchPoints[0].setState(Qt::TouchPointPressed);
678− QTouchEvent touchEvent(QEvent::TouchBegin,
679− 0 /* device */,
680− Qt::NoModifier,
681− Qt::TouchPointPressed,
682− touchPoints);
683− touchRegistry->update(&touchEvent);
684− }
685−
686− touchRegistry->addCandidateOwnerForTouch(0, &earlyCandidate);
687− touchRegistry->addCandidateOwnerForTouch(0, &lateCandidate);
688−
689− QVERIFY(earlyCandidate.ownedTouches.isEmpty());
690− QVERIFY(lateCandidate.ownedTouches.isEmpty());
691−
692− touchRegistry->requestTouchOwnership(0, &lateCandidate);
693−
694− QVERIFY(earlyCandidate.ownedTouches.isEmpty());
695− QVERIFY(lateCandidate.ownedTouches.isEmpty());
696−
697− {
698− QList<QTouchEvent::TouchPoint> touchPoints;
699− touchPoints.append(QTouchEvent::TouchPoint(0));
700− touchPoints[0].setState(Qt::TouchPointReleased);
701− QTouchEvent touchEvent(QEvent::TouchEnd,
702− 0 /* device */,
703− Qt::NoModifier,
704− Qt::TouchPointPressed,
705− touchPoints);
706− touchRegistry->update(&touchEvent);
707− }
708−
709− QVERIFY(earlyCandidate.ownedTouches.isEmpty());
710− QVERIFY(lateCandidate.ownedTouches.isEmpty());
711−
712− touchRegistry->removeCandidateOwnerForTouch(0, &earlyCandidate);
713−
714− QCOMPARE(lateCandidate.ownedTouches.count(), 1);
715− QVERIFY(lateCandidate.ownedTouches.contains(0));
716−
717− // Check that there's no trace left of touch 0 as we no longer need to keep tabs on it.
718− QVERIFY(!touchRegistry->findTouchInfo(0));
719−}
720−
721−void tst_TouchRegistry::removeOldUndecidedCandidates()
722−{
723− FakeTimerFactory *fakeTimerFactory = new FakeTimerFactory;
724− touchRegistry->setTimerFactory(fakeTimerFactory);
725−
726− DummyCandidate undecidedCandidate;
727− undecidedCandidate.setObjectName("undecided");
728−
729− DummyCandidate candidateThatWantsTouch;
730− candidateThatWantsTouch.setObjectName("wantsTouch");
731−
732− {
733− QList<QTouchEvent::TouchPoint> touchPoints;
734− touchPoints.append(QTouchEvent::TouchPoint(0));
735− touchPoints[0].setState(Qt::TouchPointPressed);
736− QTouchEvent touchEvent(QEvent::TouchBegin,
737− 0 /* device */,
738− Qt::NoModifier,
739− Qt::TouchPointPressed,
740− touchPoints);
741− touchRegistry->update(&touchEvent);
742− }
743−
744− touchRegistry->addCandidateOwnerForTouch(0, &undecidedCandidate);
745−
746− touchRegistry->requestTouchOwnership(0, &candidateThatWantsTouch);
747−
748− QVERIFY(undecidedCandidate.ownedTouches.isEmpty());
749− QVERIFY(undecidedCandidate.lostTouches.isEmpty());
750− QVERIFY(candidateThatWantsTouch.ownedTouches.isEmpty());
751− QVERIFY(candidateThatWantsTouch.lostTouches.isEmpty());
752−
753− // Simulate that enough time has passed to cause the CandidateInactivityTimer to timeout,
754− // making TouchRegistry consider that undecidedCantidate defaulted.
755− fakeTimerFactory->updateTime(10000);
756−
757− QVERIFY(undecidedCandidate.ownedTouches.isEmpty());
758− QVERIFY(undecidedCandidate.lostTouches.contains(0));
759− QVERIFY(candidateThatWantsTouch.ownedTouches.contains(0));
760− QVERIFY(candidateThatWantsTouch.lostTouches.isEmpty());
761−}
762−
763−/*
764− An item that calls requestTouchOwnership() without first having called addCandidateOwnerForTouch()
765− is assumed to be the interim owner of the touch point, thus there's no point in sending
766− UnownedTouchEvents to him as he already gets proper QTouchEvents from QQuickWindow because
767− he didn't ignore the first QTouchEvent with that touch point.
768− */
769−void tst_TouchRegistry::interimOwnerWontGetUnownedTouchEvents()
770−{
771− FakeTimerFactory *fakeTimerFactory = new FakeTimerFactory;
772− touchRegistry->setTimerFactory(fakeTimerFactory);
773−
774− DummyCandidate undecidedCandidate;
775− undecidedCandidate.setObjectName("undecided");
776−
777− DummyCandidate interimOwner;
778− interimOwner.setObjectName("interimOwner");
779−
780− {
781− QList<QTouchEvent::TouchPoint> touchPoints;
782− touchPoints.append(QTouchEvent::TouchPoint(0));
783− touchPoints[0].setState(Qt::TouchPointPressed);
784− QTouchEvent touchEvent(QEvent::TouchBegin,
785− 0 /* device */,
786− Qt::NoModifier,
787− Qt::TouchPointPressed,
788− touchPoints);
789− touchRegistry->update(&touchEvent);
790− }
791−
792− touchRegistry->addCandidateOwnerForTouch(0, &undecidedCandidate);
793− touchRegistry->requestTouchOwnership(0, &interimOwner);
794−
795− {
796− QList<QTouchEvent::TouchPoint> touchPoints;
797− touchPoints.append(QTouchEvent::TouchPoint(0));
798− touchPoints[0].setState(Qt::TouchPointMoved);
799− QTouchEvent touchEvent(QEvent::TouchUpdate,
800− 0 /* device */,
801− Qt::NoModifier,
802− Qt::TouchPointMoved,
803− touchPoints);
804− touchRegistry->update(&touchEvent);
805− }
806−
807− QCOMPARE(undecidedCandidate.unownedTouchEvents.count(), 1);
808− QCOMPARE(interimOwner.unownedTouchEvents.count(), 0);
809−
810− {
811− QList<QTouchEvent::TouchPoint> touchPoints;
812− touchPoints.append(QTouchEvent::TouchPoint(0));
813− touchPoints[0].setState(Qt::TouchPointMoved);
814− QTouchEvent touchEvent(QEvent::TouchUpdate,
815− 0 /* device */,
816− Qt::NoModifier,
817− Qt::TouchPointMoved,
818− touchPoints);
819− touchRegistry->update(&touchEvent);
820− }
821−
822− QCOMPARE(undecidedCandidate.unownedTouchEvents.count(), 2);
823− QCOMPARE(interimOwner.unownedTouchEvents.count(), 0);
824−}
825−
826−/*
827− Regression test for https://bugs.launchpad.net/ubuntu/+source/unity8/+bug/1473492
828−
829− Bug caused by candidates getting deleted before ownership resolution
830− */
831−void tst_TouchRegistry::candidateVanishes()
832−{
833− DummyCandidate mainCandidate;
834− DummyCandidate *missingCandidate = new DummyCandidate;
835−
836− {
837− QList<QTouchEvent::TouchPoint> touchPoints;
838− touchPoints.append(QTouchEvent::TouchPoint(0));
839− touchPoints[0].setState(Qt::TouchPointPressed);
840− QTouchEvent touchEvent(QEvent::TouchBegin,
841− 0 /* device */,
842− Qt::NoModifier,
843− Qt::TouchPointPressed,
844− touchPoints);
845− touchRegistry->update(&touchEvent);
846− }
847−
848− touchRegistry->addCandidateOwnerForTouch(0, &mainCandidate);
849− touchRegistry->addCandidateOwnerForTouch(0, missingCandidate);
850−
851− {
852− QList<QTouchEvent::TouchPoint> touchPoints;
853− touchPoints.append(QTouchEvent::TouchPoint(0));
854− touchPoints[0].setState(Qt::TouchPointMoved);
855− QTouchEvent touchEvent(QEvent::TouchUpdate,
856− 0 /* device */,
857− Qt::NoModifier,
858− Qt::TouchPointMoved,
859− touchPoints);
860− touchRegistry->update(&touchEvent);
861− }
862−
863− // This candidate suddenly disappears without having removed its candidacy.
864− delete missingCandidate;
865− missingCandidate = nullptr;
866−
867− touchRegistry->requestTouchOwnership(0, &mainCandidate);
868−
869− QVERIFY(mainCandidate.ownedTouches.contains(0));
870−}
871−
872−/*
873− Regression test for canidate reentrance
874−
875− Bug caused by candidates getting removed during ownership resolution
876− */
877−void tst_TouchRegistry::candicateOwnershipReentrace()
878−{
879− DummyCandidate mainCandidate;
880− DummyCandidate candicate2;
881− DummyCandidate candicate3;
882−
883− {
884− QList<QTouchEvent::TouchPoint> touchPoints;
885− touchPoints.append(QTouchEvent::TouchPoint(0));
886− touchPoints[0].setState(Qt::TouchPointPressed);
887− QTouchEvent touchEvent(QEvent::TouchBegin,
888− 0 /* device */,
889− Qt::NoModifier,
890− Qt::TouchPointPressed,
891− touchPoints);
892− touchRegistry->update(&touchEvent);
893− }
894−
895− // Re-entrance!
896− connect(&candicate2, &DummyCandidate::lostOwnership, this, [&]() {
897− touchRegistry->removeCandidateOwnerForTouch(0, &candicate2);
898− });
899−
900− touchRegistry->addCandidateOwnerForTouch(0, &mainCandidate);
901− touchRegistry->addCandidateOwnerForTouch(0, &candicate2);
902− touchRegistry->addCandidateOwnerForTouch(0, &candicate3);
903−
904− {
905− QList<QTouchEvent::TouchPoint> touchPoints;
906− touchPoints.append(QTouchEvent::TouchPoint(0));
907− touchPoints[0].setState(Qt::TouchPointMoved);
908− QTouchEvent touchEvent(QEvent::TouchUpdate,
909− 0 /* device */,
910− Qt::NoModifier,
911− Qt::TouchPointMoved,
912− touchPoints);
913− touchRegistry->update(&touchEvent);
914− }
915−
916− touchRegistry->requestTouchOwnership(0, &mainCandidate);
917−
918− QCOMPARE(mainCandidate.ownedTouches.count(), 1);
919− QCOMPARE(candicate2.lostTouches.count(), 1);
920− QCOMPARE(candicate3.lostTouches.count(), 1);
921−}
922−
923−
924−////////////// TouchMemento //////////
925−
926−TouchMemento::TouchMemento(const QTouchEvent *touchEvent)
927− : touchPointStates(touchEvent->touchPointStates()), touchPoints(touchEvent->touchPoints())
928−{
929−}
930−
931−bool TouchMemento::containsTouchWithId(int touchId) const
932−{
933− for (int i = 0; i < touchPoints.count(); ++i) {
934− if (touchPoints.at(i).id() == touchId) {
935− return true;
936− }
937− }
938− return false;
939−}
940−
941−////////////// DummyCandidate //////////
942−
943−bool DummyCandidate::event(QEvent *e)
944−{
945− if (e->type() == TouchOwnershipEvent::touchOwnershipEventType()) {
946− TouchOwnershipEvent *touchOwnershipEvent = static_cast<TouchOwnershipEvent *>(e);
947−
948− // NB: Cannot use QVERIFY here because the macro doesn't return a boolean and is
949− // meant for use only directly in the body of a test function
950− if (ownedTouches.contains(touchOwnershipEvent->touchId()))
951− qFatal("Sent ownership event for a touch that is already owned.");
952− if (lostTouches.contains(touchOwnershipEvent->touchId()))
953− qFatal("Sent ownership event for a touch that has already been lost.");
954−
955− if (touchOwnershipEvent->gained()) {
956− ownedTouches.insert(touchOwnershipEvent->touchId());
957− Q_EMIT gainedOwnership();
958− } else {
959− lostTouches.insert(touchOwnershipEvent->touchId());
960− Q_EMIT lostOwnership();
961− }
962− return true;
963− } else if (e->type() == UnownedTouchEvent::unownedTouchEventType()) {
964− UnownedTouchEvent *unownedTouchEvent = static_cast<UnownedTouchEvent *>(e);
965− unownedTouchEvents.append(TouchMemento(unownedTouchEvent->touchEvent()));
966− return true;
967− } else {
968− return QObject::event(e);
969− }
970−}
971−
972−QTEST_GUILESS_MAIN(tst_TouchRegistry)
973−
974−#include "tst_TouchRegistry.moc"
tests/plugins/Ubuntu/Gestures/CMakeLists.txt+4−4
@@ -1,5 +1,7 @@
11include(QmlTest)
22
3+pkg_check_modules(UBUNTUGESTURES REQUIRED UbuntuGestures)
4+
35# DANGER! DANGER! Using Qt's private API!
46include_directories(
57 ${Qt5Quick_PRIVATE_INCLUDE_DIRS}
@@ -7,7 +9,7 @@ include_directories(
79
810include_directories(
911 ${CMAKE_SOURCE_DIR}/plugins/Ubuntu/Gestures
10− ${CMAKE_SOURCE_DIR}/libs/UbuntuGestures
12+ ${UBUNTUGESTURES_INCLUDE_DIRS}
1113 ${CMAKE_CURRENT_BINARY_DIR}
1214 ${Qt5Gui_PRIVATE_INCLUDE_DIRS}
1315 )
@@ -17,7 +19,7 @@ export_qmlfiles(UbuntuGesturesTest .)
1719macro(build_gesture_test CLASSNAME)
1820 add_executable(${CLASSNAME}TestExec tst_${CLASSNAME}.cpp GestureTest.cpp TestItem.cpp)
1921 qt5_use_modules(${CLASSNAME}TestExec Test Core Qml Gui Quick)
20− target_link_libraries(${CLASSNAME}TestExec UbuntuGesturesQml UbuntuGestures)
22+ target_link_libraries(${CLASSNAME}TestExec UbuntuGesturesQml ${UBUNTUGESTURES_LIBRARIES})
2123endmacro()
2224
2325set(UNITY_IMPORT_PATHS
@@ -44,11 +46,9 @@ macro(add_gesture_ui_test CLASSNAME)
4446 add_manual_qml_test(. ${CLASSNAME} IMPORT_PATHS ${UNITY_IMPORT_PATHS})
4547endmacro()
4648
47−add_gesture_ui_test(DirectionalDragArea)
4849add_gesture_ui_test(FloatingFlickable)
4950add_gesture_ui_test(PressedOutsideNotifier)
5051add_gesture_ui_test(TouchDispatcher)
5152add_gesture_ui_test(TouchGate)
52−add_gesture_unit_test(Damper)
5353add_gesture_unit_test(AxisVelocityCalculator)
5454add_gesture_ui_test(TouchGestureArea)
tests/plugins/Ubuntu/Gestures/DownwardsLauncher.qmldeleted−72
@@ -1,72 +0,0 @@
1−/*
2− * Copyright (C) 2013 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.4
18−import Ubuntu.Gestures 0.1
19−import Ubuntu.Components 1.3
20−
21−Item {
22−
23− function reset() { launcher.y = -launcher.height }
24−
25− Rectangle {
26− id: launcher
27− color: "blue"
28− width: parent.width
29− height: units.gu(15)
30− x: 0
31− y: followDragArea()
32−
33− function followDragArea() {
34− return dragArea.distance < height ? -height + dragArea.distance : 0
35− }
36− }
37−
38− Rectangle {
39− id: dragAreaRect
40− opacity: dragArea.dragging ? 0.5 : 0.0
41− color: "green"
42− anchors.fill: dragArea
43− }
44−
45− DirectionalDragArea {
46− id: dragArea
47− objectName: "vpDragArea"
48−
49− height: units.gu(5)
50−
51− direction: Direction.Downwards
52−
53− onDraggingChanged: {
54− if (dragging) {
55− launcher.y = Qt.binding(launcher.followDragArea)
56− }
57− }
58−
59− anchors {
60− left: parent.left
61− right: parent.right
62− top: parent.top
63− }
64− }
65−
66− Label {
67− text: "Downwards"
68− anchors.top: parent.top
69− anchors.horizontalCenter: parent.horizontalCenter
70− anchors.topMargin: units.gu(1)
71− }
72−}
tests/plugins/Ubuntu/Gestures/GestureTest.cpp+2−2
@@ -22,8 +22,8 @@
2222#include <QQuickView>
2323#include <QtTest>
2424
25−#include <Timer.h>
26−#include <TouchRegistry.h>
25+#include <Timer>
26+#include <TouchRegistry>
2727
2828using namespace UbuntuGestures;
2929
tests/plugins/Ubuntu/Gestures/LeftwardsLauncher.qmldeleted−76
@@ -1,76 +0,0 @@
1−/*
2− * Copyright (C) 2013 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.4
18−import Ubuntu.Gestures 0.1
19−import Ubuntu.Components 1.3
20−
21−Item {
22− id: root
23−
24− function reset() { launcher.x = Qt.binding(function(){return root.width;}); }
25−
26− Rectangle {
27− id: launcher
28− color: "blue"
29− width: units.gu(15)
30− height: parent.height
31− x: root.width
32− y: 0
33−
34− function followDragArea() {
35− return dragArea.distance > -width ?
36− root.width + dragArea.distance
37− :
38− root.width - width
39− }
40− }
41−
42− Rectangle {
43− id: dragAreaRect
44− opacity: dragArea.dragging ? 0.5 : 0.0
45− color: "green"
46− anchors.fill: dragArea
47− }
48−
49− DirectionalDragArea {
50− id: dragArea
51− objectName: "hnDragArea"
52−
53− width: units.gu(5)
54−
55− direction: Direction.Leftwards
56−
57− onDraggingChanged: {
58− if (dragging) {
59− launcher.x = Qt.binding(launcher.followDragArea)
60− }
61− }
62−
63− anchors {
64− right: parent.right
65− top: parent.top
66− bottom: parent.bottom
67− }
68− }
69−
70− Label {
71− text: "Leftwards"
72− anchors.right: parent.right
73− anchors.verticalCenter: parent.verticalCenter
74− anchors.rightMargin: units.gu(1)
75− }
76−}
tests/plugins/Ubuntu/Gestures/RightwardsLauncher.qmldeleted−76
@@ -1,76 +0,0 @@
1−/*
2− * Copyright (C) 2013 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.4
18−import Ubuntu.Gestures 0.1
19−import Ubuntu.Components 1.3
20−
21−Item {
22− objectName: "rightwardsLauncher"
23−
24− function reset() { launcher.x = -launcher.width }
25−
26− Rectangle {
27− id: launcher
28− color: "blue"
29− width: units.gu(15)
30− height: parent.height
31− x: followDragArea()
32− y: 0
33−
34− function followDragArea() {
35− return dragArea.distance < width ? -width + dragArea.distance : 0
36− }
37− }
38−
39− Rectangle {
40− id: dragAreaRect
41− opacity: dragArea.dragging ? 0.5 : 0.0
42− color: "green"
43− anchors.fill: dragArea
44− }
45−
46− DirectionalDragArea {
47− id: dragArea
48− objectName: "hpDragArea"
49−
50− // give some room for items to be dynamically stacked right behind him
51− z: 10.0
52−
53− width: units.gu(5)
54−
55− direction: Direction.Rightwards
56−
57− onDraggingChanged: {
58− if (dragging) {
59− launcher.x = Qt.binding(launcher.followDragArea)
60− }
61− }
62−
63− anchors {
64− left: parent.left
65− top: parent.top
66− bottom: parent.bottom
67− }
68− }
69−
70− Label {
71− text: "Rightwards"
72− anchors.left: parent.left
73− anchors.verticalCenter: parent.verticalCenter
74− anchors.leftMargin: units.gu(1)
75− }
76−}
tests/plugins/Ubuntu/Gestures/UpwardsLauncher.qmldeleted−76
@@ -1,76 +0,0 @@
1−/*
2− * Copyright (C) 2013 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.4
18−import Ubuntu.Gestures 0.1
19−import Ubuntu.Components 1.3
20−
21−Item {
22− id: root
23−
24− function reset() { launcher.y = Qt.binding(function(){return root.height;}); }
25−
26− Rectangle {
27− id: launcher
28− color: "blue"
29− width: parent.width
30− height: units.gu(15)
31− x: 0
32− y: root.height
33−
34− function followDragArea() {
35− return dragArea.distance > -height ?
36− root.height + dragArea.distance
37− :
38− root.height - height
39− }
40− }
41−
42− Rectangle {
43− id: dragAreaRect
44− opacity: dragArea.dragging ? 0.5 : 0.0
45− color: "green"
46− anchors.fill: dragArea
47− }
48−
49− DirectionalDragArea {
50− id: dragArea
51− objectName: "vnDragArea"
52−
53− height: units.gu(5)
54−
55− direction: Direction.Upwards
56−
57− onDraggingChanged: {
58− if (dragging) {
59− launcher.y = Qt.binding(launcher.followDragArea)
60− }
61− }
62−
63− anchors {
64− left: parent.left
65− right: parent.right
66− bottom: parent.bottom
67− }
68− }
69−
70− Label {
71− text: "Upwards"
72− anchors.bottom: parent.bottom
73− anchors.horizontalCenter: parent.horizontalCenter
74− anchors.bottomMargin: units.gu(1)
75− }
76−}
tests/plugins/Ubuntu/Gestures/tst_Damper.cppdeleted−40
@@ -1,40 +0,0 @@
1−/*
2− * Copyright (C) 2013 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−#include <QtTest/QtTest>
18−
19−#include <Damper.h>
20−
21−class tst_Damper : public QObject
22−{
23− Q_OBJECT
24−private Q_SLOTS:
25− void negativeMovement();
26−};
27−
28−void tst_Damper::negativeMovement()
29−{
30− Damper<qreal> damper;
31−
32− damper.setMaxDelta(3.0);
33− damper.reset(0.0);
34− damper.update(-5.0);
35− QCOMPARE(damper.value(), -2.0);
36−}
37−
38−QTEST_MAIN(tst_Damper)
39−
40−#include "tst_Damper.moc"
tests/plugins/Ubuntu/Gestures/tst_DirectionalDragArea.cppdeleted−1250
@@ -1,1250 +0,0 @@
1−/*
2− * Copyright (C) 2013-2015 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−#include <QtTest/QtTest>
18−#include <QtCore/QObject>
19−#include <QtQuick/QQuickView>
20−#include <QtQml/QQmlEngine>
21−#include <QPointer>
22−#include <private/qquickmousearea_p.h>
23−
24−
25−#include <DirectionalDragArea.h>
26−#include <DirectionalDragArea_p.h>
27−#include <TouchRegistry.h>
28−
29−#include "GestureTest.h"
30−
31−using namespace UbuntuGestures;
32−
33−// Because QSignalSpy(directionalDragArea, SIGNAL(DirectionalDragArea::Status)) simply
34−// doesn't work
35−class StatusSpy : public QObject {
36− Q_OBJECT
37−public:
38− StatusSpy(DirectionalDragArea *edgeDragArea) {
39− m_recognized = false;
40− connect(edgeDragArea->d, &DirectionalDragAreaPrivate::statusChanged,
41− this, &StatusSpy::onStatusChanged);
42− }
43− bool recognized() {
44− return m_recognized;
45− }
46−
47−private Q_SLOTS:
48− void onStatusChanged(DirectionalDragAreaPrivate::Status status) {
49− m_recognized |= status == DirectionalDragAreaPrivate::Recognized;
50− }
51−
52−private:
53− bool m_recognized;
54−};
55−
56−/*
57− QQuickMouseArea::canceled() signal is not registered in the meta object system.
58− So using a QSignalSpy to track it won't work. Thus the only way to connect to it
59− is using its method address directly.
60− */
61−class MouseAreaSpy : public QObject
62−{
63− Q_OBJECT
64−public:
65− MouseAreaSpy(QQuickMouseArea *mouseArea)
66− : canceledCount(0)
67− {
68− connect(mouseArea, &QQuickMouseArea::canceled,
69− this, &MouseAreaSpy::onMouseAreaCanceled);
70− }
71−
72− int canceledCount;
73−
74−private Q_SLOTS:
75− void onMouseAreaCanceled() {
76− ++canceledCount;
77− }
78−};
79−
80−class tst_DirectionalDragArea: public GestureTest
81−{
82− Q_OBJECT
83−public:
84− tst_DirectionalDragArea();
85−private Q_SLOTS:
86− void init() override; // called right before each and every test function is executed
87−
88− void dragWithShortDirectionChange();
89− void recognitionTimerUsage();
90− void sceneXAndX();
91− void sceneYAndY();
92− void twoFingerTap();
93− void movingDDA();
94− void ignoreOldFinger();
95− void rotated();
96− void sceneDistance();
97− void sceneDistance_data();
98− void disabledWhileDragging();
99− void oneFingerDownFollowedByLateSecondFingerDown();
100− void givesUpWhenLosesTouch();
101− void threeFingerDrag();
102− void immediateRecognitionWhenConstraintsDisabled();
103− void withdrawTouchOwnershipCandidacyIfDisabledDuringRecognition();
104− void withdrawTouchOwnershipCandidacyIfDisabledDuringRecognition_data();
105− void gettingTouchOwnershipMakesMouseAreaBehindGetCanceled();
106− void interleavedTouches();
107− void makoRightEdgeDrag();
108− void makoRightEdgeDrag_verticalDownwards();
109− void makoLeftEdgeDrag_slowStart();
110− void makoLeftEdgeDrag_movesSlightlyBackwardsOnStart();
111−};
112−
113−tst_DirectionalDragArea::tst_DirectionalDragArea()
114− : GestureTest(QStringLiteral("tst_DirectionalDragArea.qml"))
115−{
116−}
117−
118−void tst_DirectionalDragArea::init()
119−{
120− GestureTest::init();
121−
122− // We shouldn't need the three lines below, but a compiz/unity7
123− // regression means we don't pass the test without them because
124− // the window doesn't have the proper size. Can be removed in the
125− // future if the regression is fixed and tests pass again
126− m_view->resize(m_view->rootObject()->width(), m_view->rootObject()->height());
127− QTRY_COMPARE(m_view->width(), (int)m_view->rootObject()->width());
128− QTRY_COMPARE(m_view->height(), (int)m_view->rootObject()->height());
129−}
130−
131−namespace {
132−QPointF calculateInitialTouchPos(DirectionalDragArea *edgeDragArea)
133−{
134− QPointF localCenter(edgeDragArea->width() / 2., edgeDragArea->height() / 2.);
135− return edgeDragArea->mapToScene(localCenter);
136−}
137−}
138−
139−/*
140− A directional drag should still be recognized if there is a momentaneous, small,
141− change in the direction of a drag. That should be accounted as input noise and
142− therefore ignored.
143− */
144−void tst_DirectionalDragArea::dragWithShortDirectionChange()
145−{
146− DirectionalDragArea *edgeDragArea =
147− m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
148− QVERIFY(edgeDragArea != 0);
149− edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer(edgeDragArea));
150− edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
151−
152− QPointF initialTouchPos = calculateInitialTouchPos(edgeDragArea);
153− QPointF touchPoint = initialTouchPos;
154−
155− qreal desiredDragDistance = edgeDragArea->d->distanceThreshold * 2.0;
156− QPointF dragDirectionVector(1.0, 0.0);
157− qreal touchStepDistance = edgeDragArea->d->distanceThreshold * 0.1f;
158− // make sure we are above maximum time
159− int touchStepTimeMs = edgeDragArea->d->maxTime / 20. ;
160− QPointF touchMovement = dragDirectionVector * touchStepDistance;
161−
162− QTest::touchEvent(m_view, m_device).press(0, touchPoint.toPoint());
163−
164− // Move a bit in the proper direction
165− for (int i=0; i < 3; ++i) {
166− touchPoint += touchMovement;
167− passTime(touchStepTimeMs);
168− QTest::touchEvent(m_view, m_device).move(0, touchPoint.toPoint());
169− }
170−
171− // Then a sudden and small movement to the opposite direction
172− touchPoint -= touchMovement*0.2;
173− passTime(touchStepTimeMs*0.2);
174− QTest::touchEvent(m_view, m_device).move(0, touchPoint.toPoint());
175−
176− // And then resume movment in the correct direction until it crosses the distance and time
177− // thresholds.
178− do {
179− touchPoint += touchMovement;
180− passTime(touchStepTimeMs);
181− QTest::touchEvent(m_view, m_device).move(0, touchPoint.toPoint());
182− } while ((touchPoint - initialTouchPos).manhattanLength() < desiredDragDistance
183− || m_fakeTimerFactory->timeSource()->msecsSinceReference() < (edgeDragArea->d->compositionTime * 1.5f));
184−
185− QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Recognized);
186−
187− QTest::touchEvent(m_view, m_device).release(0, touchPoint.toPoint());
188−}
189−
190−/*
191− Checks that the recognition timer is started and stopped appropriately.
192− I.e., check that it's running only while gesture recognition is taking place
193− (status == Undecided)
194− */
195−void tst_DirectionalDragArea::recognitionTimerUsage()
196−{
197− DirectionalDragArea *edgeDragArea =
198− m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
199− QVERIFY(edgeDragArea != 0);
200− AbstractTimer *fakeTimer = m_fakeTimerFactory->createTimer();
201− edgeDragArea->d->setRecognitionTimer(fakeTimer);
202− edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
203−
204− int timeStepMs = 5; // some arbitrary small value.
205−
206− QPointF initialTouchPos = calculateInitialTouchPos(edgeDragArea);
207− QPointF touchPoint = initialTouchPos;
208−
209− QPointF dragDirectionVector(1.0, 0.0);
210− QPointF touchMovement = dragDirectionVector * (edgeDragArea->d->distanceThreshold * 0.2f);
211−
212− QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch);
213− QVERIFY(!fakeTimer->isRunning());
214−
215− QTest::touchEvent(m_view, m_device).press(0, touchPoint.toPoint());
216−
217− QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Undecided);
218− QVERIFY(fakeTimer->isRunning());
219−
220− // Move beyond distance threshold and composition time to ensure recognition
221− while (m_fakeTimerFactory->timeSource()->msecsSinceReference() <= edgeDragArea->d->compositionTime ||
222− (touchPoint - initialTouchPos).manhattanLength() <= edgeDragArea->d->distanceThreshold) {
223−
224− QCOMPARE(edgeDragArea->d->status == DirectionalDragAreaPrivate::Undecided, fakeTimer->isRunning());
225−
226− touchPoint += touchMovement;
227− passTime(timeStepMs);
228− QTest::touchEvent(m_view, m_device).move(0, touchPoint.toPoint());
229− }
230−
231− QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Recognized);
232− QVERIFY(!fakeTimer->isRunning());
233−}
234−
235−/*
236− Checks that it informs the X coordinate of the touch point in local and scene coordinates
237− correctly.
238− */
239−void tst_DirectionalDragArea::sceneXAndX()
240−{
241− DirectionalDragArea *edgeDragArea =
242− m_view->rootObject()->findChild<DirectionalDragArea*>("hnDragArea");
243− QVERIFY(edgeDragArea != 0);
244− edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer(edgeDragArea));
245− edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
246− edgeDragArea->setImmediateRecognition(true);
247−
248− QPointF touchScenePos(m_view->width() - (edgeDragArea->width()/2.0f), m_view->height()/2.0f);
249−
250− sendTouchPress(0 /* timestamp */, 0 /* id */, touchScenePos);
251−
252− QSignalSpy touchXSpy(edgeDragArea, &DirectionalDragArea::touchXChanged);
253− QSignalSpy touchSceneXSpy(edgeDragArea, &DirectionalDragArea::touchSceneXChanged);
254−
255− touchScenePos.rx() = m_view->width() / 2;
256− sendTouchUpdate(50 /* timestamp */, 0 /* id */, touchScenePos);
257−
258− QCOMPARE(touchXSpy.count(), 1);
259− QCOMPARE(touchSceneXSpy.count(), 1);
260− QCOMPARE(edgeDragArea->touchX(), touchScenePos.x() - edgeDragArea->x());
261− QCOMPARE(edgeDragArea->touchSceneX(), touchScenePos.x());
262−}
263−
264−/*
265− Checks that it informs the Y coordinate of the touch point in local and scene coordinates
266− correctly.
267− */
268−void tst_DirectionalDragArea::sceneYAndY()
269−{
270− DirectionalDragArea *edgeDragArea =
271− m_view->rootObject()->findChild<DirectionalDragArea*>("vnDragArea");
272− QVERIFY(edgeDragArea != 0);
273− edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer(edgeDragArea));
274− edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
275− edgeDragArea->setImmediateRecognition(true);
276−
277− QPointF touchScenePos(m_view->width()/2.0f, m_view->height() - (edgeDragArea->height()/2.0f));
278−
279− sendTouchPress(0 /* timestamp */, 0 /* id */, touchScenePos);
280−
281− QSignalSpy touchYSpy(edgeDragArea, &DirectionalDragArea::touchYChanged);
282− QSignalSpy touchSceneYSpy(edgeDragArea, &DirectionalDragArea::touchSceneYChanged);
283−
284− touchScenePos.ry() = m_view->height() / 2;
285− sendTouchUpdate(50 /* timestamp */, 0 /* id */, touchScenePos);
286−
287− QCOMPARE(touchYSpy.count(), 1);
288− QCOMPARE(touchSceneYSpy.count(), 1);
289− QCOMPARE(edgeDragArea->touchY(), touchScenePos.y() - edgeDragArea->y());
290− QCOMPARE(edgeDragArea->touchSceneY(), touchScenePos.y());
291−}
292−
293−/*
294− Regression test for https://bugs.launchpad.net/bugs/1228336
295−
296− Perform a quick two-finger double-tap and check that DirectionalDragArea properly
297− rejects those touch points. In the bug above it got confused and crashed.
298− */
299−void tst_DirectionalDragArea::twoFingerTap()
300−{
301− DirectionalDragArea *edgeDragArea =
302− m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
303− QVERIFY(edgeDragArea != 0);
304− edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer(edgeDragArea));
305− edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
306−
307− // Make touches evenly spaced along the edgeDragArea
308− QPoint touchAPos(edgeDragArea->width()/2.0f, m_view->height()*0.33f);
309− QPoint touchBPos(edgeDragArea->width()/2.0f, m_view->height()*0.66f);
310−
311− qint64 timeStepMsecs = 5; // some arbitrary, small value
312−
313− // Perform the first two-finger tap
314− // NB: using move() instead of stationary() becasue in the latter you cannot provide
315− // the touch position and therefore it's left with some garbage numbers.
316− QTest::touchEvent(m_view, m_device)
317− .press(0, touchAPos);
318−
319− QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Undecided);
320−
321− passTime(timeStepMsecs);
322− QTest::touchEvent(m_view, m_device)
323− .move(0, touchAPos)
324− .press(1, touchBPos);
325−
326− // A second touch point appeared during recognition, reject immediately as this
327− // can't be a single-touch gesture anymore.
328− QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch);
329−
330− passTime(timeStepMsecs);
331− QTest::touchEvent(m_view, m_device)
332− .release(0, touchAPos)
333− .move(1, touchBPos);
334−
335− QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch);
336−
337− passTime(timeStepMsecs);
338− QTest::touchEvent(m_view, m_device)
339− .release(1, touchBPos);
340−
341− QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch);
342−
343− // Perform the second two-finger tap
344−
345− passTime(timeStepMsecs);
346− QTest::touchEvent(m_view, m_device)
347− .press(0, touchAPos);
348−
349− QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Undecided);
350−
351− passTime(timeStepMsecs);
352− QTest::touchEvent(m_view, m_device)
353− .move(0, touchAPos)
354− .press(1, touchBPos);
355−
356− QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch);
357−
358− passTime(timeStepMsecs);
359− QTest::touchEvent(m_view, m_device)
360− .release(0, touchAPos)
361− .move(1, touchBPos);
362−
363− QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch);
364−
365− passTime(timeStepMsecs);
366− QTest::touchEvent(m_view, m_device)
367− .release(1, touchBPos);
368−
369− QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch);
370−}
371−
372−/*
373− Tests that gesture recognition works normally even if the DirectionalDragArea moves
374− during recognition.
375− This effectively means that we have to do gesture recognition with scene coordinates
376− instead of local item coordinates.
377− */
378−void tst_DirectionalDragArea::movingDDA()
379−{
380− QQuickItem *rightwardsLauncher = m_view->rootObject()->findChild<QQuickItem*>("rightwardsLauncher");
381− Q_ASSERT(rightwardsLauncher != 0);
382−
383− DirectionalDragArea *edgeDragArea =
384− rightwardsLauncher->findChild<DirectionalDragArea*>("hpDragArea");
385− Q_ASSERT(edgeDragArea != 0);
386− edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer(edgeDragArea));
387− edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
388−
389− QPointF initialTouchPos = calculateInitialTouchPos(edgeDragArea);
390− QPointF touchPoint = initialTouchPos;
391−
392− qreal desiredDragDistance = edgeDragArea->d->distanceThreshold * 2.0f;
393− QPointF dragDirectionVector(1.0f, 0.0f);
394−
395− qreal movementStepDistance = edgeDragArea->d->distanceThreshold * 0.1f;
396− QPointF touchMovement = dragDirectionVector * movementStepDistance;
397− int totalMovementSteps = qCeil(desiredDragDistance / movementStepDistance);
398− int movementTimeStepMs = (edgeDragArea->d->compositionTime * 1.5f) / totalMovementSteps;
399−
400− QTest::touchEvent(m_view, m_device).press(0, touchPoint.toPoint());
401−
402− // Move it far ahead along the direction of the gesture
403− // rightwardsLauncher is a parent of our DirectionalDragArea. So moving it will move our DDA
404− rightwardsLauncher->setX(rightwardsLauncher->x() + edgeDragArea->d->distanceThreshold * 5.0f);
405−
406− for (int i = 0; i < totalMovementSteps; ++i) {
407− touchPoint += touchMovement;
408− passTime(movementTimeStepMs);
409− QTest::touchEvent(m_view, m_device).move(0, touchPoint.toPoint());
410− }
411−
412− QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Recognized);
413−
414− QTest::touchEvent(m_view, m_device).release(0, touchPoint.toPoint());
415−}
416−
417−/*
418− The presence of and old, rejected, touch point lying on the DirectionalDragArea
419− shouldn't impede the recognition of a gesture from a new touch point.
420− */
421−void tst_DirectionalDragArea::ignoreOldFinger()
422−{
423− DirectionalDragArea *edgeDragArea =
424− m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
425− Q_ASSERT(edgeDragArea != 0);
426− edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer(edgeDragArea));
427− edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
428−
429− // Make touches evenly spaced along the edgeDragArea
430− QPoint touch0Pos(edgeDragArea->width()/2.0f, m_view->height()*0.33f);
431− QPoint touch1Pos(edgeDragArea->width()/2.0f, m_view->height()*0.66f);
432−
433− QTest::touchEvent(m_view, m_device).press(0, touch0Pos);
434−
435− QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Undecided);
436−
437− // leave it lying around for some time
438− passTime(edgeDragArea->d->maxTime * 10);
439−
440− QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch);
441−
442− qreal desiredDragDistance = edgeDragArea->d->distanceThreshold * 2.0f;
443− QPointF dragDirectionVector(1.0f, 0.0f);
444−
445− qreal movementStepDistance = edgeDragArea->d->distanceThreshold * 0.1f;
446− QPointF touchMovement = dragDirectionVector * movementStepDistance;
447− int totalMovementSteps = qCeil(desiredDragDistance / movementStepDistance);
448− int movementTimeStepMs = (edgeDragArea->d->compositionTime * 1.5f) / totalMovementSteps;
449−
450− QTest::touchEvent(m_view, m_device)
451− .move(0, touch0Pos)
452− .press(1, touch1Pos);
453−
454− QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Undecided);
455−
456− for (int i = 0; i < totalMovementSteps; ++i) {
457− touch1Pos += touchMovement.toPoint();
458− passTime(movementTimeStepMs);
459− QTest::touchEvent(m_view, m_device)
460− .move(0, touch0Pos)
461− .move(1, touch1Pos);
462− }
463−
464− QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Recognized);
465−
466− QTest::touchEvent(m_view, m_device)
467− .move(0, touch0Pos)
468− .release(1, touch1Pos);
469−
470− QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch);
471−}
472−
473−/*
474− A Rightwards DDA that is rotated 90 degrees clockwise should recognize gestures
475− that are done downwards in scene coordinates. I.e. the gesture recognition direction
476− should be in local coordinates, not scene coordinates.
477− */
478−void tst_DirectionalDragArea::rotated()
479−{
480− QQuickItem *baseItem = m_view->rootObject()->findChild<QQuickItem*>("baseItem");
481− baseItem->setRotation(90.);
482−
483− QQuickItem *rightwardsLauncher = m_view->rootObject()->findChild<QQuickItem*>("rightwardsLauncher");
484− Q_ASSERT(rightwardsLauncher != 0);
485−
486− DirectionalDragArea *edgeDragArea =
487− rightwardsLauncher->findChild<DirectionalDragArea*>("hpDragArea");
488− Q_ASSERT(edgeDragArea != 0);
489− edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer(edgeDragArea));
490− edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
491−
492− QPointF initialTouchPos = calculateInitialTouchPos(edgeDragArea);
493− QPointF touchPoint = initialTouchPos;
494−
495− qreal desiredDragDistance = edgeDragArea->d->distanceThreshold * 2.0f;
496− QPointF dragDirectionVector(0.0f, 1.0f);
497−
498− qreal movementStepDistance = edgeDragArea->d->distanceThreshold * 0.1f;
499− QPointF touchMovement = dragDirectionVector * movementStepDistance;
500− int totalMovementSteps = qCeil(desiredDragDistance / movementStepDistance);
501− int movementTimeStepMs = (edgeDragArea->d->compositionTime * 1.5f) / totalMovementSteps;
502−
503− QTest::touchEvent(m_view, m_device).press(0, touchPoint.toPoint());
504−
505− for (int i = 0; i < totalMovementSteps; ++i) {
506− touchPoint += touchMovement;
507− passTime(movementTimeStepMs);
508− QTest::touchEvent(m_view, m_device).move(0, touchPoint.toPoint());
509− }
510−
511− QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Recognized);
512−
513− QTest::touchEvent(m_view, m_device).release(0, touchPoint.toPoint());
514−}
515−
516−void tst_DirectionalDragArea::sceneDistance()
517−{
518− QQuickItem *baseItem = m_view->rootObject()->findChild<QQuickItem*>("baseItem");
519− QFETCH(qreal, rotation);
520− QFETCH(QPointF, dragDirectionVector);
521− baseItem->setRotation(rotation);
522−
523− QQuickItem *rightwardsLauncher = m_view->rootObject()->findChild<QQuickItem*>("rightwardsLauncher");
524− Q_ASSERT(rightwardsLauncher != 0);
525−
526− DirectionalDragArea *edgeDragArea =
527− rightwardsLauncher->findChild<DirectionalDragArea*>("hpDragArea");
528− Q_ASSERT(edgeDragArea != 0);
529− edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer(edgeDragArea));
530− edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
531−
532− // to disable the position smoothing so that we can more easily check sceneDistance values
533− edgeDragArea->setImmediateRecognition(true);
534−
535− QPointF initialTouchPos = calculateInitialTouchPos(edgeDragArea);
536− QPointF touchPoint = initialTouchPos;
537−
538− qreal desiredDragDistance = edgeDragArea->d->distanceThreshold * 2.0f;
539−
540− qreal movementStepDistance = edgeDragArea->d->distanceThreshold * 0.1f;
541− QPointF touchMovement = dragDirectionVector * movementStepDistance;
542− int totalMovementSteps = qCeil(desiredDragDistance / movementStepDistance);
543− int movementTimeStepMs = (edgeDragArea->d->compositionTime * 1.5f) / totalMovementSteps;
544−
545− qint64 timestamp = 0;
546−
547− sendTouchPress(timestamp, 0, touchPoint);
548−
549− for (int i = 0; i < totalMovementSteps; ++i) {
550− touchPoint += touchMovement;
551− timestamp += movementTimeStepMs;
552− sendTouchUpdate(timestamp, 0, touchPoint);
553− }
554−
555− qreal actualDragDistance = ((qreal)totalMovementSteps) * movementStepDistance;
556−
557− // DirectionalDragArea::sceneDistance() must match the actual drag distance as the
558− // drag was aligned with the gesture direction
559− // NB: qFuzzyCompare(), used internally by QCOMPARE(), is broken.
560− QVERIFY(qAbs(edgeDragArea->sceneDistance() - actualDragDistance) < 0.001);
561−
562− timestamp += movementTimeStepMs;
563− sendTouchRelease(timestamp, 0, touchPoint);
564−}
565−
566−void tst_DirectionalDragArea::sceneDistance_data()
567−{
568− QTest::addColumn<qreal>("rotation");
569− QTest::addColumn<QPointF>("dragDirectionVector");
570−
571− QTest::newRow("not rotated") << 0. << QPointF(1., 0.);
572− QTest::newRow("rotated by 90 degrees") << 90. << QPointF(0., 1.);
573−}
574−
575−/*
576− Regression test for https://bugs.launchpad.net/unity8/+bug/1276122
577−
578− The bug:
579− If setting "enabled: false" while the DirectionalDragArea's (DDA) dragging
580− property is true, the DDA stays in that state and doesn't recover any more.
581−*/
582−void tst_DirectionalDragArea::disabledWhileDragging()
583−{
584− DirectionalDragArea *edgeDragArea =
585− m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
586− Q_ASSERT(edgeDragArea != 0);
587− edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer(edgeDragArea));
588− edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
589−
590− QPointF touchPoint = calculateInitialTouchPos(edgeDragArea);
591−
592− qreal desiredDragDistance = edgeDragArea->d->distanceThreshold * 2.0f;
593− QPointF dragDirectionVector(1., 0.); // horizontal positive
594−
595− qreal movementStepDistance = edgeDragArea->d->distanceThreshold * 0.1f;
596− QPointF touchMovement = dragDirectionVector * movementStepDistance;
597− int totalMovementSteps = qCeil(desiredDragDistance / movementStepDistance);
598− int movementTimeStepMs = (edgeDragArea->d->compositionTime * 1.5f) / totalMovementSteps;
599−
600− QTest::touchEvent(m_view, m_device).press(0, touchPoint.toPoint());
601−
602− for (int i = 0; i < totalMovementSteps; ++i) {
603− touchPoint += touchMovement;
604− passTime(movementTimeStepMs);
605− QTest::touchEvent(m_view, m_device).move(0, touchPoint.toPoint());
606− }
607−
608− QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Recognized);
609− QCOMPARE(edgeDragArea->dragging(), true);
610−
611− // disable the dragArea while it's being dragged.
612− edgeDragArea->setEnabled(false);
613−
614− QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch);
615− QCOMPARE(edgeDragArea->dragging(), false);
616−
617− QTest::touchEvent(m_view, m_device).release(0, touchPoint.toPoint());
618−}
619−
620−void tst_DirectionalDragArea::oneFingerDownFollowedByLateSecondFingerDown()
621−{
622− DirectionalDragArea *edgeDragArea =
623− m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
624− Q_ASSERT(edgeDragArea != 0);
625− edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer(edgeDragArea));
626− edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
627−
628− // Disable some constraints we're not interested in
629− edgeDragArea->d->setMaxTime(60 * 1000);
630−
631− // And ensure others have the values we want
632− edgeDragArea->d->compositionTime = 60;
633−
634− // Put an item right behind edgeDragArea to receive the touches ignored by it
635− DummyItem *dummyItem = new DummyItem;
636− dummyItem->setParentItem(edgeDragArea->parentItem());
637− dummyItem->setX(edgeDragArea->x());
638− dummyItem->setY(edgeDragArea->y());
639− dummyItem->setZ(edgeDragArea->z() - 1.0);
640− dummyItem->setWidth(edgeDragArea->width());
641− dummyItem->setHeight(edgeDragArea->height());
642−
643− // Make touches evenly spaced along the edgeDragArea
644− QPoint touch0Pos(edgeDragArea->width()/2.0f, m_view->height()*0.33f);
645− QPoint touch1Pos(edgeDragArea->width()/2.0f, m_view->height()*0.66f);
646−
647− QTest::touchEvent(m_view, m_device).press(0, touch0Pos);
648−
649− QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Undecided);
650−
651− // We are now going to be way beyond compositionTime
652− passTime(edgeDragArea->d->compositionTime*3);
653−
654− QTest::touchEvent(m_view, m_device)
655− .move(0, touch0Pos)
656− .press(1, touch1Pos);
657−
658− // A new touch has come, but as it can't be composed with touch 0, it should be
659− // ignored/rejected by the DirectionalDragArea
660− // Therefore the last event received by dummyItem must have both touch points (0 and 1)
661− {
662− TouchMemento &touchMemento = dummyItem->touchEvents.last();
663− QCOMPARE(touchMemento.touchPoints.count(), 2);
664− QVERIFY(touchMemento.containsTouchWithId(0));
665− QVERIFY(touchMemento.containsTouchWithId(1));
666− }
667−
668− passTime(30);
669−
670− QTest::touchEvent(m_view, m_device)
671− .move(0, touch0Pos)
672− .move(1, touch1Pos);
673−
674− QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Undecided);
675−
676− passTime(5);
677−
678− QTest::touchEvent(m_view, m_device)
679− .release(0, touch0Pos)
680− .move(1, touch1Pos);
681−
682− QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch);
683−
684− passTime(5);
685−
686− QTest::touchEvent(m_view, m_device)
687− .release(1, touch1Pos);
688−
689− // Shouldn't be keepping info about touches that no longer exist or interest us
690− QVERIFY(edgeDragArea->d->activeTouches.isEmpty());
691−
692− delete dummyItem;
693−}
694−
695−void tst_DirectionalDragArea::givesUpWhenLosesTouch()
696−{
697− DirectionalDragArea *edgeDragArea =
698− m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
699− Q_ASSERT(edgeDragArea != 0);
700− edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer(edgeDragArea));
701− edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
702−
703− // Disable some constraints we're not interested in
704− edgeDragArea->d->setMaxTime(60 * 1000);
705−
706− // Put an item right in front of edgeDragArea
707− DummyItem *dummyItem = new DummyItem(edgeDragArea->parentItem());
708− dummyItem->setX(edgeDragArea->x());
709− dummyItem->setY(edgeDragArea->y());
710− dummyItem->setZ(edgeDragArea->z() + 1.0);
711− dummyItem->setWidth(edgeDragArea->width());
712− dummyItem->setHeight(edgeDragArea->height());
713−
714− QPoint touchPos(edgeDragArea->width()/2.0f, m_view->height()/2.0f);
715−
716− dummyItem->touchEventHandler = [&](QTouchEvent *event) {
717− m_touchRegistry->addCandidateOwnerForTouch(0, dummyItem);
718− event->ignore();
719− };
720−
721− QTest::touchEvent(m_view, m_device).press(0, touchPos);
722−
723− QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Undecided);
724−
725− m_touchRegistry->requestTouchOwnership(0, dummyItem);
726−
727− QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch);
728−
729− dummyItem->grabTouchPoints({0});
730− dummyItem->touchEventHandler = [&](QTouchEvent *event) { event->accept(); };
731−
732− passTime(5);
733− QTest::touchEvent(m_view, m_device).release(0, touchPos);
734−
735− QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch);
736−
737− QVERIFY(edgeDragArea->d->activeTouches.isEmpty());
738−}
739−
740−void tst_DirectionalDragArea::threeFingerDrag()
741−{
742− DirectionalDragArea *edgeDragArea =
743− m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
744− Q_ASSERT(edgeDragArea != 0);
745− edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer(edgeDragArea));
746− edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
747−
748− // Disable some constraints we're not interested in
749− edgeDragArea->d->setMaxTime(60 * 1000);
750−
751− // And ensure others have the values we want
752− edgeDragArea->d->compositionTime = 60;
753−
754− // Make touches evenly spaced along the edgeDragArea
755− QPoint touch0Pos(edgeDragArea->width()/2.0f, m_view->height()*0.25f);
756− QPoint touch1Pos(edgeDragArea->width()/2.0f, m_view->height()*0.50f);
757− QPoint touch2Pos(edgeDragArea->width()/2.0f, m_view->height()*0.75f);
758−
759− QTest::touchEvent(m_view, m_device)
760− .press(0, touch0Pos);
761−
762− QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Undecided);
763−
764− passTime(5);
765− QTest::touchEvent(m_view, m_device)
766− .move(0, touch0Pos)
767− .press(1, touch1Pos);
768−
769− QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch);
770−
771− passTime(5);
772− QTest::touchEvent(m_view, m_device)
773− .move(0, touch0Pos)
774− .move(1, touch1Pos)
775− .press(2, touch2Pos);
776−
777− QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch);
778−
779− passTime(10);
780− QTest::touchEvent(m_view, m_device)
781− .move(0, touch0Pos)
782− .move(1, touch1Pos)
783− .move(2, touch2Pos);
784−
785− passTime(200);
786− QTest::touchEvent(m_view, m_device)
787− .move(0, touch0Pos)
788− .release(1, touch1Pos)
789− .move(2, touch2Pos);
790−
791− passTime(10);
792− QTest::touchEvent(m_view, m_device)
793− .move(0, touch0Pos)
794− .release(2, touch2Pos);
795−
796− passTime(5);
797− QTest::touchEvent(m_view, m_device)
798− .release(0, touch0Pos);
799−
800− // Shouldn't be keepping info about touches that no longer exist or interest us
801− QVERIFY(edgeDragArea->d->activeTouches.isEmpty());
802−}
803−
804−/*
805− If all the relevant gesture recognition constraints/parameters have been disabled,
806− it means that the gesture recognition itself has been disabled and DirectionalDragArea
807− will therefore work like a simple touch area, merely reporting touch movement.
808− */
809−void tst_DirectionalDragArea::immediateRecognitionWhenConstraintsDisabled()
810−{
811− DirectionalDragArea *edgeDragArea =
812− m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
813− Q_ASSERT(edgeDragArea != 0);
814− edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer(edgeDragArea));
815− edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
816−
817− // Disable the minimum amount of constraints to ensure immediate recognition
818− edgeDragArea->d->setDistanceThreshold(0);
819− edgeDragArea->d->compositionTime = 0;
820−
821− // Put an item right behind edgeDragArea to receive the touches ignored by it
822− DummyItem *dummyItem = new DummyItem;
823− dummyItem->setParentItem(edgeDragArea->parentItem());
824− dummyItem->setX(edgeDragArea->x());
825− dummyItem->setY(edgeDragArea->y());
826− dummyItem->setZ(edgeDragArea->z() - 1.0);
827− dummyItem->setWidth(edgeDragArea->width());
828− dummyItem->setHeight(edgeDragArea->height());
829−
830− QPoint touch0Pos(edgeDragArea->width()/2.0f, m_view->height()/2.0f);
831−
832− QTest::touchEvent(m_view, m_device).press(0, touch0Pos);
833−
834− // check for immediate recognition
835− QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Recognized);
836−
837− // and therefore it should have immediately grabbed the touch point,
838− // not letting it leak to items behind him.
839− QCOMPARE(dummyItem->touchEvents.count(), 0);
840−}
841−
842−void tst_DirectionalDragArea::withdrawTouchOwnershipCandidacyIfDisabledDuringRecognition()
843−{
844− DirectionalDragArea *edgeDragArea =
845− m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
846− Q_ASSERT(edgeDragArea != 0);
847− edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer(edgeDragArea));
848− edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
849−
850− QPointF touchPoint = calculateInitialTouchPos(edgeDragArea);
851−
852− // Move less than the minimum needed for the drag gesture recognition
853− qreal desiredDragDistance = edgeDragArea->d->distanceThreshold * 0.5f;
854− QPointF dragDirectionVector(1., 0.); // horizontal positive
855−
856− qreal movementStepDistance = edgeDragArea->d->distanceThreshold * 0.1f;
857− QPointF touchMovement = dragDirectionVector * movementStepDistance;
858− int totalMovementSteps = qCeil(desiredDragDistance / movementStepDistance);
859− int movementTimeStepMs = (edgeDragArea->d->compositionTime * 0.8f) / totalMovementSteps;
860−
861− QTest::touchEvent(m_view, m_device).press(0, touchPoint.toPoint());
862−
863− for (int i = 0; i < totalMovementSteps; ++i) {
864− touchPoint += touchMovement;
865− passTime(movementTimeStepMs);
866− QTest::touchEvent(m_view, m_device).move(0, touchPoint.toPoint());
867− }
868−
869− QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Undecided);
870−
871− // edgeDragArea should be an undecided candidate
872− {
873− auto touchInfo = m_touchRegistry->findTouchInfo(0);
874− QCOMPARE(touchInfo->candidates.size(), 1);
875− QCOMPARE(touchInfo->candidates.at(0).item.data(), edgeDragArea);
876− QCOMPARE(touchInfo->candidates.at(0).state, TouchRegistry::CandidateInfo::Undecided);
877− }
878−
879− // disable the dragArea while it's still recognizing a possible drag gesture.
880− QFETCH(bool, disable);
881− if (disable) {
882− edgeDragArea->setEnabled(false);
883− } else {
884− edgeDragArea->setVisible(false);
885− }
886−
887− // edgeDragArea should no longer be a candidate
888− {
889− auto touchInfo = m_touchRegistry->findTouchInfo(0);
890− QCOMPARE(touchInfo->candidates.size(), 0);
891− }
892−
893− QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch);
894−
895− QTest::touchEvent(m_view, m_device).release(0, touchPoint.toPoint());
896−}
897−
898−void tst_DirectionalDragArea::withdrawTouchOwnershipCandidacyIfDisabledDuringRecognition_data()
899−{
900− QTest::addColumn<bool>("disable");
901−
902− QTest::newRow("disabled") << true;
903− QTest::newRow("invisible") << false;
904−}
905−
906−void tst_DirectionalDragArea::gettingTouchOwnershipMakesMouseAreaBehindGetCanceled()
907−{
908− DirectionalDragArea *edgeDragArea =
909− m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
910− QVERIFY(edgeDragArea != nullptr);
911− edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer(edgeDragArea));
912− edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
913−
914− QQuickMouseArea *mouseArea =
915− m_view->rootObject()->findChild<QQuickMouseArea*>("mouseArea");
916− QVERIFY(mouseArea != nullptr);
917−
918− MouseAreaSpy mouseAreaSpy(mouseArea);
919−
920− QPointF initialTouchPos = calculateInitialTouchPos(edgeDragArea);
921− QPointF touchPoint = initialTouchPos;
922−
923− qreal desiredDragDistance = edgeDragArea->d->distanceThreshold * 2;
924− QPointF dragDirectionVector(1.0f, 0.0f); // rightwards
925− qreal movementStepDistance = edgeDragArea->d->distanceThreshold * 0.1f;
926− QPointF touchMovement = dragDirectionVector * movementStepDistance;
927− int totalMovementSteps = qCeil(desiredDragDistance / movementStepDistance);
928− int movementTimeStepMs = (edgeDragArea->d->compositionTime * 1.5f) / totalMovementSteps;
929−
930− QCOMPARE(mouseArea->pressed(), false);
931−
932− QTest::touchEvent(m_view, m_device).press(0, touchPoint.toPoint());
933−
934− // The TouchBegin passes through the DirectionalDragArea and reaches the MouseArea behind it,
935− // where it's converted to a MouseEvent by QQuickWindow and sent to the MouseArea which then
936− // accepts it. Making it get pressed.
937− QCOMPARE(mouseArea->pressed(), true);
938− QCOMPARE(mouseAreaSpy.canceledCount, 0);
939−
940− for (int i = 0; i < totalMovementSteps; ++i) {
941− touchPoint += touchMovement;
942− passTime(movementTimeStepMs);
943− QTest::touchEvent(m_view, m_device).move(0, touchPoint.toPoint());
944− }
945−
946− // As the DirectionalDragArea recognizes the gesture, it grabs the touch from the MouseArea,
947− // which should make the MouseArea get a cancelation event, which will then cause it to
948− // reset its state (going back to "unpressed"/"released").
949− QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Recognized);
950− QCOMPARE(mouseArea->pressed(), false);
951− QCOMPARE(mouseAreaSpy.canceledCount, 1);
952−
953− QTest::touchEvent(m_view, m_device).release(0, touchPoint.toPoint());
954−}
955−
956−void tst_DirectionalDragArea::interleavedTouches()
957−{
958− DirectionalDragArea *edgeDragArea =
959− m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
960− QVERIFY(edgeDragArea != 0);
961− edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer(edgeDragArea));
962− edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
963−
964− QPointF touch0 = edgeDragArea->mapToScene(
965− QPointF(edgeDragArea->width()*0.5, edgeDragArea->height()*0.3));
966−
967− qreal desiredDragDistance = edgeDragArea->d->distanceThreshold * 2;
968− QPointF dragDirectionVector(1.0f, 0.0f); // rightwards
969− qreal movementStepDistance = edgeDragArea->d->distanceThreshold * 0.1f;
970− QPointF touchMovement = dragDirectionVector * movementStepDistance;
971− int totalMovementSteps = qCeil(desiredDragDistance / movementStepDistance);
972− int movementTimeStepMs = (edgeDragArea->d->maxTime * 0.4f) / totalMovementSteps;
973−
974− QTest::touchEvent(m_view, m_device).press(0, touch0.toPoint());
975− for (int i = 0; i < totalMovementSteps; ++i) {
976− touch0 += touchMovement;
977− passTime(movementTimeStepMs);
978− QTest::touchEvent(m_view, m_device).move(0, touch0.toPoint());
979− }
980− QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Recognized);
981−
982− QPointF touch1 = edgeDragArea->mapToScene(
983− QPointF(edgeDragArea->width()*0.5, edgeDragArea->height()*0.6));
984−
985− QTest::touchEvent(m_view, m_device)
986− .move(0, touch0.toPoint())
987− .press(1, touch1.toPoint());
988−
989− touch1 += touchMovement;
990− passTime(movementTimeStepMs);
991− QTest::touchEvent(m_view, m_device)
992− .move(0, touch0.toPoint())
993− .move(1, touch1.toPoint());
994−
995− QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Recognized);
996−
997− QTest::touchEvent(m_view, m_device)
998− .release(0, touch0.toPoint())
999− .move(1, touch1.toPoint());
1000−
1001− QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch);
1002−
1003− touch1 += touchMovement;
1004− passTime(movementTimeStepMs);
1005− QTest::touchEvent(m_view, m_device)
1006− .move(1, touch1.toPoint());
1007−
1008− QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch);
1009−
1010− QPointF touch2 = edgeDragArea->mapToScene(
1011− QPointF(edgeDragArea->width()*0.5, edgeDragArea->height()*0.9));
1012−
1013− passTime(edgeDragArea->d->compositionTime + movementTimeStepMs);
1014− QTest::touchEvent(m_view, m_device)
1015− .move(1, touch1.toPoint())
1016− .press(2, touch2.toPoint());
1017−
1018− QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Undecided);
1019− QCOMPARE(edgeDragArea->d->touchId, 2);
1020−
1021− touch2 += touchMovement;
1022− passTime(movementTimeStepMs);
1023− QTest::touchEvent(m_view, m_device)
1024− .move(1, touch1.toPoint())
1025− .move(2, touch2.toPoint());
1026−
1027− touch1 += touchMovement;
1028− passTime(movementTimeStepMs);
1029− QTest::touchEvent(m_view, m_device)
1030− .move(1, touch1.toPoint())
1031− .move(2, touch2.toPoint());
1032−
1033− passTime(movementTimeStepMs);
1034− QTest::touchEvent(m_view, m_device)
1035− .release(1, touch1.toPoint())
1036− .move(2, touch2.toPoint());
1037−
1038− passTime(movementTimeStepMs);
1039− QTest::touchEvent(m_view, m_device)
1040− .release(2, touch2.toPoint());
1041−
1042− QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch);
1043−}
1044−
1045−/*
1046− A valid right-edge drag performed on mako
1047− */
1048−void tst_DirectionalDragArea::makoRightEdgeDrag()
1049−{
1050− m_view->resize(768, 1280);
1051− QTest::qWait(300);
1052−
1053− DirectionalDragArea *edgeDragArea =
1054− m_view->rootObject()->findChild<DirectionalDragArea*>("hnDragArea");
1055− QVERIFY(edgeDragArea != nullptr);
1056− edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer(edgeDragArea));
1057− edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
1058−
1059− StatusSpy *statusSpy = new StatusSpy(edgeDragArea);
1060−
1061− edgeDragArea->d->setPixelsPerMm(320.0 /*mako ppi*/ * 0.03937 /* inches per mm*/);
1062−
1063− sendTouchPress(319744, 0, QPointF(767.001, 719.719));
1064− sendTouchUpdate(319765, 0, QPointF(765.744,729.973));
1065− sendTouchUpdate(319784, 0, QPointF(740.879,752.182));
1066− sendTouchUpdate(319803, 0, QPointF(689.698,795.795));
1067− sendTouchUpdate(319826, 0, QPointF(616.978,856.212));
1068− sendTouchUpdate(319845, 0, QPointF(558.769,906.157));
1069− sendTouchUpdate(319859, 0, QPointF(513.219,945.266));
1070− sendTouchUpdate(319878, 0, QPointF(481.31,975.496));
1071− sendTouchUpdate(319902, 0, QPointF(460.016,997.439));
1072− sendTouchUpdate(319920, 0, QPointF(449.761,1008.6));
1073− sendTouchUpdate(319929, 0, QPointF(445.891,1012.42));
1074− sendTouchUpdate(319947, 0, QPointF(444.884,1013.93));
1075− sendTouchUpdate(319965, 0, QPointF(444.461,1014.35));
1076− sendTouchUpdate(320057, 0, QPointF(444.71,1013.56));
1077− sendTouchUpdate(320138, 0, QPointF(445.434,1013.6));
1078− sendTouchUpdate(320154, 0, QPointF(446.338,1012.98));
1079− sendTouchUpdate(320171, 0, QPointF(447.232,1012.08));
1080− sendTouchRelease(320171, 0, QPointF(447.232,1012.08));
1081−
1082− QCOMPARE(statusSpy->recognized(), true);
1083−
1084− delete statusSpy;
1085−}
1086−
1087−/*
1088− A vertical, downwards swipe performed on mako near its right edge.
1089−
1090− The DirectionalDragArea on the right edge must not recognize this
1091− gesture.
1092− */
1093−void tst_DirectionalDragArea::makoRightEdgeDrag_verticalDownwards()
1094−{
1095− m_view->resize(768, 1280);
1096− QTest::qWait(300);
1097−
1098− DirectionalDragArea *edgeDragArea =
1099− m_view->rootObject()->findChild<DirectionalDragArea*>("hnDragArea");
1100− QVERIFY(edgeDragArea != nullptr);
1101− edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer(edgeDragArea));
1102− edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
1103−
1104− edgeDragArea->d->setPixelsPerMm(320.0 /*mako ppi*/ * 0.03937 /* inches per mm*/);
1105−
1106− StatusSpy *statusSpy = new StatusSpy(edgeDragArea);
1107−
1108− sendTouchPress(12012445, 26, QPointF(767.001,461.82));
1109− sendTouchUpdate(12012472, 26, QPointF(767.001,462.569));
1110− sendTouchUpdate(12012528, 26, QPointF(767.001,463.334));
1111− sendTouchUpdate(12012546, 26, QPointF(767.001,466.856));
1112− sendTouchUpdate(12012571, 26, QPointF(767.001,473.291));
1113− sendTouchUpdate(12012587, 26, QPointF(767.001,487.31));
1114− sendTouchUpdate(12012604, 26, QPointF(765.364,507.521));
1115− sendTouchUpdate(12012618, 26, QPointF(765.364,507.521));
1116− sendTouchUpdate(12012627, 26, QPointF(762.642,534.317));
1117− sendTouchUpdate(12012655, 26, QPointF(760.846,573.406));
1118− sendTouchUpdate(12012667, 26, QPointF(759.838,625.295));
1119− sendTouchUpdate(12012675, 26, QPointF(758.875,703.207));
1120− sendTouchUpdate(12012696, 26, QPointF(761.52,777.015));
1121− sendTouchUpdate(12012713, 26, QPointF(765.659,835.591));
1122− sendTouchUpdate(12012731, 26, QPointF(766.778,883.206));
1123− sendTouchUpdate(12012748, 26, QPointF(767.001,922.937));
1124− sendTouchUpdate(12012779, 26, QPointF(767.001,967.558));
1125− sendTouchUpdate(12012798, 26, QPointF(767.001,1006.12));
1126− sendTouchUpdate(12012809, 26, QPointF(767.001,1033.1));
1127− sendTouchRelease(12012810, 26, QPointF(767.001,1033.1));
1128−
1129− QCOMPARE(statusSpy->recognized(), false);
1130−
1131− delete statusSpy;
1132−}
1133−
1134−/*
1135− A valid left-edge drag performed on mako. This one starts a bit slow than speeds up
1136− */
1137−void tst_DirectionalDragArea::makoLeftEdgeDrag_slowStart()
1138−{
1139− m_view->resize(768, 1280);
1140− QTest::qWait(300);
1141−
1142− DirectionalDragArea *edgeDragArea =
1143− m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
1144− QVERIFY(edgeDragArea != nullptr);
1145− edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer(edgeDragArea));
1146− edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
1147−
1148− edgeDragArea->d->setPixelsPerMm(320.0 /*mako ppi*/ * 0.03937 /* inches per mm*/);
1149−
1150− StatusSpy *statusSpy = new StatusSpy(edgeDragArea);
1151−
1152− sendTouchPress(4002267, 77, QPointF(0,885.154));
1153− sendTouchUpdate(4002275, 77, QPointF(0,886.214));
1154− sendTouchUpdate(4002311, 77, QPointF(1.09568,887.75));
1155− sendTouchUpdate(4002329, 77, QPointF(3.53647,890.191));
1156− sendTouchUpdate(4002347, 77, QPointF(7.87434,892.879));
1157− sendTouchUpdate(4002366, 77, QPointF(12.3036,895.075));
1158− sendTouchUpdate(4002384, 77, QPointF(15.8885,896.849));
1159− sendTouchUpdate(4002406, 77, QPointF(18.4504,897.88));
1160− sendTouchUpdate(4002420, 77, QPointF(20.2429,898.149));
1161− sendTouchUpdate(4002439, 77, QPointF(20.9945,898.149));
1162− sendTouchUpdate(4002457, 77, QPointF(21.8819,898.149));
1163− sendTouchUpdate(4002480, 77, QPointF(22.7454,897.389));
1164− sendTouchUpdate(4002493, 77, QPointF(23.5456,896.589));
1165− sendTouchUpdate(4002511, 77, QPointF(24.5435,895.031));
1166− sendTouchUpdate(4002529, 77, QPointF(25.4271,892.32));
1167− sendTouchUpdate(4002548, 77, QPointF(26.3145,889.658));
1168− sendTouchUpdate(4002566, 77, QPointF(27.2004,886.999));
1169− sendTouchUpdate(4002584, 77, QPointF(28.035,885.048));
1170− sendTouchUpdate(4002603, 77, QPointF(29.9684,883.167));
1171− sendTouchUpdate(4002620, 77, QPointF(33.3591,881.403));
1172− sendTouchUpdate(4002639, 77, QPointF(44.1017,879.642));
1173− sendTouchUpdate(4002657, 77, QPointF(64.828,878.502));
1174− sendTouchUpdate(4002675, 77, QPointF(87.9486,878.157));
1175− sendTouchUpdate(4002693, 77, QPointF(112.96,877.742));
1176− sendTouchUpdate(4002711, 77, QPointF(138.903,877.157));
1177− sendTouchUpdate(4002729, 77, QPointF(163.204,877.157));
1178− sendTouchUpdate(4002747, 77, QPointF(182.127,877.157));
1179− sendTouchUpdate(4002765, 77, QPointF(194.478,877.657));
1180− sendTouchUpdate(4002785, 77, QPointF(201.474,878.508));
1181− sendTouchUpdate(4002803, 77, QPointF(204.855,879.401));
1182− sendTouchUpdate(4002822, 77, QPointF(206.616,880.281));
1183− sendTouchUpdate(4002839, 77, QPointF(207.115,880.906));
1184− sendTouchUpdate(4002894, 77, QPointF(206.865,881.184));
1185− sendTouchUpdate(4002912, 77, QPointF(206.865,882.143));
1186− sendTouchUpdate(4002930, 77, QPointF(206.865,883.106));
1187− sendTouchUpdate(4002949, 77, QPointF(206.526,883.994));
1188− sendTouchUpdate(4002967, 77, QPointF(205.866,884.88));
1189− sendTouchUpdate(4002985, 77, QPointF(205.866,885.766));
1190− sendTouchUpdate(4003005, 77, QPointF(205.866,886.654));
1191− sendTouchUpdate(4003021, 77, QPointF(205.366,887.537));
1192− sendTouchUpdate(4003039, 77, QPointF(204.592,888.428));
1193− sendTouchUpdate(4003050, 77, QPointF(204.367,888.653));
1194− sendTouchRelease(4003050, 77, QPointF(204.367,888.653));
1195−
1196− QCOMPARE(statusSpy->recognized(), true);
1197−
1198− delete statusSpy;
1199−}
1200−
1201−void tst_DirectionalDragArea::makoLeftEdgeDrag_movesSlightlyBackwardsOnStart()
1202−{
1203− m_view->resize(768, 1280);
1204− QTest::qWait(300);
1205−
1206− DirectionalDragArea *edgeDragArea =
1207− m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
1208− QVERIFY(edgeDragArea != nullptr);
1209− edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer(edgeDragArea));
1210− edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
1211−
1212− edgeDragArea->d->setPixelsPerMm(320.0 /*mako ppi*/ * 0.03937 /* inches per mm*/);
1213−
1214− StatusSpy *statusSpy = new StatusSpy(edgeDragArea);
1215−
1216− sendTouchPress(41097, 24, QPointF(13.9909,827.177));
1217− sendTouchUpdate(41120, 24, QPointF(19.2375,825.677));
1218− sendTouchUpdate(41138, 24, QPointF(18.4057,826.177));
1219− sendTouchUpdate(41161, 24, QPointF(20.1067,825.867));
1220− sendTouchUpdate(41177, 24, QPointF(21.8869,824.977));
1221− sendTouchUpdate(41193, 24, QPointF(24.7603,823.494));
1222− sendTouchUpdate(41211, 24, QPointF(28.3889,821.725));
1223− sendTouchUpdate(41229, 24, QPointF(32.2909,819.955));
1224− sendTouchUpdate(41247, 24, QPointF(38.2251,817.431));
1225− sendTouchUpdate(41266, 24, QPointF(52.4182,814.223));
1226− sendTouchUpdate(41284, 24, QPointF(85.8465,809.483));
1227− sendTouchUpdate(41302, 24, QPointF(126.091,802.741));
1228− sendTouchUpdate(41320, 24, QPointF(153.171,797.977));
1229− sendTouchUpdate(41338, 24, QPointF(170.565,795.077));
1230− sendTouchUpdate(41356, 24, QPointF(178.685,794.101));
1231− sendTouchUpdate(41375, 24, QPointF(183.706,793.225));
1232− sendTouchUpdate(41393, 24, QPointF(186.112,793.19));
1233− sendTouchUpdate(41411, 24, QPointF(187.634,793.19));
1234− sendTouchUpdate(41429, 24, QPointF(188.505,793.19));
1235− sendTouchUpdate(41532, 24, QPointF(187.816,793.19));
1236− sendTouchUpdate(41538, 24, QPointF(186.902,793.19));
1237− sendTouchUpdate(41557, 24, QPointF(186.01,793.19));
1238− sendTouchUpdate(41575, 24, QPointF(185.125,793.444));
1239− sendTouchUpdate(41593, 24, QPointF(184.229,793.69));
1240− sendTouchUpdate(41605, 24, QPointF(183.88,793.69));
1241− sendTouchRelease(41607, 24, QPointF(183.88,793.69));
1242−
1243− QCOMPARE(statusSpy->recognized(), true);
1244−
1245− delete statusSpy;
1246−}
1247−
1248−QTEST_MAIN(tst_DirectionalDragArea)
1249−
1250−#include "tst_DirectionalDragArea.moc"
tests/plugins/Ubuntu/Gestures/tst_DirectionalDragArea.qmldeleted−76
@@ -1,76 +0,0 @@
1−/*
2− * Copyright (C) 2013,2015 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.4
18−import Ubuntu.Components 1.3
19−import Unity.Test 0.1
20−
21−Rectangle {
22− width: units.gu(60)
23− height: units.gu(60)
24− color: "white"
25−
26− Binding {
27− target: MouseTouchAdaptor
28− property: "enabled"
29− value: true
30− }
31−
32− MouseArea {
33− id: mouseArea
34− objectName: "mouseArea"
35− anchors.fill: parent
36− onClicked: {
37− hpLauncher.reset()
38− hnLauncher.reset()
39− vpLauncher.reset()
40− vnLauncher.reset()
41− }
42− }
43−
44− Item {
45− id: baseItem
46− objectName: "baseItem"
47− width: parent.width
48− height: parent.height
49−
50− // NB: Do not anchor it as we will move it programmatically from the test
51− RightwardsLauncher {
52− id: hpLauncher;
53− width: parent.width
54− height: parent.height
55− }
56−
57− LeftwardsLauncher { id: hnLauncher; anchors.fill: parent }
58− DownwardsLauncher { id: vpLauncher; anchors.fill: parent }
59− UpwardsLauncher { id: vnLauncher; anchors.fill: parent }
60− }
61−
62− Button {
63− anchors.bottom: parent.bottom
64− anchors.left: parent.left
65− anchors.margins: units.gu(1)
66−
67− text: "rotation: " + baseItem.rotation
68− onClicked: {
69− if (baseItem.rotation === 0.0) {
70− baseItem.rotation = 90.0
71− } else {
72− baseItem.rotation = 0.0
73− }
74− }
75− }
76−}
tests/plugins/Ubuntu/Gestures/tst_FloatingFlickable.cpp+25−18
@@ -17,12 +17,9 @@
1717#include <QtTest>
1818#include <QQuickView>
1919
20−// Ubuntu.Gestures plugin
21−#include <DirectionalDragArea.h>
22−#include <FloatingFlickable.h>
23−
2420#include "GestureTest.h"
2521#include "TestItem.h"
22+#include "Direction.h"
2623
2724using namespace UbuntuGestures;
2825
@@ -44,8 +41,8 @@ tst_FloatingFlickable::tst_FloatingFlickable()
4441
4542void tst_FloatingFlickable::tapGoesThrough()
4643{
47− FloatingFlickable *floatingFlickable =
48− m_view->rootObject()->findChild<FloatingFlickable*>("floatingFlickable");
44+ QQuickItem *floatingFlickable =
45+ m_view->rootObject()->findChild<QQuickItem*>("floatingFlickable");
4946 QVERIFY(floatingFlickable != nullptr);
5047
5148 TestItem *testItem = new TestItem;
@@ -62,16 +59,26 @@ void tst_FloatingFlickable::tapGoesThrough()
6259 QCOMPARE(testItem->touchEventsReceived.count(), 1);
6360}
6461
62+static void removeTimeConstraints(QQuickItem *floatingFlickable)
63+{
64+ auto children = floatingFlickable->findChildren<QObject*>();
65+ Q_FOREACH(QObject *child, children) {
66+ if (child->metaObject()->className() == QByteArray("UCSwipeAreaPrivate")) {
67+ QMetaObject::invokeMethod(child, "setMaxTime", Q_ARG(int, 60 * 60 * 1000));
68+ QMetaObject::invokeMethod(child, "setCompositionTime", Q_ARG(int, 0));
69+ }
70+ }
71+}
72+
6573void tst_FloatingFlickable::flickChangesContentX()
6674{
6775 QSKIP("This fails due to bug #1564571");
68− FloatingFlickable *floatingFlickable =
69− m_view->rootObject()->findChild<FloatingFlickable*>("floatingFlickable");
76+ QQuickItem *floatingFlickable =
77+ m_view->rootObject()->findChild<QQuickItem*>("floatingFlickable");
7078 QVERIFY(floatingFlickable != nullptr);
79+ removeTimeConstraints(floatingFlickable);
7180
72− floatingFlickable->m_dragArea->removeTimeConstraints();
73−
74− qreal startContentX = floatingFlickable->contentX();
81+ qreal startContentX = floatingFlickable->property("contentX").toReal();
7582
7683 QPoint startPos(floatingFlickable->width() - 5, 10);
7784 int stepCount = 20;
@@ -87,20 +94,20 @@ void tst_FloatingFlickable::flickChangesContentX()
8794 QTest::qWait(10);
8895 QTest::touchEvent(m_view, m_device).release(0, QPoint(5, 10));
8996
90− QVERIFY(floatingFlickable->contentX() > (startContentX + floatingFlickable->width()/2));
97+ QVERIFY(floatingFlickable->property("contentX").toReal() > (startContentX + floatingFlickable->width()/2));
9198}
9299
93100void tst_FloatingFlickable::flickChangesContentY()
94101{
95102 QSKIP("This fails due to bug #1564571");
96− FloatingFlickable *floatingFlickable =
97− m_view->rootObject()->findChild<FloatingFlickable*>("floatingFlickable");
103+ QQuickItem *floatingFlickable =
104+ m_view->rootObject()->findChild<QQuickItem*>("floatingFlickable");
98105 QVERIFY(floatingFlickable != nullptr);
99106
100− floatingFlickable->setDirection(Direction::Vertical);
101− floatingFlickable->m_dragArea->removeTimeConstraints();
107+ floatingFlickable->setProperty("direction", Direction::Vertical);
108+ removeTimeConstraints(floatingFlickable);
102109
103− qreal startContentY = floatingFlickable->contentY();
110+ qreal startContentY = floatingFlickable->property("contentY").toReal();
104111
105112 QPoint startPos(10, floatingFlickable->height() - 5);
106113 int stepCount = 20;
@@ -116,7 +123,7 @@ void tst_FloatingFlickable::flickChangesContentY()
116123 QTest::qWait(10);
117124 QTest::touchEvent(m_view, m_device).release(0, QPoint(10, 5));
118125
119− QVERIFY(floatingFlickable->contentY() > (startContentY + floatingFlickable->height()/2));
126+ QVERIFY(floatingFlickable->property("contentY").toReal() > (startContentY + floatingFlickable->height()/2));
120127}
121128
122129QTEST_MAIN(tst_FloatingFlickable)
tests/plugins/Ubuntu/Gestures/tst_FloatingFlickable.qml+1
@@ -18,6 +18,7 @@ import QtQuick 2.4
1818import Ubuntu.Components 1.3
1919import Ubuntu.Gestures 0.1
2020import Unity.Test 0.1
21+import "../../../../../qml/Components"
2122
2223Rectangle {
2324 id: root
tests/plugins/Ubuntu/Gestures/tst_TouchGate.cpp+1−1
@@ -25,7 +25,7 @@
2525#include <functional>
2626
2727#include <TouchGate.h>
28−#include <TouchRegistry.h>
28+#include <TouchRegistry>
2929
3030#include "TestItem.h"
3131
tests/qmltests/Components/CMakeLists.txt+6−3
@@ -1,18 +1,21 @@
11add_definitions(-DTEST_DIR="${CMAKE_CURRENT_LIST_DIR}")
22
3+pkg_check_modules(UBUNTUGESTURES REQUIRED UbuntuGestures)
4+
35########## tst_DragHandle
46
57include_directories(
68 ${CMAKE_SOURCE_DIR}/plugins/Ubuntu/Gestures
7− ${CMAKE_SOURCE_DIR}/libs/UbuntuGestures
9+ ${UBUNTUGESTURES_INCLUDE_DIRS}
810 ${CMAKE_CURRENT_BINARY_DIR}
911 ${Qt5Gui_PRIVATE_INCLUDE_DIRS}
1012 ${Qt5Quick_PRIVATE_INCLUDE_DIRS}
13+ ${UBUNTUGESTURES_INCLUDEDIR}/UbuntuGestures/${UBUNTUGESTURES_VERSION}
1114 )
1215
1316add_executable(DragHandleTestExec tst_DragHandle.cpp)
1417qt5_use_modules(DragHandleTestExec Test Core Qml Gui Quick)
15−target_link_libraries(DragHandleTestExec UbuntuGesturesQml UbuntuGestures)
18+target_link_libraries(DragHandleTestExec UbuntuGesturesQml ${UBUNTUGESTURES_LIBRARIES})
1619
1720add_unity8_uitest(DragHandle DragHandleTestExec ENVIRONMENT LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/plugins/Ubuntu/Gestures)
1821add_manual_qml_test(. DragHandle IMPORT_PATHS ${UNITY_IMPORT_PATHS})
@@ -20,6 +23,6 @@ add_manual_qml_test(. DragHandle IMPORT_PATHS ${UNITY_IMPORT_PATHS})
2023########## tst_EdgeDragEvaluator
2124add_executable(EdgeDragEvaluatorTestExec tst_EdgeDragEvaluator.cpp)
2225qt5_use_modules(EdgeDragEvaluatorTestExec Test Core Qml Gui Quick)
23−target_link_libraries(EdgeDragEvaluatorTestExec UbuntuGesturesQml UbuntuGestures)
26+target_link_libraries(EdgeDragEvaluatorTestExec UbuntuGesturesQml ${UBUNTUGESTURES_LIBRARIES})
2427
2528add_unity8_uitest(EdgeDragEvaluator EdgeDragEvaluatorTestExec ENVIRONMENT LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/plugins/Ubuntu/Gestures)
tests/qmltests/Components/tst_DragHandle.cpp+25−21
@@ -21,11 +21,11 @@
2121#include <QtQuick/QQuickView>
2222#include <QtQml/QQmlEngine>
2323#include <private/qquickwindow_p.h>
24+#include <UbuntuGestures/private/ucswipearea_p_p.h>
2425
2526#include <AxisVelocityCalculator.h>
26−#include <DirectionalDragArea.h>
27−#include <DirectionalDragArea_p.h>
28−#include <Timer.h>
27+#include <Timer>
28+#include "Direction.h"
2929
3030using namespace UbuntuGestures;
3131
@@ -51,11 +51,11 @@ private Q_SLOTS:
5151 void hintingAnimation_dontRestartAfterFinishedAndStillPressed();
5252
5353private:
54− void flickAndHold(DirectionalDragArea *dragHandle, qreal distance);
54+ void flickAndHold(QQuickItem *dragHandle, qreal distance);
5555 void drag(QPointF &touchPoint, const QPointF& direction, qreal distance,
5656 int numSteps, qint64 timeMs = 500);
57− DirectionalDragArea *fetchAndSetupDragHandle(const char *objectName);
58− qreal fetchDragThreshold(DirectionalDragArea *dragHandle);
57+ QQuickItem *fetchAndSetupDragHandle(const char *objectName);
58+ qreal fetchDragThreshold(QQuickItem *dragHandle);
5959 void tryCompare(std::function<qreal ()> actualFunc, qreal expectedValue);
6060
6161 QQuickView *createView();
@@ -130,11 +130,11 @@ void tst_DragHandle::tryCompare(std::function<qreal ()> actualFunc,
130130}
131131
132132namespace {
133−QPointF calculateDirectionVector(DirectionalDragArea *edgeDragArea)
133+QPointF calculateDirectionVector(QQuickItem *edgeDragArea)
134134{
135135 QPointF localOrigin(0., 0.);
136136 QPointF localDirection;
137− switch (edgeDragArea->direction()) {
137+ switch (edgeDragArea->property("direction").toInt()) {
138138 case Direction::Upwards:
139139 localDirection.rx() = 0.;
140140 localDirection.ry() = -1.;
@@ -158,7 +158,7 @@ QPointF calculateDirectionVector(DirectionalDragArea *edgeDragArea)
158158}
159159}
160160
161−void tst_DragHandle::flickAndHold(DirectionalDragArea *dragHandle,
161+void tst_DragHandle::flickAndHold(QQuickItem *dragHandle,
162162 qreal distance)
163163{
164164 QPointF initialTouchPos = dragHandle->mapToScene(
@@ -196,13 +196,17 @@ void tst_DragHandle::drag(QPointF &touchPoint, const QPointF& direction, qreal d
196196 }
197197}
198198
199−DirectionalDragArea *tst_DragHandle::fetchAndSetupDragHandle(const char *objectName)
199+QQuickItem *tst_DragHandle::fetchAndSetupDragHandle(const char *objectName)
200200{
201− DirectionalDragArea *dragHandle =
202− m_view->rootObject()->findChild<DirectionalDragArea*>(objectName);
201+ QQuickItem *dragHandle =
202+ m_view->rootObject()->findChild<QQuickItem*>(objectName);
203203 Q_ASSERT(dragHandle != 0);
204− dragHandle->d->setRecognitionTimer(m_fakeTimer);
205− dragHandle->d->setTimeSource(m_fakeTimeSource);
204+ UCSwipeArea *swipeArea = dynamic_cast<UCSwipeArea*>(dragHandle);
205+ if (swipeArea) {
206+ UCSwipeAreaPrivate *swipeAreaPrivate = dynamic_cast<UCSwipeAreaPrivate *>(QQuickItemPrivate::get(swipeArea));
207+ swipeAreaPrivate->setRecognitionTimer(m_fakeTimer);
208+ swipeAreaPrivate->setTimeSource(m_fakeTimeSource);
209+ }
206210
207211 AxisVelocityCalculator *edgeDragEvaluator =
208212 dragHandle->findChild<AxisVelocityCalculator*>("edgeDragEvaluator");
@@ -212,7 +216,7 @@ DirectionalDragArea *tst_DragHandle::fetchAndSetupDragHandle(const char *objectN
212216 return dragHandle;
213217}
214218
215−qreal tst_DragHandle::fetchDragThreshold(DirectionalDragArea *dragHandle)
219+qreal tst_DragHandle::fetchDragThreshold(QQuickItem *dragHandle)
216220{
217221 AxisVelocityCalculator *edgeDragEvaluator =
218222 dragHandle->findChild<AxisVelocityCalculator*>("edgeDragEvaluator");
@@ -233,7 +237,7 @@ void tst_DragHandle::dragThreshold_horizontal()
233237 QQuickItem *baseItem = m_view->rootObject()->findChild<QQuickItem*>("baseItem");
234238 baseItem->setRotation(rotation);
235239
236− DirectionalDragArea *dragHandle = fetchAndSetupDragHandle("rightwardsDragHandle");
240+ QQuickItem *dragHandle = fetchAndSetupDragHandle("rightwardsDragHandle");
237241 QQuickItem *parentItem = dragHandle->parentItem();
238242
239243 qreal dragThreshold = fetchDragThreshold(dragHandle);
@@ -286,7 +290,7 @@ void tst_DragHandle::dragThreshold_vertical()
286290 QQuickItem *baseItem = m_view->rootObject()->findChild<QQuickItem*>("baseItem");
287291 baseItem->setRotation(rotation);
288292
289− DirectionalDragArea *dragHandle = fetchAndSetupDragHandle("downwardsDragHandle");
293+ QQuickItem *dragHandle = fetchAndSetupDragHandle("downwardsDragHandle");
290294
291295 qreal dragThreshold = fetchDragThreshold(dragHandle);
292296
@@ -338,7 +342,7 @@ void tst_DragHandle::dragThreshold_vertical_data()
338342 */
339343void tst_DragHandle::stretch_horizontal()
340344{
341− DirectionalDragArea *dragHandle = fetchAndSetupDragHandle("rightwardsDragHandle");
345+ QQuickItem *dragHandle = fetchAndSetupDragHandle("rightwardsDragHandle");
342346 qreal totalDragDistance = dragHandle->property("maxTotalDragDistance").toReal();
343347 QQuickItem *parentItem = dragHandle->parentItem();
344348
@@ -368,7 +372,7 @@ void tst_DragHandle::stretch_horizontal()
368372
369373void tst_DragHandle::stretch_vertical()
370374{
371− DirectionalDragArea *dragHandle = fetchAndSetupDragHandle("downwardsDragHandle");
375+ QQuickItem *dragHandle = fetchAndSetupDragHandle("downwardsDragHandle");
372376 qreal totalDragDistance = dragHandle->property("maxTotalDragDistance").toReal();
373377 QQuickItem *parentItem = dragHandle->parentItem();
374378
@@ -404,7 +408,7 @@ void tst_DragHandle::stretch_vertical()
404408 */
405409void tst_DragHandle::hintingAnimation()
406410{
407− DirectionalDragArea *dragHandle = fetchAndSetupDragHandle("downwardsDragHandle");
411+ QQuickItem *dragHandle = fetchAndSetupDragHandle("downwardsDragHandle");
408412 QQuickItem *parentItem = dragHandle->parentItem();
409413 qreal hintDisplacement = 100.0;
410414
@@ -445,7 +449,7 @@ void tst_DragHandle::hintingAnimation()
445449 */
446450void tst_DragHandle::hintingAnimation_dontRestartAfterFinishedAndStillPressed()
447451{
448− DirectionalDragArea *dragHandle = fetchAndSetupDragHandle("downwardsDragHandle");
452+ QQuickItem *dragHandle = fetchAndSetupDragHandle("downwardsDragHandle");
449453 QQuickItem *parentItem = dragHandle->parentItem();
450454 qreal hintDisplacement = 100.0;
451455
tests/qmltests/Components/tst_EdgeDragEvaluator.cpp+1−1
@@ -24,7 +24,7 @@
2424// Ubuntu.Gestures plugin
2525#include <AxisVelocityCalculator.h>
2626#include <Direction.h>
27−#include <Timer.h>
27+#include <Timer>
2828
2929using namespace UbuntuGestures;
3030
tests/qmltests/Greeter/tst_Greeter.qml+1−1
@@ -166,7 +166,7 @@ Item {
166166 tryCompare(loader, "itemDestroyed", true);
167167 loader.active = true;
168168 tryCompare(loader, "status", Loader.Ready);
169− removeTimeConstraintsFromDirectionalDragAreas(loader.item);
169+ removeTimeConstraintsFromSwipeAreas(loader.item);
170170 }
171171
172172 function getIndexOf(name) {
tests/qmltests/Greeter/tst_NarrowView.qml+1−1
@@ -302,7 +302,7 @@ Item {
302302 tryCompare(loader, "itemDestroyed", true);
303303 loader.active = true;
304304 tryCompare(loader, "status", Loader.Ready);
305− removeTimeConstraintsFromDirectionalDragAreas(loader.item);
305+ removeTimeConstraintsFromSwipeAreas(loader.item);
306306 }
307307
308308 function swipeAwayCover(toTheRight) {
tests/qmltests/Greeter/tst_WideView.qml+1−1
@@ -330,7 +330,7 @@ Item {
330330 tryCompare(loader, "itemDestroyed", true);
331331 loader.active = true;
332332 tryCompare(loader, "status", Loader.Ready);
333− removeTimeConstraintsFromDirectionalDragAreas(loader.item);
333+ removeTimeConstraintsFromSwipeAreas(loader.item);
334334 }
335335
336336 function getIndexOf(name) {
tests/qmltests/Launcher/tst_Launcher.qml+1−1
@@ -254,7 +254,7 @@ Rectangle {
254254 // Now do check that snapping is in fact enabled
255255 compare(listView.snapMode, ListView.SnapToItem, "Snapping is not enabled");
256256
257− removeTimeConstraintsFromDirectionalDragAreas(root);
257+ removeTimeConstraintsFromSwipeAreas(root);
258258 }
259259
260260 function dragLauncherIntoView() {
tests/qmltests/Tutorial/tst_Tutorial.qml+2−2
@@ -261,7 +261,7 @@ Rectangle {
261261 shellLoader.active = true;
262262
263263 tryCompare(shellLoader, "status", Loader.Ready);
264− removeTimeConstraintsFromDirectionalDragAreas(shellLoader.item);
264+ removeTimeConstraintsFromSwipeAreas(shellLoader.item);
265265 }
266266
267267 function prepareShell() {
@@ -465,7 +465,7 @@ Rectangle {
465465 // compare opacity with a bound rather than hard 0.6 because progress doesn't
466466 // always match the drag perfectly (takes a moment for drag to kick in)
467467 tryCompareFunction(function() {
468− return tutorialTop.opacity >= 0.6 && tutorialTop.opacity < 0.7;
468+ return tutorialTop.opacity >= 0.5 && tutorialTop.opacity < 0.7;
469469 }, true);
470470 touchFlick(shell, halfWidth, 0, halfWidth, shell.height * 0.4, false, true);
471471
tests/qmltests/tst_OrientedShell.qml+1−1
@@ -1551,7 +1551,7 @@ Rectangle {
15511551 orientedShellLoader.active = true;
15521552
15531553 tryCompare(orientedShellLoader, "status", Loader.Ready);
1554− removeTimeConstraintsFromDirectionalDragAreas(orientedShellLoader.item);
1554+ removeTimeConstraintsFromSwipeAreas(orientedShellLoader.item);
15551555
15561556 shell = findChild(orientedShell, "shell");
15571557
tests/qmltests/tst_Shell.qml+7−5
@@ -436,7 +436,7 @@ Rectangle {
436436 shellLoader.state = formFactor;
437437 shellLoader.active = true;
438438 tryCompare(shellLoader, "status", Loader.Ready);
439− removeTimeConstraintsFromDirectionalDragAreas(shellLoader.item);
439+ removeTimeConstraintsFromSwipeAreas(shellLoader.item);
440440 tryCompare(shell, "enabled", true); // enabled by greeter when ready
441441
442442 sessionSpy.target = findChild(shell, "greeter")
@@ -749,8 +749,9 @@ Rectangle {
749749 // greeter unloads its internal components when hidden
750750 // and reloads them when shown. Thus we have to do this
751751 // again before interacting with it otherwise any
752− // DirectionalDragAreas in there won't be easily fooled by
752+ // SwipeAreas in there won't be easily fooled by
753753 // fake swipes.
754+ removeTimeConstraintsFromSwipeAreas(greeter);
754755 swipeAwayGreeter();
755756
756757 compare(mainApp.requestedState, ApplicationInfoInterface.RequestedRunning);
@@ -761,7 +762,7 @@ Rectangle {
761762 var greeter = findChild(shell, "greeter");
762763 tryCompare(greeter, "fullyShown", true);
763764 waitForGreeterToStabilize();
764− removeTimeConstraintsFromDirectionalDragAreas(greeter);
765+ removeTimeConstraintsFromSwipeAreas(greeter);
765766
766767 var touchX = shell.width - (shell.edgeSize / 2);
767768 var touchY = shell.height / 2;
@@ -1069,9 +1070,9 @@ Rectangle {
10691070 // greeter unloads its internal components when hidden
10701071 // and reloads them when shown. Thus we have to do this
10711072 // again before interacting with it otherwise any
1072− // DirectionalDragAreas in there won't be easily fooled by
1073+ // SwipeAreas in there won't be easily fooled by
10731074 // fake swipes.
1074− removeTimeConstraintsFromDirectionalDragAreas(greeter);
1075+ removeTimeConstraintsFromSwipeAreas(greeter);
10751076 }
10761077
10771078 function revealLauncherByEdgePushWithMouse() {
@@ -2203,6 +2204,7 @@ Rectangle {
22032204 compare(ApplicationManager.focusedApplicationId, "unity8-dash");
22042205
22052206 // Use Super + Tab Tab to cycle to the first entry in the launcher
2207+ wait(1000);
22062208 keyPress(Qt.Key_Super_L, Qt.MetaModifier);
22072209 keyClick(Qt.Key_Tab);
22082210 tryCompare(launcher, "state", "visible");
tests/qmltests/tst_ShellWithPin.qml+1−1
@@ -194,7 +194,7 @@ Item {
194194 shellLoader.active = true
195195
196196 tryCompare(shellLoader, "status", Loader.Ready)
197− removeTimeConstraintsFromDirectionalDragAreas(shellLoader.item)
197+ removeTimeConstraintsFromSwipeAreas(shellLoader.item)
198198 }
199199
200200 function swipeAwayGreeter(waitForCoverPage) {
tests/utils/modules/Unity/Test/CMakeLists.txt+4−2
@@ -2,10 +2,12 @@ include(QmlPlugins)
22
33add_definitions(-DQT_NO_KEYWORDS)
44
5+pkg_check_modules(UBUNTUGESTURES REQUIRED UbuntuGestures)
6+
57include_directories(
68 ${Qt5Gui_PRIVATE_INCLUDE_DIRS}
79 ${Qt5Quick_PRIVATE_INCLUDE_DIRS}
8− ${CMAKE_SOURCE_DIR}/libs/UbuntuGestures
10+ ${UBUNTUGESTURES_INCLUDE_DIRS}
911 ${CMAKE_SOURCE_DIR}/src
1012)
1113
@@ -20,7 +22,7 @@ if (ENABLE_TOUCH_EMULATION)
2022endif()
2123
2224add_library(UnityTestQml MODULE ${UnityTestQML_SOURCES})
23−target_link_libraries(UnityTestQml UbuntuGestures)
25+target_link_libraries(UnityTestQml ${UBUNTUGESTURES_LIBRARIES})
2426
2527if (ENABLE_TOUCH_EMULATION)
2628 target_link_libraries(UnityTestQml ${MOUSETOUCHADAPTOR_LIBS_LDFLAGS})
tests/utils/modules/Unity/Test/UnityTestCase.qml+8−8
@@ -18,6 +18,7 @@ import QtQuick 2.4
1818import QtTest 1.0
1919import Unity.Application 0.1
2020import Ubuntu.Components 1.3
21+import Ubuntu.Test 1.0 as UbuntuTest
2122import Unity.Test 0.1 as UT
2223import Utils 0.1
2324
@@ -572,28 +573,27 @@ TestCase {
572573 while (rootItem.parent != undefined) {
573574 rootItem = rootItem.parent;
574575 }
575− removeTimeConstraintsFromDirectionalDragAreas(rootItem);
576+ removeTimeConstraintsFromSwipeAreas(rootItem);
576577 }
577578
578579 /*
579580 In qmltests, sequences of touch events are sent all at once, unlike in "real life".
580581 Also qmltests might run really slowly, e.g. when run from inside virtual machines.
581582 Thus to remove a variable that qmltests cannot really control, namely time, this
582− function removes all constraints from DirectionalDragAreas that are sensible to
583+ function removes all constraints from SwipeAreas that are sensible to
583584 elapsed time.
584585
585− This effectively makes DirectionalDragAreas easier to fool.
586+ This effectively makes SwipeAreas easier to fool.
586587 */
587− function removeTimeConstraintsFromDirectionalDragAreas(item) {
588+ function removeTimeConstraintsFromSwipeAreas(item) {
588589 if (!item)
589590 qtest_fail("no item given", 1);
590591
591− // use duck-typing to identify a DirectionalDragArea
592− if (item.removeTimeConstraints != undefined) {
593− item.removeTimeConstraints();
592+ if (UT.Util.isInstanceOf(item, "UCSwipeArea")) {
593+ UbuntuTest.TestExtras.removeTimeConstraintsFromSwipeArea(item);
594594 } else {
595595 for (var i in item.children) {
596− removeTimeConstraintsFromDirectionalDragAreas(item.children[i]);
596+ removeTimeConstraintsFromSwipeAreas(item.children[i]);
597597 }
598598 }
599599 }
tests/utils/modules/Unity/Test/testutil.cpp+2−2
@@ -22,8 +22,8 @@
2222#include <QQuickView>
2323
2424// UbuntuGestures lib
25−#include <TouchRegistry.h>
26−#include <Timer.h>
25+#include <TouchRegistry>
26+#include <Timer>
2727
2828using namespace UbuntuGestures;
2929