From 6cd674ec0fb093ff2c1846c594e8dc4e64f93ef5 Mon Sep 17 00:00:00 2001 From: Roman Telezhynskyi Date: Wed, 2 Dec 2015 20:39:25 +0200 Subject: [PATCH] QGraphicsView Zooming in and out under mouse position using mouse wheel finally works like i want. --HG-- branch : develop --- src/libs/vwidgets/vmaingraphicsview.cpp | 50 +++++++++++++++++++++++-- src/libs/vwidgets/vmaingraphicsview.h | 13 ++----- 2 files changed, 50 insertions(+), 13 deletions(-) diff --git a/src/libs/vwidgets/vmaingraphicsview.cpp b/src/libs/vwidgets/vmaingraphicsview.cpp index db782fd14..d97d9e9de 100644 --- a/src/libs/vwidgets/vmaingraphicsview.cpp +++ b/src/libs/vwidgets/vmaingraphicsview.cpp @@ -55,11 +55,20 @@ GraphicsViewZoom::GraphicsViewZoom(QGraphicsView* view) void GraphicsViewZoom::gentle_zoom(double factor) { _view->scale(factor, factor); + if (factor < 1) + { + // Because QGraphicsView centers the picture when it's smaller than the view. And QGraphicsView's scrolls + // boundaries don't allow to put any picture point at any viewport position we will provide fictive scene size. + // Temporary and bigger than view, scene size will help position an image under cursor. + FictiveSceneRect(_view->scene(), _view); + } _view->centerOn(target_scene_pos); QPointF delta_viewport_pos = target_viewport_pos - QPointF(_view->viewport()->width() / 2.0, _view->viewport()->height() / 2.0); QPointF viewport_center = _view->mapFromScene(target_scene_pos) - delta_viewport_pos; _view->centerOn(_view->mapToScene(viewport_center.toPoint())); + // In the end we just set correct scene size + VMainGraphicsView::NewSceneRect(_view->scene(), _view); emit zoomed(); } @@ -112,12 +121,12 @@ void GraphicsViewZoom::animFinished() * If don't do that we will zoom using old value cursor position on scene. It is not what we expect. * Almoust the same we do in method GraphicsViewZoom::eventFilter. */ - QPoint pos = _view->mapFromGlobal(QCursor::pos()); - QPointF delta = target_scene_pos - _view->mapToScene(pos); + const QPoint pos = _view->mapFromGlobal(QCursor::pos()); + const QPointF delta = target_scene_pos - _view->mapToScene(pos); if (qAbs(delta.x()) > 5 || qAbs(delta.y()) > 5) { - target_viewport_pos = pos; - target_scene_pos = _view->mapToScene(pos); + target_viewport_pos = pos; + target_scene_pos = _view->mapToScene(pos); } } @@ -173,6 +182,39 @@ bool GraphicsViewZoom::eventFilter(QObject *object, QEvent *event) return false; } +//--------------------------------------------------------------------------------------------------------------------- +void GraphicsViewZoom::FictiveSceneRect(QGraphicsScene *sc, QGraphicsView *view) +{ + SCASSERT(sc != nullptr); + SCASSERT(view != nullptr); + + //Calculate view rect + //to receive the currently visible area, map the widgets bounds to the scene + const QPointF a = view->mapToScene(0, 0 ); + const QPointF b = view->mapToScene(view->viewport()->width(), view->viewport()->height()); + QRectF viewRect = QRectF( a, b ); + + //Calculate scene rect + const QRectF sceneRect = sc->sceneRect(); + + if (not sceneRect.contains(viewRect)) + {//Scene less than view + //Scale view + QLineF topLeftRay(viewRect.center(), viewRect.topLeft()); + topLeftRay.setLength(topLeftRay.length()*2); + + QLineF bottomRightRay(viewRect.center(), viewRect.bottomRight()); + bottomRightRay.setLength(bottomRightRay.length()*2); + + viewRect = QRectF(topLeftRay.p2(), bottomRightRay.p2()); + + //Unite two rects + const QRectF newRect = sceneRect.united(viewRect); + + sc->setSceneRect(newRect); + } +} + //--------------------------------------------------------------------------------------------------------------------- /** * @brief VMainGraphicsView constructor. diff --git a/src/libs/vwidgets/vmaingraphicsview.h b/src/libs/vwidgets/vmaingraphicsview.h index 4ad9462bd..021738909 100644 --- a/src/libs/vwidgets/vmaingraphicsview.h +++ b/src/libs/vwidgets/vmaingraphicsview.h @@ -36,11 +36,6 @@ * This class adds ability to zoom QGraphicsView using mouse wheel. The point under cursor * remains motionless while it's possible. * - * Note that it becomes not possible when the scene's - * size is not large enough comparing to the viewport size. QGraphicsView centers the picture - * when it's smaller than the view. And QGraphicsView's scrolls boundaries don't allow to - * put any picture point at any viewport position. - * * When the user starts scrolling, this class remembers original scene position and * keeps it until scrolling is completed. It's better than getting original scene position at * each scrolling step because that approach leads to position errors due to before-mentioned @@ -79,18 +74,18 @@ public slots: void scrollingTime(qreal x); void animFinished(); private: + Q_DISABLE_COPY(GraphicsViewZoom) QGraphicsView* _view; Qt::KeyboardModifiers _modifiers; double _zoom_factor_base; QPointF target_scene_pos; QPointF target_viewport_pos; QTimeLine *anim; - - bool eventFilter(QObject* object, QEvent* event); -private: - Q_DISABLE_COPY(GraphicsViewZoom) /** @brief _numScheduledScalings keep number scheduled scalings. */ qint32 _numScheduledScalings; + + virtual bool eventFilter(QObject* object, QEvent* event) Q_DECL_OVERRIDE; + void FictiveSceneRect(QGraphicsScene *sc, QGraphicsView *view); }; /**