on xenial help sign in
Fix EdgeDragEvaluator when a drag can happen both ways (Direction.Horizontal)
commit2543965920da5ccb1538be44165211fa985f4144 authorDaniel d'Andrada <daniel.dandrada@canonical.com> dateMon 27 Apr 2015, 12:30 (11 years ago) parent44de27c
4 files changed+228−17
qml/Components/EdgeDragEvaluator.qml+17−14 tests/qmltests/Components/CMakeLists.txt+18−3 tests/qmltests/Components/tst_EdgeDragEvaluator.cpp+166 tests/qmltests/Components/tst_EdgeDragEvaluator.qml+27
qml/Components/EdgeDragEvaluator.qml+17−14
@@ -61,18 +61,12 @@ AxisVelocityCalculator {
6161 }
6262
6363 velocity = calculate();
64+ minVelocity = __calculateMinimumVelocityForAutoCompletion();
6465
65− if (direction == Direction.Horizontal) {
66− minVelocity = __calculateMinimumVelocityForAutoCompletion(Math.abs(deltaPos));
67− return Math.abs(velocity) >= minVelocity;
66+ if (_dragDirectionIsPositive()) {
67+ return velocity >= minVelocity;
6868 } else {
69− minVelocity = __calculateMinimumVelocityForAutoCompletion(deltaPos);
70− if (Direction.isPositive(direction) && (velocity >= minVelocity)
71− || !Direction.isPositive(direction) && (velocity <= minVelocity)) {
72− return true;
73− } else {
74− return false;
75− }
69+ return velocity <= minVelocity;
7670 }
7771 }
7872
@@ -81,11 +75,20 @@ AxisVelocityCalculator {
8175 // speedThreshold in pixels per millisecond
8276 property real __speedThresholdMs: speedThreshold / 1000.0
8377
84− // Minimum velocity when a drag total distance is zero
85− property real __v0: Direction.isPositive(direction) ? __speedThresholdMs : - __speedThresholdMs
78+ function _dragDirectionIsPositive() {
79+ if (direction === Direction.Horizontal) {
80+ return (trackedPosition - __startPosition) > 0;
81+ } else {
82+ return Direction.isPositive(direction);
83+ }
84+ }
85+
86+ function __calculateMinimumVelocityForAutoCompletion() {
87+ // Minimum velocity when a drag total distance is zero
88+ var v0 = _dragDirectionIsPositive() ? __speedThresholdMs : - __speedThresholdMs;
89+ var deltaPos = trackedPosition - __startPosition;
8690
87− function __calculateMinimumVelocityForAutoCompletion(distance) {
88− return __v0 - ((__speedThresholdMs / dragThreshold) * distance);
91+ return v0 - ((__speedThresholdMs / dragThreshold) * deltaPos);
8992 }
9093
9194 function reset() {
tests/qmltests/Components/CMakeLists.txt+18−3
@@ -1,3 +1,7 @@
1+add_definitions(-DUBUNTU_GESTURES_PLUGIN_DIR="${CMAKE_BINARY_DIR}/plugins")
2+add_definitions(-DTEST_DIR="${CMAKE_CURRENT_LIST_DIR}")
3+add_definitions(-DTESTS_UTILS_MODULES_DIR="${CMAKE_BINARY_DIR}/tests/utils/modules")
4+
15########## tst_DragHandle
26
37include_directories(
@@ -15,6 +19,17 @@ target_link_libraries(DragHandleTestExec UbuntuGesturesQml UbuntuGestures)
1519add_binary_qml_test(DragHandle ${CMAKE_BINARY_DIR}/plugins/Ubuntu/Gestures "" "")
1620add_manual_qml_test(. DragHandle IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${CMAKE_BINARY_DIR}/tests/utils/modules)
1721
18−add_definitions(-DUBUNTU_GESTURES_PLUGIN_DIR="${CMAKE_BINARY_DIR}/plugins")
19−add_definitions(-DTEST_DIR="${CMAKE_CURRENT_LIST_DIR}")
20−add_definitions(-DTESTS_UTILS_MODULES_DIR="${CMAKE_BINARY_DIR}/tests/utils/modules")
22+########## tst_EdgeDragEvaluator
23+
24+include_directories(
25+ ${CMAKE_SOURCE_DIR}/plugins/Ubuntu/Gestures
26+ ${CMAKE_SOURCE_DIR}/libs/UbuntuGestures
27+ ${CMAKE_CURRENT_BINARY_DIR}
28+ ${Qt5Gui_PRIVATE_INCLUDE_DIRS}
29+ )
30+
31+add_executable(EdgeDragEvaluatorTestExec tst_EdgeDragEvaluator.cpp)
32+qt5_use_modules(EdgeDragEvaluatorTestExec Test Core Qml Gui Quick)
33+target_link_libraries(EdgeDragEvaluatorTestExec UbuntuGesturesQml UbuntuGestures)
34+
35+add_binary_qml_test(EdgeDragEvaluator ${CMAKE_BINARY_DIR}/plugins/Ubuntu/Gestures "" "")
tests/qmltests/Components/tst_EdgeDragEvaluator.cppnew file+166
@@ -0,0 +1,166 @@
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 <functional>
18+#include <QtTest>
19+#include <QObject>
20+#include <QQuickView>
21+#include <QQmlEngine>
22+#include <QQuickItem>
23+
24+// Ubuntu.Gestures plugin
25+#include <AxisVelocityCalculator.h>
26+#include <Direction.h>
27+#include <Timer.h>
28+
29+using namespace UbuntuGestures;
30+
31+class tst_EdgeDragEvaluator: public QObject
32+{
33+ Q_OBJECT
34+public:
35+ tst_EdgeDragEvaluator() {}
36+private Q_SLOTS:
37+ void initTestCase(); // will be called before the first test function is executed
38+ void cleanupTestCase(); // will be called after the last test function was executed.
39+
40+ void init(); // called right before each and every test function is executed
41+ void cleanup(); // called right after each and every test function is executed
42+
43+ void horizontalDirection();
44+ void horizontalDirection_data();
45+
46+private:
47+ void drag(qreal &pos, qreal distance, qreal speed);
48+
49+ QQuickView *createView();
50+ QQuickView *m_view;
51+ FakeTimer *m_fakeTimer;
52+ QSharedPointer<FakeTimeSource> m_fakeTimeSource;
53+ AxisVelocityCalculator *m_dragEvaluator;
54+};
55+
56+
57+void tst_EdgeDragEvaluator::initTestCase()
58+{
59+ m_view = 0;
60+}
61+
62+void tst_EdgeDragEvaluator::cleanupTestCase()
63+{
64+}
65+
66+void tst_EdgeDragEvaluator::init()
67+{
68+
69+ m_view = createView();
70+ m_view->setSource(QUrl::fromLocalFile(TEST_DIR"/tst_EdgeDragEvaluator.qml"));
71+ m_view->show();
72+ QVERIFY(QTest::qWaitForWindowExposed(m_view));
73+ QVERIFY(m_view->rootObject() != 0);
74+ qApp->processEvents();
75+
76+ m_fakeTimeSource.reset(new FakeTimeSource);
77+ m_fakeTimer = new FakeTimer(m_fakeTimeSource);
78+
79+ m_dragEvaluator =
80+ m_view->rootObject()->findChild<AxisVelocityCalculator*>("edgeDragEvaluator");
81+ QVERIFY(m_dragEvaluator);
82+ m_dragEvaluator->setTimeSource(m_fakeTimeSource);
83+}
84+
85+void tst_EdgeDragEvaluator::cleanup()
86+{
87+ m_dragEvaluator = nullptr;
88+
89+ delete m_view;
90+ m_view = 0;
91+
92+ delete m_fakeTimer;
93+ m_fakeTimer = 0;
94+
95+ m_fakeTimeSource.reset();
96+}
97+
98+QQuickView *tst_EdgeDragEvaluator::createView()
99+{
100+ QQuickView *window = new QQuickView(0);
101+ window->setResizeMode(QQuickView::SizeRootObjectToView);
102+ window->engine()->addImportPath(QLatin1String(UBUNTU_GESTURES_PLUGIN_DIR));
103+ window->engine()->addImportPath(QLatin1String(TEST_DIR));
104+
105+ return window;
106+}
107+
108+void tst_EdgeDragEvaluator::drag(qreal &pos, qreal distance, qreal speed)
109+{
110+ int numSteps = 10;
111+ qreal distanceStep = distance / ((qreal)numSteps);
112+ int timeStep = qAbs(distanceStep / speed);
113+
114+ for (int i = 0; i < numSteps; ++i) {
115+ m_fakeTimeSource->m_msecsSinceReference += timeStep;
116+ pos += distanceStep;
117+ m_dragEvaluator->setTrackedPosition(pos);
118+ }
119+}
120+
121+void tst_EdgeDragEvaluator::horizontalDirection()
122+{
123+ qreal maxDragDistance = 100.;
124+ qreal speedThreshold = 100.;
125+ qreal speedThresholdMs = speedThreshold / 1000.;
126+ QFETCH(qreal, dragDirection);
127+
128+ m_dragEvaluator->setProperty("maxDragDistance", QVariant::fromValue(maxDragDistance));
129+ m_dragEvaluator->setProperty("dragThreshold", QVariant::fromValue(maxDragDistance * 0.5));
130+ m_dragEvaluator->setProperty("speedThreshold", QVariant::fromValue(speedThreshold));
131+
132+ // If direction is "Horizontal" it means it can drag leftwards or rightwards
133+ m_dragEvaluator->setProperty("direction", QVariant::fromValue((int)Direction::Horizontal));
134+
135+ qreal pos = 0.;
136+ m_dragEvaluator->setTrackedPosition(pos);
137+
138+ // Go far beyond dragThreshold
139+ drag(pos, maxDragDistance * 0.75 * dragDirection /*distance*/, speedThresholdMs * 0.5 /*speed*/);
140+
141+ // Then come back a bit, getting close to dragThreshold
142+ drag(pos, -maxDragDistance * 0.20 * dragDirection /*distance*/, speedThresholdMs * 0.5 /*speed*/);
143+
144+ QVariant shouldAutoComplete;
145+ bool ok = QMetaObject::invokeMethod(m_dragEvaluator, "shouldAutoComplete", Qt::DirectConnection,
146+ Q_RETURN_ARG(QVariant, shouldAutoComplete));
147+ QVERIFY(ok);
148+
149+ // It should not autocomplete because the current negative velocity (speedThresholdMs * 0.5)
150+ // is bigger (in absolute terms) than the minimum negative velocity at this position needed to
151+ // cancel autocompletion (speedThreshold * 0.1)
152+ QCOMPARE(shouldAutoComplete.toBool(), false);
153+}
154+
155+void tst_EdgeDragEvaluator::horizontalDirection_data()
156+{
157+ QTest::addColumn<qreal>("dragDirection");
158+
159+ QTest::newRow("right") << 1.;
160+ QTest::newRow("left") << -1.;
161+}
162+
163+QTEST_MAIN(tst_EdgeDragEvaluator)
164+
165+#include "tst_EdgeDragEvaluator.moc"
166+
tests/qmltests/Components/tst_EdgeDragEvaluator.qmlnew file+27
@@ -0,0 +1,27 @@
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+import QtQuick 2.0
18+import "../../../qml/Components"
19+
20+Item {
21+ width: units.gu(70)
22+ height: units.gu(70)
23+
24+ EdgeDragEvaluator {
25+ objectName: "edgeDragEvaluator"
26+ }
27+}