diff options
author | Miikka Heikkinen <miikka.heikkinen@digia.com> | 2014-09-25 15:04:44 +0300 |
---|---|---|
committer | Miikka Heikkinen <miikka.heikkinen@digia.com> | 2014-09-26 10:06:52 +0300 |
commit | 0ab45b018fa98e9ef6cffd70178f208eb4f16550 (patch) | |
tree | 77d324f47ccb52cc543df9e8990153b82ead2688 /src/datavisualization/input | |
parent | 36bc54f5720bddb9899e64d665117ac1e1b5bc94 (diff) |
Implement zooming to cursor
Zooming to cursor is now default operating mode of
the default input handler.
Task-number: QTRD-3263
Change-Id: I5699fc0ce7393059538972cd52f31f06d87e3d8d
Reviewed-by: Tomi Korpipää <tomi.korpipaa@digia.com>
Diffstat (limited to 'src/datavisualization/input')
-rw-r--r-- | src/datavisualization/input/q3dinputhandler.cpp | 122 | ||||
-rw-r--r-- | src/datavisualization/input/q3dinputhandler.h | 4 | ||||
-rw-r--r-- | src/datavisualization/input/q3dinputhandler_p.h | 19 | ||||
-rw-r--r-- | src/datavisualization/input/qtouch3dinputhandler.cpp | 22 | ||||
-rw-r--r-- | src/datavisualization/input/qtouch3dinputhandler_p.h | 9 |
5 files changed, 160 insertions, 16 deletions
diff --git a/src/datavisualization/input/q3dinputhandler.cpp b/src/datavisualization/input/q3dinputhandler.cpp index e6f3de24..0bed3cb9 100644 --- a/src/datavisualization/input/q3dinputhandler.cpp +++ b/src/datavisualization/input/q3dinputhandler.cpp @@ -18,13 +18,16 @@ #include "datavisualizationglobal_p.h" #include "q3dinputhandler_p.h" +#include "abstract3dcontroller_p.h" QT_BEGIN_NAMESPACE_DATAVISUALIZATION -const int minZoomLevel = 10; -const int halfSizeZoomLevel = 50; -const int oneToOneZoomLevel = 100; -const int maxZoomLevel = 500; +const int minZoomLevel = 10; +const int halfSizeZoomLevel = 50; +const int oneToOneZoomLevel = 100; +const int maxZoomLevel = 500; +const int driftTowardCenterLevel = 175; +const float wheelZoomDrift = 0.1f; const int nearZoomRangeDivider = 12; const int midZoomRangeDivider = 60; @@ -84,6 +87,7 @@ const float rotationSpeed = 100.0f; * \since QtDataVisualization 1.2 * * This property specifies if this input handler allows graph rotation. + * Defaults to \c{true}. */ /*! @@ -91,6 +95,7 @@ const float rotationSpeed = 100.0f; * \since QtDataVisualization 1.2 * * This property specifies if this input handler allows graph zooming. + * Defaults to \c{true}. */ /*! @@ -98,6 +103,16 @@ const float rotationSpeed = 100.0f; * \since QtDataVisualization 1.2 * * This property specifies if this input handler allows selection from the graph. + * Defaults to \c{true}. + */ + +/*! + * \qmlproperty bool InputHandler3D::zoomAtTargetEnabled + * \since QtDataVisualization 1.2 + * + * This property specifies if zooming changes the camera target to the position of the input + * at the time of the zoom. + * Defaults to \c{true}. */ /*! @@ -236,7 +251,16 @@ void Q3DInputHandler::wheelEvent(QWheelEvent *event) else if (zoomLevel < minZoomLevel) zoomLevel = minZoomLevel; - scene()->activeCamera()->setZoomLevel(zoomLevel); + if (isZoomAtTargetEnabled()) { + scene()->setGraphPositionQuery(event->pos()); + d_ptr->m_zoomAtTargetPending = true; + // If zoom at target is enabled, we don't want to zoom yet, as that causes + // jitter. Instead, we zoom next frame, when we apply the camera position. + d_ptr->m_requestedZoomLevel = zoomLevel; + d_ptr->m_driftMultiplier = wheelZoomDrift; + } else { + scene()->activeCamera()->setZoomLevel(zoomLevel); + } } } @@ -245,6 +269,7 @@ void Q3DInputHandler::wheelEvent(QWheelEvent *event) * \since QtDataVisualization 1.2 * * This property specifies if this input handler allows graph rotation. + * Defaults to \c{true}. */ void Q3DInputHandler::setRotationEnabled(bool enable) { @@ -264,6 +289,7 @@ bool Q3DInputHandler::isRotationEnabled() const * \since QtDataVisualization 1.2 * * This property specifies if this input handler allows graph zooming. + * Defaults to \c{true}. */ void Q3DInputHandler::setZoomEnabled(bool enable) { @@ -283,6 +309,7 @@ bool Q3DInputHandler::isZoomEnabled() const * \since QtDataVisualization 1.2 * * This property specifies if this input handler allows selection from the graph. + * Defaults to \c{true}. */ void Q3DInputHandler::setSelectionEnabled(bool enable) { @@ -297,17 +324,100 @@ bool Q3DInputHandler::isSelectionEnabled() const return d_ptr->m_selectionEnabled; } +/*! + * \property Q3DInputHandler::zoomAtTargetEnabled + * \since QtDataVisualization 1.2 + * + * This property specifies if zooming should change the camera target so that the zoomed point + * of the graph stays at the same location after the zoom. + * Defaults to \c{true}. + */ +void Q3DInputHandler::setZoomAtTargetEnabled(bool enable) +{ + if (d_ptr->m_zoomAtTargetEnabled != enable) { + d_ptr->m_zoomAtTargetEnabled = enable; + emit zoomAtTargetEnabledChanged(enable); + } +} + +bool Q3DInputHandler::isZoomAtTargetEnabled() const +{ + return d_ptr->m_zoomAtTargetEnabled; +} + Q3DInputHandlerPrivate::Q3DInputHandlerPrivate(Q3DInputHandler *q) : q_ptr(q), m_inputState(QAbstract3DInputHandlerPrivate::InputStateNone), m_rotationEnabled(true), m_zoomEnabled(true), - m_selectionEnabled(true) + m_selectionEnabled(true), + m_zoomAtTargetEnabled(true), + m_zoomAtTargetPending(false), + m_controller(0), + m_requestedZoomLevel(0.0f), + m_driftMultiplier(0.0f) { + QObject::connect(q, &QAbstract3DInputHandler::sceneChanged, + this, &Q3DInputHandlerPrivate::handleSceneChange); } Q3DInputHandlerPrivate::~Q3DInputHandlerPrivate() { } +void Q3DInputHandlerPrivate::handleSceneChange(Q3DScene *scene) +{ + if (scene) { + if (m_controller) { + QObject::disconnect(m_controller, &Abstract3DController::queriedGraphPositionChanged, + this, &Q3DInputHandlerPrivate::handleQueriedGraphPositionChange); + } + + m_controller = qobject_cast<Abstract3DController *>(scene->parent()); + + if (m_controller) { + QObject::connect(m_controller, &Abstract3DController::queriedGraphPositionChanged, + this, &Q3DInputHandlerPrivate::handleQueriedGraphPositionChange); + } + } +} + +void Q3DInputHandlerPrivate::handleQueriedGraphPositionChange() +{ + if (m_zoomAtTargetPending) { + // Check if the zoom point is on graph + QVector3D newTarget = m_controller->queriedGraphPosition(); + float currentZoom = m_requestedZoomLevel; + float previousZoom = q_ptr->scene()->activeCamera()->zoomLevel(); + q_ptr->scene()->activeCamera()->setZoomLevel(currentZoom); + float diffAdj = 0.0f; + + // If zooming in/out outside the graph, or zooming out after certain point, + // move towards the center. + if ((qAbs(newTarget.x()) > 1.0f + || qAbs(newTarget.y()) > 1.0f + || qAbs(newTarget.z()) > 1.0f) + || (previousZoom > currentZoom && currentZoom <= driftTowardCenterLevel)) { + newTarget = zeroVector; + // Add some extra correction so that we actually reach the center eventually + diffAdj = m_driftMultiplier; + if (previousZoom > currentZoom) + diffAdj *= 2.0f; // Correct towards center little more when zooming out + } + + float zoomFraction = 1.0f - (previousZoom / currentZoom); + + // Adjust camera towards the zoom point, attempting to keep the cursor at same graph point + QVector3D oldTarget = q_ptr->scene()->activeCamera()->target(); + QVector3D origDiff = newTarget - oldTarget; + QVector3D diff = origDiff * zoomFraction + (origDiff.normalized() * diffAdj); + if (diff.length() > origDiff.length()) + diff = origDiff; + q_ptr->scene()->activeCamera()->setTarget(oldTarget + diff); + + if (q_ptr->scene()->selectionQueryPosition() == Q3DScene::invalidSelectionPoint()) + m_zoomAtTargetPending = false; + } +} + QT_END_NAMESPACE_DATAVISUALIZATION diff --git a/src/datavisualization/input/q3dinputhandler.h b/src/datavisualization/input/q3dinputhandler.h index 9afeb945..5423b4ea 100644 --- a/src/datavisualization/input/q3dinputhandler.h +++ b/src/datavisualization/input/q3dinputhandler.h @@ -31,6 +31,7 @@ class QT_DATAVISUALIZATION_EXPORT Q3DInputHandler : public QAbstract3DInputHandl Q_PROPERTY(bool rotationEnabled READ isRotationEnabled WRITE setRotationEnabled NOTIFY rotationEnabledChanged) Q_PROPERTY(bool zoomEnabled READ isZoomEnabled WRITE setZoomEnabled NOTIFY zoomEnabledChanged) Q_PROPERTY(bool selectionEnabled READ isSelectionEnabled WRITE setSelectionEnabled NOTIFY selectionEnabledChanged) + Q_PROPERTY(bool zoomAtTargetEnabled READ isZoomAtTargetEnabled WRITE setZoomAtTargetEnabled NOTIFY zoomAtTargetEnabledChanged) public: explicit Q3DInputHandler(QObject *parent = 0); @@ -42,6 +43,8 @@ public: bool isZoomEnabled() const; void setSelectionEnabled(bool enable); bool isSelectionEnabled() const; + void setZoomAtTargetEnabled(bool enable); + bool isZoomAtTargetEnabled() const; // Input event listeners virtual void mousePressEvent(QMouseEvent *event, const QPoint &mousePos); @@ -53,6 +56,7 @@ signals: void rotationEnabledChanged(bool enable); void zoomEnabledChanged(bool enable); void selectionEnabledChanged(bool enable); + void zoomAtTargetEnabledChanged(bool enable); private: Q_DISABLE_COPY(Q3DInputHandler) diff --git a/src/datavisualization/input/q3dinputhandler_p.h b/src/datavisualization/input/q3dinputhandler_p.h index a3ed8c9c..79b1c8dd 100644 --- a/src/datavisualization/input/q3dinputhandler_p.h +++ b/src/datavisualization/input/q3dinputhandler_p.h @@ -34,19 +34,34 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION -class Q3DInputHandlerPrivate +class Abstract3DController; + +class Q3DInputHandlerPrivate : public QObject { + Q_OBJECT public: Q3DInputHandlerPrivate(Q3DInputHandler *q); ~Q3DInputHandlerPrivate(); -protected: +public slots: + void handleSceneChange(Q3DScene *scene); + void handleQueriedGraphPositionChange(); + +private: Q3DInputHandler *q_ptr; +protected: QAbstract3DInputHandlerPrivate::InputState m_inputState; bool m_rotationEnabled; bool m_zoomEnabled; bool m_selectionEnabled; + bool m_zoomAtTargetEnabled; + bool m_zoomAtTargetPending; + + Abstract3DController *m_controller; // Not owned + + float m_requestedZoomLevel; + float m_driftMultiplier; friend class Q3DInputHandler; }; diff --git a/src/datavisualization/input/qtouch3dinputhandler.cpp b/src/datavisualization/input/qtouch3dinputhandler.cpp index 5d62922b..b811548b 100644 --- a/src/datavisualization/input/qtouch3dinputhandler.cpp +++ b/src/datavisualization/input/qtouch3dinputhandler.cpp @@ -33,6 +33,7 @@ const int tapAndHoldTime = 250; const float rotationSpeed = 200.0f; const int minZoomLevel = 10; const int maxZoomLevel = 500; +const float touchZoomDrift = 0.02f; /*! * \class QTouch3DInputHandler @@ -113,7 +114,8 @@ void QTouch3DInputHandler::touchEvent(QTouchEvent *event) 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()); + QPoint midPoint = ((points.at(0).pos() + points.at(1).pos()) / 2.0).toPoint(); + d_ptr->handlePinchZoom(distance.manhattanLength(), midPoint); } else if (points.count() == 1) { QPointF pointerPos = points.at(0).pos(); if (event->type() == QEvent::TouchBegin) { @@ -165,7 +167,8 @@ void QTouch3DInputHandler::touchEvent(QTouchEvent *event) } QTouch3DInputHandlerPrivate::QTouch3DInputHandlerPrivate(QTouch3DInputHandler *q) - : q_ptr(q), + : Q3DInputHandlerPrivate(q), + q_ptr(q), m_holdTimer(0), m_inputState(QAbstract3DInputHandlerPrivate::InputStateNone) { @@ -181,7 +184,7 @@ QTouch3DInputHandlerPrivate::~QTouch3DInputHandlerPrivate() delete m_holdTimer; } -void QTouch3DInputHandlerPrivate::handlePinchZoom(float distance) +void QTouch3DInputHandlerPrivate::handlePinchZoom(float distance, const QPoint &pos) { if (q_ptr->isZoomEnabled()) { int newDistance = distance; @@ -200,7 +203,18 @@ void QTouch3DInputHandlerPrivate::handlePinchZoom(float distance) zoomLevel = maxZoomLevel; else if (zoomLevel < minZoomLevel) zoomLevel = minZoomLevel; - camera->setZoomLevel(zoomLevel); + + if (q_ptr->isZoomAtTargetEnabled()) { + q_ptr->scene()->setGraphPositionQuery(pos); + m_zoomAtTargetPending = true; + // If zoom at target is enabled, we don't want to zoom yet, as that causes + // jitter. Instead, we zoom next frame, when we apply the camera position. + m_requestedZoomLevel = zoomLevel; + m_driftMultiplier = touchZoomDrift; + } else { + camera->setZoomLevel(zoomLevel); + } + q_ptr->setPrevDistance(newDistance); } } diff --git a/src/datavisualization/input/qtouch3dinputhandler_p.h b/src/datavisualization/input/qtouch3dinputhandler_p.h index 613b5f28..b01904ca 100644 --- a/src/datavisualization/input/qtouch3dinputhandler_p.h +++ b/src/datavisualization/input/qtouch3dinputhandler_p.h @@ -19,7 +19,7 @@ #ifndef QTOUCH3DINPUTHANDLER_P_H #define QTOUCH3DINPUTHANDLER_P_H -#include "qabstract3dinputhandler_p.h" +#include "q3dinputhandler_p.h" #include "qtouch3dinputhandler.h" class QTimer; @@ -28,7 +28,7 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION class QAbstract3DInputHandler; -class QTouch3DInputHandlerPrivate : public QObject +class QTouch3DInputHandlerPrivate : public Q3DInputHandlerPrivate { Q_OBJECT @@ -36,13 +36,14 @@ public: QTouch3DInputHandlerPrivate(QTouch3DInputHandler *q); ~QTouch3DInputHandlerPrivate(); - void handlePinchZoom(float distance); + void handlePinchZoom(float distance, const QPoint &pos); void handleTapAndHold(); void handleSelection(const QPointF &position); void handleRotation(const QPointF &position); -public: +private: QTouch3DInputHandler *q_ptr; +public: QTimer *m_holdTimer; QAbstract3DInputHandlerPrivate::InputState m_inputState; QPointF m_startHoldPos; |