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