2 * Copyright (C) 2013 Canonical, Ltd.
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.
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.
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/>.
17#include "DirectionalDragArea.h"
19#include <QtCore/qmath.h>
21DirectionalDragArea::DirectionalDragArea(QQuickItem *parent)
23 , m_status(WaitingForTouch)
25 , m_direction(DirectionalDragArea::Rightwards)
28 , m_distanceThreshold(0)
32DirectionalDragArea::Direction DirectionalDragArea::direction() const
37void DirectionalDragArea::setDirection(DirectionalDragArea::Direction direction)
39 if (direction != m_direction) {
40 m_direction = direction;
41 Q_EMIT directionChanged(m_direction);
45void DirectionalDragArea::setMaxDeviation(qreal value)
47 if (m_dampedPos.maxDelta() != value) {
48 m_dampedPos.setMaxDelta(value);
49 Q_EMIT maxDeviationChanged(value);
53qreal DirectionalDragArea::wideningAngle() const
55 return m_wideningAngle;
58void DirectionalDragArea::setWideningAngle(qreal angle)
60 if (angle == m_wideningAngle)
63 m_wideningAngle = angle;
64 m_wideningFactor = qTan(angle * M_PI / 180.0);
65 Q_EMIT wideningAngleChanged(angle);
68void DirectionalDragArea::setDistanceThreshold(qreal value)
70 if (m_distanceThreshold != value) {
71 m_distanceThreshold = value;
72 Q_EMIT distanceThresholdChanged(value);
76qreal DirectionalDragArea::distance() const
78 if (directionIsHorizontal()) {
79 return m_previousPos.x() - m_startPos.x();
81 return m_previousPos.y() - m_startPos.y();
85qreal DirectionalDragArea::touchX() const
87 return m_previousPos.x();
90qreal DirectionalDragArea::touchY() const
92 return m_previousPos.y();
95void DirectionalDragArea::touchEvent(QTouchEvent *event)
97 if (!isEnabled() || !isVisible()) {
98 QQuickItem::touchEvent(event);
103 case WaitingForTouch:
104 touchEvent_absent(event);
107 touchEvent_undecided(event);
110 touchEvent_recognized(event);
113 touchEvent_rejected(event);
118void DirectionalDragArea::touchEvent_absent(QTouchEvent *event)
120 if ((event->touchPointStates() && (Qt::TouchPointPressed || Qt::TouchPointMoved))
121 && event->touchPoints().count() == 1) {
122 m_startPos = event->touchPoints()[0].pos();
123 m_touchId = event->touchPoints()[0].id();
124 m_dampedPos.reset(m_startPos);
125 setPreviousPos(m_startPos);
126 setStatus(Undecided);
130void DirectionalDragArea::touchEvent_undecided(QTouchEvent *event)
132 const QTouchEvent::TouchPoint *touchPoint = fetchTargetTouchPoint(event);
133 const QPointF &touchPos = touchPoint->pos();
135 if (touchPoint->state() == Qt::TouchPointReleased) {
136 // touch has ended before recognition concluded
137 setStatus(WaitingForTouch);
141 if (event->touchPointStates().testFlag(Qt::TouchPointPressed)
142 || event->touchPoints().count() > 1) {
143 // multi-finger drags are not accepted
148 m_previousDampedPos.setX(m_dampedPos.x());
149 m_previousDampedPos.setY(m_dampedPos.y());
150 m_dampedPos.update(touchPos);
152 if (!pointInsideAllowedArea()) {
157 if (!movingInRightDirection()) {
162 setPreviousPos(touchPos);
164 if (movedFarEnough(touchPos)) {
165 setStatus(Recognized);
169void DirectionalDragArea::touchEvent_recognized(QTouchEvent *event)
171 const QTouchEvent::TouchPoint *touchPoint = fetchTargetTouchPoint(event);
173 setPreviousPos(touchPoint->pos());
175 if (touchPoint->state() == Qt::TouchPointReleased) {
176 setStatus(WaitingForTouch);
180void DirectionalDragArea::touchEvent_rejected(QTouchEvent *event)
182 const QTouchEvent::TouchPoint *touchPoint = fetchTargetTouchPoint(event);
184 if (!touchPoint || touchPoint->state() == Qt::TouchPointReleased) {
185 setStatus(WaitingForTouch);
189const QTouchEvent::TouchPoint *DirectionalDragArea::fetchTargetTouchPoint(QTouchEvent *event)
191 const QList<QTouchEvent::TouchPoint> &touchPoints = event->touchPoints();
192 const QTouchEvent::TouchPoint *touchPoint = 0;
193 for (int i = 0; i < touchPoints.size(); ++i) {
194 if (touchPoints.at(i).id() == m_touchId) {
195 touchPoint = &touchPoints.at(i);
202bool DirectionalDragArea::pointInsideAllowedArea() const
204 qreal dX = m_dampedPos.x() - m_startPos.x();
205 qreal dY = m_dampedPos.y() - m_startPos.y();
207 switch (m_direction) {
209 return dY <= 0 && qFabs(dX) <= qFabs(dY) * m_wideningFactor;
211 return dY >= 0 && qFabs(dX) <= dY * m_wideningFactor;
213 return dX <= 0 && qFabs(dY) <= qFabs(dX) * m_wideningFactor;
214 default: // Rightwards:
215 return dX >= 0 && qFabs(dY) <= dX * m_wideningFactor;
219bool DirectionalDragArea::movingInRightDirection() const
221 switch (m_direction) {
223 return m_dampedPos.y() <= m_previousDampedPos.y();
225 return m_dampedPos.y() >= m_previousDampedPos.y();
227 return m_dampedPos.x() <= m_previousDampedPos.x();
228 default: // Rightwards:
229 return m_dampedPos.x() >= m_previousDampedPos.x();
233bool DirectionalDragArea::movedFarEnough(const QPointF &point) const
235 if (directionIsHorizontal())
236 return qFabs(point.x() - m_startPos.x()) > m_distanceThreshold;
238 return qFabs(point.y() - m_startPos.y()) > m_distanceThreshold;
241void DirectionalDragArea::setStatus(DirectionalDragArea::Status newStatus)
243 if (newStatus == m_status)
246 DirectionalDragArea::Status oldStatus = m_status;
248 m_status = newStatus;
249 Q_EMIT statusChanged(m_status);
252 case WaitingForTouch:
253 if (oldStatus != DirectionalDragArea::Rejected) {
254 Q_EMIT draggingChanged(false);
258 Q_EMIT draggingChanged(true);
261 Q_EMIT draggingChanged(false);
269void DirectionalDragArea::setPreviousPos(QPointF point)
271 Q_ASSERT(m_status != Rejected);
273 bool xChanged = m_previousPos.x() != point.x();
274 bool yChanged = m_previousPos.y() != point.y();
276 m_previousPos = point;
279 Q_EMIT touchXChanged(point.x());
280 if (directionIsHorizontal())
281 Q_EMIT distanceChanged(distance());
285 Q_EMIT touchYChanged(point.y());
286 if (directionIsVertical())
287 Q_EMIT distanceChanged(distance());
291bool DirectionalDragArea::directionIsHorizontal() const
293 return m_direction == Leftwards || m_direction == Rightwards;
296bool DirectionalDragArea::directionIsVertical() const
298 return m_direction == Upwards || m_direction == Downwards;
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list