1 /****************************************************************************
3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QML Touch Area plugin of the Qt Toolkit.
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
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.
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.
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
40 ****************************************************************************/
43 #include "qdeclarativetoucharea.h"
45 #include <QGraphicsScene>
46 #include <QGraphicsSceneMouseEvent>
47 #include <QDeclarativeExpression>
48 #include <QDeclarativeInfo>
53 QDeclarativeTouchArea::registerQML()
55 qmlRegisterType<QDeclarativeTouchArea>("TouchArea", 1, 0, "TouchArea");
56 qmlRegisterType<QDeclarativeTouchPoint>("TouchArea", 1, 0, "TouchPoint");
59 QDeclarativeTouchArea::QDeclarativeTouchArea(QDeclarativeItem *parent)
60 : QDeclarativeItem(parent),
62 _maximumTouches(INT_MAX),
65 _parentTouchArea(this),
69 setAcceptTouchEvents(true);
70 setAcceptedMouseButtons(Qt::LeftButton);
71 setFiltersChildEvents(true);
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;
83 QDeclarativeTouchArea::~QDeclarativeTouchArea() {
86 bool QDeclarativeTouchArea::sceneEvent(QEvent *event) {
88 switch (event->type()) {
89 case QEvent::TouchBegin:
91 if (_parentTouchArea != this) {
92 if (_active || !_parentTouchArea->_active) {
94 _parentTouchArea->_active = true;
95 updateTouchData(event);
99 updateTouchData(event);
103 case QEvent::TouchUpdate:
104 updateTouchData(event);
107 case QEvent::TouchEnd: {
108 updateTouchData(event);
109 if (_parentTouchArea != this) {
110 if (_touches.empty()) {
112 _parentTouchArea->_active = false;
123 rv = QDeclarativeItem::sceneEvent(event);
124 if (event->type() == QEvent::UngrabMouse) {
125 setKeepMouseGrab(false);
130 void QDeclarativeTouchArea::updateTouchData(QEvent *event) {
133 bool started = false;
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())) {
140 setKeepMouseGrab(true);
143 if (!_keepMouseFocus.script().isEmpty()) {
144 QDeclarativeExpression expr(_keepMouseFocus.context(), _keepMouseFocus.scopeObject(), _keepMouseFocus.script());
145 QVariant result = expr.evaluate();
147 qmlInfo(this) << expr.error();
153 QTouchEvent *e = static_cast<QTouchEvent*>(event);
154 clearChangedAndReleasedTouches();
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();
162 if (touchPointState & Qt::TouchPointReleased) {
163 QDeclarativeTouchPoint* dtp = static_cast<QDeclarativeTouchPoint*>(_touches[id]);
164 _changedTouches.insert(id,dtp);
165 _releasedTouches.append(dtp);
168 } else if (touchPointState & Qt::TouchPointMoved) {
169 updateTouchPoint(static_cast<QDeclarativeTouchPoint*>(_touches[id]),&p);
170 updatePinch(&touchPoints);
172 } else if (!_touches.contains(id)) {
177 if (moved) emit(touchMove());
178 if (ended) emit(touchEnd());
179 if (started) emit(touchStart());
184 void QDeclarativeTouchArea::clearChangedAndReleasedTouches() {
185 foreach (QObject *p, _releasedTouches) {
186 QDeclarativeTouchPoint* dtp = static_cast<QDeclarativeTouchPoint*>(p);
187 if (!dtp->isQmlReferenced())
190 dtp->setValid(false);
192 _changedTouches.clear();
193 _releasedTouches.clear();
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()) {
208 dtp = new QDeclarativeTouchPoint(false);
210 updateTouchPoint(dtp,p);
211 _touches.insert(p->id(),dtp);
214 void QDeclarativeTouchArea::addTouchPrototype(QDeclarativeTouchPoint *prototype) {
215 int id = _touchPrototypes.count();
216 prototype->setId(id);
217 _touchPrototypes.insert(id, prototype);
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);
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);
233 QPointF tp1LastPos = tp1.lastPos();
234 QPointF tp2LastPos = tp2.lastPos();
235 QPointF tp1Pos = tp1.pos();
236 QPointF tp2Pos = tp2.pos();
238 QPointF deltaA = tp1LastPos - tp2LastPos;
239 QPointF deltaB = tp1Pos - tp2Pos;
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));
244 if (distanceA != 0 && distanceB != 0) {
245 _scaleFactor*=(distanceB/distanceA);
246 emit(scaleFactorChanged());
249 QLineF lineA(tp1LastPos, tp2LastPos);
250 QLineF lineB(tp1Pos,tp2Pos);
251 _rotationAngle-=lineA.angleTo(lineB);
252 emit(rotationAngleChanged());
257 bool QDeclarativeTouchArea::event(QEvent *event)
259 switch (event->type()) {
260 case QEvent::TouchBegin:
261 case QEvent::TouchUpdate: {
262 updateTouchData(event);
265 case QEvent::TouchEnd: {
266 updateTouchData(event);
268 QDeclarativeTouchArea *touchGrabber = scene() ? qobject_cast<QDeclarativeTouchArea*>(scene()->mouseGrabberItem()) : 0;
269 if (touchGrabber == this)
271 setKeepMouseGrab(false);
275 return QDeclarativeItem::event(event);
278 return QDeclarativeItem::event(event);
281 bool QDeclarativeTouchArea::sceneEventFilter(QGraphicsItem *i, QEvent *event)
284 return QDeclarativeItem::sceneEventFilter(i, event);
285 switch (event->type()) {
286 case QEvent::TouchBegin:
287 case QEvent::TouchUpdate:
288 updateTouchData(event);
290 case QEvent::TouchEnd: {
291 updateTouchData(event);
293 QDeclarativeTouchArea *touchGrabber = scene() ? qobject_cast<QDeclarativeTouchArea*>(scene()->mouseGrabberItem()) : 0;
294 if (touchGrabber == this)
296 setKeepMouseGrab(false);
302 return QDeclarativeItem::sceneEventFilter(i, event);