1 // Commit: 2ec2dc55ddf424f5a7acd0a4729ddd9af2d7c398
2 /****************************************************************************
4 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
5 ** All rights reserved.
6 ** Contact: Nokia Corporation (qt-info@nokia.com)
8 ** This file is part of the QtSG module of the Qt Toolkit.
10 ** $QT_BEGIN_LICENSE:LGPL$
11 ** No Commercial Usage
12 ** This file contains pre-release code and may not be distributed.
13 ** You may use this file in accordance with the terms and conditions
14 ** contained in the Technology Preview License Agreement accompanying
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 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 ** In addition, as a special exception, Nokia gives you certain additional
26 ** rights. These rights are described in the Nokia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 ** If you have questions regarding the use of this file, please contact
30 ** Nokia at qt-info@nokia.com.
41 ****************************************************************************/
43 #include "qsgpincharea_p_p.h"
44 #include "qsgcanvas.h"
46 #include <QtGui/qgraphicssceneevent.h>
47 #include <QtGui/qapplication.h>
55 : m_target(0), m_minScale(1.0), m_maxScale(1.0)
56 , m_minRotation(0.0), m_maxRotation(0.0)
57 , m_axis(NoDrag), m_xmin(-FLT_MAX), m_xmax(FLT_MAX)
58 , m_ymin(-FLT_MAX), m_ymax(FLT_MAX), m_active(false)
62 QSGPinchAreaPrivate::~QSGPinchAreaPrivate()
67 QSGPinchArea::QSGPinchArea(QSGItem *parent)
68 : QSGItem(*(new QSGPinchAreaPrivate), parent)
74 QSGPinchArea::~QSGPinchArea()
78 bool QSGPinchArea::isEnabled() const
80 Q_D(const QSGPinchArea);
84 void QSGPinchArea::setEnabled(bool a)
89 emit enabledChanged();
93 void QSGPinchArea::touchEvent(QTouchEvent *event)
96 if (!d->absorb || !isVisible()) {
97 QSGItem::event(event);
101 switch (event->type()) {
102 case QEvent::TouchBegin:
103 case QEvent::TouchUpdate:
104 d->touchPoints.clear();
105 for (int i = 0; i < event->touchPoints().count(); ++i) {
106 if (!(event->touchPoints().at(i).state() & Qt::TouchPointReleased)) {
107 d->touchPoints << event->touchPoints().at(i);
112 case QEvent::TouchEnd:
113 d->touchPoints.clear();
117 QSGItem::event(event);
121 void QSGPinchArea::updatePinch()
124 if (d->touchPoints.count() != 2) {
126 d->stealMouse = false;
127 setKeepMouseGrab(false);
129 QPointF pinchCenter = mapFromScene(d->sceneLastCenter);
130 QSGPinchEvent pe(pinchCenter, d->pinchLastScale, d->pinchLastAngle, d->pinchRotation);
131 pe.setStartCenter(d->pinchStartCenter);
132 pe.setPreviousCenter(pinchCenter);
133 pe.setPreviousAngle(d->pinchLastAngle);
134 pe.setPreviousScale(d->pinchLastScale);
135 pe.setStartPoint1(mapFromScene(d->sceneStartPoint1));
136 pe.setStartPoint2(mapFromScene(d->sceneStartPoint2));
137 pe.setPoint1(d->lastPoint1);
138 pe.setPoint2(d->lastPoint2);
139 emit pinchFinished(&pe);
140 d->pinchStartDist = 0;
141 if (d->pinch && d->pinch->target())
142 d->pinch->setActive(false);
146 if (d->touchPoints.at(0).state() & Qt::TouchPointPressed
147 || d->touchPoints.at(1).state() & Qt::TouchPointPressed) {
148 d->sceneStartPoint1 = d->touchPoints.at(0).scenePos();
149 d->sceneStartPoint2 = d->touchPoints.at(1).scenePos();
151 d->pinchRejected = false;
152 } else if (!d->pinchRejected){
153 QSGItem *grabber = canvas() ? canvas()->mouseGrabberItem() : 0;
154 if (grabber == this || !grabber || !grabber->keepMouseGrab()) {
155 const int dragThreshold = QApplication::startDragDistance();
156 QPointF p1 = d->touchPoints.at(0).scenePos();
157 QPointF p2 = d->touchPoints.at(1).scenePos();
158 qreal dx = p1.x() - p2.x();
159 qreal dy = p1.y() - p2.y();
160 qreal dist = sqrt(dx*dx + dy*dy);
161 QPointF sceneCenter = (p1 + p2)/2;
162 qreal angle = QLineF(p1, p2).angle();
166 if (qAbs(p1.x()-d->sceneStartPoint1.x()) > dragThreshold
167 || qAbs(p1.y()-d->sceneStartPoint1.y()) > dragThreshold
168 || qAbs(p2.x()-d->sceneStartPoint2.x()) > dragThreshold
169 || qAbs(p2.y()-d->sceneStartPoint2.y()) > dragThreshold) {
170 d->sceneStartCenter = sceneCenter;
171 d->sceneLastCenter = sceneCenter;
172 d->pinchStartCenter = mapFromScene(sceneCenter);
173 d->pinchStartDist = dist;
174 d->pinchStartAngle = angle;
175 d->pinchLastScale = 1.0;
176 d->pinchLastAngle = angle;
177 d->pinchRotation = 0.0;
178 d->lastPoint1 = d->touchPoints.at(0).pos();
179 d->lastPoint2 = d->touchPoints.at(1).pos();
180 QSGPinchEvent pe(d->pinchStartCenter, 1.0, angle, 0.0);
181 pe.setStartCenter(d->pinchStartCenter);
182 pe.setPreviousCenter(d->pinchStartCenter);
183 pe.setPreviousAngle(d->pinchLastAngle);
184 pe.setPreviousScale(d->pinchLastScale);
185 pe.setStartPoint1(mapFromScene(d->sceneStartPoint1));
186 pe.setStartPoint2(mapFromScene(d->sceneStartPoint2));
187 pe.setPoint1(d->lastPoint1);
188 pe.setPoint2(d->lastPoint2);
189 emit pinchStarted(&pe);
192 d->stealMouse = true;
193 QSGCanvas *c = canvas();
194 if (c && c->mouseGrabberItem() != this)
196 setKeepMouseGrab(true);
197 if (d->pinch && d->pinch->target()) {
198 d->pinchStartPos = pinch()->target()->pos();
199 d->pinchStartScale = d->pinch->target()->scale();
200 d->pinchStartRotation = d->pinch->target()->rotation();
201 d->pinch->setActive(true);
204 d->pinchRejected = true;
207 } else if (d->pinchStartDist > 0) {
208 qreal scale = dist / d->pinchStartDist;
209 qreal da = d->pinchLastAngle - angle;
214 d->pinchRotation += da;
215 QPointF pinchCenter = mapFromScene(sceneCenter);
216 QSGPinchEvent pe(pinchCenter, scale, angle, d->pinchRotation);
217 pe.setStartCenter(d->pinchStartCenter);
218 pe.setPreviousCenter(mapFromScene(d->sceneLastCenter));
219 pe.setPreviousAngle(d->pinchLastAngle);
220 pe.setPreviousScale(d->pinchLastScale);
221 pe.setStartPoint1(mapFromScene(d->sceneStartPoint1));
222 pe.setStartPoint2(mapFromScene(d->sceneStartPoint2));
223 pe.setPoint1(d->touchPoints.at(0).pos());
224 pe.setPoint2(d->touchPoints.at(1).pos());
225 d->pinchLastScale = scale;
226 d->sceneLastCenter = sceneCenter;
227 d->pinchLastAngle = angle;
228 d->lastPoint1 = d->touchPoints.at(0).pos();
229 d->lastPoint2 = d->touchPoints.at(1).pos();
230 emit pinchUpdated(&pe);
231 if (d->pinch && d->pinch->target()) {
232 qreal s = d->pinchStartScale * scale;
233 s = qMin(qMax(pinch()->minimumScale(),s), pinch()->maximumScale());
234 pinch()->target()->setScale(s);
235 QPointF pos = sceneCenter - d->sceneStartCenter + d->pinchStartPos;
236 if (pinch()->axis() & QSGPinch::XAxis) {
238 if (x < pinch()->xmin())
240 else if (x > pinch()->xmax())
242 pinch()->target()->setX(x);
244 if (pinch()->axis() & QSGPinch::YAxis) {
246 if (y < pinch()->ymin())
248 else if (y > pinch()->ymax())
250 pinch()->target()->setY(y);
252 if (d->pinchStartRotation >= pinch()->minimumRotation()
253 && d->pinchStartRotation <= pinch()->maximumRotation()) {
254 qreal r = d->pinchRotation + d->pinchStartRotation;
255 r = qMin(qMax(pinch()->minimumRotation(),r), pinch()->maximumRotation());
256 pinch()->target()->setRotation(r);
264 void QSGPinchArea::mousePressEvent(QGraphicsSceneMouseEvent *event)
267 d->stealMouse = false;
269 QSGItem::mousePressEvent(event);
271 setKeepMouseGrab(false);
272 event->setAccepted(true);
276 void QSGPinchArea::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
280 QSGItem::mouseMoveEvent(event);
285 void QSGPinchArea::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
288 d->stealMouse = false;
290 QSGItem::mouseReleaseEvent(event);
292 QSGCanvas *c = canvas();
293 if (c && c->mouseGrabberItem() == this)
295 setKeepMouseGrab(false);
299 void QSGPinchArea::mouseUngrabEvent()
301 setKeepMouseGrab(false);
304 bool QSGPinchArea::sendMouseEvent(QGraphicsSceneMouseEvent *event)
307 QGraphicsSceneMouseEvent mouseEvent(event->type());
308 QRectF myRect = mapRectToScene(QRectF(0, 0, width(), height()));
310 QSGCanvas *c = canvas();
311 QSGItem *grabber = c ? c->mouseGrabberItem() : 0;
312 bool stealThisEvent = d->stealMouse;
313 if ((stealThisEvent || myRect.contains(event->scenePos().toPoint())) && (!grabber || !grabber->keepMouseGrab())) {
314 mouseEvent.setAccepted(false);
315 for (int i = 0x1; i <= 0x10; i <<= 1) {
316 if (event->buttons() & i) {
317 Qt::MouseButton button = Qt::MouseButton(i);
318 mouseEvent.setButtonDownPos(button, mapFromScene(event->buttonDownPos(button)));
321 mouseEvent.setScenePos(event->scenePos());
322 mouseEvent.setLastScenePos(event->lastScenePos());
323 mouseEvent.setPos(mapFromScene(event->scenePos()));
324 mouseEvent.setLastPos(mapFromScene(event->lastScenePos()));
326 switch(mouseEvent.type()) {
327 case QEvent::GraphicsSceneMouseMove:
328 mouseMoveEvent(&mouseEvent);
330 case QEvent::GraphicsSceneMousePress:
331 mousePressEvent(&mouseEvent);
333 case QEvent::GraphicsSceneMouseRelease:
334 mouseReleaseEvent(&mouseEvent);
339 grabber = c->mouseGrabberItem();
340 if (grabber && stealThisEvent && !grabber->keepMouseGrab() && grabber != this)
343 return stealThisEvent;
345 if (mouseEvent.type() == QEvent::GraphicsSceneMouseRelease) {
346 d->stealMouse = false;
347 if (c && c->mouseGrabberItem() == this)
349 setKeepMouseGrab(false);
354 bool QSGPinchArea::childMouseEventFilter(QSGItem *i, QEvent *e)
357 if (!d->absorb || !isVisible())
358 return QSGItem::childMouseEventFilter(i, e);
360 case QEvent::GraphicsSceneMousePress:
361 case QEvent::GraphicsSceneMouseMove:
362 case QEvent::GraphicsSceneMouseRelease:
363 return sendMouseEvent(static_cast<QGraphicsSceneMouseEvent *>(e));
365 case QEvent::TouchBegin:
366 case QEvent::TouchUpdate: {
367 QTouchEvent *touch = static_cast<QTouchEvent*>(e);
368 d->touchPoints.clear();
369 for (int i = 0; i < touch->touchPoints().count(); ++i)
370 if (!(touch->touchPoints().at(i).state() & Qt::TouchPointReleased))
371 d->touchPoints << touch->touchPoints().at(i);
375 case QEvent::TouchEnd:
376 d->touchPoints.clear();
383 return QSGItem::childMouseEventFilter(i, e);
386 void QSGPinchArea::geometryChanged(const QRectF &newGeometry,
387 const QRectF &oldGeometry)
389 QSGItem::geometryChanged(newGeometry, oldGeometry);
392 void QSGPinchArea::itemChange(ItemChange change, const ItemChangeData &value)
394 QSGItem::itemChange(change, value);
397 QSGPinch *QSGPinchArea::pinch()
401 d->pinch = new QSGPinch;