aboutsummaryrefslogtreecommitdiffstats
path: root/src/declarative/items/qsgpincharea.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/declarative/items/qsgpincharea.cpp')
-rw-r--r--src/declarative/items/qsgpincharea.cpp407
1 files changed, 407 insertions, 0 deletions
diff --git a/src/declarative/items/qsgpincharea.cpp b/src/declarative/items/qsgpincharea.cpp
new file mode 100644
index 0000000000..e32f6bfe71
--- /dev/null
+++ b/src/declarative/items/qsgpincharea.cpp
@@ -0,0 +1,407 @@
+// Commit: 2ec2dc55ddf424f5a7acd0a4729ddd9af2d7c398
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtSG module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgpincharea_p_p.h"
+#include "qsgcanvas.h"
+
+#include <QtGui/qgraphicssceneevent.h>
+#include <QtGui/qapplication.h>
+
+#include <float.h>
+#include <math.h>
+
+QT_BEGIN_NAMESPACE
+
+QSGPinch::QSGPinch()
+ : m_target(0), m_minScale(1.0), m_maxScale(1.0)
+ , m_minRotation(0.0), m_maxRotation(0.0)
+ , m_axis(NoDrag), m_xmin(-FLT_MAX), m_xmax(FLT_MAX)
+ , m_ymin(-FLT_MAX), m_ymax(FLT_MAX), m_active(false)
+{
+}
+
+QSGPinchAreaPrivate::~QSGPinchAreaPrivate()
+{
+ delete pinch;
+}
+
+QSGPinchArea::QSGPinchArea(QSGItem *parent)
+ : QSGItem(*(new QSGPinchAreaPrivate), parent)
+{
+ Q_D(QSGPinchArea);
+ d->init();
+}
+
+QSGPinchArea::~QSGPinchArea()
+{
+}
+
+bool QSGPinchArea::isEnabled() const
+{
+ Q_D(const QSGPinchArea);
+ return d->absorb;
+}
+
+void QSGPinchArea::setEnabled(bool a)
+{
+ Q_D(QSGPinchArea);
+ if (a != d->absorb) {
+ d->absorb = a;
+ emit enabledChanged();
+ }
+}
+
+void QSGPinchArea::touchEvent(QTouchEvent *event)
+{
+ Q_D(QSGPinchArea);
+ if (!d->absorb || !isVisible()) {
+ QSGItem::event(event);
+ return;
+ }
+
+ switch (event->type()) {
+ case QEvent::TouchBegin:
+ case QEvent::TouchUpdate:
+ d->touchPoints.clear();
+ for (int i = 0; i < event->touchPoints().count(); ++i) {
+ if (!(event->touchPoints().at(i).state() & Qt::TouchPointReleased)) {
+ d->touchPoints << event->touchPoints().at(i);
+ }
+ }
+ updatePinch();
+ break;
+ case QEvent::TouchEnd:
+ d->touchPoints.clear();
+ updatePinch();
+ break;
+ default:
+ QSGItem::event(event);
+ }
+}
+
+void QSGPinchArea::updatePinch()
+{
+ Q_D(QSGPinchArea);
+ if (d->touchPoints.count() != 2) {
+ if (d->inPinch) {
+ d->stealMouse = false;
+ setKeepMouseGrab(false);
+ d->inPinch = false;
+ QPointF pinchCenter = mapFromScene(d->sceneLastCenter);
+ QSGPinchEvent pe(pinchCenter, d->pinchLastScale, d->pinchLastAngle, d->pinchRotation);
+ pe.setStartCenter(d->pinchStartCenter);
+ pe.setPreviousCenter(pinchCenter);
+ pe.setPreviousAngle(d->pinchLastAngle);
+ pe.setPreviousScale(d->pinchLastScale);
+ pe.setStartPoint1(mapFromScene(d->sceneStartPoint1));
+ pe.setStartPoint2(mapFromScene(d->sceneStartPoint2));
+ pe.setPoint1(d->lastPoint1);
+ pe.setPoint2(d->lastPoint2);
+ emit pinchFinished(&pe);
+ d->pinchStartDist = 0;
+ if (d->pinch && d->pinch->target())
+ d->pinch->setActive(false);
+ }
+ return;
+ }
+ if (d->touchPoints.at(0).state() & Qt::TouchPointPressed
+ || d->touchPoints.at(1).state() & Qt::TouchPointPressed) {
+ d->sceneStartPoint1 = d->touchPoints.at(0).scenePos();
+ d->sceneStartPoint2 = d->touchPoints.at(1).scenePos();
+ d->inPinch = false;
+ d->pinchRejected = false;
+ } else if (!d->pinchRejected){
+ QSGItem *grabber = canvas() ? canvas()->mouseGrabberItem() : 0;
+ if (grabber == this || !grabber || !grabber->keepMouseGrab()) {
+ const int dragThreshold = QApplication::startDragDistance();
+ QPointF p1 = d->touchPoints.at(0).scenePos();
+ QPointF p2 = d->touchPoints.at(1).scenePos();
+ qreal dx = p1.x() - p2.x();
+ qreal dy = p1.y() - p2.y();
+ qreal dist = sqrt(dx*dx + dy*dy);
+ QPointF sceneCenter = (p1 + p2)/2;
+ qreal angle = QLineF(p1, p2).angle();
+ if (angle > 180)
+ angle -= 360;
+ if (!d->inPinch) {
+ if (qAbs(p1.x()-d->sceneStartPoint1.x()) > dragThreshold
+ || qAbs(p1.y()-d->sceneStartPoint1.y()) > dragThreshold
+ || qAbs(p2.x()-d->sceneStartPoint2.x()) > dragThreshold
+ || qAbs(p2.y()-d->sceneStartPoint2.y()) > dragThreshold) {
+ d->sceneStartCenter = sceneCenter;
+ d->sceneLastCenter = sceneCenter;
+ d->pinchStartCenter = mapFromScene(sceneCenter);
+ d->pinchStartDist = dist;
+ d->pinchStartAngle = angle;
+ d->pinchLastScale = 1.0;
+ d->pinchLastAngle = angle;
+ d->pinchRotation = 0.0;
+ d->lastPoint1 = d->touchPoints.at(0).pos();
+ d->lastPoint2 = d->touchPoints.at(1).pos();
+ QSGPinchEvent pe(d->pinchStartCenter, 1.0, angle, 0.0);
+ pe.setStartCenter(d->pinchStartCenter);
+ pe.setPreviousCenter(d->pinchStartCenter);
+ pe.setPreviousAngle(d->pinchLastAngle);
+ pe.setPreviousScale(d->pinchLastScale);
+ pe.setStartPoint1(mapFromScene(d->sceneStartPoint1));
+ pe.setStartPoint2(mapFromScene(d->sceneStartPoint2));
+ pe.setPoint1(d->lastPoint1);
+ pe.setPoint2(d->lastPoint2);
+ emit pinchStarted(&pe);
+ if (pe.accepted()) {
+ d->inPinch = true;
+ d->stealMouse = true;
+ QSGCanvas *c = canvas();
+ if (c && c->mouseGrabberItem() != this)
+ grabMouse();
+ setKeepMouseGrab(true);
+ if (d->pinch && d->pinch->target()) {
+ d->pinchStartPos = pinch()->target()->pos();
+ d->pinchStartScale = d->pinch->target()->scale();
+ d->pinchStartRotation = d->pinch->target()->rotation();
+ d->pinch->setActive(true);
+ }
+ } else {
+ d->pinchRejected = true;
+ }
+ }
+ } else if (d->pinchStartDist > 0) {
+ qreal scale = dist / d->pinchStartDist;
+ qreal da = d->pinchLastAngle - angle;
+ if (da > 180)
+ da -= 360;
+ else if (da < -180)
+ da += 360;
+ d->pinchRotation += da;
+ QPointF pinchCenter = mapFromScene(sceneCenter);
+ QSGPinchEvent pe(pinchCenter, scale, angle, d->pinchRotation);
+ pe.setStartCenter(d->pinchStartCenter);
+ pe.setPreviousCenter(mapFromScene(d->sceneLastCenter));
+ pe.setPreviousAngle(d->pinchLastAngle);
+ pe.setPreviousScale(d->pinchLastScale);
+ pe.setStartPoint1(mapFromScene(d->sceneStartPoint1));
+ pe.setStartPoint2(mapFromScene(d->sceneStartPoint2));
+ pe.setPoint1(d->touchPoints.at(0).pos());
+ pe.setPoint2(d->touchPoints.at(1).pos());
+ d->pinchLastScale = scale;
+ d->sceneLastCenter = sceneCenter;
+ d->pinchLastAngle = angle;
+ d->lastPoint1 = d->touchPoints.at(0).pos();
+ d->lastPoint2 = d->touchPoints.at(1).pos();
+ emit pinchUpdated(&pe);
+ if (d->pinch && d->pinch->target()) {
+ qreal s = d->pinchStartScale * scale;
+ s = qMin(qMax(pinch()->minimumScale(),s), pinch()->maximumScale());
+ pinch()->target()->setScale(s);
+ QPointF pos = sceneCenter - d->sceneStartCenter + d->pinchStartPos;
+ if (pinch()->axis() & QSGPinch::XAxis) {
+ qreal x = pos.x();
+ if (x < pinch()->xmin())
+ x = pinch()->xmin();
+ else if (x > pinch()->xmax())
+ x = pinch()->xmax();
+ pinch()->target()->setX(x);
+ }
+ if (pinch()->axis() & QSGPinch::YAxis) {
+ qreal y = pos.y();
+ if (y < pinch()->ymin())
+ y = pinch()->ymin();
+ else if (y > pinch()->ymax())
+ y = pinch()->ymax();
+ pinch()->target()->setY(y);
+ }
+ if (d->pinchStartRotation >= pinch()->minimumRotation()
+ && d->pinchStartRotation <= pinch()->maximumRotation()) {
+ qreal r = d->pinchRotation + d->pinchStartRotation;
+ r = qMin(qMax(pinch()->minimumRotation(),r), pinch()->maximumRotation());
+ pinch()->target()->setRotation(r);
+ }
+ }
+ }
+ }
+ }
+}
+
+void QSGPinchArea::mousePressEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QSGPinchArea);
+ d->stealMouse = false;
+ if (!d->absorb)
+ QSGItem::mousePressEvent(event);
+ else {
+ setKeepMouseGrab(false);
+ event->setAccepted(true);
+ }
+}
+
+void QSGPinchArea::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QSGPinchArea);
+ if (!d->absorb) {
+ QSGItem::mouseMoveEvent(event);
+ return;
+ }
+}
+
+void QSGPinchArea::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QSGPinchArea);
+ d->stealMouse = false;
+ if (!d->absorb) {
+ QSGItem::mouseReleaseEvent(event);
+ } else {
+ QSGCanvas *c = canvas();
+ if (c && c->mouseGrabberItem() == this)
+ ungrabMouse();
+ setKeepMouseGrab(false);
+ }
+}
+
+void QSGPinchArea::mouseUngrabEvent()
+{
+ setKeepMouseGrab(false);
+}
+
+bool QSGPinchArea::sendMouseEvent(QGraphicsSceneMouseEvent *event)
+{
+ Q_D(QSGPinchArea);
+ QGraphicsSceneMouseEvent mouseEvent(event->type());
+ QRectF myRect = mapRectToScene(QRectF(0, 0, width(), height()));
+
+ QSGCanvas *c = canvas();
+ QSGItem *grabber = c ? c->mouseGrabberItem() : 0;
+ bool stealThisEvent = d->stealMouse;
+ if ((stealThisEvent || myRect.contains(event->scenePos().toPoint())) && (!grabber || !grabber->keepMouseGrab())) {
+ mouseEvent.setAccepted(false);
+ for (int i = 0x1; i <= 0x10; i <<= 1) {
+ if (event->buttons() & i) {
+ Qt::MouseButton button = Qt::MouseButton(i);
+ mouseEvent.setButtonDownPos(button, mapFromScene(event->buttonDownPos(button)));
+ }
+ }
+ mouseEvent.setScenePos(event->scenePos());
+ mouseEvent.setLastScenePos(event->lastScenePos());
+ mouseEvent.setPos(mapFromScene(event->scenePos()));
+ mouseEvent.setLastPos(mapFromScene(event->lastScenePos()));
+
+ switch(mouseEvent.type()) {
+ case QEvent::GraphicsSceneMouseMove:
+ mouseMoveEvent(&mouseEvent);
+ break;
+ case QEvent::GraphicsSceneMousePress:
+ mousePressEvent(&mouseEvent);
+ break;
+ case QEvent::GraphicsSceneMouseRelease:
+ mouseReleaseEvent(&mouseEvent);
+ break;
+ default:
+ break;
+ }
+ grabber = c->mouseGrabberItem();
+ if (grabber && stealThisEvent && !grabber->keepMouseGrab() && grabber != this)
+ grabMouse();
+
+ return stealThisEvent;
+ }
+ if (mouseEvent.type() == QEvent::GraphicsSceneMouseRelease) {
+ d->stealMouse = false;
+ if (c && c->mouseGrabberItem() == this)
+ ungrabMouse();
+ setKeepMouseGrab(false);
+ }
+ return false;
+}
+
+bool QSGPinchArea::childMouseEventFilter(QSGItem *i, QEvent *e)
+{
+ Q_D(QSGPinchArea);
+ if (!d->absorb || !isVisible())
+ return QSGItem::childMouseEventFilter(i, e);
+ switch (e->type()) {
+ case QEvent::GraphicsSceneMousePress:
+ case QEvent::GraphicsSceneMouseMove:
+ case QEvent::GraphicsSceneMouseRelease:
+ return sendMouseEvent(static_cast<QGraphicsSceneMouseEvent *>(e));
+ break;
+ case QEvent::TouchBegin:
+ case QEvent::TouchUpdate: {
+ QTouchEvent *touch = static_cast<QTouchEvent*>(e);
+ d->touchPoints.clear();
+ for (int i = 0; i < touch->touchPoints().count(); ++i)
+ if (!(touch->touchPoints().at(i).state() & Qt::TouchPointReleased))
+ d->touchPoints << touch->touchPoints().at(i);
+ updatePinch();
+ }
+ return d->inPinch;
+ case QEvent::TouchEnd:
+ d->touchPoints.clear();
+ updatePinch();
+ break;
+ default:
+ break;
+ }
+
+ return QSGItem::childMouseEventFilter(i, e);
+}
+
+void QSGPinchArea::geometryChanged(const QRectF &newGeometry,
+ const QRectF &oldGeometry)
+{
+ QSGItem::geometryChanged(newGeometry, oldGeometry);
+}
+
+void QSGPinchArea::itemChange(ItemChange change, const ItemChangeData &value)
+{
+ QSGItem::itemChange(change, value);
+}
+
+QSGPinch *QSGPinchArea::pinch()
+{
+ Q_D(QSGPinchArea);
+ if (!d->pinch)
+ d->pinch = new QSGPinch;
+ return d->pinch;
+}
+
+
+QT_END_NAMESPACE
+