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"
20#include "TouchOwnershipEvent.h"
21#include "TouchRegistry.h"
22#include "UnownedTouchEvent.h"
24#include <QGuiApplication>
26#include <private/qquickwindow_p.h>
28#define TOUCHGESTUREAREA_DEBUG 0
30// TODO - understand more about why we lose touch event releases.
31// Workaround for now is to monitor all the touch points from first touch till
32// all have been released; no matter if we've rejected the gesture.
36struct InternalStatus {
39 WaitingForMoreTouches,
40 WaitingForOwnership, //Recognizing,
47TouchGestureArea::Status internalStatusToGestureStatus(int internalStatus) {
48 switch (internalStatus) {
49 case InternalStatus::WaitingForTouch: return TouchGestureArea::WaitingForTouch;
50 case InternalStatus::WaitingForMoreTouches: return TouchGestureArea::Undecided;
51 case InternalStatus::WaitingForOwnership: return TouchGestureArea::Undecided;
52 case InternalStatus::Recognized: return TouchGestureArea::Recognized;
53 case InternalStatus::WaitingForRejection: return TouchGestureArea::Recognized;
54 case InternalStatus::Rejected: return TouchGestureArea::Rejected;
56 return TouchGestureArea::WaitingForTouch;
61#if TOUCHGESTUREAREA_DEBUG
62#define tgaDebug(params) qDebug().nospace() << "[TGA(" << qPrintable(objectName()) << ")] " << params
63#include "DebugHelpers.h"
67const char *statusToString(int status)
69 if (status == InternalStatus::WaitingForTouch) {
70 return "WaitingForTouch";
71 } else if (status == InternalStatus::WaitingForMoreTouches) {
72 return "WaitingForMoreTouches";
73 } else if (status == InternalStatus::WaitingForOwnership) {
74 return "WaitingForOwnership";
75 } else if (status == InternalStatus::Rejected) {
77 } else if (status == InternalStatus::WaitingForRejection) {
78 return "WaitingForRejection";
85QString touchState(Qt::TouchPointState state) {
87 case Qt::TouchPointPressed: return "pressed";
88 case Qt::TouchPointMoved: return "moved";
89 case Qt::TouchPointStationary: return "stationary";
90 case Qt::TouchPointReleased: return "released";
96QString touchesString(const QList<QObject*> touches) {
98 Q_FOREACH(QObject* object, touches) {
99 GestureTouchPoint* touchPoint = qobject_cast<GestureTouchPoint*>(object);
101 str += QStringLiteral("[%1 @ (%2, %3)], ").arg(touchPoint->id())
102 .arg(touchPoint->x())
103 .arg(touchPoint->y());
109QString touchEventString(QTouchEvent* event) {
110 if (!event) return QString();
112 Q_FOREACH(const auto& touchPoint, event->touchPoints()) {
113 str += QStringLiteral("[%1:%2 @ (%3, %4)], ").arg(touchPoint.id())
114 .arg(touchState(touchPoint.state()))
115 .arg(touchPoint.pos().x())
116 .arg(touchPoint.pos().y());
123#else // TOUCHGESTUREAREA_DEBUG
124#define tgaDebug(params) ((void)0)
125#endif // TOUCHGESTUREAREA_DEBUG
127TouchGestureArea::TouchGestureArea(QQuickItem* parent)
129 , m_status(WaitingForTouch)
130 , m_recognitionTimer(nullptr)
132 , m_minimumTouchPoints(1)
133 , m_maximumTouchPoints(INT_MAX)
134 , m_recognitionPeriod(50)
135 , m_releaseRejectPeriod(100)
137 setRecognitionTimer(new UbuntuGestures::Timer(this));
138 m_recognitionTimer->setInterval(m_recognitionPeriod);
139 m_recognitionTimer->setSingleShot(true);
142TouchGestureArea::~TouchGestureArea()
145 qDeleteAll(m_liveTouchPoints);
146 m_liveTouchPoints.clear();
147 qDeleteAll(m_cachedTouchPoints);
148 m_cachedTouchPoints.clear();
151bool TouchGestureArea::event(QEvent *event)
153 // Process unowned touch events (handles update/release for incomplete gestures)
154 if (event->type() == TouchOwnershipEvent::touchOwnershipEventType()) {
155 touchOwnershipEvent(static_cast<TouchOwnershipEvent *>(event));
157 } else if (event->type() == UnownedTouchEvent::unownedTouchEventType()) {
158 unownedTouchEvent(static_cast<UnownedTouchEvent *>(event)->touchEvent());
162 return QQuickItem::event(event);
165void TouchGestureArea::touchOwnershipEvent(TouchOwnershipEvent *event)
167 int touchId = event->touchId();
168 tgaDebug("touchOwnershipEvent - id:" << touchId << ", gained:" << event->gained());
170 if (event->gained()) {
171 grabTouchPoints(QVector<int>() << touchId);
172 m_candidateTouches.remove(touchId);
173 TouchRegistry::instance()->addTouchWatcher(touchId, this);
174 m_watchedTouches.insert(touchId);
176 if (m_watchedTouches.count() >= m_minimumTouchPoints) {
177 setInternalStatus(InternalStatus::Recognized);
184void TouchGestureArea::touchEvent(QTouchEvent *event)
186 if (!isEnabled() || !isVisible()) {
187 tgaDebug(QString("NOT ENABLED touchEvent(%1) %2").arg(statusToString(m_status)).arg(touchEventString(event)));
188 QQuickItem::touchEvent(event);
192 tgaDebug(QString("touchEvent(%1) %2").arg(statusToString(m_status)).arg(touchEventString(event)));
195 case InternalStatus::WaitingForTouch:
196 touchEvent_waitingForTouch(event);
198 case InternalStatus::WaitingForMoreTouches:
199 touchEvent_waitingForMoreTouches(event);
201 case InternalStatus::WaitingForOwnership:
202 touchEvent_waitingForOwnership(event);
204 case InternalStatus::Recognized:
205 case InternalStatus::WaitingForRejection:
206 touchEvent_recognized(event);
208 case InternalStatus::Rejected:
209 touchEvent_rejected(event);
211 default: // Recognized:
215 updateTouchPoints(event);
218void TouchGestureArea::touchEvent_waitingForTouch(QTouchEvent *event)
220 Q_FOREACH(const QTouchEvent::TouchPoint& touchPoint, event->touchPoints()) {
221 Qt::TouchPointState touchPointState = touchPoint.state();
222 int touchId = touchPoint.id();
224 if (touchPointState == Qt::TouchPointPressed) {
225 if (!m_candidateTouches.contains(touchId)) {
226 TouchRegistry::instance()->addCandidateOwnerForTouch(touchId, this);
227 m_candidateTouches.insert(touchId);
233 if (m_candidateTouches.count() > m_maximumTouchPoints) {
235 } else if (m_candidateTouches.count() >= m_minimumTouchPoints) {
236 setInternalStatus(InternalStatus::WaitingForOwnership);
238 QSet<int> tmpCandidates(m_candidateTouches);
239 Q_FOREACH(int candidateTouchId, tmpCandidates) {
240 TouchRegistry::instance()->requestTouchOwnership(candidateTouchId, this);
242 // We accept the gesture; so don't pass to lower items
244 } else if (m_candidateTouches.count() > 0) {
245 setInternalStatus(InternalStatus::WaitingForMoreTouches);
249void TouchGestureArea::touchEvent_waitingForMoreTouches(QTouchEvent *event)
251 Q_FOREACH(const QTouchEvent::TouchPoint& touchPoint, event->touchPoints()) {
252 Qt::TouchPointState touchPointState = touchPoint.state();
253 int touchId = touchPoint.id();
255 if (touchPointState == Qt::TouchPointPressed) {
256 if (!m_candidateTouches.contains(touchId)) {
257 TouchRegistry::instance()->addCandidateOwnerForTouch(touchId, this);
258 m_candidateTouches.insert(touchId);
264 if (m_candidateTouches.count() > m_maximumTouchPoints) {
266 } else if (m_candidateTouches.count() >= m_minimumTouchPoints) {
267 setInternalStatus(InternalStatus::WaitingForOwnership);
269 QSet<int> tmpCandidates(m_candidateTouches);
270 Q_FOREACH(int candidateTouchId, tmpCandidates) {
271 TouchRegistry::instance()->requestTouchOwnership(candidateTouchId, this);
273 // We accept the gesture; so don't pass to lower items
278void TouchGestureArea::touchEvent_waitingForOwnership(QTouchEvent *event)
280 Q_FOREACH(const QTouchEvent::TouchPoint& touchPoint, event->touchPoints()) {
281 Qt::TouchPointState touchPointState = touchPoint.state();
282 int touchId = touchPoint.id();
284 if (touchPointState == Qt::TouchPointPressed) {
285 if (!m_watchedTouches.contains(touchId)) {
286 TouchRegistry::instance()->addTouchWatcher(touchId, this);
287 m_watchedTouches.insert(touchId);
293void TouchGestureArea::touchEvent_recognized(QTouchEvent *event)
295 Q_FOREACH(const QTouchEvent::TouchPoint& touchPoint, event->touchPoints()) {
296 Qt::TouchPointState touchPointState = touchPoint.state();
297 int touchId = touchPoint.id();
299 if (touchPointState == Qt::TouchPointPressed) {
300 if (!m_watchedTouches.contains(touchId)) {
301 TouchRegistry::instance()->addTouchWatcher(touchId, this);
302 m_watchedTouches.insert(touchId);
307 if (m_watchedTouches.count() > m_maximumTouchPoints) {
309 } else if (m_watchedTouches.count() >= m_minimumTouchPoints &&
310 m_status==InternalStatus::WaitingForRejection) {
311 setInternalStatus(InternalStatus::Recognized);
315void TouchGestureArea::touchEvent_rejected(QTouchEvent *event)
317 Q_FOREACH(const QTouchEvent::TouchPoint& touchPoint, event->touchPoints()) {
318 Qt::TouchPointState touchPointState = touchPoint.state();
319 int touchId = touchPoint.id();
321 if (touchPointState == Qt::TouchPointPressed) {
322 if (!m_watchedTouches.contains(touchId)) {
323 TouchRegistry::instance()->addTouchWatcher(touchId, this);
324 m_watchedTouches.insert(touchId);
330void TouchGestureArea::unownedTouchEvent(QTouchEvent *unownedTouchEvent)
332 tgaDebug(QString("unownedTouchEvent(%1) %2").arg(statusToString(m_status)).arg(touchEventString(unownedTouchEvent)));
334 // Only monitor unowned touch events for presses/releases
335 if ((unownedTouchEvent->touchPointStates() & (Qt::TouchPointPressed|Qt::TouchPointReleased)) == 0) {
340 case InternalStatus::WaitingForTouch:
342 case InternalStatus::WaitingForMoreTouches:
343 unownedTouchEvent_waitingForMoreTouches(unownedTouchEvent);
346 case InternalStatus::WaitingForOwnership:
347 unownedTouchEvent_waitingForOwnership(unownedTouchEvent);
349 case InternalStatus::Recognized:
350 case InternalStatus::WaitingForRejection:
351 unownedTouchEvent_recognised(unownedTouchEvent);
353 case InternalStatus::Rejected:
354 unownedTouchEvent_rejected(unownedTouchEvent);
360 updateTouchPoints(unownedTouchEvent);
363void TouchGestureArea::unownedTouchEvent_waitingForMoreTouches(QTouchEvent *event)
365 Q_FOREACH(const QTouchEvent::TouchPoint& touchPoint, event->touchPoints()) {
366 Qt::TouchPointState touchPointState = touchPoint.state();
367 int touchId = touchPoint.id();
369 if (touchPointState == Qt::TouchPointReleased) {
370 if (m_candidateTouches.contains(touchId)) {
371 TouchRegistry::instance()->removeCandidateOwnerForTouch(touchId, this);
372 m_candidateTouches.remove(touchId);
377 if (m_candidateTouches.count() == 0) {
378 setInternalStatus(InternalStatus::WaitingForTouch);
382void TouchGestureArea::unownedTouchEvent_waitingForOwnership(QTouchEvent *event)
384 Q_FOREACH(const QTouchEvent::TouchPoint& touchPoint, event->touchPoints()) {
385 Qt::TouchPointState touchPointState = touchPoint.state();
386 int touchId = touchPoint.id();
388 if (touchPointState == Qt::TouchPointReleased) {
389 if (m_candidateTouches.contains(touchId)) {
390 TouchRegistry::instance()->removeCandidateOwnerForTouch(touchId, this);
391 m_candidateTouches.remove(touchId);
393 if (m_watchedTouches.contains(touchId)) {
394 m_watchedTouches.remove(touchId);
399 if (m_candidateTouches.count() + m_watchedTouches.count() == 0) {
400 setInternalStatus(InternalStatus::WaitingForTouch);
404void TouchGestureArea::unownedTouchEvent_recognised(QTouchEvent *event)
406 Q_FOREACH(const QTouchEvent::TouchPoint& touchPoint, event->touchPoints()) {
407 Qt::TouchPointState touchPointState = touchPoint.state();
408 int touchId = touchPoint.id();
410 if (touchPointState == Qt::TouchPointReleased) {
411 if (m_watchedTouches.contains(touchId)) {
412 m_watchedTouches.remove(touchId);
417 if (m_watchedTouches.count() < m_minimumTouchPoints && m_status==InternalStatus::Recognized) {
418 setInternalStatus(InternalStatus::WaitingForRejection);
422void TouchGestureArea::unownedTouchEvent_rejected(QTouchEvent *event)
424 Q_FOREACH(const QTouchEvent::TouchPoint& touchPoint, event->touchPoints()) {
425 Qt::TouchPointState touchPointState = touchPoint.state();
426 int touchId = touchPoint.id();
428 if (touchPointState == Qt::TouchPointPressed) {
429 if (!m_watchedTouches.contains(touchId)) {
430 TouchRegistry::instance()->addTouchWatcher(touchId, this);
431 m_watchedTouches.insert(touchId);
434 if (touchPointState == Qt::TouchPointReleased) {
435 if (m_watchedTouches.contains(touchId)) {
436 m_watchedTouches.remove(touchId);
441 if (m_watchedTouches.count() == 0) {
442 setInternalStatus(InternalStatus::WaitingForTouch);
446void TouchGestureArea::updateTouchPoints(QTouchEvent *touchEvent)
452 const int dragThreshold = qApp->styleHints()->startDragDistance();
453 const int dragVelocity = qApp->styleHints()->startDragVelocity();
456 bool updateable = m_status != InternalStatus::WaitingForRejection;
458 Q_FOREACH(const QTouchEvent::TouchPoint& touchPoint, touchEvent->touchPoints()) {
459 Qt::TouchPointState touchPointState = touchPoint.state();
460 int touchId = touchPoint.id();
462 if (touchPointState & Qt::TouchPointReleased) {
463 GestureTouchPoint* gtp = m_liveTouchPoints.value(touchId);
466 gtp->setPos(touchPoint.pos());
467 gtp->setPressed(false);
468 m_releasedTouchPoints.append(gtp);
469 m_liveTouchPoints.remove(touchId);
472 if (m_cachedTouchPoints.contains(touchId)) {
473 GestureTouchPoint* cachedPoint = m_cachedTouchPoints.take(touchId);
474 cachedPoint->deleteLater();
479 GestureTouchPoint* gtp = m_liveTouchPoints.value(touchPoint.id(), nullptr);
481 gtp = addTouchPoint(&touchPoint);
482 m_pressedTouchPoints.append(gtp);
485 if (m_cachedTouchPoints.contains(touchId)) {
486 m_cachedTouchPoints[touchId]->setPos(touchPoint.pos());
488 m_cachedTouchPoints[touchId] = new GestureTouchPoint(*gtp);
492 } else if (touchPointState & Qt::TouchPointMoved) {
493 gtp->setPos(touchPoint.pos());
494 m_movedTouchPoints.append(gtp);
497 const QPointF ¤tPos = touchPoint.scenePos();
498 const QPointF &startPos = touchPoint.startScenePos();
500 bool overDragThreshold = false;
501 bool supportsVelocity = (touchEvent->device()->capabilities() & QTouchDevice::Velocity) && dragVelocity;
502 overDragThreshold |= qAbs(currentPos.x() - startPos.x()) > dragThreshold ||
503 qAbs(currentPos.y() - startPos.y()) > dragThreshold;
504 if (supportsVelocity) {
505 QVector2D velocityVec = touchPoint.velocity();
506 overDragThreshold |= qAbs(velocityVec.x()) > dragVelocity;
507 overDragThreshold |= qAbs(velocityVec.y()) > dragVelocity;
510 if (overDragThreshold) {
511 gtp->setDragging(true);
515 if (m_cachedTouchPoints.contains(touchId)) {
516 m_cachedTouchPoints[touchId]->setPos(touchPoint.pos());
517 if (overDragThreshold) {
518 m_cachedTouchPoints[touchId]->setDragging(true);
527 if (!dragging() && m_status == InternalStatus::Recognized) {
528 bool allWantDrag = !m_liveTouchPoints.isEmpty();
529 Q_FOREACH(auto point, m_liveTouchPoints) {
530 allWantDrag &= point->dragging();
532 // only dragging if all points are dragging.
539 if (m_liveTouchPoints.isEmpty()) {
540 if (!dragging()) Q_EMIT clicked();
543 tgaDebug("Released " << touchesString(m_releasedTouchPoints));
544 Q_EMIT released(m_releasedTouchPoints);
547 tgaDebug("Pressed " << touchesString(m_pressedTouchPoints));
548 Q_EMIT pressed(m_pressedTouchPoints);
551 tgaDebug("Updated " << touchesString(m_movedTouchPoints));
552 Q_EMIT updated(m_movedTouchPoints);
554 if (added || ended || moved) {
555 Q_EMIT touchPointsUpdated();
560void TouchGestureArea::clearTouchLists()
562 Q_FOREACH (QObject *gtp, m_releasedTouchPoints) {
565 m_releasedTouchPoints.clear();
566 m_pressedTouchPoints.clear();
567 m_movedTouchPoints.clear();
570void TouchGestureArea::setInternalStatus(uint newStatus)
572 if (newStatus == m_status)
575 uint oldStatus = m_status;
577 m_status = newStatus;
578 Q_EMIT statusChanged(status());
580 if (oldStatus == InternalStatus::WaitingForMoreTouches || oldStatus == InternalStatus::WaitingForRejection) {
581 m_recognitionTimer->stop();
584 tgaDebug(statusToString(oldStatus) << " -> " << statusToString(newStatus));
587 case InternalStatus::WaitingForTouch:
588 resyncCachedTouchPoints();
590 case InternalStatus::WaitingForMoreTouches:
591 m_recognitionTimer->start(m_recognitionPeriod);
593 case InternalStatus::Recognized:
594 resyncCachedTouchPoints();
596 case InternalStatus::WaitingForRejection:
597 m_recognitionTimer->start(m_releaseRejectPeriod);
599 case InternalStatus::Rejected:
600 resyncCachedTouchPoints();
608void TouchGestureArea::setRecognitionTimer(UbuntuGestures::AbstractTimer *timer)
611 bool timerWasRunning = false;
612 bool wasSingleShot = false;
614 // can be null when called from the constructor
615 if (m_recognitionTimer) {
616 interval = m_recognitionTimer->interval();
617 timerWasRunning = m_recognitionTimer->isRunning();
618 if (m_recognitionTimer->parent() == this) {
619 delete m_recognitionTimer;
623 m_recognitionTimer = timer;
624 timer->setInterval(interval);
625 timer->setSingleShot(wasSingleShot);
626 connect(timer, SIGNAL(timeout()),
627 this, SLOT(rejectGesture()));
628 if (timerWasRunning) {
629 m_recognitionTimer->start();
633int TouchGestureArea::status() const
635 return internalStatusToGestureStatus(m_status);
638bool TouchGestureArea::dragging() const
643QQmlListProperty<GestureTouchPoint> TouchGestureArea::touchPoints()
645 return QQmlListProperty<GestureTouchPoint>(this,
648 TouchGestureArea::touchPoint_count,
649 TouchGestureArea::touchPoint_at,
653int TouchGestureArea::minimumTouchPoints() const
655 return m_minimumTouchPoints;
658void TouchGestureArea::setMinimumTouchPoints(int value)
660 if (m_minimumTouchPoints != value) {
661 m_minimumTouchPoints = value;
662 Q_EMIT minimumTouchPointsChanged(value);
666int TouchGestureArea::maximumTouchPoints() const
668 return m_maximumTouchPoints;
671void TouchGestureArea::setMaximumTouchPoints(int value)
673 if (m_maximumTouchPoints != value) {
674 m_maximumTouchPoints = value;
675 Q_EMIT maximumTouchPointsChanged(value);
679int TouchGestureArea::recognitionPeriod() const
681 return m_recognitionPeriod;
684void TouchGestureArea::setRecognitionPeriod(int value)
686 if (value != m_recognitionPeriod) {
687 m_recognitionPeriod = value;
688 Q_EMIT recognitionPeriodChanged(value);
692int TouchGestureArea::releaseRejectPeriod() const
694 return m_releaseRejectPeriod;
697void TouchGestureArea::setReleaseRejectPeriod(int value)
699 if (value != m_releaseRejectPeriod) {
700 m_releaseRejectPeriod = value;
701 Q_EMIT releaseRejectPeriodChanged(value);
705void TouchGestureArea::rejectGesture()
707 tgaDebug("rejectGesture");
710 Q_FOREACH(int touchId, m_candidateTouches) {
711 TouchRegistry::instance()->removeCandidateOwnerForTouch(touchId, this);
714 // Monitor the candidates
715 Q_FOREACH(int touchId, m_candidateTouches) {
716 TouchRegistry::instance()->addTouchWatcher(touchId, this);
717 m_watchedTouches.insert(touchId);
719 m_candidateTouches.clear();
721 if (m_watchedTouches.count() == 0) {
722 setInternalStatus(InternalStatus::WaitingForTouch);
724 setInternalStatus(InternalStatus::Rejected);
728void TouchGestureArea::resyncCachedTouchPoints()
735 bool wantsDrag = false;
738 QMutableHashIterator<int, GestureTouchPoint*> removeIter(m_cachedTouchPoints);
739 while(removeIter.hasNext()) {
741 if (!m_liveTouchPoints.contains(removeIter.key())) {
742 m_releasedTouchPoints.append(removeIter.value());
748 // list of adds/moves
749 Q_FOREACH(GestureTouchPoint* touchPoint, m_liveTouchPoints) {
750 if (m_cachedTouchPoints.contains(touchPoint->id())) {
751 GestureTouchPoint* cachedPoint = m_cachedTouchPoints[touchPoint->id()];
753 if (*cachedPoint != *touchPoint) {
754 *cachedPoint = *touchPoint;
755 m_movedTouchPoints.append(touchPoint);
759 m_cachedTouchPoints.insert(touchPoint->id(), new GestureTouchPoint(*touchPoint));
760 m_pressedTouchPoints.append(touchPoint);
765 if (wantsDrag && !dragging()) {
770 if (m_cachedTouchPoints.isEmpty()) {
771 if (!dragging()) Q_EMIT clicked();
774 tgaDebug("Cached Release " << touchesString(m_releasedTouchPoints));
775 Q_EMIT released(m_releasedTouchPoints);
778 tgaDebug("Cached Press " << touchesString(m_pressedTouchPoints));
779 Q_EMIT pressed(m_pressedTouchPoints);
782 tgaDebug("Cached Update " << touchesString(m_movedTouchPoints));
783 Q_EMIT updated(m_movedTouchPoints);
785 if (added || ended || moved) Q_EMIT touchPointsUpdated();
788int TouchGestureArea::touchPoint_count(QQmlListProperty<GestureTouchPoint> *list)
790 TouchGestureArea *q = static_cast<TouchGestureArea*>(list->object);
791 return q->m_cachedTouchPoints.count();
794GestureTouchPoint *TouchGestureArea::touchPoint_at(QQmlListProperty<GestureTouchPoint> *list, int index)
796 TouchGestureArea *q = static_cast<TouchGestureArea*>(list->object);
797 return (q->m_cachedTouchPoints.begin()+index).value();
800GestureTouchPoint* TouchGestureArea::addTouchPoint(QTouchEvent::TouchPoint const* tp)
802 GestureTouchPoint* gtp = new GestureTouchPoint();
803 gtp->setId(tp->id());
804 gtp->setPressed(true);
805 gtp->setPos(tp->pos());
806 m_liveTouchPoints.insert(tp->id(), gtp);
810void TouchGestureArea::itemChange(ItemChange change, const ItemChangeData &value)
812 if (change == QQuickItem::ItemSceneChange) {
813 if (value.window != nullptr) {
814 value.window->installEventFilter(TouchRegistry::instance());
819void TouchGestureArea::setDragging(bool dragging)
821 if (m_dragging == dragging)
824 tgaDebug("setDragging " << dragging);
826 m_dragging = dragging;
827 Q_EMIT draggingChanged(m_dragging);
830void GestureTouchPoint::setId(int id)
838void GestureTouchPoint::setPressed(bool pressed)
840 if (m_pressed == pressed)
843 Q_EMIT pressedChanged();
846void GestureTouchPoint::setX(qreal x)
854void GestureTouchPoint::setY(qreal y)
862void GestureTouchPoint::setDragging(bool dragging)
864 if (m_dragging == dragging)
867 m_dragging = dragging;
868 Q_EMIT draggingChanged();
871void 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