8dca5e3835b90a073793926c8aada8fd3a0bac64
[profile/ivi/qtdeclarative.git] / src / imports / gestures / qdeclarativegesturearea.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: http://www.qt-project.org/
6 **
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 **
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 **
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
29 **
30 ** Other Usage
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qdeclarativegesturearea_p.h"
43
44 #include <qdeclarativeexpression.h>
45 #include <qdeclarativecontext.h>
46 #include <qdeclarativeinfo.h>
47
48 #include <private/qdeclarativeproperty_p.h>
49 #include <private/qdeclarativescript_p.h>
50 #include <QtQuick1/private/qdeclarativeitem_p.h>
51
52 #include <QtCore/qdebug.h>
53 #include <QtCore/qstringlist.h>
54
55 #include <QtGui/qevent.h>
56
57 #include <private/qobject_p.h>
58
59 #ifndef QT_NO_GESTURES
60
61 QT_BEGIN_NAMESPACE
62
63 class QDeclarativeGestureAreaPrivate : public QDeclarativeItemPrivate
64 {
65     Q_DECLARE_PUBLIC(QDeclarativeGestureArea)
66 public:
67     QDeclarativeGestureAreaPrivate() : componentcomplete(false), gesture(0) {}
68
69     typedef QMap<Qt::GestureType,QDeclarativeExpression*> Bindings;
70     Bindings bindings;
71
72     bool componentcomplete;
73
74     QByteArray data;
75
76     QGesture *gesture;
77
78     bool gestureEvent(QGestureEvent *event);
79 };
80
81 /*!
82     \qmlclass GestureArea QDeclarativeGestureArea
83     \ingroup qml-basic-interaction-elements
84
85     \brief The GestureArea item enables simple gesture handling.
86     \inherits Item
87
88     A GestureArea is like a MouseArea, but it has signals for gesture events.
89
90     \warning Elements in the Qt.labs module are not guaranteed to remain compatible
91     in future versions.
92
93     \warning GestureArea is an experimental element whose development has
94     been discontinued.  PinchArea is available in QtQuick 1.1 and handles
95     two finger gesture input.
96
97     \note This element is only functional on devices with touch input.
98
99     \qml
100     import Qt.labs.gestures 1.0
101
102     GestureArea {
103         anchors.fill: parent
104      // onPan:        ... gesture.acceleration ...
105      // onPinch:      ... gesture.rotationAngle ...
106      // onSwipe:      ...
107      // onTapAndHold: ...
108      // onTap:        ...
109      // onGesture:    ...
110     }
111     \endqml
112
113     Each signal has a \e gesture parameter that has the
114     properties of the gesture.
115
116     \table
117     \header \o Signal \o Type \o Property \o Description
118     \row \o onTap \o point \o position \o the position of the tap
119     \row \o onTapAndHold \o point \o position \o the position of the tap
120     \row \o onPan \o real \o acceleration \o the acceleration of the pan
121     \row \o onPan \o point \o delta \o the offset from the previous input position to the current input
122     \row \o onPan \o point \o offset \o the total offset from the first input position to the current input position
123     \row \o onPan \o point \o lastOffset \o the previous value of offset
124     \row \o onPinch \o point \o centerPoint \o the midpoint between the two input points
125     \row \o onPinch \o point \o lastCenterPoint \o the previous value of centerPoint
126     \row \o onPinch \o point \o startCenterPoint \o the first value of centerPoint
127     \row \o onPinch \o real \o rotationAngle \o the angle covered by the gesture motion
128     \row \o onPinch \o real \o lastRotationAngle \o the previous value of rotationAngle
129     \row \o onPinch \o real \o totalRotationAngle \o the complete angle covered by the gesture
130     \row \o onPinch \o real \o scaleFactor \o the change in distance between the two input points
131     \row \o onPinch \o real \o lastScaleFactor \o the previous value of scaleFactor
132     \row \o onPinch \o real \o totalScaleFactor \o the complete scale factor of the gesture
133     \row \o onSwipe \o real \o swipeAngle \o the angle of the swipe
134     \endtable
135
136     Custom gestures, handled by onGesture, will have custom properties.
137
138     GestureArea is an invisible item: it is never painted.
139
140     \sa MouseArea
141 */
142
143 /*!
144     \internal
145     \class QDeclarativeGestureArea
146     \brief The QDeclarativeGestureArea class provides simple gesture handling.
147
148 */
149 QDeclarativeGestureArea::QDeclarativeGestureArea(QDeclarativeItem *parent) :
150     QDeclarativeItem(*(new QDeclarativeGestureAreaPrivate), parent)
151 {
152     setAcceptedMouseButtons(Qt::LeftButton);
153     setAcceptTouchEvents(true);
154 }
155
156 QDeclarativeGestureArea::~QDeclarativeGestureArea()
157 {
158 }
159
160 QByteArray
161 QDeclarativeGestureAreaParser::compile(const QList<QDeclarativeCustomParserProperty> &props)
162 {
163     QByteArray rv;
164     QDataStream ds(&rv, QIODevice::WriteOnly);
165
166     for(int ii = 0; ii < props.count(); ++ii)
167     {
168         QString propName = props.at(ii).name();
169         Qt::GestureType type;
170
171         if (propName == QLatin1String("onTap")) {
172             type = Qt::TapGesture;
173         } else if (propName == QLatin1String("onTapAndHold")) {
174             type = Qt::TapAndHoldGesture;
175         } else if (propName == QLatin1String("onPan")) {
176             type = Qt::PanGesture;
177         } else if (propName == QLatin1String("onPinch")) {
178             type = Qt::PinchGesture;
179         } else if (propName == QLatin1String("onSwipe")) {
180             type = Qt::SwipeGesture;
181         } else if (propName == QLatin1String("onGesture")) {
182             type = Qt::CustomGesture;
183         } else {
184             error(props.at(ii), QDeclarativeGestureArea::tr("Cannot assign to non-existent property \"%1\"").arg(propName));
185             return QByteArray();
186         }
187
188         QList<QVariant> values = props.at(ii).assignedValues();
189
190         for (int i = 0; i < values.count(); ++i) {
191             const QVariant &value = values.at(i);
192
193             if (value.userType() == qMetaTypeId<QDeclarativeCustomParserNode>()) {
194                 error(props.at(ii), QDeclarativeGestureArea::tr("GestureArea: nested objects not allowed"));
195                 return QByteArray();
196             } else if (value.userType() == qMetaTypeId<QDeclarativeCustomParserProperty>()) {
197                 error(props.at(ii), QDeclarativeGestureArea::tr("GestureArea: syntax error"));
198                 return QByteArray();
199             } else {
200                 QDeclarativeScript::Variant v = qvariant_cast<QDeclarativeScript::Variant>(value);
201                 if (v.isScript()) {
202                     ds << propName;
203                     ds << int(type);
204                     ds << v.asScript();
205                 } else {
206                     error(props.at(ii), QDeclarativeGestureArea::tr("GestureArea: script expected"));
207                     return QByteArray();
208                 }
209             }
210         }
211     }
212
213     return rv;
214 }
215
216 void QDeclarativeGestureAreaParser::setCustomData(QObject *object,
217                                             const QByteArray &data)
218 {
219     QDeclarativeGestureArea *ga = static_cast<QDeclarativeGestureArea*>(object);
220     ga->d_func()->data = data;
221 }
222
223
224 void QDeclarativeGestureArea::connectSignals()
225 {
226     Q_D(QDeclarativeGestureArea);
227     if (!d->componentcomplete)
228         return;
229
230     QDataStream ds(d->data);
231     while (!ds.atEnd()) {
232         QString propName;
233         ds >> propName;
234         int gesturetype;
235         ds >> gesturetype;
236         QString script;
237         ds >> script;
238         QDeclarativeExpression *exp = new QDeclarativeExpression(qmlContext(this), this, script);
239         d->bindings.insert(Qt::GestureType(gesturetype),exp);
240         grabGesture(Qt::GestureType(gesturetype));
241     }
242 }
243
244 void QDeclarativeGestureArea::componentComplete()
245 {
246     QDeclarativeItem::componentComplete();
247     Q_D(QDeclarativeGestureArea);
248     d->componentcomplete=true;
249     connectSignals();
250 }
251
252 QGesture *QDeclarativeGestureArea::gesture() const
253 {
254     Q_D(const QDeclarativeGestureArea);
255     return d->gesture;
256 }
257
258 bool QDeclarativeGestureArea::sceneEvent(QEvent *event)
259 {
260     Q_D(QDeclarativeGestureArea);
261     if (event->type() == QEvent::Gesture)
262         return d->gestureEvent(static_cast<QGestureEvent*>(event));
263     return QDeclarativeItem::sceneEvent(event);
264 }
265
266 bool QDeclarativeGestureAreaPrivate::gestureEvent(QGestureEvent *event)
267 {
268     bool accept = true;
269     for (Bindings::Iterator it = bindings.begin(); it != bindings.end(); ++it) {
270         if ((gesture = event->gesture(it.key()))) {
271             QDeclarativeExpression *expr = it.value();
272             expr->evaluate();
273             if (expr->hasError())
274                 qmlInfo(q_func()) << expr->error();
275             event->setAccepted(true); // XXX only if value returns true?
276         }
277     }
278     return accept;
279 }
280
281 QT_END_NAMESPACE
282
283 #endif // QT_NO_GESTURES