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/TouchOwnershipEvent>
20#include <UbuntuGestures/TouchRegistry>
21#include <UbuntuGestures/UnownedTouchEvent>
22// #include "TouchRegistry.h"
23// #include "UnownedTouchEvent.h"
25#include <QGuiApplication>
27#include <private/qquickwindow_p.h>
29#define TOUCHGESTUREAREA_DEBUG 0
31// TODO - understand more about why we lose touch event releases.
32// Workaround for now is to monitor all the touch points from first touch till
33// all have been released; no matter if we've rejected the gesture.
37struct InternalStatus {
40 WaitingForMoreTouches,
41 WaitingForOwnership, //Recognizing,
48TouchGestureArea::Status internalStatusToGestureStatus(int internalStatus) {
49 switch (internalStatus) {
50 case InternalStatus::WaitingForTouch: return TouchGestureArea::WaitingForTouch;
51 case InternalStatus::WaitingForMoreTouches: return TouchGestureArea::Undecided;
52 case InternalStatus::WaitingForOwnership: return TouchGestureArea::Undecided;
53 case InternalStatus::Recognized: return TouchGestureArea::Recognized;
54 case InternalStatus::WaitingForRejection: return TouchGestureArea::Recognized;
55 case InternalStatus::Rejected: return TouchGestureArea::Rejected;
57 return TouchGestureArea::WaitingForTouch;
62#if TOUCHGESTUREAREA_DEBUG
63#define tgaDebug(params) qDebug().nospace() << "[TGA(" << qPrintable(objectName()) << ")] " << params
64#include "DebugHelpers.h"
68const char *statusToString(int status)
70 if (status == InternalStatus::WaitingForTouch) {
71 return "WaitingForTouch";
72 } else if (status == InternalStatus::WaitingForMoreTouches) {
73 return "WaitingForMoreTouches";
74 } else if (status == InternalStatus::WaitingForOwnership) {
75 return "WaitingForOwnership";
76 } else if (status == InternalStatus::Rejected) {
78 } else if (status == InternalStatus::WaitingForRejection) {
79 return "WaitingForRejection";
86QString touchState(Qt::TouchPointState state) {
88 case Qt::TouchPointPressed: return "pressed";
89 case Qt::TouchPointMoved: return "moved";
90 case Qt::TouchPointStationary: return "stationary";
91 case Qt::TouchPointReleased: return "released";
97QString touchesString(const QList<QObject*> touches) {
99 Q_FOREACH(QObject* object, touches) {
100 GestureTouchPoint* touchPoint = qobject_cast<GestureTouchPoint*>(object);
102 str += QStringLiteral("[%1 @ (%2, %3)], ").arg(touchPoint->id())
103 .arg(touchPoint->x())
104 .arg(touchPoint->y());
110QString touchEventString(QTouchEvent* event) {
111 if (!event) return QString();
113 Q_FOREACH(const auto& touchPoint, event->touchPoints()) {
114 str += QStringLiteral("[%1:%2 @ (%3, %4)], ").arg(touchPoint.id())
115 .arg(touchState(touchPoint.state()))
116 .arg(touchPoint.pos().x())
117 .arg(touchPoint.pos().y());
124#else // TOUCHGESTUREAREA_DEBUG
125#define tgaDebug(params) ((void)0)
126#endif // TOUCHGESTUREAREA_DEBUG
128TouchGestureArea::TouchGestureArea(QQuickItem* parent)
130 , m_status(WaitingForTouch)
131 , m_recognitionTimer(nullptr)
133 , m_minimumTouchPoints(1)
134 , m_maximumTouchPoints(INT_MAX)
135 , m_recognitionPeriod(50)
136 , m_releaseRejectPeriod(100)
138 setRecognitionTimer(new UbuntuGestures::Timer(this));
139 m_recognitionTimer->setInterval(m_recognitionPeriod);
140 m_recognitionTimer->setSingleShot(true);
143TouchGestureArea::~TouchGestureArea()
146 qDeleteAll(m_liveTouchPoints);
147 m_liveTouchPoints.clear();
148 qDeleteAll(m_cachedTouchPoints);
149 m_cachedTouchPoints.clear();
152bool TouchGestureArea::event(QEvent *event)
154 // Process unowned touch events (handles update/release for incomplete gestures)
155 if (event->type() == TouchOwnershipEvent::touchOwnershipEventType()) {
156 touchOwnershipEvent(static_cast<TouchOwnershipEvent *>(event));
158 } else if (event->type() == UnownedTouchEvent::unownedTouchEventType()) {
159 unownedTouchEvent(static_cast<UnownedTouchEvent *>(event)->touchEvent());
163 return QQuickItem::event(event);
166void TouchGestureArea::touchOwnershipEvent(TouchOwnershipEvent *event)
168 int touchId = event->touchId();
169 tgaDebug("touchOwnershipEvent - id:" << touchId << ", gained:" << event->gained());
171 if (event->gained()) {
172 grabTouchPoints(QVector<int>() << touchId);
173 m_candidateTouches.remove(touchId);
174 TouchRegistry::instance()->addTouchWatcher(touchId, this);
175 m_watchedTouches.insert(touchId);
177 if (m_watchedTouches.count() >= m_minimumTouchPoints) {
178 setInternalStatus(InternalStatus::Recognized);
185void TouchGestureArea::touchEvent(QTouchEvent *event)
187 if (!isEnabled() || !isVisible()) {
188 tgaDebug(QString("NOT ENABLED touchEvent(%1) %2").arg(statusToString(m_status)).arg(touchEventString(event)));
189 QQuickItem::touchEvent(event);
193 tgaDebug(QString("touchEvent(%1) %2").arg(statusToString(m_status)).arg(touchEventString(event)));
196 case InternalStatus::WaitingForTouch:
197 touchEvent_waitingForTouch(event);
199 case InternalStatus::WaitingForMoreTouches:
200 touchEvent_waitingForMoreTouches(event);
202 case InternalStatus::WaitingForOwnership:
203 touchEvent_waitingForOwnership(event);
205 case InternalStatus::Recognized:
206 case InternalStatus::WaitingForRejection:
207 touchEvent_recognized(event);
209 case InternalStatus::Rejected:
210 touchEvent_rejected(event);
212 default: // Recognized:
216 updateTouchPoints(event);
219void TouchGestureArea::touchEvent_waitingForTouch(QTouchEvent *event)
221 Q_FOREACH(const QTouchEvent::TouchPoint& touchPoint, event->touchPoints()) {
222 Qt::TouchPointState touchPointState = touchPoint.state();
223 int touchId = touchPoint.id();
225 if (touchPointState == Qt::TouchPointPressed) {
226 if (!m_candidateTouches.contains(touchId)) {
227 TouchRegistry::instance()->addCandidateOwnerForTouch(touchId, this);
228 m_candidateTouches.insert(touchId);
234 if (m_candidateTouches.count() > m_maximumTouchPoints) {
236 } else if (m_candidateTouches.count() >= m_minimumTouchPoints) {
237 setInternalStatus(InternalStatus::WaitingForOwnership);
239 QSet<int> tmpCandidates(m_candidateTouches);
240 Q_FOREACH(int candidateTouchId, tmpCandidates) {
241 TouchRegistry::instance()->requestTouchOwnership(candidateTouchId, this);
243 // We accept the gesture; so don't pass to lower items
245 } else if (m_candidateTouches.count() > 0) {
246 setInternalStatus(InternalStatus::WaitingForMoreTouches);
250void TouchGestureArea::touchEvent_waitingForMoreTouches(QTouchEvent *event)
252 Q_FOREACH(const QTouchEvent::TouchPoint& touchPoint, event->touchPoints()) {
253 Qt::TouchPointState touchPointState = touchPoint.state();
254 int touchId = touchPoint.id();
256 if (touchPointState == Qt::TouchPointPressed) {
257 if (!m_candidateTouches.contains(touchId)) {
258 TouchRegistry::instance()->addCandidateOwnerForTouch(touchId, this);
259 m_candidateTouches.insert(touchId);
265 if (m_candidateTouches.count() > m_maximumTouchPoints) {
267 } else if (m_candidateTouches.count() >= m_minimumTouchPoints) {
268 setInternalStatus(InternalStatus::WaitingForOwnership);
270 QSet<int> tmpCandidates(m_candidateTouches);
271 Q_FOREACH(int candidateTouchId, tmpCandidates) {
272 TouchRegistry::instance()->requestTouchOwnership(candidateTouchId, this);
274 // We accept the gesture; so don't pass to lower items
279void TouchGestureArea::touchEvent_waitingForOwnership(QTouchEvent *event)
281 Q_FOREACH(const QTouchEvent::TouchPoint& touchPoint, event->touchPoints()) {
282 Qt::TouchPointState touchPointState = touchPoint.state();
283 int touchId = touchPoint.id();
285 if (touchPointState == Qt::TouchPointPressed) {
286 if (!m_watchedTouches.contains(touchId)) {
287 TouchRegistry::instance()->addTouchWatcher(touchId, this);
288 m_watchedTouches.insert(touchId);
294void TouchGestureArea::touchEvent_recognized(QTouchEvent *event)
296 Q_FOREACH(const QTouchEvent::TouchPoint& touchPoint, event->touchPoints()) {
297 Qt::TouchPointState touchPointState = touchPoint.state();
298 int touchId = touchPoint.id();
300 if (touchPointState == Qt::TouchPointPressed) {
301 if (!m_watchedTouches.contains(touchId)) {
302 TouchRegistry::instance()->addTouchWatcher(touchId, this);
303 m_watchedTouches.insert(touchId);
308 if (m_watchedTouches.count() > m_maximumTouchPoints) {
310 } else if (m_watchedTouches.count() >= m_minimumTouchPoints &&
311 m_status==InternalStatus::WaitingForRejection) {
312 setInternalStatus(InternalStatus::Recognized);
316void TouchGestureArea::touchEvent_rejected(QTouchEvent *event)
318 Q_FOREACH(const QTouchEvent::TouchPoint& touchPoint, event->touchPoints()) {
319 Qt::TouchPointState touchPointState = touchPoint.state();
320 int touchId = touchPoint.id();
322 if (touchPointState == Qt::TouchPointPressed) {
323 if (!m_watchedTouches.contains(touchId)) {
324 TouchRegistry::instance()->addTouchWatcher(touchId, this);
325 m_watchedTouches.insert(touchId);
331void TouchGestureArea::unownedTouchEvent(QTouchEvent *unownedTouchEvent)
333 tgaDebug(QString("unownedTouchEvent(%1) %2").arg(statusToString(m_status)).arg(touchEventString(unownedTouchEvent)));
335 // Only monitor unowned touch events for presses/releases
336 if ((unownedTouchEvent->touchPointStates() & (Qt::TouchPointPressed|Qt::TouchPointReleased)) == 0) {
341 case InternalStatus::WaitingForTouch:
343 case InternalStatus::WaitingForMoreTouches:
344 unownedTouchEvent_waitingForMoreTouches(unownedTouchEvent);
347 case InternalStatus::WaitingForOwnership:
348 unownedTouchEvent_waitingForOwnership(unownedTouchEvent);
350 case InternalStatus::Recognized:
351 case InternalStatus::WaitingForRejection:
352 unownedTouchEvent_recognised(unownedTouchEvent);
354 case InternalStatus::Rejected:
355 unownedTouchEvent_rejected(unownedTouchEvent);
361 updateTouchPoints(unownedTouchEvent);
364void TouchGestureArea::unownedTouchEvent_waitingForMoreTouches(QTouchEvent *event)
366 Q_FOREACH(const QTouchEvent::TouchPoint& touchPoint, event->touchPoints()) {
367 Qt::TouchPointState touchPointState = touchPoint.state();
368 int touchId = touchPoint.id();
370 if (touchPointState == Qt::TouchPointReleased) {
371 if (m_candidateTouches.contains(touchId)) {
372 TouchRegistry::instance()->removeCandidateOwnerForTouch(touchId, this);
373 m_candidateTouches.remove(touchId);
378 if (m_candidateTouches.isEmpty()) {
379 setInternalStatus(InternalStatus::WaitingForTouch);
383void TouchGestureArea::unownedTouchEvent_waitingForOwnership(QTouchEvent *event)
385 Q_FOREACH(const QTouchEvent::TouchPoint& touchPoint, event->touchPoints()) {
386 Qt::TouchPointState touchPointState = touchPoint.state();
387 int touchId = touchPoint.id();
389 if (touchPointState == Qt::TouchPointReleased) {
390 if (m_candidateTouches.contains(touchId)) {
391 TouchRegistry::instance()->removeCandidateOwnerForTouch(touchId, this);
392 m_candidateTouches.remove(touchId);
394 if (m_watchedTouches.contains(touchId)) {
395 m_watchedTouches.remove(touchId);
400 if (m_candidateTouches.count() + m_watchedTouches.count() == 0) {
401 setInternalStatus(InternalStatus::WaitingForTouch);
405void TouchGestureArea::unownedTouchEvent_recognised(QTouchEvent *event)
407 Q_FOREACH(const QTouchEvent::TouchPoint& touchPoint, event->touchPoints()) {
408 Qt::TouchPointState touchPointState = touchPoint.state();
409 int touchId = touchPoint.id();
411 if (touchPointState == Qt::TouchPointReleased) {
412 if (m_watchedTouches.contains(touchId)) {
413 m_watchedTouches.remove(touchId);
418 if (m_watchedTouches.count() < m_minimumTouchPoints && m_status==InternalStatus::Recognized) {
419 setInternalStatus(InternalStatus::WaitingForRejection);
423void TouchGestureArea::unownedTouchEvent_rejected(QTouchEvent *event)
425 Q_FOREACH(const QTouchEvent::TouchPoint& touchPoint, event->touchPoints()) {
426 Qt::TouchPointState touchPointState = touchPoint.state();
427 int touchId = touchPoint.id();
429 if (touchPointState == Qt::TouchPointPressed) {
430 if (!m_watchedTouches.contains(touchId)) {
431 TouchRegistry::instance()->addTouchWatcher(touchId, this);
432 m_watchedTouches.insert(touchId);
435 if (touchPointState == Qt::TouchPointReleased) {
436 if (m_watchedTouches.contains(touchId)) {
437 m_watchedTouches.remove(touchId);
442 if (m_watchedTouches.isEmpty()) {
443 setInternalStatus(InternalStatus::WaitingForTouch);
447void TouchGestureArea::updateTouchPoints(QTouchEvent *touchEvent)
453 const int dragThreshold = qApp->styleHints()->startDragDistance();
454 const int dragVelocity = qApp->styleHints()->startDragVelocity();
457 bool updateable = m_status != InternalStatus::WaitingForRejection;
459 Q_FOREACH(const QTouchEvent::TouchPoint& touchPoint, touchEvent->touchPoints()) {
460 Qt::TouchPointState touchPointState = touchPoint.state();
461 int touchId = touchPoint.id();
463 if (touchPointState & Qt::TouchPointReleased) {
464 GestureTouchPoint* gtp = m_liveTouchPoints.value(touchId);
467 gtp->setPos(touchPoint.pos());
468 gtp->setPressed(false);
469 m_releasedTouchPoints.append(gtp);
470 m_liveTouchPoints.remove(touchId);
473 if (m_cachedTouchPoints.contains(touchId)) {
474 GestureTouchPoint* cachedPoint = m_cachedTouchPoints.take(touchId);
475 cachedPoint->deleteLater();
480 GestureTouchPoint* gtp = m_liveTouchPoints.value(touchPoint.id(), nullptr);
482 gtp = addTouchPoint(&touchPoint);
483 m_pressedTouchPoints.append(gtp);
486 if (m_cachedTouchPoints.contains(touchId)) {
487 m_cachedTouchPoints[touchId]->setPos(touchPoint.pos());
489 m_cachedTouchPoints[touchId] = new GestureTouchPoint(*gtp);
493 } else if (touchPointState & Qt::TouchPointMoved) {
494 gtp->setPos(touchPoint.pos());
495 m_movedTouchPoints.append(gtp);
498 const QPointF ¤tPos = touchPoint.scenePos();
499 const QPointF &startPos = touchPoint.startScenePos();
501 bool overDragThreshold = false;
502 bool supportsVelocity = (touchEvent->device()->capabilities() & QTouchDevice::Velocity) && dragVelocity;
503 overDragThreshold |= qAbs(currentPos.x() - startPos.x()) > dragThreshold ||
504 qAbs(currentPos.y() - startPos.y()) > dragThreshold;
505 if (supportsVelocity) {
506 QVector2D velocityVec = touchPoint.velocity();
507 overDragThreshold |= qAbs(velocityVec.x()) > dragVelocity;
508 overDragThreshold |= qAbs(velocityVec.y()) > dragVelocity;
511 if (overDragThreshold) {
512 gtp->setDragging(true);
516 if (m_cachedTouchPoints.contains(touchId)) {
517 m_cachedTouchPoints[touchId]->setPos(touchPoint.pos());
518 if (overDragThreshold) {
519 m_cachedTouchPoints[touchId]->setDragging(true);
528 if (!dragging() && m_status == InternalStatus::Recognized) {
529 bool allWantDrag = !m_liveTouchPoints.isEmpty();
530 Q_FOREACH(const auto &point, m_liveTouchPoints) {
531 allWantDrag &= point->dragging();
533 // only dragging if all points are dragging.
540 if (m_liveTouchPoints.isEmpty()) {
541 if (!dragging()) Q_EMIT clicked();
544 tgaDebug("Released " << touchesString(m_releasedTouchPoints));
545 Q_EMIT released(m_releasedTouchPoints);
548 tgaDebug("Pressed " << touchesString(m_pressedTouchPoints));
549 Q_EMIT pressed(m_pressedTouchPoints);
552 tgaDebug("Updated " << touchesString(m_movedTouchPoints));
553 Q_EMIT updated(m_movedTouchPoints);
555 if (added || ended || moved) {
556 Q_EMIT touchPointsUpdated();
561void TouchGestureArea::clearTouchLists()
563 Q_FOREACH (QObject *gtp, m_releasedTouchPoints) {
566 m_releasedTouchPoints.clear();
567 m_pressedTouchPoints.clear();
568 m_movedTouchPoints.clear();
571void TouchGestureArea::setInternalStatus(uint newStatus)
573 if (newStatus == m_status)
576 uint oldStatus = m_status;
578 m_status = newStatus;
579 Q_EMIT statusChanged(status());
581 if (oldStatus == InternalStatus::WaitingForMoreTouches || oldStatus == InternalStatus::WaitingForRejection) {
582 m_recognitionTimer->stop();
585 tgaDebug(statusToString(oldStatus) << " -> " << statusToString(newStatus));
588 case InternalStatus::WaitingForTouch:
589 resyncCachedTouchPoints();
591 case InternalStatus::WaitingForMoreTouches:
592 m_recognitionTimer->setInterval(m_recognitionPeriod);
593 m_recognitionTimer->start();
595 case InternalStatus::Recognized:
596 resyncCachedTouchPoints();
598 case InternalStatus::WaitingForRejection:
599 m_recognitionTimer->setInterval(m_releaseRejectPeriod);
600 m_recognitionTimer->start();
602 case InternalStatus::Rejected:
603 resyncCachedTouchPoints();
611void TouchGestureArea::setRecognitionTimer(UbuntuGestures::AbstractTimer *timer)
614 bool timerWasRunning = false;
615 bool wasSingleShot = false;
617 // can be null when called from the constructor
618 if (m_recognitionTimer) {
619 interval = m_recognitionTimer->interval();
620 timerWasRunning = m_recognitionTimer->isRunning();
621 if (m_recognitionTimer->parent() == this) {
622 delete m_recognitionTimer;
626 m_recognitionTimer = timer;
627 timer->setInterval(interval);
628 timer->setSingleShot(wasSingleShot);
629 connect(timer, SIGNAL(timeout()),
630 this, SLOT(rejectGesture()));
631 if (timerWasRunning) {
632 m_recognitionTimer->start();
636int TouchGestureArea::status() const
638 return internalStatusToGestureStatus(m_status);
641bool TouchGestureArea::dragging() const
646QQmlListProperty<GestureTouchPoint> TouchGestureArea::touchPoints()
648 return QQmlListProperty<GestureTouchPoint>(this,
650 TouchGestureArea::touchPoint_count,
651 TouchGestureArea::touchPoint_at);
654int TouchGestureArea::minimumTouchPoints() const
656 return m_minimumTouchPoints;
659void TouchGestureArea::setMinimumTouchPoints(int value)
661 if (m_minimumTouchPoints != value) {
662 m_minimumTouchPoints = value;
663 Q_EMIT minimumTouchPointsChanged(value);
667int TouchGestureArea::maximumTouchPoints() const
669 return m_maximumTouchPoints;
672void TouchGestureArea::setMaximumTouchPoints(int value)
674 if (m_maximumTouchPoints != value) {
675 m_maximumTouchPoints = value;
676 Q_EMIT maximumTouchPointsChanged(value);
680int TouchGestureArea::recognitionPeriod() const
682 return m_recognitionPeriod;
685void TouchGestureArea::setRecognitionPeriod(int value)
687 if (value != m_recognitionPeriod) {
688 m_recognitionPeriod = value;
689 Q_EMIT recognitionPeriodChanged(value);
693int TouchGestureArea::releaseRejectPeriod() const
695 return m_releaseRejectPeriod;
698void TouchGestureArea::setReleaseRejectPeriod(int value)
700 if (value != m_releaseRejectPeriod) {
701 m_releaseRejectPeriod = value;
702 Q_EMIT releaseRejectPeriodChanged(value);
706void TouchGestureArea::rejectGesture()
708 tgaDebug("rejectGesture");
711 Q_FOREACH(int touchId, m_candidateTouches) {
712 TouchRegistry::instance()->removeCandidateOwnerForTouch(touchId, this);
715 // Monitor the candidates
716 Q_FOREACH(int touchId, m_candidateTouches) {
717 TouchRegistry::instance()->addTouchWatcher(touchId, this);
718 m_watchedTouches.insert(touchId);
720 m_candidateTouches.clear();
722 if (m_watchedTouches.isEmpty()) {
723 setInternalStatus(InternalStatus::WaitingForTouch);
725 setInternalStatus(InternalStatus::Rejected);
729void TouchGestureArea::resyncCachedTouchPoints()
736 bool wantsDrag = false;
739 QMutableHashIterator<int, GestureTouchPoint*> removeIter(m_cachedTouchPoints);
740 while(removeIter.hasNext()) {
742 if (!m_liveTouchPoints.contains(removeIter.key())) {
743 m_releasedTouchPoints.append(removeIter.value());
749 // list of adds/moves
750 Q_FOREACH(GestureTouchPoint* touchPoint, m_liveTouchPoints) {
751 if (m_cachedTouchPoints.contains(touchPoint->id())) {
752 GestureTouchPoint* cachedPoint = m_cachedTouchPoints[touchPoint->id()];
754 if (*cachedPoint != *touchPoint) {
755 *cachedPoint = *touchPoint;
756 m_movedTouchPoints.append(touchPoint);
760 m_cachedTouchPoints.insert(touchPoint->id(), new GestureTouchPoint(*touchPoint));
761 m_pressedTouchPoints.append(touchPoint);
766 if (wantsDrag && !dragging()) {
771 if (m_cachedTouchPoints.isEmpty()) {
772 if (!dragging()) Q_EMIT clicked();
775 tgaDebug("Cached Release " << touchesString(m_releasedTouchPoints));
776 Q_EMIT released(m_releasedTouchPoints);
779 tgaDebug("Cached Press " << touchesString(m_pressedTouchPoints));
780 Q_EMIT pressed(m_pressedTouchPoints);
783 tgaDebug("Cached Update " << touchesString(m_movedTouchPoints));
784 Q_EMIT updated(m_movedTouchPoints);
786 if (added || ended || moved) Q_EMIT touchPointsUpdated();
789int TouchGestureArea::touchPoint_count(QQmlListProperty<GestureTouchPoint> *list)
791 TouchGestureArea *q = static_cast<TouchGestureArea*>(list->object);
792 return q->m_cachedTouchPoints.count();
795GestureTouchPoint *TouchGestureArea::touchPoint_at(QQmlListProperty<GestureTouchPoint> *list, int index)
797 TouchGestureArea *q = static_cast<TouchGestureArea*>(list->object);
798 return (q->m_cachedTouchPoints.begin()+index).value();
801GestureTouchPoint* TouchGestureArea::addTouchPoint(QTouchEvent::TouchPoint const* tp)
803 GestureTouchPoint* gtp = new GestureTouchPoint();
804 gtp->setId(tp->id());
805 gtp->setPressed(true);
806 gtp->setPos(tp->pos());
807 m_liveTouchPoints.insert(tp->id(), gtp);
811void TouchGestureArea::itemChange(ItemChange change, const ItemChangeData &value)
813 if (change == QQuickItem::ItemSceneChange) {
814 if (value.window != nullptr) {
815 value.window->installEventFilter(TouchRegistry::instance());
820void TouchGestureArea::setDragging(bool dragging)
822 if (m_dragging == dragging)
825 tgaDebug("setDragging " << dragging);
827 m_dragging = dragging;
828 Q_EMIT draggingChanged(m_dragging);
831void GestureTouchPoint::setId(int id)
839void GestureTouchPoint::setPressed(bool pressed)
841 if (m_pressed == pressed)
844 Q_EMIT pressedChanged();
847void GestureTouchPoint::setX(qreal x)
855void GestureTouchPoint::setY(qreal y)
863void GestureTouchPoint::setDragging(bool dragging)
865 if (m_dragging == dragging)
868 m_dragging = dragging;
869 Q_EMIT draggingChanged();
872void 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