1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the QtDeclarative module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file.  Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #include "qdeclarativepincharea_p.h"
43 #include "qdeclarativepincharea_p_p.h"
44 
45 #include <QApplication>
46 #include <QGraphicsScene>
47 
48 #include <float.h>
49 #include <math.h>
50 
51 QT_BEGIN_NAMESPACE
52 
53 
54 /*!
55     \qmlclass PinchEvent QDeclarativePinchEvent
56     \ingroup qml-event-elements
57     \brief The PinchEvent object provides information about a pinch event.
58 
59     \bold {The PinchEvent element was added in QtQuick 1.1}
60 
61     The \c center, \c startCenter, \c previousCenter properties provide the center position between the two touch points.
62 
63     The \c scale and \c previousScale properties provide the scale factor.
64 
65     The \c angle, \c previousAngle and \c rotation properties provide the angle between the two points and the amount of rotation.
66 
67     The \c point1, \c point2, \c startPoint1, \c startPoint2 properties provide the positions of the touch points.
68 
69     The \c accepted property may be set to false in the \c onPinchStarted handler if the gesture should not
70     be handled.
71 
72     \sa PinchArea
73 */
74 
75 /*!
76     \qmlproperty QPointF PinchEvent::center
77     \qmlproperty QPointF PinchEvent::startCenter
78     \qmlproperty QPointF PinchEvent::previousCenter
79 
80     These properties hold the position of the center point between the two touch points.
81 
82     \list
83     \o \c center is the current center point
84     \o \c previousCenter is the center point of the previous event.
85     \o \c startCenter is the center point when the gesture began
86     \endlist
87 */
88 
89 /*!
90     \qmlproperty real PinchEvent::scale
91     \qmlproperty real PinchEvent::previousScale
92 
93     These properties hold the scale factor determined by the change in distance between the two touch points.
94 
95     \list
96     \o \c scale is the current scale factor.
97     \o \c previousScale is the scale factor of the previous event.
98     \endlist
99 
100     When a pinch gesture is started, the scale is 1.0.
101 */
102 
103 /*!
104     \qmlproperty real PinchEvent::angle
105     \qmlproperty real PinchEvent::previousAngle
106     \qmlproperty real PinchEvent::rotation
107 
108     These properties hold the angle between the two touch points.
109 
110     \list
111     \o \c angle is the current angle between the two points in the range -180 to 180.
112     \o \c previousAngle is the angle of the previous event.
113     \o \c rotation is the total rotation since the pinch gesture started.
114     \endlist
115 
116     When a pinch gesture is started, the rotation is 0.0.
117 */
118 
119 /*!
120     \qmlproperty QPointF PinchEvent::point1
121     \qmlproperty QPointF PinchEvent::startPoint1
122     \qmlproperty QPointF PinchEvent::point2
123     \qmlproperty QPointF PinchEvent::startPoint2
124 
125     These properties provide the actual touch points generating the pinch.
126 
127     \list
128     \o \c point1 and \c point2 hold the current positions of the points.
129     \o \c startPoint1 and \c startPoint2 hold the positions of the points when the second point was touched.
130     \endlist
131 */
132 
133 /*!
134     \qmlproperty bool PinchEvent::accepted
135 
136     Setting this property to false in the \c PinchArea::onPinchStarted handler
137     will result in no further pinch events being generated, and the gesture
138     ignored.
139 */
140 
141 /*!
142     \qmlproperty int PinchEvent::pointCount
143 
144     Holds the number of points currently touched.  The PinchArea will not react
145     until two touch points have initited a gesture, but will remain active until
146     all touch points have been released.
147 */
148 
QDeclarativePinch()149 QDeclarativePinch::QDeclarativePinch()
150     : m_target(0), m_minScale(1.0), m_maxScale(1.0)
151     , m_minRotation(0.0), m_maxRotation(0.0)
152     , m_axis(NoDrag), m_xmin(-FLT_MAX), m_xmax(FLT_MAX)
153     , m_ymin(-FLT_MAX), m_ymax(FLT_MAX), m_active(false)
154 {
155 }
156 
~QDeclarativePinchAreaPrivate()157 QDeclarativePinchAreaPrivate::~QDeclarativePinchAreaPrivate()
158 {
159     delete pinch;
160 }
161 
162 /*!
163     \qmlclass PinchArea QDeclarativePinchArea
164     \brief The PinchArea item enables simple pinch gesture handling.
165     \inherits Item
166 
167     \bold {The PinchArea element was added in QtQuick 1.1}
168 
169     A PinchArea is an invisible item that is typically used in conjunction with
170     a visible item in order to provide pinch gesture handling for that item.
171 
172     The \l enabled property is used to enable and disable pinch handling for
173     the proxied item. When disabled, the pinch area becomes transparent to
174     mouse/touch events.
175 
176     PinchArea can be used in two ways:
177 
178     \list
179     \o setting a \c pinch.target to provide automatic interaction with an element
180     \o using the onPinchStarted, onPinchUpdated and onPinchFinished handlers
181     \endlist
182 
183     \sa PinchEvent
184 */
185 
186 /*!
187     \qmlsignal PinchArea::onPinchStarted()
188 
189     This handler is called when the pinch area detects that a pinch gesture has started.
190 
191     The \l {PinchEvent}{pinch} parameter provides information about the pinch gesture,
192     including the scale, center and angle of the pinch.
193 
194     To ignore this gesture set the \c pinch.accepted property to false.  The gesture
195     will be cancelled and no further events will be sent.
196 */
197 
198 /*!
199     \qmlsignal PinchArea::onPinchUpdated()
200 
201     This handler is called when the pinch area detects that a pinch gesture has changed.
202 
203     The \l {PinchEvent}{pinch} parameter provides information about the pinch gesture,
204     including the scale, center and angle of the pinch.
205 */
206 
207 /*!
208     \qmlsignal PinchArea::onPinchFinished()
209 
210     This handler is called when the pinch area detects that a pinch gesture has finished.
211 
212     The \l {PinchEvent}{pinch} parameter provides information about the pinch gesture,
213     including the scale, center and angle of the pinch.
214 */
215 
216 
217 /*!
218     \qmlproperty Item PinchArea::pinch.target
219     \qmlproperty bool PinchArea::pinch.active
220     \qmlproperty real PinchArea::pinch.minimumScale
221     \qmlproperty real PinchArea::pinch.maximumScale
222     \qmlproperty real PinchArea::pinch.minimumRotation
223     \qmlproperty real PinchArea::pinch.maximumRotation
224     \qmlproperty enumeration PinchArea::pinch.dragAxis
225     \qmlproperty real PinchArea::pinch.minimumX
226     \qmlproperty real PinchArea::pinch.maximumX
227     \qmlproperty real PinchArea::pinch.minimumY
228     \qmlproperty real PinchArea::pinch.maximumY
229 
230     \c pinch provides a convenient way to make an item react to pinch gestures.
231 
232     \list
233     \i \c pinch.target specifies the id of the item to drag.
234     \i \c pinch.active specifies if the target item is currently being dragged.
235     \i \c pinch.minimumScale and \c pinch.maximumScale limit the range of the Item::scale property.
236     \i \c pinch.minimumRotation and \c pinch.maximumRotation limit the range of the Item::rotation property.
237     \i \c pinch.dragAxis specifies whether dragging in not allowed (\c Pinch.NoDrag), can be done horizontally (\c Pinch.XAxis), vertically (\c Pinch.YAxis), or both (\c Pinch.XandYAxis)
238     \i \c pinch.minimum and \c pinch.maximum limit how far the target can be dragged along the corresponding axes.
239     \endlist
240 */
241 
QDeclarativePinchArea(QDeclarativeItem * parent)242 QDeclarativePinchArea::QDeclarativePinchArea(QDeclarativeItem *parent)
243   : QDeclarativeItem(*(new QDeclarativePinchAreaPrivate), parent)
244 {
245     Q_D(QDeclarativePinchArea);
246     d->init();
247 }
248 
~QDeclarativePinchArea()249 QDeclarativePinchArea::~QDeclarativePinchArea()
250 {
251 }
252 
253 /*!
254     \qmlproperty bool PinchArea::enabled
255     This property holds whether the item accepts pinch gestures.
256 
257     This property defaults to true.
258 */
isEnabled() const259 bool QDeclarativePinchArea::isEnabled() const
260 {
261     Q_D(const QDeclarativePinchArea);
262     return d->absorb;
263 }
264 
setEnabled(bool a)265 void QDeclarativePinchArea::setEnabled(bool a)
266 {
267     Q_D(QDeclarativePinchArea);
268     if (a != d->absorb) {
269         d->absorb = a;
270         emit enabledChanged();
271     }
272 }
273 
event(QEvent * event)274 bool QDeclarativePinchArea::event(QEvent *event)
275 {
276     Q_D(QDeclarativePinchArea);
277     if (!d->absorb || !isVisible())
278         return QDeclarativeItem::event(event);
279     switch (event->type()) {
280     case QEvent::TouchBegin:
281         d->touchEventsActive = true;
282         // No break, continue to next case.
283     case QEvent::TouchUpdate:
284         if (d->touchEventsActive) {
285             QTouchEvent *touch = static_cast<QTouchEvent*>(event);
286             d->touchPoints.clear();
287             for (int i = 0; i < touch->touchPoints().count(); ++i) {
288                 if (!(touch->touchPoints().at(i).state() & Qt::TouchPointReleased)) {
289                     d->touchPoints << touch->touchPoints().at(i);
290                 }
291             }
292             updatePinch();
293             return true;
294         }
295         break;
296     case QEvent::WindowDeactivate:
297         // No break, continue to next case.
298     case QEvent::TouchEnd:
299         d->touchEventsActive = false;
300         d->touchPoints.clear();
301         updatePinch();
302         break;
303     default:
304         return QDeclarativeItem::event(event);
305     }
306 
307     return QDeclarativeItem::event(event);
308 }
309 
updatePinch()310 void QDeclarativePinchArea::updatePinch()
311 {
312     Q_D(QDeclarativePinchArea);
313     if (d->touchPoints.count() == 0) {
314         if (d->inPinch) {
315             d->stealMouse = false;
316             setKeepMouseGrab(false);
317             d->inPinch = false;
318             QPointF pinchCenter = mapFromScene(d->sceneLastCenter);
319             QDeclarativePinchEvent pe(pinchCenter, d->pinchLastScale, d->pinchLastAngle, d->pinchRotation);
320             pe.setStartCenter(d->pinchStartCenter);
321             pe.setPreviousCenter(pinchCenter);
322             pe.setPreviousAngle(d->pinchLastAngle);
323             pe.setPreviousScale(d->pinchLastScale);
324             pe.setStartPoint1(mapFromScene(d->sceneStartPoint1));
325             pe.setStartPoint2(mapFromScene(d->sceneStartPoint2));
326             pe.setPoint1(mapFromScene(d->lastPoint1));
327             pe.setPoint2(mapFromScene(d->lastPoint2));
328             emit pinchFinished(&pe);
329             d->pinchStartDist = 0;
330             d->pinchActivated = false;
331             if (d->pinch && d->pinch->target())
332                 d->pinch->setActive(false);
333         }
334         return;
335     }
336     QTouchEvent::TouchPoint touchPoint1 = d->touchPoints.at(0);
337     QTouchEvent::TouchPoint touchPoint2 = d->touchPoints.at(d->touchPoints. count() >= 2 ? 1 : 0);
338     if (d->touchPoints.count() == 2
339         && (touchPoint1.state() & Qt::TouchPointPressed || touchPoint2.state() & Qt::TouchPointPressed)) {
340         d->id1 = touchPoint1.id();
341         d->sceneStartPoint1 = touchPoint1.scenePos();
342         d->sceneStartPoint2 = touchPoint2.scenePos();
343         d->inPinch = false;
344         d->pinchRejected = false;
345         d->pinchActivated = true;
346     } else if (d->pinchActivated && !d->pinchRejected) {
347         const int dragThreshold = QApplication::startDragDistance();
348         QPointF p1 = touchPoint1.scenePos();
349         QPointF p2 = touchPoint2.scenePos();
350         qreal dx = p1.x() - p2.x();
351         qreal dy = p1.y() - p2.y();
352         qreal dist = sqrt(dx*dx + dy*dy);
353         QPointF sceneCenter = (p1 + p2)/2;
354         qreal angle = QLineF(p1, p2).angle();
355         if (d->touchPoints.count() == 1) {
356             // If we only have one point then just move the center
357             if (d->id1 == touchPoint1.id())
358                 sceneCenter = d->sceneLastCenter + touchPoint1.scenePos() - d->lastPoint1;
359             else
360                 sceneCenter = d->sceneLastCenter + touchPoint2.scenePos() - d->lastPoint2;
361             angle = d->pinchLastAngle;
362         }
363         d->id1 = touchPoint1.id();
364         if (angle > 180)
365             angle -= 360;
366         if (!d->inPinch) {
367             if (d->touchPoints.count() >= 2
368                     && (qAbs(p1.x()-d->sceneStartPoint1.x()) > dragThreshold
369                     || qAbs(p1.y()-d->sceneStartPoint1.y()) > dragThreshold
370                     || qAbs(p2.x()-d->sceneStartPoint2.x()) > dragThreshold
371                     || qAbs(p2.y()-d->sceneStartPoint2.y()) > dragThreshold)) {
372                 d->sceneStartCenter = sceneCenter;
373                 d->sceneLastCenter = sceneCenter;
374                 d->pinchStartCenter = mapFromScene(sceneCenter);
375                 d->pinchStartDist = dist;
376                 d->pinchStartAngle = angle;
377                 d->pinchLastScale = 1.0;
378                 d->pinchLastAngle = angle;
379                 d->pinchRotation = 0.0;
380                 d->lastPoint1 = p1;
381                 d->lastPoint2 = p2;
382                 QDeclarativePinchEvent pe(d->pinchStartCenter, 1.0, angle, 0.0);
383                 pe.setStartCenter(d->pinchStartCenter);
384                 pe.setPreviousCenter(d->pinchStartCenter);
385                 pe.setPreviousAngle(d->pinchLastAngle);
386                 pe.setPreviousScale(d->pinchLastScale);
387                 pe.setStartPoint1(mapFromScene(d->sceneStartPoint1));
388                 pe.setStartPoint2(mapFromScene(d->sceneStartPoint2));
389                 pe.setPoint1(mapFromScene(d->lastPoint1));
390                 pe.setPoint2(mapFromScene(d->lastPoint2));
391                 pe.setPointCount(d->touchPoints.count());
392                 emit pinchStarted(&pe);
393                 if (pe.accepted()) {
394                     d->inPinch = true;
395                     d->stealMouse = true;
396                     QGraphicsScene *s = scene();
397                     if (s && s->mouseGrabberItem() != this)
398                         grabMouse();
399                     setKeepMouseGrab(true);
400                     if (d->pinch && d->pinch->target()) {
401                         d->pinchStartPos = pinch()->target()->pos();
402                         d->pinchStartScale = d->pinch->target()->scale();
403                         d->pinchStartRotation = d->pinch->target()->rotation();
404                         d->pinch->setActive(true);
405                     }
406                 } else {
407                     d->pinchRejected = true;
408                 }
409             }
410         } else if (d->pinchStartDist > 0) {
411             qreal scale = dist ? dist / d->pinchStartDist : d->pinchLastScale;
412             qreal da = d->pinchLastAngle - angle;
413             if (da > 180)
414                 da -= 360;
415             else if (da < -180)
416                 da += 360;
417             d->pinchRotation += da;
418             QPointF pinchCenter = mapFromScene(sceneCenter);
419             QDeclarativePinchEvent pe(pinchCenter, scale, angle, d->pinchRotation);
420             pe.setStartCenter(d->pinchStartCenter);
421             pe.setPreviousCenter(mapFromScene(d->sceneLastCenter));
422             pe.setPreviousAngle(d->pinchLastAngle);
423             pe.setPreviousScale(d->pinchLastScale);
424             pe.setStartPoint1(mapFromScene(d->sceneStartPoint1));
425             pe.setStartPoint2(mapFromScene(d->sceneStartPoint2));
426             pe.setPoint1(touchPoint1.pos());
427             pe.setPoint2(touchPoint2.pos());
428             pe.setPointCount(d->touchPoints.count());
429             d->pinchLastScale = scale;
430             d->sceneLastCenter = sceneCenter;
431             d->pinchLastAngle = angle;
432             d->lastPoint1 = touchPoint1.scenePos();
433             d->lastPoint2 = touchPoint2.scenePos();
434             emit pinchUpdated(&pe);
435             if (d->pinch && d->pinch->target()) {
436                 qreal s = d->pinchStartScale * scale;
437                 s = qMin(qMax(pinch()->minimumScale(),s), pinch()->maximumScale());
438                 pinch()->target()->setScale(s);
439                 QPointF pos = sceneCenter - d->sceneStartCenter + d->pinchStartPos;
440                 if (pinch()->axis() & QDeclarativePinch::XAxis) {
441                     qreal x = pos.x();
442                     if (x < pinch()->xmin())
443                         x = pinch()->xmin();
444                     else if (x > pinch()->xmax())
445                         x = pinch()->xmax();
446                     pinch()->target()->setX(x);
447                 }
448                 if (pinch()->axis() & QDeclarativePinch::YAxis) {
449                     qreal y = pos.y();
450                     if (y < pinch()->ymin())
451                         y = pinch()->ymin();
452                     else if (y > pinch()->ymax())
453                         y = pinch()->ymax();
454                     pinch()->target()->setY(y);
455                 }
456                 if (d->pinchStartRotation >= pinch()->minimumRotation()
457                         && d->pinchStartRotation <= pinch()->maximumRotation()) {
458                     qreal r = d->pinchRotation + d->pinchStartRotation;
459                     r = qMin(qMax(pinch()->minimumRotation(),r), pinch()->maximumRotation());
460                     pinch()->target()->setRotation(r);
461                 }
462             }
463         }
464     }
465 }
466 
mousePressEvent(QGraphicsSceneMouseEvent * event)467 void QDeclarativePinchArea::mousePressEvent(QGraphicsSceneMouseEvent *event)
468 {
469     Q_D(QDeclarativePinchArea);
470     d->stealMouse = false;
471     if (!d->absorb)
472         QDeclarativeItem::mousePressEvent(event);
473     else {
474         setKeepMouseGrab(false);
475         event->setAccepted(true);
476     }
477 }
478 
mouseMoveEvent(QGraphicsSceneMouseEvent * event)479 void QDeclarativePinchArea::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
480 {
481     Q_D(QDeclarativePinchArea);
482     if (!d->absorb) {
483         QDeclarativeItem::mouseMoveEvent(event);
484         return;
485     }
486 }
487 
mouseReleaseEvent(QGraphicsSceneMouseEvent * event)488 void QDeclarativePinchArea::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
489 {
490     Q_D(QDeclarativePinchArea);
491     d->stealMouse = false;
492     if (!d->absorb) {
493         QDeclarativeItem::mouseReleaseEvent(event);
494     } else {
495         QGraphicsScene *s = scene();
496         if (s && s->mouseGrabberItem() == this)
497             ungrabMouse();
498         setKeepMouseGrab(false);
499     }
500 }
501 
sceneEvent(QEvent * event)502 bool QDeclarativePinchArea::sceneEvent(QEvent *event)
503 {
504     bool rv = QDeclarativeItem::sceneEvent(event);
505     if (event->type() == QEvent::UngrabMouse) {
506         setKeepMouseGrab(false);
507     }
508     return rv;
509 }
510 
sendMouseEvent(QGraphicsSceneMouseEvent * event)511 bool QDeclarativePinchArea::sendMouseEvent(QGraphicsSceneMouseEvent *event)
512 {
513     Q_D(QDeclarativePinchArea);
514     QGraphicsSceneMouseEvent mouseEvent(event->type());
515     QRectF myRect = mapToScene(QRectF(0, 0, width(), height())).boundingRect();
516 
517     QGraphicsScene *s = scene();
518     QDeclarativeItem *grabber = s ? qobject_cast<QDeclarativeItem*>(s->mouseGrabberItem()) : 0;
519     bool stealThisEvent = d->stealMouse;
520     if ((stealThisEvent || myRect.contains(event->scenePos().toPoint())) && (!grabber || !grabber->keepMouseGrab())) {
521         mouseEvent.setAccepted(false);
522         for (int i = 0x1; i <= 0x10; i <<= 1) {
523             if (event->buttons() & i) {
524                 Qt::MouseButton button = Qt::MouseButton(i);
525                 mouseEvent.setButtonDownPos(button, mapFromScene(event->buttonDownPos(button)));
526             }
527         }
528         mouseEvent.setScenePos(event->scenePos());
529         mouseEvent.setLastScenePos(event->lastScenePos());
530         mouseEvent.setPos(mapFromScene(event->scenePos()));
531         mouseEvent.setLastPos(mapFromScene(event->lastScenePos()));
532 
533         switch(mouseEvent.type()) {
534         case QEvent::GraphicsSceneMouseMove:
535             mouseMoveEvent(&mouseEvent);
536             break;
537         case QEvent::GraphicsSceneMousePress:
538             mousePressEvent(&mouseEvent);
539             break;
540         case QEvent::GraphicsSceneMouseRelease:
541             mouseReleaseEvent(&mouseEvent);
542             break;
543         default:
544             break;
545         }
546         grabber = qobject_cast<QDeclarativeItem*>(s->mouseGrabberItem());
547         if (grabber && stealThisEvent && !grabber->keepMouseGrab() && grabber != this)
548             grabMouse();
549 
550         return stealThisEvent;
551     }
552     if (mouseEvent.type() == QEvent::GraphicsSceneMouseRelease) {
553         d->stealMouse = false;
554         if (s && s->mouseGrabberItem() == this)
555             ungrabMouse();
556         setKeepMouseGrab(false);
557     }
558     return false;
559 }
560 
sceneEventFilter(QGraphicsItem * i,QEvent * e)561 bool QDeclarativePinchArea::sceneEventFilter(QGraphicsItem *i, QEvent *e)
562 {
563     Q_D(QDeclarativePinchArea);
564     if (!d->absorb || !isVisible())
565         return QDeclarativeItem::sceneEventFilter(i, e);
566     switch (e->type()) {
567     case QEvent::GraphicsSceneMousePress:
568     case QEvent::GraphicsSceneMouseMove:
569     case QEvent::GraphicsSceneMouseRelease:
570         return sendMouseEvent(static_cast<QGraphicsSceneMouseEvent *>(e));
571         break;
572     case QEvent::TouchBegin:
573     case QEvent::TouchUpdate: {
574             QTouchEvent *touch = static_cast<QTouchEvent*>(e);
575             d->touchPoints.clear();
576             for (int i = 0; i < touch->touchPoints().count(); ++i)
577                 if (!(touch->touchPoints().at(i).state() & Qt::TouchPointReleased))
578                     d->touchPoints << touch->touchPoints().at(i);
579             updatePinch();
580         }
581         return d->inPinch;
582     case QEvent::TouchEnd:
583         d->touchPoints.clear();
584         updatePinch();
585         break;
586     default:
587         break;
588     }
589 
590     return QDeclarativeItem::sceneEventFilter(i, e);
591 }
592 
geometryChanged(const QRectF & newGeometry,const QRectF & oldGeometry)593 void QDeclarativePinchArea::geometryChanged(const QRectF &newGeometry,
594                                             const QRectF &oldGeometry)
595 {
596     QDeclarativeItem::geometryChanged(newGeometry, oldGeometry);
597 }
598 
itemChange(GraphicsItemChange change,const QVariant & value)599 QVariant QDeclarativePinchArea::itemChange(GraphicsItemChange change,
600                                        const QVariant &value)
601 {
602     return QDeclarativeItem::itemChange(change, value);
603 }
604 
pinch()605 QDeclarativePinch *QDeclarativePinchArea::pinch()
606 {
607     Q_D(QDeclarativePinchArea);
608     if (!d->pinch)
609         d->pinch = new QDeclarativePinch;
610     return d->pinch;
611 }
612 
613 
614 QT_END_NAMESPACE
615