2 * Copyright (C) 2016 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 "TouchGestureArea.h"
19#include <UbuntuGestures/private/touchownershipevent_p.h>
20#include <UbuntuGestures/private/touchregistry_p.h>
21#include <UbuntuGestures/private/unownedtouchevent_p.h>
22// #include "TouchRegistry.h"
23// #include "UnownedTouchEvent.h"
25#include <QGuiApplication>
27#include <private/qquickwindow_p.h>
31#define TOUCHGESTUREAREA_DEBUG 0
33// TODO - understand more about why we lose touch event releases.
34// Workaround for now is to monitor all the touch points from first touch till
35// all have been released; no matter if we've rejected the gesture.
39struct InternalStatus {
42 WaitingForMoreTouches,
43 WaitingForOwnership, //Recognizing,
50TouchGestureArea::Status internalStatusToGestureStatus(int internalStatus) {
51 switch (internalStatus) {
52 case InternalStatus::WaitingForTouch: return TouchGestureArea::WaitingForTouch;
53 case InternalStatus::WaitingForMoreTouches: return TouchGestureArea::Undecided;
54 case InternalStatus::WaitingForOwnership: return TouchGestureArea::Undecided;
55 case InternalStatus::Recognized: return TouchGestureArea::Recognized;
56 case InternalStatus::WaitingForRejection: return TouchGestureArea::Recognized;
57 case InternalStatus::Rejected: return TouchGestureArea::Rejected;
59 return TouchGestureArea::WaitingForTouch;
64#if TOUCHGESTUREAREA_DEBUG
65#define tgaDebug(params) qDebug().nospace() << "[TGA(" << qPrintable(objectName()) << ")] " << params
66#include "DebugHelpers.h"
70const char *statusToString(int status)
72 if (status == InternalStatus::WaitingForTouch) {
73 return "WaitingForTouch";
74 } else if (status == InternalStatus::WaitingForMoreTouches) {
75 return "WaitingForMoreTouches";
76 } else if (status == InternalStatus::WaitingForOwnership) {
77 return "WaitingForOwnership";
78 } else if (status == InternalStatus::Rejected) {
80 } else if (status == InternalStatus::WaitingForRejection) {
81 return "WaitingForRejection";
88QString touchState(Qt::TouchPointState state) {
90 case Qt::TouchPointPressed: return "pressed";
91 case Qt::TouchPointMoved: return "moved";
92 case Qt::TouchPointStationary: return "stationary";
93 case Qt::TouchPointReleased: return "released";
99QString touchesString(const QList<QObject*> touches) {
101 Q_FOREACH(QObject* object, touches) {
102 GestureTouchPoint* touchPoint = qobject_cast<GestureTouchPoint*>(object);
104 str += QStringLiteral("[%1 @ (%2, %3)], ").arg(touchPoint->id())
105 .arg(touchPoint->x())
106 .arg(touchPoint->y());
112QString touchEventString(QTouchEvent* event) {
113 if (!event) return QString();
115 Q_FOREACH(const auto& touchPoint, event->touchPoints()) {
116 str += QStringLiteral("[%1:%2 @ (%3, %4)], ").arg(touchPoint.id())
117 .arg(touchState(touchPoint.state()))
118 .arg(touchPoint.pos().x())
119 .arg(touchPoint.pos().y());
126#else // TOUCHGESTUREAREA_DEBUG
127#define tgaDebug(params) ((void)0)
128#endif // TOUCHGESTUREAREA_DEBUG
130TouchGestureArea::TouchGestureArea(QQuickItem* parent)
132 , m_status(WaitingForTouch)
133 , m_recognitionTimer(nullptr)
135 , m_minimumTouchPoints(1)
136 , m_maximumTouchPoints(INT_MAX)
137 , m_recognitionPeriod(50)
138 , m_releaseRejectPeriod(100)
140 setRecognitionTimer(new Timer(this));
141 m_recognitionTimer->setInterval(m_recognitionPeriod);
142 m_recognitionTimer->setSingleShot(true);
145TouchGestureArea::~TouchGestureArea()
148 qDeleteAll(m_liveTouchPoints);
149 m_liveTouchPoints.clear();
150 qDeleteAll(m_cachedTouchPoints);
151 m_cachedTouchPoints.clear();
154bool TouchGestureArea::event(QEvent *event)
156 // Process unowned touch events (handles update/release for incomplete gestures)
157 if (event->type() == TouchOwnershipEvent::touchOwnershipEventType()) {
158 touchOwnershipEvent(static_cast<TouchOwnershipEvent*>(event));
160 } else if (event->type() == UnownedTouchEvent::unownedTouchEventType()) {
161 unownedTouchEvent(static_cast<UnownedTouchEvent*>(event)->touchEvent());
165 return QQuickItem::event(event);
168void TouchGestureArea::touchOwnershipEvent(TouchOwnershipEvent *event)
170 int touchId = event->touchId();
171 tgaDebug("touchOwnershipEvent - id:" << touchId << ", gained:" << event->gained());
173 if (event->gained()) {
174 grabTouchPoints(QVector<int>() << touchId);
175 m_candidateTouches.remove(touchId);
176 TouchRegistry::instance()->addTouchWatcher(touchId, this);
177 m_watchedTouches.insert(touchId);
179 if (m_watchedTouches.count() >= m_minimumTouchPoints) {
180 setInternalStatus(InternalStatus::Recognized);
187void TouchGestureArea::touchEvent(QTouchEvent *event)
189 if (!isEnabled() || !isVisible()) {
190 tgaDebug(QString("NOT ENABLED touchEvent(%1) %2").arg(statusToString(m_status)).arg(touchEventString(event)));
191 QQuickItem::touchEvent(event);
195 tgaDebug(QString("touchEvent(%1) %2").arg(statusToString(m_status)).arg(touchEventString(event)));
198 case InternalStatus::WaitingForTouch:
199 touchEvent_waitingForTouch(event);
201 case InternalStatus::WaitingForMoreTouches:
202 touchEvent_waitingForMoreTouches(event);
204 case InternalStatus::WaitingForOwnership:
205 touchEvent_waitingForOwnership(event);
207 case InternalStatus::Recognized:
208 case InternalStatus::WaitingForRejection:
209 touchEvent_recognized(event);
211 case InternalStatus::Rejected:
212 touchEvent_rejected(event);
214 default: // Recognized:
218 updateTouchPoints(event);
221void TouchGestureArea::touchEvent_waitingForTouch(QTouchEvent *event)
223 Q_FOREACH(const QTouchEvent::TouchPoint& touchPoint, event->touchPoints()) {
224 Qt::TouchPointState touchPointState = touchPoint.state();
225 int touchId = touchPoint.id();
227 if (touchPointState == Qt::TouchPointPressed) {
228 if (!m_candidateTouches.contains(touchId)) {
229 TouchRegistry::instance()->addCandidateOwnerForTouch(touchId, this);
230 m_candidateTouches.insert(touchId);
236 if (m_candidateTouches.count() > m_maximumTouchPoints) {
238 } else if (m_candidateTouches.count() >= m_minimumTouchPoints) {
239 setInternalStatus(InternalStatus::WaitingForOwnership);
241 QSet<int> tmpCandidates(m_candidateTouches);
242 Q_FOREACH(int candidateTouchId, tmpCandidates) {
243 TouchRegistry::instance()->requestTouchOwnership(candidateTouchId, this);
245 // We accept the gesture; so don't pass to lower items
247 } else if (m_candidateTouches.count() > 0) {
248 setInternalStatus(InternalStatus::WaitingForMoreTouches);
252void TouchGestureArea::touchEvent_waitingForMoreTouches(QTouchEvent *event)
254 Q_FOREACH(const QTouchEvent::TouchPoint& touchPoint, event->touchPoints()) {
255 Qt::TouchPointState touchPointState = touchPoint.state();
256 int touchId = touchPoint.id();
258 if (touchPointState == Qt::TouchPointPressed) {
259 if (!m_candidateTouches.contains(touchId)) {
260 TouchRegistry::instance()->addCandidateOwnerForTouch(touchId, this);
261 m_candidateTouches.insert(touchId);
267 if (m_candidateTouches.count() > m_maximumTouchPoints) {
269 } else if (m_candidateTouches.count() >= m_minimumTouchPoints) {
270 setInternalStatus(InternalStatus::WaitingForOwnership);
272 QSet<int> tmpCandidates(m_candidateTouches);
273 Q_FOREACH(int candidateTouchId, tmpCandidates) {
274 TouchRegistry::instance()->requestTouchOwnership(candidateTouchId, this);
276 // We accept the gesture; so don't pass to lower items
281void TouchGestureArea::touchEvent_waitingForOwnership(QTouchEvent *event)
283 Q_FOREACH(const QTouchEvent::TouchPoint& touchPoint, event->touchPoints()) {
284 Qt::TouchPointState touchPointState = touchPoint.state();
285 int touchId = touchPoint.id();
287 if (touchPointState == Qt::TouchPointPressed) {
288 if (!m_watchedTouches.contains(touchId)) {
289 TouchRegistry::instance()->addTouchWatcher(touchId, this);
290 m_watchedTouches.insert(touchId);
296void TouchGestureArea::touchEvent_recognized(QTouchEvent *event)
298 Q_FOREACH(const QTouchEvent::TouchPoint& touchPoint, event->touchPoints()) {
299 Qt::TouchPointState touchPointState = touchPoint.state();
300 int touchId = touchPoint.id();
302 if (touchPointState == Qt::TouchPointPressed) {
303 if (!m_watchedTouches.contains(touchId)) {
304 TouchRegistry::instance()->addTouchWatcher(touchId, this);
305 m_watchedTouches.insert(touchId);
310 if (m_watchedTouches.count() > m_maximumTouchPoints) {
312 } else if (m_watchedTouches.count() >= m_minimumTouchPoints &&
313 m_status==InternalStatus::WaitingForRejection) {
314 setInternalStatus(InternalStatus::Recognized);
318void TouchGestureArea::touchEvent_rejected(QTouchEvent *event)
320 Q_FOREACH(const QTouchEvent::TouchPoint& touchPoint, event->touchPoints()) {
321 Qt::TouchPointState touchPointState = touchPoint.state();
322 int touchId = touchPoint.id();
324 if (touchPointState == Qt::TouchPointPressed) {
325 if (!m_watchedTouches.contains(touchId)) {
326 TouchRegistry::instance()->addTouchWatcher(touchId, this);
327 m_watchedTouches.insert(touchId);
333void TouchGestureArea::unownedTouchEvent(QTouchEvent *unownedTouchEvent)
335 tgaDebug(QString("unownedTouchEvent(%1) %2").arg(statusToString(m_status)).arg(touchEventString(unownedTouchEvent)));
337 // Only monitor unowned touch events for presses/releases
338 if ((unownedTouchEvent->touchPointStates() & (Qt::TouchPointPressed|Qt::TouchPointReleased)) == 0) {
343 case InternalStatus::WaitingForTouch:
345 case InternalStatus::WaitingForMoreTouches:
346 unownedTouchEvent_waitingForMoreTouches(unownedTouchEvent);
349 case InternalStatus::WaitingForOwnership:
350 unownedTouchEvent_waitingForOwnership(unownedTouchEvent);
352 case InternalStatus::Recognized:
353 case InternalStatus::WaitingForRejection:
354 unownedTouchEvent_recognised(unownedTouchEvent);
356 case InternalStatus::Rejected:
357 unownedTouchEvent_rejected(unownedTouchEvent);
363 updateTouchPoints(unownedTouchEvent);
366void TouchGestureArea::unownedTouchEvent_waitingForMoreTouches(QTouchEvent *event)
368 Q_FOREACH(const QTouchEvent::TouchPoint& touchPoint, event->touchPoints()) {
369 Qt::TouchPointState touchPointState = touchPoint.state();
370 int touchId = touchPoint.id();
372 if (touchPointState == Qt::TouchPointReleased) {
373 if (m_candidateTouches.contains(touchId)) {
374 TouchRegistry::instance()->removeCandidateOwnerForTouch(touchId, this);
375 m_candidateTouches.remove(touchId);
380 if (m_candidateTouches.isEmpty()) {
381 setInternalStatus(InternalStatus::WaitingForTouch);
385void TouchGestureArea::unownedTouchEvent_waitingForOwnership(QTouchEvent *event)
387 Q_FOREACH(const QTouchEvent::TouchPoint& touchPoint, event->touchPoints()) {
388 Qt::TouchPointState touchPointState = touchPoint.state();
389 int touchId = touchPoint.id();
391 if (touchPointState == Qt::TouchPointReleased) {
392 if (m_candidateTouches.contains(touchId)) {
393 TouchRegistry::instance()->removeCandidateOwnerForTouch(touchId, this);
394 m_candidateTouches.remove(touchId);
396 if (m_watchedTouches.contains(touchId)) {
397 m_watchedTouches.remove(touchId);
402 if (m_candidateTouches.count() + m_watchedTouches.count() == 0) {
403 setInternalStatus(InternalStatus::WaitingForTouch);
407void TouchGestureArea::unownedTouchEvent_recognised(QTouchEvent *event)
409 Q_FOREACH(const QTouchEvent::TouchPoint& touchPoint, event->touchPoints()) {
410 Qt::TouchPointState touchPointState = touchPoint.state();
411 int touchId = touchPoint.id();
413 if (touchPointState == Qt::TouchPointReleased) {
414 if (m_watchedTouches.contains(touchId)) {
415 m_watchedTouches.remove(touchId);
420 if (m_watchedTouches.count() < m_minimumTouchPoints && m_status==InternalStatus::Recognized) {
421 setInternalStatus(InternalStatus::WaitingForRejection);
425void TouchGestureArea::unownedTouchEvent_rejected(QTouchEvent *event)
427 Q_FOREACH(const QTouchEvent::TouchPoint& touchPoint, event->touchPoints()) {
428 Qt::TouchPointState touchPointState = touchPoint.state();
429 int touchId = touchPoint.id();
431 if (touchPointState == Qt::TouchPointPressed) {
432 if (!m_watchedTouches.contains(touchId)) {
433 TouchRegistry::instance()->addTouchWatcher(touchId, this);
434 m_watchedTouches.insert(touchId);
437 if (touchPointState == Qt::TouchPointReleased) {
438 if (m_watchedTouches.contains(touchId)) {
439 m_watchedTouches.remove(touchId);
444 if (m_watchedTouches.isEmpty()) {
445 setInternalStatus(InternalStatus::WaitingForTouch);
449void TouchGestureArea::updateTouchPoints(QTouchEvent *touchEvent)
455 const int dragThreshold = qApp->styleHints()->startDragDistance();
456 const int dragVelocity = qApp->styleHints()->startDragVelocity();
459 bool updateable = m_status != InternalStatus::WaitingForRejection;
461 Q_FOREACH(const QTouchEvent::TouchPoint& touchPoint, touchEvent->touchPoints()) {
462 Qt::TouchPointState touchPointState = touchPoint.state();
463 int touchId = touchPoint.id();
465 if (touchPointState & Qt::TouchPointReleased) {
466 GestureTouchPoint* gtp = m_liveTouchPoints.value(touchId);
469 gtp->setPos(touchPoint.pos());
470 gtp->setPressed(false);
471 m_releasedTouchPoints.append(gtp);
472 m_liveTouchPoints.remove(touchId);
475 if (m_cachedTouchPoints.contains(touchId)) {
476 GestureTouchPoint* cachedPoint = m_cachedTouchPoints.take(touchId);
477 cachedPoint->deleteLater();
482 GestureTouchPoint* gtp = m_liveTouchPoints.value(touchPoint.id(), nullptr);
484 gtp = addTouchPoint(&touchPoint);
485 m_pressedTouchPoints.append(gtp);
488 if (m_cachedTouchPoints.contains(touchId)) {
489 m_cachedTouchPoints[touchId]->setPos(touchPoint.pos());
491 m_cachedTouchPoints[touchId] = new GestureTouchPoint(*gtp);
495 } else if (touchPointState & Qt::TouchPointMoved) {
496 gtp->setPos(touchPoint.pos());
497 m_movedTouchPoints.append(gtp);
500 const QPointF ¤tPos = touchPoint.scenePos();
501 const QPointF &startPos = touchPoint.startScenePos();
503 bool overDragThreshold = false;
504 bool supportsVelocity = (touchEvent->device()->capabilities() & QTouchDevice::Velocity) && dragVelocity;
505 overDragThreshold |= qAbs(currentPos.x() - startPos.x()) > dragThreshold ||
506 qAbs(currentPos.y() - startPos.y()) > dragThreshold;
507 if (supportsVelocity) {
508 QVector2D velocityVec = touchPoint.velocity();
509 overDragThreshold |= qAbs(velocityVec.x()) > dragVelocity;
510 overDragThreshold |= qAbs(velocityVec.y()) > dragVelocity;
513 if (overDragThreshold) {
514 gtp->setDragging(true);
518 if (m_cachedTouchPoints.contains(touchId)) {
519 m_cachedTouchPoints[touchId]->setPos(touchPoint.pos());
520 if (overDragThreshold) {
521 m_cachedTouchPoints[touchId]->setDragging(true);
530 if (!dragging() && m_status == InternalStatus::Recognized) {
531 bool allWantDrag = !m_liveTouchPoints.isEmpty();
532 Q_FOREACH(const auto &point, m_liveTouchPoints) {
533 allWantDrag &= point->dragging();
535 // only dragging if all points are dragging.
542 if (m_liveTouchPoints.isEmpty()) {
543 if (!dragging()) Q_EMIT clicked();
546 tgaDebug("Released " << touchesString(m_releasedTouchPoints));
547 Q_EMIT released(m_releasedTouchPoints);
550 tgaDebug("Pressed " << touchesString(m_pressedTouchPoints));
551 Q_EMIT pressed(m_pressedTouchPoints);
554 tgaDebug("Updated " << touchesString(m_movedTouchPoints));
555 Q_EMIT updated(m_movedTouchPoints);
557 if (added || ended || moved) {
558 Q_EMIT touchPointsUpdated();
563void TouchGestureArea::clearTouchLists()
565 Q_FOREACH (QObject *gtp, m_releasedTouchPoints) {
568 m_releasedTouchPoints.clear();
569 m_pressedTouchPoints.clear();
570 m_movedTouchPoints.clear();
573void TouchGestureArea::setInternalStatus(uint newStatus)
575 if (newStatus == m_status)
578 uint oldStatus = m_status;
580 m_status = newStatus;
581 Q_EMIT statusChanged(status());
583 if (oldStatus == InternalStatus::WaitingForMoreTouches || oldStatus == InternalStatus::WaitingForRejection) {
584 m_recognitionTimer->stop();
587 tgaDebug(statusToString(oldStatus) << " -> " << statusToString(newStatus));
590 case InternalStatus::WaitingForTouch:
591 resyncCachedTouchPoints();
593 case InternalStatus::WaitingForMoreTouches:
594 m_recognitionTimer->setInterval(m_recognitionPeriod);
595 m_recognitionTimer->start();
597 case InternalStatus::Recognized:
598 resyncCachedTouchPoints();
600 case InternalStatus::WaitingForRejection:
601 m_recognitionTimer->setInterval(m_releaseRejectPeriod);
602 m_recognitionTimer->start();
604 case InternalStatus::Rejected:
605 resyncCachedTouchPoints();
613void TouchGestureArea::setRecognitionTimer(AbstractTimer *timer)
616 bool timerWasRunning = false;
617 bool wasSingleShot = false;
619 // can be null when called from the constructor
620 if (m_recognitionTimer) {
621 interval = m_recognitionTimer->interval();
622 timerWasRunning = m_recognitionTimer->isRunning();
623 if (m_recognitionTimer->parent() == this) {
624 delete m_recognitionTimer;
628 m_recognitionTimer = timer;
629 timer->setInterval(interval);
630 timer->setSingleShot(wasSingleShot);
631 connect(timer, SIGNAL(timeout()),
632 this, SLOT(rejectGesture()));
633 if (timerWasRunning) {
634 m_recognitionTimer->start();
638int TouchGestureArea::status() const
640 return internalStatusToGestureStatus(m_status);
643bool TouchGestureArea::dragging() const
648QQmlListProperty<GestureTouchPoint> TouchGestureArea::touchPoints()
650 return QQmlListProperty<GestureTouchPoint>(this,
652 TouchGestureArea::touchPoint_count,
653 TouchGestureArea::touchPoint_at);
656int TouchGestureArea::minimumTouchPoints() const
658 return m_minimumTouchPoints;
661void TouchGestureArea::setMinimumTouchPoints(int value)
663 if (m_minimumTouchPoints != value) {
664 m_minimumTouchPoints = value;
665 Q_EMIT minimumTouchPointsChanged(value);
669int TouchGestureArea::maximumTouchPoints() const
671 return m_maximumTouchPoints;
674void TouchGestureArea::setMaximumTouchPoints(int value)
676 if (m_maximumTouchPoints != value) {
677 m_maximumTouchPoints = value;
678 Q_EMIT maximumTouchPointsChanged(value);
682int TouchGestureArea::recognitionPeriod() const
684 return m_recognitionPeriod;
687void TouchGestureArea::setRecognitionPeriod(int value)
689 if (value != m_recognitionPeriod) {
690 m_recognitionPeriod = value;
691 Q_EMIT recognitionPeriodChanged(value);
695int TouchGestureArea::releaseRejectPeriod() const
697 return m_releaseRejectPeriod;
700void TouchGestureArea::setReleaseRejectPeriod(int value)
702 if (value != m_releaseRejectPeriod) {
703 m_releaseRejectPeriod = value;
704 Q_EMIT releaseRejectPeriodChanged(value);
708void TouchGestureArea::rejectGesture()
710 tgaDebug("rejectGesture");
713 Q_FOREACH(int touchId, m_candidateTouches) {
714 TouchRegistry::instance()->removeCandidateOwnerForTouch(touchId, this);
717 // Monitor the candidates
718 Q_FOREACH(int touchId, m_candidateTouches) {
719 TouchRegistry::instance()->addTouchWatcher(touchId, this);
720 m_watchedTouches.insert(touchId);
722 m_candidateTouches.clear();
724 if (m_watchedTouches.isEmpty()) {
725 setInternalStatus(InternalStatus::WaitingForTouch);
727 setInternalStatus(InternalStatus::Rejected);
731void TouchGestureArea::resyncCachedTouchPoints()
738 bool wantsDrag = false;
741 QMutableHashIterator<int, GestureTouchPoint*> removeIter(m_cachedTouchPoints);
742 while(removeIter.hasNext()) {
744 if (!m_liveTouchPoints.contains(removeIter.key())) {
745 m_releasedTouchPoints.append(removeIter.value());
751 // list of adds/moves
752 Q_FOREACH(GestureTouchPoint* touchPoint, m_liveTouchPoints) {
753 if (m_cachedTouchPoints.contains(touchPoint->id())) {
754 GestureTouchPoint* cachedPoint = m_cachedTouchPoints[touchPoint->id()];
756 if (*cachedPoint != *touchPoint) {
757 *cachedPoint = *touchPoint;
758 m_movedTouchPoints.append(touchPoint);
762 m_cachedTouchPoints.insert(touchPoint->id(), new GestureTouchPoint(*touchPoint));
763 m_pressedTouchPoints.append(touchPoint);
768 if (wantsDrag && !dragging()) {
773 if (m_cachedTouchPoints.isEmpty()) {
774 if (!dragging()) Q_EMIT clicked();
777 tgaDebug("Cached Release " << touchesString(m_releasedTouchPoints));
778 Q_EMIT released(m_releasedTouchPoints);
781 tgaDebug("Cached Press " << touchesString(m_pressedTouchPoints));
782 Q_EMIT pressed(m_pressedTouchPoints);
785 tgaDebug("Cached Update " << touchesString(m_movedTouchPoints));
786 Q_EMIT updated(m_movedTouchPoints);
788 if (added || ended || moved) Q_EMIT touchPointsUpdated();
791int TouchGestureArea::touchPoint_count(QQmlListProperty<GestureTouchPoint> *list)
793 TouchGestureArea *q = static_cast<TouchGestureArea*>(list->object);
794 return q->m_cachedTouchPoints.count();
797GestureTouchPoint *TouchGestureArea::touchPoint_at(QQmlListProperty<GestureTouchPoint> *list, int index)
799 TouchGestureArea *q = static_cast<TouchGestureArea*>(list->object);
800 return (q->m_cachedTouchPoints.begin()+index).value();
803GestureTouchPoint* TouchGestureArea::addTouchPoint(QTouchEvent::TouchPoint const* tp)
805 GestureTouchPoint* gtp = new GestureTouchPoint();
806 gtp->setId(tp->id());
807 gtp->setPressed(true);
808 gtp->setPos(tp->pos());
809 m_liveTouchPoints.insert(tp->id(), gtp);
813void TouchGestureArea::itemChange(ItemChange change, const ItemChangeData &value)
815 if (change == QQuickItem::ItemSceneChange) {
816 if (value.window != nullptr) {
817 value.window->installEventFilter(TouchRegistry::instance());
822void TouchGestureArea::setDragging(bool dragging)
824 if (m_dragging == dragging)
827 tgaDebug("setDragging " << dragging);
829 m_dragging = dragging;
830 Q_EMIT draggingChanged(m_dragging);
833void GestureTouchPoint::setId(int id)
841void GestureTouchPoint::setPressed(bool pressed)
843 if (m_pressed == pressed)
846 Q_EMIT pressedChanged();
849void GestureTouchPoint::setX(qreal x)
857void GestureTouchPoint::setY(qreal y)
865void GestureTouchPoint::setDragging(bool dragging)
867 if (m_dragging == dragging)
870 m_dragging = dragging;
871 Q_EMIT draggingChanged();
874void GestureTouchPoint::setPos(const QPointF &pos)
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