Skip to content

Commit

Permalink
Port ability to wheel zoom into/out of layout designer
Browse files Browse the repository at this point in the history
  • Loading branch information
nyalldawson committed Jul 11, 2017
1 parent 4065a7f commit 20ca51b
Show file tree
Hide file tree
Showing 5 changed files with 146 additions and 1 deletion.
6 changes: 6 additions & 0 deletions python/gui/layout/qgslayoutview.sip
Expand Up @@ -67,6 +67,12 @@ class QgsLayoutView: QGraphicsView
You don't have to call it manually, QgsLayoutViewTool takes care of it.
%End

void scaleSafe( double scale );
%Docstring
Scales the view in a safe way, by limiting the acceptable range
of the scale applied. The ``scale`` parameter specifies the zoom factor to scale the view by.
%End

signals:

void layoutSet( QgsLayout *layout );
Expand Down
68 changes: 67 additions & 1 deletion src/gui/layout/qgslayoutview.cpp
Expand Up @@ -19,8 +19,13 @@
#include "qgslayout.h"
#include "qgslayoutviewtool.h"
#include "qgslayoutviewmouseevent.h"
#include "qgssettings.h"
#include "qgsrectangle.h"
#include <memory>

#define MIN_VIEW_SCALE 0.05
#define MAX_VIEW_SCALE 1000.0

QgsLayoutView::QgsLayoutView( QWidget *parent )
: QGraphicsView( parent )
{
Expand Down Expand Up @@ -74,6 +79,14 @@ void QgsLayoutView::unsetTool( QgsLayoutViewTool *tool )
}
}

void QgsLayoutView::scaleSafe( double scale )
{
double currentScale = transform().m11();
scale *= currentScale;
scale = qBound( MIN_VIEW_SCALE, scale, MAX_VIEW_SCALE );
setTransform( QTransform::fromScale( scale, scale ) );
}

void QgsLayoutView::mousePressEvent( QMouseEvent *event )
{
if ( mTool )
Expand Down Expand Up @@ -134,7 +147,10 @@ void QgsLayoutView::wheelEvent( QWheelEvent *event )
}

if ( !mTool || !event->isAccepted() )
QGraphicsView::wheelEvent( event );
{
event->accept();
wheelZoom( event );
}
}

void QgsLayoutView::keyPressEvent( QKeyEvent *event )
Expand All @@ -158,3 +174,53 @@ void QgsLayoutView::keyReleaseEvent( QKeyEvent *event )
if ( !mTool || !event->isAccepted() )
QGraphicsView::keyReleaseEvent( event );
}

void QgsLayoutView::wheelZoom( QWheelEvent *event )
{
//get mouse wheel zoom behavior settings
QgsSettings settings;
double zoomFactor = settings.value( QStringLiteral( "qgis/zoom_factor" ), 2 ).toDouble();

// "Normal" mouse have an angle delta of 120, precision mouses provide data faster, in smaller steps
zoomFactor = 1.0 + ( zoomFactor - 1.0 ) / 120.0 * qAbs( event->angleDelta().y() );

if ( event->modifiers() & Qt::ControlModifier )
{
//holding ctrl while wheel zooming results in a finer zoom
zoomFactor = 1.0 + ( zoomFactor - 1.0 ) / 20.0;
}

//calculate zoom scale factor
bool zoomIn = event->angleDelta().y() > 0;
double scaleFactor = ( zoomIn ? 1 / zoomFactor : zoomFactor );

//get current visible part of scene
QRect viewportRect( 0, 0, viewport()->width(), viewport()->height() );
QgsRectangle visibleRect = QgsRectangle( mapToScene( viewportRect ).boundingRect() );

//transform the mouse pos to scene coordinates
QPointF scenePoint = mapToScene( event->pos() );

//adjust view center
QgsPointXY oldCenter( visibleRect.center() );
QgsPointXY newCenter( scenePoint.x() + ( ( oldCenter.x() - scenePoint.x() ) * scaleFactor ),
scenePoint.y() + ( ( oldCenter.y() - scenePoint.y() ) * scaleFactor ) );
centerOn( newCenter.x(), newCenter.y() );

//zoom layout
if ( zoomIn )
{
scaleSafe( zoomFactor );
}
else
{
scaleSafe( 1 / zoomFactor );
}

//update layout for new zoom
#if 0 // TODO
emit zoomLevelChanged();
updateRulers();
#endif
update();
}
9 changes: 9 additions & 0 deletions src/gui/layout/qgslayoutview.h
Expand Up @@ -85,6 +85,12 @@ class GUI_EXPORT QgsLayoutView: public QGraphicsView
*/
void unsetTool( QgsLayoutViewTool *tool );

/**
* Scales the view in a safe way, by limiting the acceptable range
* of the scale applied. The \a scale parameter specifies the zoom factor to scale the view by.
*/
void scaleSafe( double scale );

signals:

/**
Expand All @@ -111,6 +117,9 @@ class GUI_EXPORT QgsLayoutView: public QGraphicsView

private:

//! Zoom layout from a mouse wheel event
void wheelZoom( QWheelEvent *event );

QPointer< QgsLayoutViewTool > mTool;

friend class TestQgsLayoutView;
Expand Down
1 change: 1 addition & 0 deletions tests/src/python/CMakeLists.txt
Expand Up @@ -73,6 +73,7 @@ ADD_PYTHON_TEST(PyQgsJsonUtils test_qgsjsonutils.py)
ADD_PYTHON_TEST(PyQgsLayerTreeMapCanvasBridge test_qgslayertreemapcanvasbridge.py)
ADD_PYTHON_TEST(PyQgsLayerTree test_qgslayertree.py)
ADD_PYTHON_TEST(PyQgsLayoutManager test_qgslayoutmanager.py)
ADD_PYTHON_TEST(PyQgsLayoutView test_qgslayoutview.py)
ADD_PYTHON_TEST(PyQgsLineSymbolLayers test_qgslinesymbollayers.py)
ADD_PYTHON_TEST(PyQgsLayerMetadata test_qgslayermetadata.py)
ADD_PYTHON_TEST(PyQgsLocator test_qgslocator.py)
Expand Down
63 changes: 63 additions & 0 deletions tests/src/python/test_qgslayoutview.py
@@ -0,0 +1,63 @@
# -*- coding: utf-8 -*-
"""QGIS Unit tests for QgsLayoutView.
.. note:: This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
"""
__author__ = 'Nyall Dawson'
__date__ = '05/07/2017'
__copyright__ = 'Copyright 2017, The QGIS Project'
# This will get replaced with a git SHA1 when you do a git archive
__revision__ = '$Format:%H$'

import qgis # NOQA

from qgis.gui import QgsLayoutView
from qgis.PyQt.QtCore import QRectF
from qgis.PyQt.QtGui import QTransform

from qgis.testing import start_app, unittest

start_app()


class TestQgsLayoutView(unittest.TestCase):

def testScaleSafe(self):
""" test scaleSafe method """

view = QgsLayoutView()
view.fitInView(QRectF(0, 0, 10, 10))
scale = view.transform().m11()
view.scaleSafe(2)
self.assertAlmostEqual(view.transform().m11(), 2)
view.scaleSafe(4)
self.assertAlmostEqual(view.transform().m11(), 8)

# try to zoom in heaps
view.scaleSafe(99999999)
# assume we have hit the limit
scale = view.transform().m11()
view.scaleSafe(2)
self.assertAlmostEqual(view.transform().m11(), scale)

view.setTransform(QTransform.fromScale(1, 1))
self.assertAlmostEqual(view.transform().m11(), 1)
# test zooming out
view.scaleSafe(0.5)
self.assertAlmostEqual(view.transform().m11(), 0.5)
view.scaleSafe(0.1)
self.assertAlmostEqual(view.transform().m11(), 0.05)

# try zooming out heaps
view.scaleSafe(0.000000001)
# assume we have hit the limit
scale = view.transform().m11()
view.scaleSafe(0.5)
self.assertAlmostEqual(view.transform().m11(), scale)


if __name__ == '__main__':
unittest.main()

0 comments on commit 20ca51b

Please sign in to comment.