on xenial help sign in
Remove DirectionalDragArea and libs/UbuntuGestures and port to SDK equivalents
eacc6beDaniel d'Andrada
CMakeLists.txt+12−1
@@ -63,6 +63,18 @@ pkg_check_modules(GIO REQUIRED gio-2.0>=2.32)
63pkg_check_modules(GLIB REQUIRED glib-2.0>=2.32)
63pkg_check_modules(GLIB REQUIRED glib-2.0>=2.32)
64pkg_check_modules(QMENUMODEL REQUIRED qmenumodel)
64pkg_check_modules(QMENUMODEL REQUIRED qmenumodel)
65
65
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+
66# Standard install paths
78# Standard install paths
67include(GNUInstallDirs)
79include(GNUInstallDirs)
68
80
@@ -144,7 +156,6 @@ endif()
144
156
145# add subdirectories to build
157# add subdirectories to build
146add_subdirectory(include)
158add_subdirectory(include)
147−add_subdirectory(libs)
148add_subdirectory(src)
159add_subdirectory(src)
149add_subdirectory(tools)
160add_subdirectory(tools)
150add_subdirectory(qml)
161add_subdirectory(qml)
debian/control+2
@@ -29,6 +29,8 @@ Build-Depends: cmake,
29 libqt5svg5-dev,
29 libqt5svg5-dev,
30 libqt5xmlpatterns5-dev,
30 libqt5xmlpatterns5-dev,
31 libsystemsettings-dev,
31 libsystemsettings-dev,
32+ libubuntugestures5-dev,
33+ libubuntugestures5-private-dev,
32 libudev-dev,
34 libudev-dev,
33 libunity-api-dev (>= 7.112),
35 libunity-api-dev (>= 7.112),
34 libusermetricsoutput1-dev,
36 libusermetricsoutput1-dev,
debian/unity8-private.install−1
@@ -1,5 +1,4 @@
1usr/lib/*/libunity8-private.*
1usr/lib/*/libunity8-private.*
2−usr/lib/*/unity8/libUbuntuGestures*
3usr/lib/*/unity8/qml/AccountsService
2usr/lib/*/unity8/qml/AccountsService
4usr/lib/*/unity8/qml/Cursor
3usr/lib/*/unity8/qml/Cursor
5usr/lib/*/unity8/qml/Dash
4usr/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 @@
24#include "UbuntuGesturesQmlGlobal.h"
24#include "UbuntuGesturesQmlGlobal.h"
25#include <stdint.h>
25#include <stdint.h>
26#include <QtCore/QObject>
26#include <QtCore/QObject>
27−#include "TimeSource.h"
27+#include <TimeSource>
28
28
29/*
29/*
30 Estimates the current velocity of a finger based on recent movement along an axis
30 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)
4set(UbuntuGesturesQml_SOURCES
4set(UbuntuGesturesQml_SOURCES
5 plugin.cpp
5 plugin.cpp
6 AxisVelocityCalculator.cpp
6 AxisVelocityCalculator.cpp
7− Damper.cpp
8 Direction.cpp
7 Direction.cpp
9− DirectionalDragArea.cpp
8+ MouseEventGenerator.cpp
10− FloatingFlickable.cpp
11 PressedOutsideNotifier.cpp
9 PressedOutsideNotifier.cpp
12 TouchDispatcher.cpp
10 TouchDispatcher.cpp
13 TouchGate.cpp
11 TouchGate.cpp
14 TouchGestureArea.cpp
12 TouchGestureArea.cpp
15)
13)
16
14
15+pkg_check_modules(UBUNTUGESTURES REQUIRED UbuntuGestures)
16+
17add_definitions(-DUBUNTUGESTURESQML_LIBRARY)
17add_definitions(-DUBUNTUGESTURESQML_LIBRARY)
18
18
19add_library(UbuntuGesturesQml MODULE ${UbuntuGesturesQml_SOURCES})
19add_library(UbuntuGesturesQml MODULE ${UbuntuGesturesQml_SOURCES})
20−target_link_libraries(UbuntuGesturesQml UbuntuGestures)
20+target_link_libraries(UbuntuGesturesQml ${UBUNTUGESTURES_LIBRARIES})
21
21
22qt5_use_modules(UbuntuGesturesQml Core Quick)
22qt5_use_modules(UbuntuGesturesQml Core Quick)
23
23
24# So that Foo.cpp can #include "Foo.moc"
24# So that Foo.cpp can #include "Foo.moc"
25include_directories(${CMAKE_CURRENT_BINARY_DIR})
25include_directories(${CMAKE_CURRENT_BINARY_DIR})
26
26
27−include_directories(${CMAKE_SOURCE_DIR}/libs/UbuntuGestures)
27+include_directories(${UBUNTUGESTURES_INCLUDE_DIRS})
28
28
29# There's no cmake var for v8 include path :-/ so create one
29# There's no cmake var for v8 include path :-/ so create one
30LIST(GET Qt5Core_INCLUDE_DIRS 0 QtCoreDir0)
30LIST(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 {
29 Q_ENUMS(Type)
29 Q_ENUMS(Type)
30
30
31public:
31public:
32+ // Make sure it is kept synchronized with SDK UCSwipeArea::Direction
32 enum Type {
33 enum Type {
33 Rightwards, // Along the positive direction of the X axis
34 Rightwards, // Along the positive direction of the X axis
34 Leftwards, // Along the negative direction of the X axis
35 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 {
54 Parameter { name: "type"; type: "Direction::Type" }
54 Parameter { name: "type"; type: "Direction::Type" }
55 }
55 }
56 }
56 }
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− }
139 Component {
57 Component {
140 name: "PressedOutsideNotifier"
58 name: "PressedOutsideNotifier"
141 defaultProperty: "data"
59 defaultProperty: "data"
@@ -156,54 +74,4 @@ Module {
156 Parameter { name: "item"; type: "QQuickItem"; isPointer: true }
74 Parameter { name: "item"; type: "QQuickItem"; isPointer: true }
157 }
75 }
158 }
76 }
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− }
209}
77}
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 @@
23#include <QPointer>
23#include <QPointer>
24#include <QTimer>
24#include <QTimer>
25
25
26−#include "UbuntuGesturesGlobal.h"
26+#include <ubuntugesturesglobal.h>
27
27
28/*
28/*
29 Notifies when a point, mouse or touch, is pressed outside its area.
29 Notifies when a point, mouse or touch, is pressed outside its area.
plugins/Ubuntu/Gestures/TouchGate.cpp+2−2
@@ -20,8 +20,8 @@
20#include <QDebug>
20#include <QDebug>
21#include <QQuickWindow>
21#include <QQuickWindow>
22
22
23−#include <TouchOwnershipEvent.h>
23+#include <TouchOwnershipEvent>
24−#include <TouchRegistry.h>
24+#include <TouchRegistry>
25
25
26#if TOUCHGATE_DEBUG
26#if TOUCHGATE_DEBUG
27#define ugDebug(params) qDebug().nospace() << "[TouchGate(" << (void*)this << ")] " << params
27#define ugDebug(params) qDebug().nospace() << "[TouchGate(" << (void*)this << ")] " << params
plugins/Ubuntu/Gestures/TouchGestureArea.cpp+9−6
@@ -16,10 +16,11 @@
16
16
17#include "TouchGestureArea.h"
17#include "TouchGestureArea.h"
18
18
19−// local
20−#include "TouchOwnershipEvent.h"
19+#include <UbuntuGestures/TouchOwnershipEvent>
20+#include <UbuntuGestures/TouchRegistry>
21+#include <UbuntuGestures/UnownedTouchEvent>
21−#include "TouchRegistry.h"
22+// #include "TouchRegistry.h"
22−#include "UnownedTouchEvent.h"
23+// #include "UnownedTouchEvent.h"
23
24
24#include <QGuiApplication>
25#include <QGuiApplication>
25#include <QStyleHints>
26#include <QStyleHints>
@@ -588,13 +589,15 @@ void TouchGestureArea::setInternalStatus(uint newStatus)
588 resyncCachedTouchPoints();
589 resyncCachedTouchPoints();
589 break;
590 break;
590 case InternalStatus::WaitingForMoreTouches:
591 case InternalStatus::WaitingForMoreTouches:
591− m_recognitionTimer->start(m_recognitionPeriod);
592+ m_recognitionTimer->setInterval(m_recognitionPeriod);
593+ m_recognitionTimer->start();
592 break;
594 break;
593 case InternalStatus::Recognized:
595 case InternalStatus::Recognized:
594 resyncCachedTouchPoints();
596 resyncCachedTouchPoints();
595 break;
597 break;
596 case InternalStatus::WaitingForRejection:
598 case InternalStatus::WaitingForRejection:
597− m_recognitionTimer->start(m_releaseRejectPeriod);
599+ m_recognitionTimer->setInterval(m_releaseRejectPeriod);
600+ m_recognitionTimer->start();
598 break;
601 break;
599 case InternalStatus::Rejected:
602 case InternalStatus::Rejected:
600 resyncCachedTouchPoints();
603 resyncCachedTouchPoints();
plugins/Ubuntu/Gestures/TouchGestureArea.h+1−2
@@ -21,8 +21,7 @@
21
21
22#include <QQuickItem>
22#include <QQuickItem>
23
23
24−// lib UbuntuGestures
25−#include <Timer.h>
24+#include <UbuntuGestures/Timer>
26
25
27class TouchOwnershipEvent;
26class TouchOwnershipEvent;
28class UnownedTouchEvent;
27class UnownedTouchEvent;
plugins/Ubuntu/Gestures/plugin.cpp+3−5
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright (C) 2013,2015 Canonical, Ltd.
2+ * Copyright (C) 2013,2015,2016 Canonical, Ltd.
3 *
3 *
4 * This program is free software; you can redistribute it and/or modify
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
5 * it under the terms of the GNU General Public License as published by
@@ -17,8 +17,7 @@
17#include "plugin.h"
17#include "plugin.h"
18#include "AxisVelocityCalculator.h"
18#include "AxisVelocityCalculator.h"
19#include "Direction.h"
19#include "Direction.h"
20−#include "DirectionalDragArea.h"
20+#include "MouseEventGenerator.h"
21−#include "FloatingFlickable.h"
22#include "PressedOutsideNotifier.h"
21#include "PressedOutsideNotifier.h"
23#include "TouchGate.h"
22#include "TouchGate.h"
24#include "TouchGestureArea.h"
23#include "TouchGestureArea.h"
@@ -34,9 +33,8 @@ static QObject* directionSingleton(QQmlEngine* engine, QJSEngine* scriptEngine)
34void UbuntuGesturesQmlPlugin::registerTypes(const char *uri)
33void UbuntuGesturesQmlPlugin::registerTypes(const char *uri)
35{
34{
36 qmlRegisterSingletonType<Direction>(uri, 0, 1, "Direction", directionSingleton);
35 qmlRegisterSingletonType<Direction>(uri, 0, 1, "Direction", directionSingleton);
37− qmlRegisterType<DirectionalDragArea>(uri, 0, 1, "DirectionalDragArea");
38 qmlRegisterType<AxisVelocityCalculator>(uri, 0, 1, "AxisVelocityCalculator");
36 qmlRegisterType<AxisVelocityCalculator>(uri, 0, 1, "AxisVelocityCalculator");
39− qmlRegisterType<FloatingFlickable>(uri, 0, 1, "FloatingFlickable");
37+ qmlRegisterType<MouseEventGenerator>(uri, 0, 1, "MouseEventGenerator");
40 qmlRegisterType<PressedOutsideNotifier>(uri, 0, 1, "PressedOutsideNotifier");
38 qmlRegisterType<PressedOutsideNotifier>(uri, 0, 1, "PressedOutsideNotifier");
41 qmlRegisterType<TouchGate>(uri, 0, 1, "TouchGate");
39 qmlRegisterType<TouchGate>(uri, 0, 1, "TouchGate");
42 qmlRegisterType<TouchGestureArea>(uri, 0, 1, "TouchGestureArea");
40 qmlRegisterType<TouchGestureArea>(uri, 0, 1, "TouchGestureArea");
qml/Components/DragHandle.qml+16−18
@@ -38,12 +38,12 @@ import Ubuntu.Gestures 0.1
38 anchors.bottom: parent.bottom
38 anchors.bottom: parent.bottom
39 width: units.gu(2)
39 width: units.gu(2)
40
40
41− direction: DirectionalDragArea::Leftwards
41+ direction: SwipeArea::Leftwards
42 }
42 }
43 }
43 }
44
44
45 */
45 */
46−DirectionalDragArea {
46+SwipeArea {
47 id: dragArea
47 id: dragArea
48
48
49 property bool stretch: false
49 property bool stretch: false
@@ -118,26 +118,26 @@ DirectionalDragArea {
118 }
118 }
119 }
119 }
120
120
121− function limitMovement(inputStep) {
121+ function limitMovement(distance) {
122− var targetValue = MathUtils.clamp(dragParent[targetProp] + inputStep, minValue, maxValue);
122+ var targetValue = MathUtils.clamp(d.startValue + distance, minValue, maxValue);
123− var step = targetValue - dragParent[targetProp];
123+ var diff = targetValue - d.startValue;
124
124
125 if (hintDisplacement == 0) {
125 if (hintDisplacement == 0) {
126− return step;
126+ return diff;
127 }
127 }
128
128
129 // we should not go behind hintingAnimation's current value
129 // we should not go behind hintingAnimation's current value
130 if (Direction.isPositive(direction)) {
130 if (Direction.isPositive(direction)) {
131− if (dragParent[targetProp] + step < hintingAnimation.targetValue) {
131+ if (d.startValue + diff < hintingAnimation.targetValue) {
132− step = hintingAnimation.targetValue - dragParent[targetProp];
132+ diff = hintingAnimation.targetValue - d.startValue;
133 }
133 }
134 } else {
134 } else {
135− if (dragParent[targetProp] + step > hintingAnimation.targetValue) {
135+ if (d.startValue + diff > hintingAnimation.targetValue) {
136− step = hintingAnimation.targetValue - dragParent[targetProp];
136+ diff = hintingAnimation.targetValue - d.startValue;
137 }
137 }
138 }
138 }
139
139
140− return step;
140+ return diff;
141 }
141 }
142
142
143 function onFinishedRecognizedGesture() {
143 function onFinishedRecognizedGesture() {
@@ -171,19 +171,17 @@ DirectionalDragArea {
171 objectName: "edgeDragEvaluator"
171 objectName: "edgeDragEvaluator"
172 id: dragEvaluator
172 id: dragEvaluator
173 // Effectively convert distance into the drag position projected onto the gesture direction axis
173 // 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
175 maxDragDistance: maxTotalDragDistance
175 maxDragDistance: maxTotalDragDistance
176 direction: dragArea.direction
176 direction: dragArea.direction
177 }
177 }
178
178
179 onDistanceChanged: {
179 onDistanceChanged: {
180 if (dragging) {
180 if (dragging) {
181− // don't go the whole distance in order to smooth out the movement
181+ if (!Direction.isPositive(direction))
182− var step = distance * 0.3;
182+ distance = -distance;
183−
184− step = d.limitMovement(step);
183+ var toAdd = d.limitMovement(distance);
185−
186− parent[d.targetProp] += step;
184+ parent[d.targetProp] = d.startValue + toAdd;
187 }
185 }
188 }
186 }
189
187
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 {
349 }
349 }
350 }
350 }
351
351
352− DirectionalDragArea {
352+ SwipeArea {
353 id: overviewDragHandle
353 id: overviewDragHandle
354 objectName: "overviewDragHandle"
354 objectName: "overviewDragHandle"
355 z: 1
355 z: 1
@@ -364,10 +364,10 @@ Showable {
364 anchors { left: parent.left; right: parent.right; bottom: parent.bottom }
364 anchors { left: parent.left; right: parent.right; bottom: parent.bottom }
365 height: units.gu(2)
365 height: units.gu(2)
366
366
367− onSceneDistanceChanged: {
367+ onDistanceChanged: {
368 if (dragging) {
368 if (dragging) {
369 bottomEdgeController.enableAnimation = false;
369 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));
371 }
371 }
372 }
372 }
373
373
qml/Launcher/Launcher.qml+4−4
@@ -31,14 +31,14 @@ FocusScope {
31 property int panelWidth: units.gu(10)
31 property int panelWidth: units.gu(10)
32 property int dragAreaWidth: units.gu(1)
32 property int dragAreaWidth: units.gu(1)
33 property int minimizeDistance: units.gu(26)
33 property int minimizeDistance: units.gu(26)
34− property real progress: dragArea.dragging && dragArea.touchX > panelWidth ?
34+ property real progress: dragArea.dragging && dragArea.touchPosition.x > panelWidth ?
35− (width * (dragArea.touchX-panelWidth) / (width - panelWidth)) : 0
35+ (width * (dragArea.touchPosition.x-panelWidth) / (width - panelWidth)) : 0
36
36
37 property bool superPressed: false
37 property bool superPressed: false
38 property bool superTabPressed: false
38 property bool superTabPressed: false
39
39
40 readonly property bool dragging: dragArea.dragging
40 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
42 readonly property real visibleWidth: panel.width + panel.x
42 readonly property real visibleWidth: panel.width + panel.x
43
43
44 readonly property bool shown: panel.x > -panel.width
44 readonly property bool shown: panel.x > -panel.width
@@ -400,7 +400,7 @@ FocusScope {
400 }
400 }
401 }
401 }
402
402
403− DirectionalDragArea {
403+ SwipeArea {
404 id: dragArea
404 id: dragArea
405 objectName: "launcherDragArea"
405 objectName: "launcherDragArea"
406
406
qml/Panel/IndicatorsMenu.qml+17−13
@@ -39,7 +39,7 @@ Showable {
39 property bool showOnClick: true
39 property bool showOnClick: true
40 property color panelColor: theme.palette.normal.background
40 property color panelColor: theme.palette.normal.background
41
41
42− signal showTapped(point position)
42+ signal showTapped()
43
43
44 // TODO: Perhaps we need a animation standard for showing/hiding? Each showable seems to
44 // TODO: Perhaps we need a animation standard for showing/hiding? Each showable seems to
45 // use its own values. Need to ask design about this.
45 // use its own values. Need to ask design about this.
@@ -204,7 +204,7 @@ Showable {
204 } else {
204 } else {
205 var touchReleaseTime = new Date().getTime();
205 var touchReleaseTime = new Date().getTime();
206 if (touchReleaseTime - touchPressTime <= 300) {
206 if (touchReleaseTime - touchPressTime <= 300) {
207− root.showTapped(Qt.point(touchSceneX, touchSceneY));
207+ root.showTapped();
208 }
208 }
209 }
209 }
210 }
210 }
@@ -233,10 +233,10 @@ Showable {
233 stretch: true
233 stretch: true
234 maxTotalDragDistance: openedHeight - expandedPanelHeight - handle.height
234 maxTotalDragDistance: openedHeight - expandedPanelHeight - handle.height
235
235
236− onTouchSceneXChanged: {
236+ onTouchPositionChanged: {
237 if (root.state === "locked") {
237 if (root.state === "locked") {
238− d.xDisplacementSinceLock += (touchSceneX - d.lastHideTouchSceneX)
238+ d.xDisplacementSinceLock += (touchPosition.x - d.lastHideTouchX)
239− d.lastHideTouchSceneX = touchSceneX;
239+ d.lastHideTouchX = touchPosition.x;
240 }
240 }
241 }
241 }
242 }
242 }
@@ -244,7 +244,11 @@ Showable {
244 PanelVelocityCalculator {
244 PanelVelocityCalculator {
245 id: yVelocityCalculator
245 id: yVelocityCalculator
246 velocityThreshold: d.hasCommitted ? 0.1 : 0.3
246 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
248
252
249 onVelocityAboveThresholdChanged: d.updateState()
253 onVelocityAboveThresholdChanged: d.updateState()
250 }
254 }
@@ -271,13 +275,13 @@ Showable {
271 id: d
275 id: d
272 property var activeDragHandle: showDragHandle.dragging ? showDragHandle : hideDragHandle.dragging ? hideDragHandle : null
276 property var activeDragHandle: showDragHandle.dragging ? showDragHandle : hideDragHandle.dragging ? hideDragHandle : null
273 property bool hasCommitted: false
277 property bool hasCommitted: false
274− property real lastHideTouchSceneX: 0
278+ property real lastHideTouchX: 0
275 property real xDisplacementSinceLock: 0
279 property real xDisplacementSinceLock: 0
276 onXDisplacementSinceLockChanged: d.updateState()
280 onXDisplacementSinceLockChanged: d.updateState()
277
281
278 property real rowMappedLateralPosition: {
282 property real rowMappedLateralPosition: {
279 if (!d.activeDragHandle) return -1;
283 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;
281 }
285 }
282
286
283 function updateState() {
287 function updateState() {
@@ -305,7 +309,7 @@ Showable {
305 script: {
309 script: {
306 yVelocityCalculator.reset();
310 yVelocityCalculator.reset();
307 // initial item selection
311 // 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);
309 d.hasCommitted = false;
313 d.hasCommitted = false;
310 }
314 }
311 }
315 }
@@ -323,7 +327,7 @@ Showable {
323 target: leftScroller
327 target: leftScroller
324 lateralPosition: {
328 lateralPosition: {
325 if (!d.activeDragHandle) return -1;
329 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);
327 return mapped.x;
331 return mapped.x;
328 }
332 }
329 }
333 }
@@ -332,7 +336,7 @@ Showable {
332 target: rightScroller
336 target: rightScroller
333 lateralPosition: {
337 lateralPosition: {
334 if (!d.activeDragHandle) return -1;
338 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);
336 return mapped.x;
340 return mapped.x;
337 }
341 }
338 }
342 }
@@ -342,7 +346,7 @@ Showable {
342 StateChangeScript {
346 StateChangeScript {
343 script: {
347 script: {
344 d.xDisplacementSinceLock = 0;
348 d.xDisplacementSinceLock = 0;
345− d.lastHideTouchSceneX = hideDragHandle.touchSceneX;
349+ d.lastHideTouchX = hideDragHandle.touchPosition.x;
346 }
350 }
347 }
351 }
348 PropertyChanges { target: bar; expanded: true }
352 PropertyChanges { target: bar; expanded: true }
@@ -354,7 +358,7 @@ Showable {
354 PropertyChanges {
358 PropertyChanges {
355 target: d;
359 target: d;
356 hasCommitted: true
360 hasCommitted: true
357− lastHideTouchSceneX: 0
361+ lastHideTouchX: 0
358 xDisplacementSinceLock: 0
362 xDisplacementSinceLock: 0
359 restoreEntryValues: false
363 restoreEntryValues: false
360 }
364 }
qml/Stages/DesktopStage.qml+1−1
@@ -650,7 +650,7 @@ AbstractStage {
650 }
650 }
651 }
651 }
652
652
653− DirectionalDragArea {
653+ SwipeArea {
654 direction: Direction.Leftwards
654 direction: Direction.Leftwards
655 anchors { top: parent.top; right: parent.right; bottom: parent.bottom }
655 anchors { top: parent.top; right: parent.right; bottom: parent.bottom }
656 width: units.gu(1)
656 width: units.gu(1)
qml/Stages/PhoneStage.qml+4−4
@@ -713,7 +713,7 @@ AbstractStage {
713 enabled: spreadDragArea.dragging
713 enabled: spreadDragArea.dragging
714 }
714 }
715
715
716− DirectionalDragArea {
716+ SwipeArea {
717 id: spreadDragArea
717 id: spreadDragArea
718 objectName: "spreadDragArea"
718 objectName: "spreadDragArea"
719 direction: Direction.Leftwards
719 direction: Direction.Leftwards
@@ -724,10 +724,10 @@ AbstractStage {
724
724
725 property var gesturePoints: new Array()
725 property var gesturePoints: new Array()
726
726
727− onTouchXChanged: {
727+ onTouchPositionChanged: {
728 if (dragging) {
728 if (dragging) {
729 // Gesture recognized. Let's move the spreadView with the finger
729 // 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
731 dragX = -dragX + spreadDragArea.width - spreadView.shift;
731 dragX = -dragX + spreadDragArea.width - spreadView.shift;
732 // Don't allow dragging further than the animation crossing with phase2's animation
732 // Don't allow dragging further than the animation crossing with phase2's animation
733 var maxMovement = spreadView.width * spreadView.positionMarker4 - spreadView.shift;
733 var maxMovement = spreadView.width * spreadView.positionMarker4 - spreadView.shift;
@@ -739,7 +739,7 @@ AbstractStage {
739 spreadView.contentX = -spreadView.shift;
739 spreadView.contentX = -spreadView.shift;
740 }
740 }
741
741
742− gesturePoints.push(touchX);
742+ gesturePoints.push(touchPosition.x);
743 }
743 }
744
744
745 onDraggingChanged: {
745 onDraggingChanged: {
qml/Stages/TabletStage.qml+4−4
@@ -1106,7 +1106,7 @@ AbstractStage {
1106 enabled: spreadDragArea.dragging
1106 enabled: spreadDragArea.dragging
1107 }
1107 }
1108
1108
1109− DirectionalDragArea {
1109+ SwipeArea {
1110 id: spreadDragArea
1110 id: spreadDragArea
1111 objectName: "spreadDragArea"
1111 objectName: "spreadDragArea"
1112 x: parent.width - root.dragAreaWidth
1112 x: parent.width - root.dragAreaWidth
@@ -1117,18 +1117,18 @@ AbstractStage {
1117
1117
1118 property var gesturePoints: new Array()
1118 property var gesturePoints: new Array()
1119
1119
1120− onTouchXChanged: {
1120+ onTouchPositionChanged: {
1121 if (!dragging) {
1121 if (!dragging) {
1122 spreadView.phase = 0;
1122 spreadView.phase = 0;
1123 spreadView.contentX = -spreadView.shift;
1123 spreadView.contentX = -spreadView.shift;
1124 }
1124 }
1125
1125
1126 if (dragging) {
1126 if (dragging) {
1127− var dragX = -touchX + spreadDragArea.width - spreadView.shift;
1127+ var dragX = -touchPosition.x + spreadDragArea.width - spreadView.shift;
1128 var maxDrag = spreadView.width * spreadView.positionMarker4 - spreadView.shift;
1128 var maxDrag = spreadView.width * spreadView.positionMarker4 - spreadView.shift;
1129 spreadView.contentX = Math.min(dragX, maxDrag);
1129 spreadView.contentX = Math.min(dragX, maxDrag);
1130 }
1130 }
1131− gesturePoints.push(touchX);
1131+ gesturePoints.push(touchPosition.x);
1132 }
1132 }
1133
1133
1134 onDraggingChanged: {
1134 onDraggingChanged: {
qml/Tutorial/TutorialBottom.qml+3−3
@@ -51,7 +51,7 @@ TutorialPage {
51 readonly property real dragAreaHeight: units.gu(3) // based on PageWithBottomEdge.qml
51 readonly property real dragAreaHeight: units.gu(3) // based on PageWithBottomEdge.qml
52 readonly property real targetDistance: height * 0.2 + dragAreaHeight // based on PageWithBottomEdge.qml
52 readonly property real targetDistance: height * 0.2 + dragAreaHeight // based on PageWithBottomEdge.qml
53
53
54− opacityOverride: dragArea.dragging ? 1 - (-dragArea.distance / targetDistance) : 1
54+ opacityOverride: dragArea.dragging ? 1 - (dragArea.distance / targetDistance) : 1
55
55
56 mouseArea {
56 mouseArea {
57 anchors.bottomMargin: root.dragAreaHeight
57 anchors.bottomMargin: root.dragAreaHeight
@@ -95,9 +95,9 @@ TutorialPage {
95
95
96 // Watches drag events but does not intercept them, so that the app beneath
96 // Watches drag events but does not intercept them, so that the app beneath
97 // will still drag the bottom edge up.
97 // will still drag the bottom edge up.
98− DirectionalDragArea {
98+ SwipeArea {
99 id: dragArea
99 id: dragArea
100− monitorOnly: true
100+ grabGesture: false
101 direction: Direction.Upwards
101 direction: Direction.Upwards
102 anchors.left: parent.left
102 anchors.left: parent.left
103 anchors.right: parent.right
103 anchors.right: parent.right
src/CMakeLists.txt−4
@@ -2,7 +2,6 @@ pkg_check_modules(CONNECTIVITY REQUIRED connectivity-qt1)
2
2
3include_directories(
3include_directories(
4 ${Qt5Gui_PRIVATE_INCLUDE_DIRS}
4 ${Qt5Gui_PRIVATE_INCLUDE_DIRS}
5− ${CMAKE_SOURCE_DIR}/libs/UbuntuGestures
6 ${CONNECTIVITY_INCLUDE_DIRS}
5 ${CONNECTIVITY_INCLUDE_DIRS}
7)
6)
8
7
@@ -44,9 +43,6 @@ if (ENABLE_TOUCH_EMULATION)
44 target_link_libraries(${SHELL_APP} ${MOUSETOUCHADAPTOR_LIBS_LDFLAGS})
43 target_link_libraries(${SHELL_APP} ${MOUSETOUCHADAPTOR_LIBS_LDFLAGS})
45endif()
44endif()
46
45
47−# For it to find libUbuntuGestures.so
48−set_target_properties(${SHELL_APP} PROPERTIES INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${SHELL_PRIVATE_LIBDIR}")
49−
50# install binaries
46# install binaries
51install(TARGETS ${SHELL_APP}
47install(TARGETS ${SHELL_APP}
52 RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
48 RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
tests/CMakeLists.txt−1
@@ -128,7 +128,6 @@ endfunction()
128
128
129
129
130# Actual test definitions
130# Actual test definitions
131−add_subdirectory(libs)
132add_subdirectory(plugins)
131add_subdirectory(plugins)
133add_subdirectory(qmltests)
132add_subdirectory(qmltests)
134add_subdirectory(whitespace)
133add_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 @@
1include(QmlTest)
1include(QmlTest)
2
2
3+pkg_check_modules(UBUNTUGESTURES REQUIRED UbuntuGestures)
4+
3# DANGER! DANGER! Using Qt's private API!
5# DANGER! DANGER! Using Qt's private API!
4include_directories(
6include_directories(
5 ${Qt5Quick_PRIVATE_INCLUDE_DIRS}
7 ${Qt5Quick_PRIVATE_INCLUDE_DIRS}
@@ -7,7 +9,7 @@ include_directories(
7
9
8include_directories(
10include_directories(
9 ${CMAKE_SOURCE_DIR}/plugins/Ubuntu/Gestures
11 ${CMAKE_SOURCE_DIR}/plugins/Ubuntu/Gestures
10− ${CMAKE_SOURCE_DIR}/libs/UbuntuGestures
12+ ${UBUNTUGESTURES_INCLUDE_DIRS}
11 ${CMAKE_CURRENT_BINARY_DIR}
13 ${CMAKE_CURRENT_BINARY_DIR}
12 ${Qt5Gui_PRIVATE_INCLUDE_DIRS}
14 ${Qt5Gui_PRIVATE_INCLUDE_DIRS}
13 )
15 )
@@ -17,7 +19,7 @@ export_qmlfiles(UbuntuGesturesTest .)
17macro(build_gesture_test CLASSNAME)
19macro(build_gesture_test CLASSNAME)
18 add_executable(${CLASSNAME}TestExec tst_${CLASSNAME}.cpp GestureTest.cpp TestItem.cpp)
20 add_executable(${CLASSNAME}TestExec tst_${CLASSNAME}.cpp GestureTest.cpp TestItem.cpp)
19 qt5_use_modules(${CLASSNAME}TestExec Test Core Qml Gui Quick)
21 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})
21endmacro()
23endmacro()
22
24
23set(UNITY_IMPORT_PATHS
25set(UNITY_IMPORT_PATHS
@@ -44,11 +46,9 @@ macro(add_gesture_ui_test CLASSNAME)
44 add_manual_qml_test(. ${CLASSNAME} IMPORT_PATHS ${UNITY_IMPORT_PATHS})
46 add_manual_qml_test(. ${CLASSNAME} IMPORT_PATHS ${UNITY_IMPORT_PATHS})
45endmacro()
47endmacro()
46
48
47−add_gesture_ui_test(DirectionalDragArea)
48add_gesture_ui_test(FloatingFlickable)
49add_gesture_ui_test(FloatingFlickable)
49add_gesture_ui_test(PressedOutsideNotifier)
50add_gesture_ui_test(PressedOutsideNotifier)
50add_gesture_ui_test(TouchDispatcher)
51add_gesture_ui_test(TouchDispatcher)
51add_gesture_ui_test(TouchGate)
52add_gesture_ui_test(TouchGate)
52−add_gesture_unit_test(Damper)
53add_gesture_unit_test(AxisVelocityCalculator)
53add_gesture_unit_test(AxisVelocityCalculator)
54add_gesture_ui_test(TouchGestureArea)
54add_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 @@
22#include <QQuickView>
22#include <QQuickView>
23#include <QtTest>
23#include <QtTest>
24
24
25−#include <Timer.h>
25+#include <Timer>
26−#include <TouchRegistry.h>
26+#include <TouchRegistry>
27
27
28using namespace UbuntuGestures;
28using namespace UbuntuGestures;
29
29
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 @@
17#include <QtTest>
17#include <QtTest>
18#include <QQuickView>
18#include <QQuickView>
19
19
20−// Ubuntu.Gestures plugin
21−#include <DirectionalDragArea.h>
22−#include <FloatingFlickable.h>
23−
24#include "GestureTest.h"
20#include "GestureTest.h"
25#include "TestItem.h"
21#include "TestItem.h"
22+#include "Direction.h"
26
23
27using namespace UbuntuGestures;
24using namespace UbuntuGestures;
28
25
@@ -44,8 +41,8 @@ tst_FloatingFlickable::tst_FloatingFlickable()
44
41
45void tst_FloatingFlickable::tapGoesThrough()
42void tst_FloatingFlickable::tapGoesThrough()
46{
43{
47− FloatingFlickable *floatingFlickable =
44+ QQuickItem *floatingFlickable =
48− m_view->rootObject()->findChild<FloatingFlickable*>("floatingFlickable");
45+ m_view->rootObject()->findChild<QQuickItem*>("floatingFlickable");
49 QVERIFY(floatingFlickable != nullptr);
46 QVERIFY(floatingFlickable != nullptr);
50
47
51 TestItem *testItem = new TestItem;
48 TestItem *testItem = new TestItem;
@@ -62,16 +59,26 @@ void tst_FloatingFlickable::tapGoesThrough()
62 QCOMPARE(testItem->touchEventsReceived.count(), 1);
59 QCOMPARE(testItem->touchEventsReceived.count(), 1);
63}
60}
64
61
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+
65void tst_FloatingFlickable::flickChangesContentX()
73void tst_FloatingFlickable::flickChangesContentX()
66{
74{
67 QSKIP("This fails due to bug #1564571");
75 QSKIP("This fails due to bug #1564571");
68− FloatingFlickable *floatingFlickable =
76+ QQuickItem *floatingFlickable =
69− m_view->rootObject()->findChild<FloatingFlickable*>("floatingFlickable");
77+ m_view->rootObject()->findChild<QQuickItem*>("floatingFlickable");
70 QVERIFY(floatingFlickable != nullptr);
78 QVERIFY(floatingFlickable != nullptr);
79+ removeTimeConstraints(floatingFlickable);
71
80
72− floatingFlickable->m_dragArea->removeTimeConstraints();
73−
74− qreal startContentX = floatingFlickable->contentX();
81+ qreal startContentX = floatingFlickable->property("contentX").toReal();
75
82
76 QPoint startPos(floatingFlickable->width() - 5, 10);
83 QPoint startPos(floatingFlickable->width() - 5, 10);
77 int stepCount = 20;
84 int stepCount = 20;
@@ -87,20 +94,20 @@ void tst_FloatingFlickable::flickChangesContentX()
87 QTest::qWait(10);
94 QTest::qWait(10);
88 QTest::touchEvent(m_view, m_device).release(0, QPoint(5, 10));
95 QTest::touchEvent(m_view, m_device).release(0, QPoint(5, 10));
89
96
90− QVERIFY(floatingFlickable->contentX() > (startContentX + floatingFlickable->width()/2));
97+ QVERIFY(floatingFlickable->property("contentX").toReal() > (startContentX + floatingFlickable->width()/2));
91}
98}
92
99
93void tst_FloatingFlickable::flickChangesContentY()
100void tst_FloatingFlickable::flickChangesContentY()
94{
101{
95 QSKIP("This fails due to bug #1564571");
102 QSKIP("This fails due to bug #1564571");
96− FloatingFlickable *floatingFlickable =
103+ QQuickItem *floatingFlickable =
97− m_view->rootObject()->findChild<FloatingFlickable*>("floatingFlickable");
104+ m_view->rootObject()->findChild<QQuickItem*>("floatingFlickable");
98 QVERIFY(floatingFlickable != nullptr);
105 QVERIFY(floatingFlickable != nullptr);
99
106
100− floatingFlickable->setDirection(Direction::Vertical);
107+ floatingFlickable->setProperty("direction", Direction::Vertical);
101− floatingFlickable->m_dragArea->removeTimeConstraints();
108+ removeTimeConstraints(floatingFlickable);
102
109
103− qreal startContentY = floatingFlickable->contentY();
110+ qreal startContentY = floatingFlickable->property("contentY").toReal();
104
111
105 QPoint startPos(10, floatingFlickable->height() - 5);
112 QPoint startPos(10, floatingFlickable->height() - 5);
106 int stepCount = 20;
113 int stepCount = 20;
@@ -116,7 +123,7 @@ void tst_FloatingFlickable::flickChangesContentY()
116 QTest::qWait(10);
123 QTest::qWait(10);
117 QTest::touchEvent(m_view, m_device).release(0, QPoint(10, 5));
124 QTest::touchEvent(m_view, m_device).release(0, QPoint(10, 5));
118
125
119− QVERIFY(floatingFlickable->contentY() > (startContentY + floatingFlickable->height()/2));
126+ QVERIFY(floatingFlickable->property("contentY").toReal() > (startContentY + floatingFlickable->height()/2));
120}
127}
121
128
122QTEST_MAIN(tst_FloatingFlickable)
129QTEST_MAIN(tst_FloatingFlickable)
tests/plugins/Ubuntu/Gestures/tst_FloatingFlickable.qml+1
@@ -18,6 +18,7 @@ import QtQuick 2.4
18import Ubuntu.Components 1.3
18import Ubuntu.Components 1.3
19import Ubuntu.Gestures 0.1
19import Ubuntu.Gestures 0.1
20import Unity.Test 0.1
20import Unity.Test 0.1
21+import "../../../../../qml/Components"
21
22
22Rectangle {
23Rectangle {
23 id: root
24 id: root
tests/plugins/Ubuntu/Gestures/tst_TouchGate.cpp+1−1
@@ -25,7 +25,7 @@
25#include <functional>
25#include <functional>
26
26
27#include <TouchGate.h>
27#include <TouchGate.h>
28−#include <TouchRegistry.h>
28+#include <TouchRegistry>
29
29
30#include "TestItem.h"
30#include "TestItem.h"
31
31
tests/qmltests/Components/CMakeLists.txt+6−3
@@ -1,18 +1,21 @@
1add_definitions(-DTEST_DIR="${CMAKE_CURRENT_LIST_DIR}")
1add_definitions(-DTEST_DIR="${CMAKE_CURRENT_LIST_DIR}")
2
2
3+pkg_check_modules(UBUNTUGESTURES REQUIRED UbuntuGestures)
4+
3########## tst_DragHandle
5########## tst_DragHandle
4
6
5include_directories(
7include_directories(
6 ${CMAKE_SOURCE_DIR}/plugins/Ubuntu/Gestures
8 ${CMAKE_SOURCE_DIR}/plugins/Ubuntu/Gestures
7− ${CMAKE_SOURCE_DIR}/libs/UbuntuGestures
9+ ${UBUNTUGESTURES_INCLUDE_DIRS}
8 ${CMAKE_CURRENT_BINARY_DIR}
10 ${CMAKE_CURRENT_BINARY_DIR}
9 ${Qt5Gui_PRIVATE_INCLUDE_DIRS}
11 ${Qt5Gui_PRIVATE_INCLUDE_DIRS}
10 ${Qt5Quick_PRIVATE_INCLUDE_DIRS}
12 ${Qt5Quick_PRIVATE_INCLUDE_DIRS}
13+ ${UBUNTUGESTURES_INCLUDEDIR}/UbuntuGestures/${UBUNTUGESTURES_VERSION}
11 )
14 )
12
15
13add_executable(DragHandleTestExec tst_DragHandle.cpp)
16add_executable(DragHandleTestExec tst_DragHandle.cpp)
14qt5_use_modules(DragHandleTestExec Test Core Qml Gui Quick)
17qt5_use_modules(DragHandleTestExec Test Core Qml Gui Quick)
15−target_link_libraries(DragHandleTestExec UbuntuGesturesQml UbuntuGestures)
18+target_link_libraries(DragHandleTestExec UbuntuGesturesQml ${UBUNTUGESTURES_LIBRARIES})
16
19
17add_unity8_uitest(DragHandle DragHandleTestExec ENVIRONMENT LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/plugins/Ubuntu/Gestures)
20add_unity8_uitest(DragHandle DragHandleTestExec ENVIRONMENT LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/plugins/Ubuntu/Gestures)
18add_manual_qml_test(. DragHandle IMPORT_PATHS ${UNITY_IMPORT_PATHS})
21add_manual_qml_test(. DragHandle IMPORT_PATHS ${UNITY_IMPORT_PATHS})
@@ -20,6 +23,6 @@ add_manual_qml_test(. DragHandle IMPORT_PATHS ${UNITY_IMPORT_PATHS})
20########## tst_EdgeDragEvaluator
23########## tst_EdgeDragEvaluator
21add_executable(EdgeDragEvaluatorTestExec tst_EdgeDragEvaluator.cpp)
24add_executable(EdgeDragEvaluatorTestExec tst_EdgeDragEvaluator.cpp)
22qt5_use_modules(EdgeDragEvaluatorTestExec Test Core Qml Gui Quick)
25qt5_use_modules(EdgeDragEvaluatorTestExec Test Core Qml Gui Quick)
23−target_link_libraries(EdgeDragEvaluatorTestExec UbuntuGesturesQml UbuntuGestures)
26+target_link_libraries(EdgeDragEvaluatorTestExec UbuntuGesturesQml ${UBUNTUGESTURES_LIBRARIES})
24
27
25add_unity8_uitest(EdgeDragEvaluator EdgeDragEvaluatorTestExec ENVIRONMENT LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/plugins/Ubuntu/Gestures)
28add_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 @@
21#include <QtQuick/QQuickView>
21#include <QtQuick/QQuickView>
22#include <QtQml/QQmlEngine>
22#include <QtQml/QQmlEngine>
23#include <private/qquickwindow_p.h>
23#include <private/qquickwindow_p.h>
24+#include <UbuntuGestures/private/ucswipearea_p_p.h>
24
25
25#include <AxisVelocityCalculator.h>
26#include <AxisVelocityCalculator.h>
26−#include <DirectionalDragArea.h>
27−#include <DirectionalDragArea_p.h>
28−#include <Timer.h>
27+#include <Timer>
28+#include "Direction.h"
29
29
30using namespace UbuntuGestures;
30using namespace UbuntuGestures;
31
31
@@ -51,11 +51,11 @@ private Q_SLOTS:
51 void hintingAnimation_dontRestartAfterFinishedAndStillPressed();
51 void hintingAnimation_dontRestartAfterFinishedAndStillPressed();
52
52
53private:
53private:
54− void flickAndHold(DirectionalDragArea *dragHandle, qreal distance);
54+ void flickAndHold(QQuickItem *dragHandle, qreal distance);
55 void drag(QPointF &touchPoint, const QPointF& direction, qreal distance,
55 void drag(QPointF &touchPoint, const QPointF& direction, qreal distance,
56 int numSteps, qint64 timeMs = 500);
56 int numSteps, qint64 timeMs = 500);
57− DirectionalDragArea *fetchAndSetupDragHandle(const char *objectName);
57+ QQuickItem *fetchAndSetupDragHandle(const char *objectName);
58− qreal fetchDragThreshold(DirectionalDragArea *dragHandle);
58+ qreal fetchDragThreshold(QQuickItem *dragHandle);
59 void tryCompare(std::function<qreal ()> actualFunc, qreal expectedValue);
59 void tryCompare(std::function<qreal ()> actualFunc, qreal expectedValue);
60
60
61 QQuickView *createView();
61 QQuickView *createView();
@@ -130,11 +130,11 @@ void tst_DragHandle::tryCompare(std::function<qreal ()> actualFunc,
130}
130}
131
131
132namespace {
132namespace {
133−QPointF calculateDirectionVector(DirectionalDragArea *edgeDragArea)
133+QPointF calculateDirectionVector(QQuickItem *edgeDragArea)
134{
134{
135 QPointF localOrigin(0., 0.);
135 QPointF localOrigin(0., 0.);
136 QPointF localDirection;
136 QPointF localDirection;
137− switch (edgeDragArea->direction()) {
137+ switch (edgeDragArea->property("direction").toInt()) {
138 case Direction::Upwards:
138 case Direction::Upwards:
139 localDirection.rx() = 0.;
139 localDirection.rx() = 0.;
140 localDirection.ry() = -1.;
140 localDirection.ry() = -1.;
@@ -158,7 +158,7 @@ QPointF calculateDirectionVector(DirectionalDragArea *edgeDragArea)
158}
158}
159}
159}
160
160
161−void tst_DragHandle::flickAndHold(DirectionalDragArea *dragHandle,
161+void tst_DragHandle::flickAndHold(QQuickItem *dragHandle,
162 qreal distance)
162 qreal distance)
163{
163{
164 QPointF initialTouchPos = dragHandle->mapToScene(
164 QPointF initialTouchPos = dragHandle->mapToScene(
@@ -196,13 +196,17 @@ void tst_DragHandle::drag(QPointF &touchPoint, const QPointF& direction, qreal d
196 }
196 }
197}
197}
198
198
199−DirectionalDragArea *tst_DragHandle::fetchAndSetupDragHandle(const char *objectName)
199+QQuickItem *tst_DragHandle::fetchAndSetupDragHandle(const char *objectName)
200{
200{
201− DirectionalDragArea *dragHandle =
201+ QQuickItem *dragHandle =
202− m_view->rootObject()->findChild<DirectionalDragArea*>(objectName);
202+ m_view->rootObject()->findChild<QQuickItem*>(objectName);
203 Q_ASSERT(dragHandle != 0);
203 Q_ASSERT(dragHandle != 0);
204+ UCSwipeArea *swipeArea = dynamic_cast<UCSwipeArea*>(dragHandle);
205+ if (swipeArea) {
206+ UCSwipeAreaPrivate *swipeAreaPrivate = dynamic_cast<UCSwipeAreaPrivate *>(QQuickItemPrivate::get(swipeArea));
204− dragHandle->d->setRecognitionTimer(m_fakeTimer);
207+ swipeAreaPrivate->setRecognitionTimer(m_fakeTimer);
205− dragHandle->d->setTimeSource(m_fakeTimeSource);
208+ swipeAreaPrivate->setTimeSource(m_fakeTimeSource);
209+ }
206
210
207 AxisVelocityCalculator *edgeDragEvaluator =
211 AxisVelocityCalculator *edgeDragEvaluator =
208 dragHandle->findChild<AxisVelocityCalculator*>("edgeDragEvaluator");
212 dragHandle->findChild<AxisVelocityCalculator*>("edgeDragEvaluator");
@@ -212,7 +216,7 @@ DirectionalDragArea *tst_DragHandle::fetchAndSetupDragHandle(const char *objectN
212 return dragHandle;
216 return dragHandle;
213}
217}
214
218
215−qreal tst_DragHandle::fetchDragThreshold(DirectionalDragArea *dragHandle)
219+qreal tst_DragHandle::fetchDragThreshold(QQuickItem *dragHandle)
216{
220{
217 AxisVelocityCalculator *edgeDragEvaluator =
221 AxisVelocityCalculator *edgeDragEvaluator =
218 dragHandle->findChild<AxisVelocityCalculator*>("edgeDragEvaluator");
222 dragHandle->findChild<AxisVelocityCalculator*>("edgeDragEvaluator");
@@ -233,7 +237,7 @@ void tst_DragHandle::dragThreshold_horizontal()
233 QQuickItem *baseItem = m_view->rootObject()->findChild<QQuickItem*>("baseItem");
237 QQuickItem *baseItem = m_view->rootObject()->findChild<QQuickItem*>("baseItem");
234 baseItem->setRotation(rotation);
238 baseItem->setRotation(rotation);
235
239
236− DirectionalDragArea *dragHandle = fetchAndSetupDragHandle("rightwardsDragHandle");
240+ QQuickItem *dragHandle = fetchAndSetupDragHandle("rightwardsDragHandle");
237 QQuickItem *parentItem = dragHandle->parentItem();
241 QQuickItem *parentItem = dragHandle->parentItem();
238
242
239 qreal dragThreshold = fetchDragThreshold(dragHandle);
243 qreal dragThreshold = fetchDragThreshold(dragHandle);
@@ -286,7 +290,7 @@ void tst_DragHandle::dragThreshold_vertical()
286 QQuickItem *baseItem = m_view->rootObject()->findChild<QQuickItem*>("baseItem");
290 QQuickItem *baseItem = m_view->rootObject()->findChild<QQuickItem*>("baseItem");
287 baseItem->setRotation(rotation);
291 baseItem->setRotation(rotation);
288
292
289− DirectionalDragArea *dragHandle = fetchAndSetupDragHandle("downwardsDragHandle");
293+ QQuickItem *dragHandle = fetchAndSetupDragHandle("downwardsDragHandle");
290
294
291 qreal dragThreshold = fetchDragThreshold(dragHandle);
295 qreal dragThreshold = fetchDragThreshold(dragHandle);
292
296
@@ -338,7 +342,7 @@ void tst_DragHandle::dragThreshold_vertical_data()
338 */
342 */
339void tst_DragHandle::stretch_horizontal()
343void tst_DragHandle::stretch_horizontal()
340{
344{
341− DirectionalDragArea *dragHandle = fetchAndSetupDragHandle("rightwardsDragHandle");
345+ QQuickItem *dragHandle = fetchAndSetupDragHandle("rightwardsDragHandle");
342 qreal totalDragDistance = dragHandle->property("maxTotalDragDistance").toReal();
346 qreal totalDragDistance = dragHandle->property("maxTotalDragDistance").toReal();
343 QQuickItem *parentItem = dragHandle->parentItem();
347 QQuickItem *parentItem = dragHandle->parentItem();
344
348
@@ -368,7 +372,7 @@ void tst_DragHandle::stretch_horizontal()
368
372
369void tst_DragHandle::stretch_vertical()
373void tst_DragHandle::stretch_vertical()
370{
374{
371− DirectionalDragArea *dragHandle = fetchAndSetupDragHandle("downwardsDragHandle");
375+ QQuickItem *dragHandle = fetchAndSetupDragHandle("downwardsDragHandle");
372 qreal totalDragDistance = dragHandle->property("maxTotalDragDistance").toReal();
376 qreal totalDragDistance = dragHandle->property("maxTotalDragDistance").toReal();
373 QQuickItem *parentItem = dragHandle->parentItem();
377 QQuickItem *parentItem = dragHandle->parentItem();
374
378
@@ -404,7 +408,7 @@ void tst_DragHandle::stretch_vertical()
404 */
408 */
405void tst_DragHandle::hintingAnimation()
409void tst_DragHandle::hintingAnimation()
406{
410{
407− DirectionalDragArea *dragHandle = fetchAndSetupDragHandle("downwardsDragHandle");
411+ QQuickItem *dragHandle = fetchAndSetupDragHandle("downwardsDragHandle");
408 QQuickItem *parentItem = dragHandle->parentItem();
412 QQuickItem *parentItem = dragHandle->parentItem();
409 qreal hintDisplacement = 100.0;
413 qreal hintDisplacement = 100.0;
410
414
@@ -445,7 +449,7 @@ void tst_DragHandle::hintingAnimation()
445 */
449 */
446void tst_DragHandle::hintingAnimation_dontRestartAfterFinishedAndStillPressed()
450void tst_DragHandle::hintingAnimation_dontRestartAfterFinishedAndStillPressed()
447{
451{
448− DirectionalDragArea *dragHandle = fetchAndSetupDragHandle("downwardsDragHandle");
452+ QQuickItem *dragHandle = fetchAndSetupDragHandle("downwardsDragHandle");
449 QQuickItem *parentItem = dragHandle->parentItem();
453 QQuickItem *parentItem = dragHandle->parentItem();
450 qreal hintDisplacement = 100.0;
454 qreal hintDisplacement = 100.0;
451
455
tests/qmltests/Components/tst_EdgeDragEvaluator.cpp+1−1
@@ -24,7 +24,7 @@
24// Ubuntu.Gestures plugin
24// Ubuntu.Gestures plugin
25#include <AxisVelocityCalculator.h>
25#include <AxisVelocityCalculator.h>
26#include <Direction.h>
26#include <Direction.h>
27−#include <Timer.h>
27+#include <Timer>
28
28
29using namespace UbuntuGestures;
29using namespace UbuntuGestures;
30
30
tests/qmltests/Greeter/tst_Greeter.qml+1−1
@@ -166,7 +166,7 @@ Item {
166 tryCompare(loader, "itemDestroyed", true);
166 tryCompare(loader, "itemDestroyed", true);
167 loader.active = true;
167 loader.active = true;
168 tryCompare(loader, "status", Loader.Ready);
168 tryCompare(loader, "status", Loader.Ready);
169− removeTimeConstraintsFromDirectionalDragAreas(loader.item);
169+ removeTimeConstraintsFromSwipeAreas(loader.item);
170 }
170 }
171
171
172 function getIndexOf(name) {
172 function getIndexOf(name) {
tests/qmltests/Greeter/tst_NarrowView.qml+1−1
@@ -302,7 +302,7 @@ Item {
302 tryCompare(loader, "itemDestroyed", true);
302 tryCompare(loader, "itemDestroyed", true);
303 loader.active = true;
303 loader.active = true;
304 tryCompare(loader, "status", Loader.Ready);
304 tryCompare(loader, "status", Loader.Ready);
305− removeTimeConstraintsFromDirectionalDragAreas(loader.item);
305+ removeTimeConstraintsFromSwipeAreas(loader.item);
306 }
306 }
307
307
308 function swipeAwayCover(toTheRight) {
308 function swipeAwayCover(toTheRight) {
tests/qmltests/Greeter/tst_WideView.qml+1−1
@@ -330,7 +330,7 @@ Item {
330 tryCompare(loader, "itemDestroyed", true);
330 tryCompare(loader, "itemDestroyed", true);
331 loader.active = true;
331 loader.active = true;
332 tryCompare(loader, "status", Loader.Ready);
332 tryCompare(loader, "status", Loader.Ready);
333− removeTimeConstraintsFromDirectionalDragAreas(loader.item);
333+ removeTimeConstraintsFromSwipeAreas(loader.item);
334 }
334 }
335
335
336 function getIndexOf(name) {
336 function getIndexOf(name) {
tests/qmltests/Launcher/tst_Launcher.qml+1−1
@@ -254,7 +254,7 @@ Rectangle {
254 // Now do check that snapping is in fact enabled
254 // Now do check that snapping is in fact enabled
255 compare(listView.snapMode, ListView.SnapToItem, "Snapping is not enabled");
255 compare(listView.snapMode, ListView.SnapToItem, "Snapping is not enabled");
256
256
257− removeTimeConstraintsFromDirectionalDragAreas(root);
257+ removeTimeConstraintsFromSwipeAreas(root);
258 }
258 }
259
259
260 function dragLauncherIntoView() {
260 function dragLauncherIntoView() {
tests/qmltests/Tutorial/tst_Tutorial.qml+2−2
@@ -261,7 +261,7 @@ Rectangle {
261 shellLoader.active = true;
261 shellLoader.active = true;
262
262
263 tryCompare(shellLoader, "status", Loader.Ready);
263 tryCompare(shellLoader, "status", Loader.Ready);
264− removeTimeConstraintsFromDirectionalDragAreas(shellLoader.item);
264+ removeTimeConstraintsFromSwipeAreas(shellLoader.item);
265 }
265 }
266
266
267 function prepareShell() {
267 function prepareShell() {
@@ -465,7 +465,7 @@ Rectangle {
465 // compare opacity with a bound rather than hard 0.6 because progress doesn't
465 // compare opacity with a bound rather than hard 0.6 because progress doesn't
466 // always match the drag perfectly (takes a moment for drag to kick in)
466 // always match the drag perfectly (takes a moment for drag to kick in)
467 tryCompareFunction(function() {
467 tryCompareFunction(function() {
468− return tutorialTop.opacity >= 0.6 && tutorialTop.opacity < 0.7;
468+ return tutorialTop.opacity >= 0.5 && tutorialTop.opacity < 0.7;
469 }, true);
469 }, true);
470 touchFlick(shell, halfWidth, 0, halfWidth, shell.height * 0.4, false, true);
470 touchFlick(shell, halfWidth, 0, halfWidth, shell.height * 0.4, false, true);
471
471
tests/qmltests/tst_OrientedShell.qml+1−1
@@ -1551,7 +1551,7 @@ Rectangle {
1551 orientedShellLoader.active = true;
1551 orientedShellLoader.active = true;
1552
1552
1553 tryCompare(orientedShellLoader, "status", Loader.Ready);
1553 tryCompare(orientedShellLoader, "status", Loader.Ready);
1554− removeTimeConstraintsFromDirectionalDragAreas(orientedShellLoader.item);
1554+ removeTimeConstraintsFromSwipeAreas(orientedShellLoader.item);
1555
1555
1556 shell = findChild(orientedShell, "shell");
1556 shell = findChild(orientedShell, "shell");
1557
1557
tests/qmltests/tst_Shell.qml+7−5
@@ -436,7 +436,7 @@ Rectangle {
436 shellLoader.state = formFactor;
436 shellLoader.state = formFactor;
437 shellLoader.active = true;
437 shellLoader.active = true;
438 tryCompare(shellLoader, "status", Loader.Ready);
438 tryCompare(shellLoader, "status", Loader.Ready);
439− removeTimeConstraintsFromDirectionalDragAreas(shellLoader.item);
439+ removeTimeConstraintsFromSwipeAreas(shellLoader.item);
440 tryCompare(shell, "enabled", true); // enabled by greeter when ready
440 tryCompare(shell, "enabled", true); // enabled by greeter when ready
441
441
442 sessionSpy.target = findChild(shell, "greeter")
442 sessionSpy.target = findChild(shell, "greeter")
@@ -749,8 +749,9 @@ Rectangle {
749 // greeter unloads its internal components when hidden
749 // greeter unloads its internal components when hidden
750 // and reloads them when shown. Thus we have to do this
750 // and reloads them when shown. Thus we have to do this
751 // again before interacting with it otherwise any
751 // 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
753 // fake swipes.
753 // fake swipes.
754+ removeTimeConstraintsFromSwipeAreas(greeter);
754 swipeAwayGreeter();
755 swipeAwayGreeter();
755
756
756 compare(mainApp.requestedState, ApplicationInfoInterface.RequestedRunning);
757 compare(mainApp.requestedState, ApplicationInfoInterface.RequestedRunning);
@@ -761,7 +762,7 @@ Rectangle {
761 var greeter = findChild(shell, "greeter");
762 var greeter = findChild(shell, "greeter");
762 tryCompare(greeter, "fullyShown", true);
763 tryCompare(greeter, "fullyShown", true);
763 waitForGreeterToStabilize();
764 waitForGreeterToStabilize();
764− removeTimeConstraintsFromDirectionalDragAreas(greeter);
765+ removeTimeConstraintsFromSwipeAreas(greeter);
765
766
766 var touchX = shell.width - (shell.edgeSize / 2);
767 var touchX = shell.width - (shell.edgeSize / 2);
767 var touchY = shell.height / 2;
768 var touchY = shell.height / 2;
@@ -1069,9 +1070,9 @@ Rectangle {
1069 // greeter unloads its internal components when hidden
1070 // greeter unloads its internal components when hidden
1070 // and reloads them when shown. Thus we have to do this
1071 // and reloads them when shown. Thus we have to do this
1071 // again before interacting with it otherwise any
1072 // 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
1073 // fake swipes.
1074 // fake swipes.
1074− removeTimeConstraintsFromDirectionalDragAreas(greeter);
1075+ removeTimeConstraintsFromSwipeAreas(greeter);
1075 }
1076 }
1076
1077
1077 function revealLauncherByEdgePushWithMouse() {
1078 function revealLauncherByEdgePushWithMouse() {
@@ -2203,6 +2204,7 @@ Rectangle {
2203 compare(ApplicationManager.focusedApplicationId, "unity8-dash");
2204 compare(ApplicationManager.focusedApplicationId, "unity8-dash");
2204
2205
2205 // Use Super + Tab Tab to cycle to the first entry in the launcher
2206 // Use Super + Tab Tab to cycle to the first entry in the launcher
2207+ wait(1000);
2206 keyPress(Qt.Key_Super_L, Qt.MetaModifier);
2208 keyPress(Qt.Key_Super_L, Qt.MetaModifier);
2207 keyClick(Qt.Key_Tab);
2209 keyClick(Qt.Key_Tab);
2208 tryCompare(launcher, "state", "visible");
2210 tryCompare(launcher, "state", "visible");
tests/qmltests/tst_ShellWithPin.qml+1−1
@@ -194,7 +194,7 @@ Item {
194 shellLoader.active = true
194 shellLoader.active = true
195
195
196 tryCompare(shellLoader, "status", Loader.Ready)
196 tryCompare(shellLoader, "status", Loader.Ready)
197− removeTimeConstraintsFromDirectionalDragAreas(shellLoader.item)
197+ removeTimeConstraintsFromSwipeAreas(shellLoader.item)
198 }
198 }
199
199
200 function swipeAwayGreeter(waitForCoverPage) {
200 function swipeAwayGreeter(waitForCoverPage) {
tests/utils/modules/Unity/Test/CMakeLists.txt+4−2
@@ -2,10 +2,12 @@ include(QmlPlugins)
2
2
3add_definitions(-DQT_NO_KEYWORDS)
3add_definitions(-DQT_NO_KEYWORDS)
4
4
5+pkg_check_modules(UBUNTUGESTURES REQUIRED UbuntuGestures)
6+
5include_directories(
7include_directories(
6 ${Qt5Gui_PRIVATE_INCLUDE_DIRS}
8 ${Qt5Gui_PRIVATE_INCLUDE_DIRS}
7 ${Qt5Quick_PRIVATE_INCLUDE_DIRS}
9 ${Qt5Quick_PRIVATE_INCLUDE_DIRS}
8− ${CMAKE_SOURCE_DIR}/libs/UbuntuGestures
10+ ${UBUNTUGESTURES_INCLUDE_DIRS}
9 ${CMAKE_SOURCE_DIR}/src
11 ${CMAKE_SOURCE_DIR}/src
10)
12)
11
13
@@ -20,7 +22,7 @@ if (ENABLE_TOUCH_EMULATION)
20endif()
22endif()
21
23
22add_library(UnityTestQml MODULE ${UnityTestQML_SOURCES})
24add_library(UnityTestQml MODULE ${UnityTestQML_SOURCES})
23−target_link_libraries(UnityTestQml UbuntuGestures)
25+target_link_libraries(UnityTestQml ${UBUNTUGESTURES_LIBRARIES})
24
26
25if (ENABLE_TOUCH_EMULATION)
27if (ENABLE_TOUCH_EMULATION)
26 target_link_libraries(UnityTestQml ${MOUSETOUCHADAPTOR_LIBS_LDFLAGS})
28 target_link_libraries(UnityTestQml ${MOUSETOUCHADAPTOR_LIBS_LDFLAGS})
tests/utils/modules/Unity/Test/UnityTestCase.qml+8−8
@@ -18,6 +18,7 @@ import QtQuick 2.4
18import QtTest 1.0
18import QtTest 1.0
19import Unity.Application 0.1
19import Unity.Application 0.1
20import Ubuntu.Components 1.3
20import Ubuntu.Components 1.3
21+import Ubuntu.Test 1.0 as UbuntuTest
21import Unity.Test 0.1 as UT
22import Unity.Test 0.1 as UT
22import Utils 0.1
23import Utils 0.1
23
24
@@ -572,28 +573,27 @@ TestCase {
572 while (rootItem.parent != undefined) {
573 while (rootItem.parent != undefined) {
573 rootItem = rootItem.parent;
574 rootItem = rootItem.parent;
574 }
575 }
575− removeTimeConstraintsFromDirectionalDragAreas(rootItem);
576+ removeTimeConstraintsFromSwipeAreas(rootItem);
576 }
577 }
577
578
578 /*
579 /*
579 In qmltests, sequences of touch events are sent all at once, unlike in "real life".
580 In qmltests, sequences of touch events are sent all at once, unlike in "real life".
580 Also qmltests might run really slowly, e.g. when run from inside virtual machines.
581 Also qmltests might run really slowly, e.g. when run from inside virtual machines.
581 Thus to remove a variable that qmltests cannot really control, namely time, this
582 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
583 elapsed time.
584 elapsed time.
584
585
585− This effectively makes DirectionalDragAreas easier to fool.
586+ This effectively makes SwipeAreas easier to fool.
586 */
587 */
587− function removeTimeConstraintsFromDirectionalDragAreas(item) {
588+ function removeTimeConstraintsFromSwipeAreas(item) {
588 if (!item)
589 if (!item)
589 qtest_fail("no item given", 1);
590 qtest_fail("no item given", 1);
590
591
591− // use duck-typing to identify a DirectionalDragArea
592+ if (UT.Util.isInstanceOf(item, "UCSwipeArea")) {
592− if (item.removeTimeConstraints != undefined) {
593+ UbuntuTest.TestExtras.removeTimeConstraintsFromSwipeArea(item);
593− item.removeTimeConstraints();
594 } else {
594 } else {
595 for (var i in item.children) {
595 for (var i in item.children) {
596− removeTimeConstraintsFromDirectionalDragAreas(item.children[i]);
596+ removeTimeConstraintsFromSwipeAreas(item.children[i]);
597 }
597 }
598 }
598 }
599 }
599 }
tests/utils/modules/Unity/Test/testutil.cpp+2−2
@@ -22,8 +22,8 @@
22#include <QQuickView>
22#include <QQuickView>
23
23
24// UbuntuGestures lib
24// UbuntuGestures lib
25−#include <TouchRegistry.h>
25+#include <TouchRegistry>
26−#include <Timer.h>
26+#include <Timer>
27
27
28using namespace UbuntuGestures;
28using namespace UbuntuGestures;
29
29