summaryrefslogtreecommitdiffstats
path: root/src/datavisualization/input/qtouch3dinputhandler.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/datavisualization/input/qtouch3dinputhandler.cpp')
-rw-r--r--src/datavisualization/input/qtouch3dinputhandler.cpp209
1 files changed, 209 insertions, 0 deletions
diff --git a/src/datavisualization/input/qtouch3dinputhandler.cpp b/src/datavisualization/input/qtouch3dinputhandler.cpp
new file mode 100644
index 00000000..fd079e88
--- /dev/null
+++ b/src/datavisualization/input/qtouch3dinputhandler.cpp
@@ -0,0 +1,209 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc
+** All rights reserved.
+** For any questions to Digia, please use contact form at http://qt.digia.com
+**
+** This file is part of the QtDataVisualization module.
+**
+** Licensees holding valid Qt Enterprise licenses may use this file in
+** accordance with the Qt Enterprise License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.
+**
+** If you have questions regarding the use of this file, please use
+** contact form at http://qt.digia.com
+**
+****************************************************************************/
+
+#include "qtouch3dinputhandler_p.h"
+#include "q3dcamera_p.h"
+#include <QTimer>
+#include <qmath.h>
+
+QT_DATAVISUALIZATION_BEGIN_NAMESPACE
+
+const qreal maxTapAndHoldJitter = 20;
+const int maxPinchJitter = 10;
+#if defined (Q_OS_ANDROID)
+const int maxSelectionJitter = 10;
+#else
+const int maxSelectionJitter = 5;
+#endif
+const int tapAndHoldTime = 250;
+const float rotationSpeed = 200.0f;
+const int minZoomLevel = 10;
+const int maxZoomLevel = 500;
+
+/*!
+ * \class QTouch3DInputHandler
+ * \inmodule QtDataVisualization
+ * \brief Basic touch display based input handler.
+ * \since 1.0.0
+ *
+ * QTouch3DInputHandler is the basic input handler for touch screen devices.
+ *
+ * Default touch input handler has the following functionalty:
+ * \table
+ * \header
+ * \li Gesture \li Action
+ * \row
+ * \li Touch-And-Move \li Rotate graph within limits set for Q3DCamera
+ * \row
+ * \li Tap \li Select item under pointer or remove selection if none
+ * \row
+ * \li Tap-And-Hold \li Select item under pointer or remove selection if none
+ * \row
+ * \li Pinch \li Zoom in/out within default range (10...500%)
+ * \row
+ * \li Tap on secondary view \li Return to primary view when in slice mode
+ * \note Slice mode is available in Q3DBars and Q3DSurface only
+ * \endtable
+ */
+
+/*!
+ * Constructs the basic touch display input handler. An optional \a parent parameter can be given
+ * and is then passed to QObject constructor.
+ */
+QTouch3DInputHandler::QTouch3DInputHandler(QObject *parent)
+ : Q3DInputHandler(parent),
+ d_ptr(new QTouch3DInputHandlerPrivate(this))
+{
+}
+
+/*!
+ * Destroys the input handler.
+ */
+QTouch3DInputHandler::~QTouch3DInputHandler()
+{
+}
+
+/*!
+ * Override this to change handling of touch events.
+ * Touch event is given in the \a event.
+ */
+void QTouch3DInputHandler::touchEvent(QTouchEvent *event)
+{
+ QList<QTouchEvent::TouchPoint> points;
+ points = event->touchPoints();
+
+ if (!scene()->isSlicingActive() && points.count() == 2) {
+ d_ptr->m_holdTimer->stop();
+ QPointF distance = points.at(0).pos() - points.at(1).pos();
+ d_ptr->handlePinchZoom(distance.manhattanLength());
+ } else if (points.count() == 1) {
+ QPointF pointerPos = points.at(0).pos();
+ if (event->type() == QEvent::TouchBegin) {
+ if (scene()->isSlicingActive()) {
+ if (scene()->isPointInPrimarySubView(pointerPos.toPoint()))
+ setInputState(QDataVis::InputStateOnOverview);
+ else if (scene()->isPointInSecondarySubView(pointerPos.toPoint()))
+ setInputState(QDataVis::InputStateOnSlice);
+ else
+ setInputState(QDataVis::InputStateNone);
+ } else {
+ // Handle possible tap-and-hold selection
+ d_ptr->m_startHoldPos = pointerPos;
+ d_ptr->m_touchHoldPos = d_ptr->m_startHoldPos;
+ d_ptr->m_holdTimer->start();
+ // Start rotating
+ setInputState(QDataVis::InputStateRotating);
+ setInputPosition(pointerPos.toPoint());
+ }
+ } else if (event->type() == QEvent::TouchEnd) {
+ d_ptr->m_holdTimer->stop();
+ // Handle possible selection
+ d_ptr->handleSelection(pointerPos);
+ } else if (event->type() == QEvent::TouchUpdate) {
+ if (!scene()->isSlicingActive()) {
+ d_ptr->m_touchHoldPos = pointerPos;
+ // Handle rotation
+ d_ptr->handleRotation(pointerPos);
+ }
+ }
+ } else {
+ d_ptr->m_holdTimer->stop();
+ }
+}
+
+QTouch3DInputHandlerPrivate::QTouch3DInputHandlerPrivate(QTouch3DInputHandler *q)
+ : q_ptr(q),
+ m_holdTimer(0)
+{
+ m_holdTimer = new QTimer();
+ m_holdTimer->setSingleShot(true);
+ m_holdTimer->setInterval(tapAndHoldTime);
+ connect(m_holdTimer, &QTimer::timeout, this, &QTouch3DInputHandlerPrivate::handleTapAndHold);
+}
+
+QTouch3DInputHandlerPrivate::~QTouch3DInputHandlerPrivate()
+{
+ m_holdTimer->stop();
+ delete m_holdTimer;
+}
+
+void QTouch3DInputHandlerPrivate::handlePinchZoom(qreal distance)
+{
+ int newDistance = distance;
+ int prevDist = q_ptr->prevDistance();
+ if (prevDist > 0 && qAbs(prevDist - newDistance) < maxPinchJitter)
+ return;
+ q_ptr->setInputState(QDataVis::InputStateOnPinch);
+ Q3DCamera *camera = q_ptr->scene()->activeCamera();
+ int zoomLevel = camera->zoomLevel();
+ qreal zoomRate = qSqrt(qSqrt(zoomLevel));
+ if (newDistance > prevDist)
+ zoomLevel += zoomRate;
+ else
+ zoomLevel -= zoomRate;
+ if (zoomLevel > maxZoomLevel)
+ zoomLevel = maxZoomLevel;
+ else if (zoomLevel < minZoomLevel)
+ zoomLevel = minZoomLevel;
+ camera->setZoomLevel(zoomLevel);
+ q_ptr->setPrevDistance(newDistance);
+}
+
+void QTouch3DInputHandlerPrivate::handleTapAndHold()
+{
+ QPointF distance = m_startHoldPos - m_touchHoldPos;
+ if (distance.manhattanLength() < maxTapAndHoldJitter) {
+ q_ptr->setInputPosition(m_touchHoldPos.toPoint());
+ q_ptr->setInputState(QDataVis::InputStateOnScene);
+ }
+}
+
+void QTouch3DInputHandlerPrivate::handleSelection(const QPointF &position)
+{
+ QPointF distance = m_startHoldPos - position;
+ if (distance.manhattanLength() < maxSelectionJitter)
+ q_ptr->setInputState(QDataVis::InputStateOnScene);
+ else
+ q_ptr->setInputState(QDataVis::InputStateNone);
+ q_ptr->setPreviousInputPos(position.toPoint());
+}
+
+void QTouch3DInputHandlerPrivate::handleRotation(const QPointF &position)
+{
+ if (QDataVis::InputStateRotating == q_ptr->inputState()) {
+ Q3DScene *scene = q_ptr->scene();
+ Q3DCamera *camera = scene->activeCamera();
+ float xRotation = camera->xRotation();
+ float yRotation = camera->yRotation();
+ QPointF inputPos = q_ptr->inputPosition();
+ float mouseMoveX = float(inputPos.x() - position.x())
+ / (scene->viewport().width() / rotationSpeed);
+ float mouseMoveY = float(inputPos.y() - position.y())
+ / (scene->viewport().height() / rotationSpeed);
+ xRotation -= mouseMoveX;
+ yRotation -= mouseMoveY;
+ camera->setXRotation(xRotation);
+ camera->setYRotation(yRotation);
+ camera->d_ptr->updateViewMatrix(1.0f);
+
+ q_ptr->setPreviousInputPos(inputPos.toPoint());
+ q_ptr->setInputPosition(position.toPoint());
+ }
+}
+
+QT_DATAVISUALIZATION_END_NAMESPACE