libandroidplugin added
[mardrone] / mardrone / qdeclarativetoucharea.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the QML Touch Area plugin of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
14 ** this package.
15 **
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file.  Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23 **
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27 **
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
30 **
31 **
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42
43 #include "qdeclarativetoucharea.h"
44 #include <QEvent>
45 #include <QGraphicsScene>
46 #include <QGraphicsSceneMouseEvent>
47 #include <QDeclarativeExpression>
48 #include <QDeclarativeInfo>
49 #include <math.h>
50
51
52 void
53 QDeclarativeTouchArea::registerQML()
54 {
55     qmlRegisterType<QDeclarativeTouchArea>("TouchArea", 1, 0, "TouchArea");
56     qmlRegisterType<QDeclarativeTouchPoint>("TouchArea", 1, 0, "TouchPoint");
57 }
58
59 QDeclarativeTouchArea::QDeclarativeTouchArea(QDeclarativeItem *parent)
60     : QDeclarativeItem(parent),
61       _minimumTouches(0),
62       _maximumTouches(INT_MAX),
63       _scaleFactor(1.0),
64       _rotationAngle(0.0),
65       _parentTouchArea(this),
66       _active(false),
67       _stealMouse(false)
68 {
69     setAcceptTouchEvents(true);
70     setAcceptedMouseButtons(Qt::LeftButton);
71     setFiltersChildEvents(true);
72 }
73
74 void QDeclarativeTouchArea::updateTopTouchArea() {
75     for (QDeclarativeItem* pItem = parentItem(); pItem != 0; pItem = pItem->parentItem()) {
76         if (QDeclarativeTouchArea* ta = qobject_cast<QDeclarativeTouchArea*>(pItem)) {
77             _parentTouchArea = ta;
78             break;
79         }
80     }
81 }
82
83 QDeclarativeTouchArea::~QDeclarativeTouchArea() {
84 }
85
86 bool QDeclarativeTouchArea::sceneEvent(QEvent *event) {
87     bool rv = false;
88     switch (event->type()) {
89     case QEvent::TouchBegin:
90         updateTopTouchArea();
91         if (_parentTouchArea != this) {
92             if (_active || !_parentTouchArea->_active) {
93                 _active = true;
94                 _parentTouchArea->_active = true;
95                 updateTouchData(event);
96                 rv = true;
97             }
98         } else {
99             updateTouchData(event);
100             rv = true;
101         }
102         break;
103     case QEvent::TouchUpdate:
104         updateTouchData(event);
105         rv = true;
106         break;
107     case QEvent::TouchEnd: {
108         updateTouchData(event);
109         if (_parentTouchArea != this) {
110             if (_touches.empty()) {
111                 _active = false;
112                 _parentTouchArea->_active = false;
113             }
114         }
115         rv = true;
116         break;
117     }
118     default:
119         break;
120     }
121
122     if (!rv)
123         rv = QDeclarativeItem::sceneEvent(event);
124     if (event->type() == QEvent::UngrabMouse) {
125         setKeepMouseGrab(false);
126     }
127     return rv;
128 }
129
130 void QDeclarativeTouchArea::updateTouchData(QEvent *event) {
131     bool ended = false;
132     bool moved = false;
133     bool started = false;
134
135     QDeclarativeItem *grabber = scene() ? qobject_cast<QDeclarativeItem*>(scene()->mouseGrabberItem()) : 0;
136     QDeclarativeTouchArea *touchGrabber = scene() ? qobject_cast<QDeclarativeTouchArea*>(scene()->mouseGrabberItem()) : 0;
137     if (grabber == this || !grabber || !grabber->keepMouseGrab() || touchGrabber) {
138         if (_stealMouse && (grabber != this || !grabber->keepMouseGrab())) {
139             grabMouse();
140             setKeepMouseGrab(true);
141         }
142
143         if (!_keepMouseFocus.script().isEmpty()) {
144             QDeclarativeExpression expr(_keepMouseFocus.context(), _keepMouseFocus.scopeObject(), _keepMouseFocus.script());
145             QVariant result = expr.evaluate();
146             if (expr.hasError())
147                 qmlInfo(this) << expr.error();
148             else
149                 _stealMouse = true;
150         }
151     }
152
153     QTouchEvent *e = static_cast<QTouchEvent*>(event);
154     clearChangedAndReleasedTouches();
155
156     QList<QTouchEvent::TouchPoint> touchPoints = e->touchPoints();
157     int numTouchPoints = touchPoints.count();
158     if (numTouchPoints >= _minimumTouches && numTouchPoints <= _maximumTouches) {
159         foreach (QTouchEvent::TouchPoint p, touchPoints) {
160             Qt::TouchPointState touchPointState = p.state();
161             int id = p.id();
162             if (touchPointState & Qt::TouchPointReleased) {
163                 QDeclarativeTouchPoint* dtp = static_cast<QDeclarativeTouchPoint*>(_touches[id]);
164                 _changedTouches.insert(id,dtp);
165                 _releasedTouches.append(dtp);
166                 _touches.remove(id);
167                 ended = true;
168             } else if (touchPointState & Qt::TouchPointMoved) {
169                 updateTouchPoint(static_cast<QDeclarativeTouchPoint*>(_touches[id]),&p);
170                 updatePinch(&touchPoints);
171                 moved = true;
172             } else if (!_touches.contains(id)) {
173                     addTouchPoint(&p);
174                     started = true;
175             }
176         }
177         if (moved) emit(touchMove());
178         if (ended) emit(touchEnd());
179         if (started) emit(touchStart());
180     }
181     event->accept();
182 }
183
184 void QDeclarativeTouchArea::clearChangedAndReleasedTouches() {
185     foreach (QObject *p, _releasedTouches) {
186         QDeclarativeTouchPoint* dtp = static_cast<QDeclarativeTouchPoint*>(p);
187         if (!dtp->isQmlReferenced())
188             delete dtp;
189         else
190             dtp->setValid(false);
191     }
192     _changedTouches.clear();
193     _releasedTouches.clear();
194 }
195
196 void QDeclarativeTouchArea::addTouchPoint(const QTouchEvent::TouchPoint *p) {
197     QDeclarativeTouchPoint *dtp = 0;
198     foreach (QObject* proto, _touchPrototypes) {
199         QDeclarativeTouchPoint* tp = static_cast<QDeclarativeTouchPoint*>(proto);
200         if (!tp->isValid()) {
201             tp->setValid(true);
202             dtp = tp;
203             break;
204         }
205     }
206
207     if (dtp == 0)
208         dtp = new QDeclarativeTouchPoint(false);
209     dtp->setId(p->id());
210     updateTouchPoint(dtp,p);
211     _touches.insert(p->id(),dtp);
212 }
213
214 void QDeclarativeTouchArea::addTouchPrototype(QDeclarativeTouchPoint *prototype) {
215     int id = _touchPrototypes.count();
216     prototype->setId(id);
217     _touchPrototypes.insert(id, prototype);
218 }
219
220 void QDeclarativeTouchArea::updateTouchPoint(QDeclarativeTouchPoint *dtp, const QTouchEvent::TouchPoint *p) {
221     dtp->setX(p->pos().x());
222     dtp->setY(p->pos().y());
223     dtp->setSceneX(p->scenePos().x());
224     dtp->setSceneY(p->scenePos().y());
225     _changedTouches.insert(dtp->id(),dtp);
226 }
227
228 void QDeclarativeTouchArea::updatePinch(QList<QTouchEvent::TouchPoint> *touchPoints) {
229     if (touchPoints->count()==2) {
230         QTouchEvent::TouchPoint tp1 = touchPoints->at(0);
231         QTouchEvent::TouchPoint tp2 = touchPoints->at(1);
232
233         QPointF tp1LastPos = tp1.lastPos();
234         QPointF tp2LastPos = tp2.lastPos();
235         QPointF tp1Pos = tp1.pos();
236         QPointF tp2Pos = tp2.pos();
237
238         QPointF deltaA = tp1LastPos - tp2LastPos;
239         QPointF deltaB = tp1Pos - tp2Pos;
240
241         qreal distanceA = sqrt(pow(deltaA.x(),2.0)+pow(deltaA.y(),2.0));
242         qreal distanceB = sqrt(pow(deltaB.x(),2.0)+pow(deltaB.y(),2.0));
243
244         if (distanceA != 0 && distanceB != 0) {
245             _scaleFactor*=(distanceB/distanceA);
246             emit(scaleFactorChanged());
247         }
248
249         QLineF lineA(tp1LastPos, tp2LastPos);
250         QLineF lineB(tp1Pos,tp2Pos);
251         _rotationAngle-=lineA.angleTo(lineB);
252         emit(rotationAngleChanged());
253     }
254
255 }
256
257 bool QDeclarativeTouchArea::event(QEvent *event)
258 {
259     switch (event->type()) {
260     case QEvent::TouchBegin:
261     case QEvent::TouchUpdate: {
262             updateTouchData(event);
263         }
264         return true;
265     case QEvent::TouchEnd: {
266             updateTouchData(event);
267             _stealMouse = false;
268             QDeclarativeTouchArea *touchGrabber = scene() ? qobject_cast<QDeclarativeTouchArea*>(scene()->mouseGrabberItem()) : 0;
269             if (touchGrabber == this)
270                 ungrabMouse();
271             setKeepMouseGrab(false);
272         }
273         return true;
274     default:
275         return QDeclarativeItem::event(event);
276     }
277
278     return QDeclarativeItem::event(event);
279 }
280
281 bool QDeclarativeTouchArea::sceneEventFilter(QGraphicsItem *i, QEvent *event)
282 {
283     if (!isVisible())
284         return QDeclarativeItem::sceneEventFilter(i, event);
285     switch (event->type()) {
286     case QEvent::TouchBegin:
287     case QEvent::TouchUpdate:
288             updateTouchData(event);
289         return true;
290     case QEvent::TouchEnd: {
291             updateTouchData(event);
292             _stealMouse = false;
293             QDeclarativeTouchArea *touchGrabber = scene() ? qobject_cast<QDeclarativeTouchArea*>(scene()->mouseGrabberItem()) : 0;
294             if (touchGrabber == this)
295                 ungrabMouse();
296             setKeepMouseGrab(false);
297         }
298         return true;
299     default:
300         break;
301     }
302     return QDeclarativeItem::sceneEventFilter(i, event);
303 }
304