Rename QDeclarative symbols to QQuick and QQml
[profile/ivi/qtdeclarative.git] / src / quick / items / qquickmultipointtoucharea.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtQml module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qquickmultipointtoucharea_p.h"
43 #include <QtQuick/qquickcanvas.h>
44 #include <private/qsgadaptationlayer_p.h>
45 #include <private/qquickitem_p.h>
46 #include <QEvent>
47 #include <QMouseEvent>
48 #include <math.h>
49 #include <QDebug>
50
51 QT_BEGIN_NAMESPACE
52
53 DEFINE_BOOL_CONFIG_OPTION(qmlVisualTouchDebugging, QML_VISUAL_TOUCH_DEBUGGING)
54
55 /*!
56     \qmlclass TouchPoint QQuickTouchPoint
57     \inqmlmodule QtQuick 2
58     \ingroup qml-event-elements
59     \brief The TouchPoint element describes a touch point in a MultiPointTouchArea.
60
61     The TouchPoint element contains information about a touch point, such as the current
62     position, pressure, and area.
63 */
64
65 /*!
66     \qmlproperty int QtQuick2::TouchPoint::pointId
67
68     This property holds the point id of the touch point.
69
70     Each touch point within a MultiPointTouchArea will have a unique id.
71 */
72 void QQuickTouchPoint::setPointId(int id)
73 {
74     if (_id == id)
75         return;
76     _id = id;
77     emit pointIdChanged();
78 }
79
80 /*!
81     \qmlproperty real QtQuick2::TouchPoint::x
82     \qmlproperty real QtQuick2::TouchPoint::y
83
84     These properties hold the current position of the touch point.
85 */
86
87 void QQuickTouchPoint::setX(qreal x)
88 {
89     if (_x == x)
90         return;
91     _x = x;
92     emit xChanged();
93 }
94
95 void QQuickTouchPoint::setY(qreal y)
96 {
97     if (_y == y)
98         return;
99     _y = y;
100     emit yChanged();
101 }
102
103 /*!
104     \qmlproperty real QtQuick2::TouchPoint::pressure
105     \qmlproperty vector2d QtQuick2::TouchPoint::velocity
106     \qmlproperty rectangle QtQuick2::TouchPoint::area
107
108     These properties hold additional information about the current state of the touch point.
109
110     \list
111     \i \c pressure is a value in the range of 0.0 to 1.0.
112     \i \c velocity is a vector with magnitude reported in pixels per second.
113     \i \c area is a rectangle covering the area of the touch point, centered on the current position of the touch point.
114     \endlist
115
116     Not all touch devices support velocity. If velocity is not supported, it will be reported
117     as 0,0.
118 */
119 void QQuickTouchPoint::setPressure(qreal pressure)
120 {
121     if (_pressure == pressure)
122         return;
123     _pressure = pressure;
124     emit pressureChanged();
125 }
126
127 void QQuickTouchPoint::setVelocity(const QVector2D &velocity)
128 {
129     if (_velocity == velocity)
130         return;
131     _velocity = velocity;
132     emit velocityChanged();
133 }
134
135 void QQuickTouchPoint::setArea(const QRectF &area)
136 {
137     if (_area == area)
138         return;
139     _area = area;
140     emit areaChanged();
141 }
142
143 /*!
144     \qmlproperty bool QtQuick2::TouchPoint::pressed
145
146     This property holds whether the touch point is currently pressed.
147 */
148 void QQuickTouchPoint::setPressed(bool pressed)
149 {
150     if (_pressed == pressed)
151         return;
152     _pressed = pressed;
153     emit pressedChanged();
154 }
155
156 /*!
157     \qmlproperty real QtQuick2::TouchPoint::startX
158     \qmlproperty real QtQuick2::TouchPoint::startY
159
160     These properties hold the starting position of the touch point.
161 */
162
163 void QQuickTouchPoint::setStartX(qreal startX)
164 {
165     if (_startX == startX)
166         return;
167     _startX = startX;
168     emit startXChanged();
169 }
170
171 void QQuickTouchPoint::setStartY(qreal startY)
172 {
173     if (_startY == startY)
174         return;
175     _startY = startY;
176     emit startYChanged();
177 }
178
179 /*!
180     \qmlproperty real QtQuick2::TouchPoint::previousX
181     \qmlproperty real QtQuick2::TouchPoint::previousY
182
183     These properties hold the previous position of the touch point.
184 */
185 void QQuickTouchPoint::setPreviousX(qreal previousX)
186 {
187     if (_previousX == previousX)
188         return;
189     _previousX = previousX;
190     emit previousXChanged();
191 }
192
193 void QQuickTouchPoint::setPreviousY(qreal previousY)
194 {
195     if (_previousY == previousY)
196         return;
197     _previousY = previousY;
198     emit previousYChanged();
199 }
200
201 /*!
202     \qmlproperty real QtQuick2::TouchPoint::sceneX
203     \qmlproperty real QtQuick2::TouchPoint::sceneY
204
205     These properties hold the current position of the touch point in scene coordinates.
206 */
207
208 void QQuickTouchPoint::setSceneX(qreal sceneX)
209 {
210     if (_sceneX == sceneX)
211         return;
212     _sceneX = sceneX;
213     emit sceneXChanged();
214 }
215
216 void QQuickTouchPoint::setSceneY(qreal sceneY)
217 {
218     if (_sceneY == sceneY)
219         return;
220     _sceneY = sceneY;
221     emit sceneYChanged();
222 }
223
224 /*!
225     \qmlclass MultiPointTouchArea QQuickMultiPointTouchArea
226     \inqmlmodule QtQuick 2
227     \brief The MultiPointTouchArea item enables handling of multiple touch points.
228     \inherits Item
229
230     A MultiPointTouchArea is an invisible item that is used to track multiple touch points.
231
232     The \l enabled property is used to enable and disable touch handling. When disabled,
233     the touch area becomes transparent to mouse/touch events.
234
235     MultiPointTouchArea can be used in two ways:
236
237     \list
238     \o setting \c touchPoints to provide touch point objects with properties that can be bound to
239     \o using the onTouchUpdated or onTouchPointsPressed, onTouchPointsUpdated and onTouchPointsReleased handlers
240     \endlist
241
242     While a MultiPointTouchArea \i can take exclusive ownership of certain touch points, it is also possible to have
243     multiple MultiPointTouchAreas active at the same time, each operating on a different set of touch points.
244
245     \sa TouchPoint
246 */
247
248 /*!
249     \qmlsignal QtQuick2::MultiPointTouchArea::onPressed(list<TouchPoint> touchPoints)
250
251     This handler is called when new touch points are added. \a touchPoints is a list of these new points.
252
253     If minimumTouchPoints is set to a value greater than one, this handler will not be called until the minimum number
254     of required touch points has been reached. At that point, onPressed will be called with all the current touch points.
255 */
256
257 /*!
258     \qmlsignal QtQuick2::MultiPointTouchArea::onUpdated(list<TouchPoint> touchPoints)
259
260     This handler is called when existing touch points are updated. \a touchPoints is a list of these updated points.
261 */
262
263 /*!
264     \qmlsignal QtQuick2::MultiPointTouchArea::onReleased(list<TouchPoint> touchPoints)
265
266     This handler is called when existing touch points are removed. \a touchPoints is a list of these removed points.
267 */
268
269 /*!
270     \qmlsignal QtQuick2::MultiPointTouchArea::onCanceled(list<TouchPoint> touchPoints)
271
272     This handler is called when new touch events have been canceled because another element stole the touch event handling.
273
274     This signal is for advanced use: it is useful when there is more than one MultiPointTouchArea
275     that is handling input, or when there is a MultiPointTouchArea inside a \l Flickable. In the latter
276     case, if you execute some logic on the onPressed signal and then start dragging, the
277     \l Flickable may steal the touch handling from the MultiPointTouchArea. In these cases, to reset
278     the logic when the MultiPointTouchArea has lost the touch handling to the \l Flickable,
279     \c onCanceled should be used in addition to onReleased.
280
281     \a touchPoints is the list of canceled points.
282 */
283
284 /*!
285     \qmlsignal QtQuick2::MultiPointTouchArea::onGestureStarted(GestureEvent gesture)
286
287     This handler is called when the global drag threshold has been reached.
288
289     This function is typically used when a MultiPointTouchAreas has been nested in a Flickable or another MultiPointTouchArea.
290     Wnen the threshold has been reached, and the handler called, you can determine whether or not the touch
291     area should grab the current touch points. By default they will not be grabbed; to grab them call \c gesture.grab(). If the
292     gesture is not grabbed, the nesting Flickable, for example, would also have an opportunity to grab.
293
294     The gesture object also includes information on the current set of \c touchPoints and the \c dragThreshold.
295 */
296
297 /*!
298     \qmlsignal QtQuick2::MultiPointTouchArea::onTouchUpdated(list<TouchPoint> touchPoints)
299
300     This handler is called when the touch points handled by the MultiPointTouchArea change. This includes adding new touch points,
301     removing or canceling previous touch points, as well as updating current touch point data. \a touchPoints is the list of all current touch
302     points.
303 */
304
305 /*!
306     \qmlproperty list<TouchPoint> QtQuick2::MultiPointTouchArea::touchPoints
307
308     This property holds a set of user-defined touch point objects that can be bound to.
309
310     In the following example, we have two small rectangles that follow our touch points.
311
312     \snippet doc/src/snippets/qml/multipointtoucharea/multipointtoucharea.qml 0
313
314     By default this property holds an empty list.
315
316     \sa TouchPoint
317 */
318
319 QQuickMultiPointTouchArea::QQuickMultiPointTouchArea(QQuickItem *parent)
320     : QQuickItem(parent),
321       _minimumTouchPoints(0),
322       _maximumTouchPoints(INT_MAX),
323       _stealMouse(false)
324 {
325     setAcceptedMouseButtons(Qt::LeftButton);
326     setFiltersChildMouseEvents(true);
327     if (qmlVisualTouchDebugging()) {
328         setFlag(QQuickItem::ItemHasContents);
329     }
330 }
331
332 QQuickMultiPointTouchArea::~QQuickMultiPointTouchArea()
333 {
334     clearTouchLists();
335     foreach (QObject *obj, _touchPoints) {
336         QQuickTouchPoint *dtp = static_cast<QQuickTouchPoint*>(obj);
337         if (!dtp->isQmlDefined())
338             delete dtp;
339     }
340 }
341
342 /*!
343     \qmlproperty int QtQuick2::MultiPointTouchArea::minimumTouchPoints
344     \qmlproperty int QtQuick2::MultiPointTouchArea::maximumTouchPoints
345
346     These properties hold the range of touch points to be handled by the touch area.
347
348     These are convenience that allow you to, for example, have nested MultiPointTouchAreas,
349     one handling two finger touches, and another handling three finger touches.
350
351     By default, all touch points within the touch area are handled.
352 */
353
354 int QQuickMultiPointTouchArea::minimumTouchPoints() const
355 {
356     return _minimumTouchPoints;
357 }
358
359 void QQuickMultiPointTouchArea::setMinimumTouchPoints(int num)
360 {
361     if (_minimumTouchPoints == num)
362         return;
363     _minimumTouchPoints = num;
364     emit minimumTouchPointsChanged();
365 }
366
367 int QQuickMultiPointTouchArea::maximumTouchPoints() const
368 {
369     return _maximumTouchPoints;
370 }
371
372 void QQuickMultiPointTouchArea::setMaximumTouchPoints(int num)
373 {
374     if (_maximumTouchPoints == num)
375         return;
376     _maximumTouchPoints = num;
377     emit maximumTouchPointsChanged();
378 }
379
380 void QQuickMultiPointTouchArea::touchEvent(QTouchEvent *event)
381 {
382     switch (event->type()) {
383     case QEvent::TouchBegin:
384     case QEvent::TouchUpdate:
385     case QEvent::TouchEnd: {
386         //if e.g. a parent Flickable has the mouse grab, don't process the touch events
387         QQuickCanvas *c = canvas();
388         QQuickItem *grabber = c ? c->mouseGrabberItem() : 0;
389         if (grabber && grabber != this && grabber->keepMouseGrab() && grabber->isEnabled()) {
390             QQuickItem *item = this;
391             while ((item = item->parentItem())) {
392                 if (item == grabber)
393                     return;
394             }
395         }
396         updateTouchData(event);
397         if (event->type() == QEvent::TouchEnd) {
398             //TODO: move to canvas
399             _stealMouse = false;
400             setKeepMouseGrab(false);
401             QQuickCanvas *c = canvas();
402             if (c && c->mouseGrabberItem() == this)
403                 ungrabMouse();
404             setKeepTouchGrab(false);
405             ungrabTouchPoints();
406         }
407         break;
408     }
409     default:
410         QQuickItem::touchEvent(event);
411         break;
412     }
413 }
414
415 void QQuickMultiPointTouchArea::grabGesture()
416 {
417     _stealMouse = true;
418
419     grabMouse();
420     setKeepMouseGrab(true);
421
422     grabTouchPoints(_touchPoints.keys());
423     setKeepTouchGrab(true);
424 }
425
426 void QQuickMultiPointTouchArea::updateTouchData(QEvent *event)
427 {
428     bool ended = false;
429     bool moved = false;
430     bool started = false;
431
432     clearTouchLists();
433     QTouchEvent *e = static_cast<QTouchEvent*>(event);
434     QList<QTouchEvent::TouchPoint> touchPoints = e->touchPoints();
435     int numTouchPoints = touchPoints.count();
436     //always remove released touches, and make sure we handle all releases before adds.
437     foreach (const QTouchEvent::TouchPoint &p, touchPoints) {
438         Qt::TouchPointState touchPointState = p.state();
439         int id = p.id();
440         if (touchPointState & Qt::TouchPointReleased) {
441             QQuickTouchPoint* dtp = static_cast<QQuickTouchPoint*>(_touchPoints.value(id));
442             if (!dtp)
443                 continue;
444             updateTouchPoint(dtp, &p);
445             dtp->setPressed(false);
446             _releasedTouchPoints.append(dtp);
447             _touchPoints.remove(id);
448             ended = true;
449         }
450     }
451     if (numTouchPoints >= _minimumTouchPoints && numTouchPoints <= _maximumTouchPoints) {
452         foreach (const QTouchEvent::TouchPoint &p, touchPoints) {
453             Qt::TouchPointState touchPointState = p.state();
454             int id = p.id();
455             if (touchPointState & Qt::TouchPointReleased) {
456                 //handled above
457             } else if (!_touchPoints.contains(id)) { //could be pressed, moved, or stationary
458                 // (we may have just obtained enough points to start tracking them -- in that case moved or stationary count as newly pressed)
459                 addTouchPoint(&p);
460                 started = true;
461             } else if (touchPointState & Qt::TouchPointMoved) {
462                 QQuickTouchPoint* dtp = static_cast<QQuickTouchPoint*>(_touchPoints[id]);
463                 Q_ASSERT(dtp);
464                 _movedTouchPoints.append(dtp);
465                 updateTouchPoint(dtp,&p);
466                 moved = true;
467             } else {
468                 QQuickTouchPoint* dtp = static_cast<QQuickTouchPoint*>(_touchPoints[id]);
469                 Q_ASSERT(dtp);
470                 updateTouchPoint(dtp,&p);
471             }
472         }
473
474         //see if we should be grabbing the gesture
475         if (!_stealMouse /* !ignoring gesture*/) {
476             bool offerGrab = false;
477             const int dragThreshold = qApp->styleHints()->startDragDistance();
478             foreach (const QTouchEvent::TouchPoint &p, touchPoints) {
479                 if (p.state() == Qt::TouchPointReleased)
480                     continue;
481                 const QPointF &currentPos = p.scenePos();
482                 const QPointF &startPos = p.startScenePos();
483                 if (qAbs(currentPos.x() - startPos.x()) > dragThreshold)
484                     offerGrab = true;
485                 else if (qAbs(currentPos.y() - startPos.y()) > dragThreshold)
486                     offerGrab = true;
487                 if (offerGrab)
488                     break;
489             }
490
491             if (offerGrab) {
492                 QQuickGrabGestureEvent event;
493                 event._touchPoints = _touchPoints.values();
494                 emit gestureStarted(&event);
495                 if (event.wantsGrab())
496                     grabGesture();
497             }
498         }
499
500         if (ended) {
501             emit released(_releasedTouchPoints);
502             emit touchPointsReleased(_releasedTouchPoints);
503         }
504         if (moved) {
505             emit updated(_movedTouchPoints);
506             emit touchPointsUpdated(_movedTouchPoints);
507         }
508         if (started) {
509             emit pressed(_pressedTouchPoints);
510             emit touchPointsPressed(_pressedTouchPoints);
511         }
512         if (ended || moved || started) emit touchUpdated(_touchPoints.values());
513     }
514 }
515
516 void QQuickMultiPointTouchArea::clearTouchLists()
517 {
518     foreach (QObject *obj, _releasedTouchPoints) {
519         QQuickTouchPoint *dtp = static_cast<QQuickTouchPoint*>(obj);
520         if (!dtp->isQmlDefined())
521             delete dtp;
522         else
523             dtp->setInUse(false);
524     }
525     _releasedTouchPoints.clear();
526     _pressedTouchPoints.clear();
527     _movedTouchPoints.clear();
528 }
529
530 void QQuickMultiPointTouchArea::addTouchPoint(const QTouchEvent::TouchPoint *p)
531 {
532     QQuickTouchPoint *dtp = 0;
533     foreach (QQuickTouchPoint* tp, _touchPrototypes) {
534         if (!tp->inUse()) {
535             tp->setInUse(true);
536             dtp = tp;
537             break;
538         }
539     }
540
541     if (dtp == 0)
542         dtp = new QQuickTouchPoint(false);
543     dtp->setPointId(p->id());
544     updateTouchPoint(dtp,p);
545     dtp->setPressed(true);
546     _touchPoints.insert(p->id(),dtp);
547     _pressedTouchPoints.append(dtp);
548 }
549
550 void QQuickMultiPointTouchArea::addTouchPrototype(QQuickTouchPoint *prototype)
551 {
552     int id = _touchPrototypes.count();
553     prototype->setPointId(id);
554     _touchPrototypes.insert(id, prototype);
555 }
556
557 void QQuickMultiPointTouchArea::updateTouchPoint(QQuickTouchPoint *dtp, const QTouchEvent::TouchPoint *p)
558 {
559     //TODO: if !qmlDefined, could bypass setters.
560     //      also, should only emit signals after all values have been set
561     dtp->setX(p->pos().x());
562     dtp->setY(p->pos().y());
563     dtp->setPressure(p->pressure());
564     dtp->setVelocity(p->velocity());
565     dtp->setArea(p->rect());
566     dtp->setStartX(p->startPos().x());
567     dtp->setStartY(p->startPos().y());
568     dtp->setPreviousX(p->lastPos().x());
569     dtp->setPreviousY(p->lastPos().y());
570     dtp->setSceneX(p->scenePos().x());
571     dtp->setSceneY(p->scenePos().y());
572 }
573
574 void QQuickMultiPointTouchArea::mousePressEvent(QMouseEvent *event)
575 {
576     if (!isEnabled()) {
577         QQuickItem::mousePressEvent(event);
578         return;
579     }
580
581     _stealMouse = false;
582     setKeepMouseGrab(false);
583     event->setAccepted(true);
584 }
585
586 void QQuickMultiPointTouchArea::mouseMoveEvent(QMouseEvent *event)
587 {
588     if (!isEnabled()) {
589         QQuickItem::mouseMoveEvent(event);
590         return;
591     }
592
593     //do nothing
594 }
595
596 void QQuickMultiPointTouchArea::mouseReleaseEvent(QMouseEvent *event)
597 {
598     _stealMouse = false;
599     if (!isEnabled()) {
600         QQuickItem::mouseReleaseEvent(event);
601         return;
602     }
603     QQuickCanvas *c = canvas();
604     if (c && c->mouseGrabberItem() == this)
605         ungrabMouse();
606     setKeepMouseGrab(false);
607 }
608
609 void QQuickMultiPointTouchArea::ungrab()
610 {
611     if (_touchPoints.count()) {
612         QQuickCanvas *c = canvas();
613         if (c && c->mouseGrabberItem() == this) {
614             _stealMouse = false;
615             setKeepMouseGrab(false);
616         }
617         setKeepTouchGrab(false);
618         foreach (QObject *obj, _touchPoints)
619             static_cast<QQuickTouchPoint*>(obj)->setPressed(false);
620         emit canceled(_touchPoints.values());
621         emit touchPointsCanceled(_touchPoints.values());
622         clearTouchLists();
623         foreach (QObject *obj, _touchPoints) {
624             QQuickTouchPoint *dtp = static_cast<QQuickTouchPoint*>(obj);
625             if (!dtp->isQmlDefined())
626                 delete dtp;
627             else
628                 dtp->setInUse(false);
629         }
630         _touchPoints.clear();
631         emit touchUpdated(QList<QObject*>());
632     }
633 }
634
635 void QQuickMultiPointTouchArea::mouseUngrabEvent()
636 {
637     ungrab();
638 }
639
640 void QQuickMultiPointTouchArea::touchUngrabEvent()
641 {
642     ungrab();
643 }
644
645 bool QQuickMultiPointTouchArea::sendMouseEvent(QMouseEvent *event)
646 {
647     QRectF myRect = mapRectToScene(QRectF(0, 0, width(), height()));
648
649     QQuickCanvas *c = canvas();
650     QQuickItem *grabber = c ? c->mouseGrabberItem() : 0;
651     bool stealThisEvent = _stealMouse;
652     if ((stealThisEvent || myRect.contains(event->windowPos())) && (!grabber || !grabber->keepMouseGrab())) {
653         QMouseEvent mouseEvent(event->type(), mapFromScene(event->windowPos()), event->windowPos(), event->screenPos(),
654                                event->button(), event->buttons(), event->modifiers());
655         mouseEvent.setAccepted(false);
656
657         switch (mouseEvent.type()) {
658         case QEvent::MouseMove:
659             mouseMoveEvent(&mouseEvent);
660             break;
661         case QEvent::MouseButtonPress:
662             mousePressEvent(&mouseEvent);
663             break;
664         case QEvent::MouseButtonRelease:
665             mouseReleaseEvent(&mouseEvent);
666             break;
667         default:
668             break;
669         }
670         grabber = c->mouseGrabberItem();
671         if (grabber && stealThisEvent && !grabber->keepMouseGrab() && grabber != this)
672             grabMouse();
673
674         return stealThisEvent;
675     }
676     if (event->type() == QEvent::MouseButtonRelease) {
677         _stealMouse = false;
678         if (c && c->mouseGrabberItem() == this)
679             ungrabMouse();
680         setKeepMouseGrab(false);
681     }
682     return false;
683 }
684
685 bool QQuickMultiPointTouchArea::childMouseEventFilter(QQuickItem *i, QEvent *event)
686 {
687     if (!isEnabled() || !isVisible())
688         return QQuickItem::childMouseEventFilter(i, event);
689     switch (event->type()) {
690     case QEvent::MouseButtonPress:
691     case QEvent::MouseMove:
692     case QEvent::MouseButtonRelease:
693         return sendMouseEvent(static_cast<QMouseEvent *>(event));
694         break;
695     case QEvent::TouchBegin:
696     case QEvent::TouchUpdate:
697         if (!shouldFilter(event))
698             return false;
699         updateTouchData(event);
700         return _stealMouse;
701     case QEvent::TouchEnd: {
702             if (!shouldFilter(event))
703                 return false;
704             updateTouchData(event);
705             //TODO: verify this behavior
706             _stealMouse = false;
707             setKeepMouseGrab(false);
708             QQuickCanvas *c = canvas();
709             if (c && c->mouseGrabberItem() == this)
710                 ungrabMouse();
711             setKeepTouchGrab(false);
712             ungrabTouchPoints();
713         }
714         break;
715     default:
716         break;
717     }
718     return QQuickItem::childMouseEventFilter(i, event);
719 }
720
721 bool QQuickMultiPointTouchArea::shouldFilter(QEvent *event)
722 {
723     QQuickCanvas *c = canvas();
724     QQuickItem *grabber = c ? c->mouseGrabberItem() : 0;
725     bool disabledItem = grabber && !grabber->isEnabled();
726     bool stealThisEvent = _stealMouse;
727     bool contains = false;
728     if (!stealThisEvent) {
729         switch (event->type()) {
730         case QEvent::MouseButtonPress:
731         case QEvent::MouseMove:
732         case QEvent::MouseButtonRelease: {
733                 QMouseEvent *me = static_cast<QMouseEvent*>(event);
734                 QRectF myRect = mapRectToScene(QRectF(0, 0, width(), height()));
735                 contains = myRect.contains(me->windowPos());
736             }
737             break;
738         case QEvent::TouchBegin:
739         case QEvent::TouchUpdate:
740         case QEvent::TouchEnd: {
741                 QTouchEvent *te = static_cast<QTouchEvent*>(event);
742                 QRectF myRect = mapRectToScene(QRectF(0, 0, width(), height()));
743                 foreach (const QTouchEvent::TouchPoint &point, te->touchPoints()) {
744                     if (myRect.contains(point.scenePos())) {
745                         contains = true;
746                         break;
747                     }
748                 }
749             }
750             break;
751         default:
752             break;
753         }
754     }
755     if ((stealThisEvent || contains) && (!grabber || !grabber->keepMouseGrab() || disabledItem)) {
756         return true;
757     }
758     ungrab();
759     return false;
760 }
761
762 QSGNode *QQuickMultiPointTouchArea::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
763 {
764     Q_UNUSED(data);
765
766     if (!qmlVisualTouchDebugging())
767         return 0;
768
769     QSGRectangleNode *rectangle = static_cast<QSGRectangleNode *>(oldNode);
770     if (!rectangle) rectangle = QQuickItemPrivate::get(this)->sceneGraphContext()->createRectangleNode();
771
772     rectangle->setRect(QRectF(0, 0, width(), height()));
773     rectangle->setColor(QColor(255, 0, 0, 50));
774     rectangle->update();
775     return rectangle;
776 }
777
778 QT_END_NAMESPACE