Skip to content

Commit 20ca51b

Browse files
committedJul 11, 2017
Port ability to wheel zoom into/out of layout designer
1 parent 4065a7f commit 20ca51b

File tree

5 files changed

+146
-1
lines changed

5 files changed

+146
-1
lines changed
 

‎python/gui/layout/qgslayoutview.sip

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,12 @@ class QgsLayoutView: QGraphicsView
6767
You don't have to call it manually, QgsLayoutViewTool takes care of it.
6868
%End
6969

70+
void scaleSafe( double scale );
71+
%Docstring
72+
Scales the view in a safe way, by limiting the acceptable range
73+
of the scale applied. The ``scale`` parameter specifies the zoom factor to scale the view by.
74+
%End
75+
7076
signals:
7177

7278
void layoutSet( QgsLayout *layout );

‎src/gui/layout/qgslayoutview.cpp

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,13 @@
1919
#include "qgslayout.h"
2020
#include "qgslayoutviewtool.h"
2121
#include "qgslayoutviewmouseevent.h"
22+
#include "qgssettings.h"
23+
#include "qgsrectangle.h"
2224
#include <memory>
2325

26+
#define MIN_VIEW_SCALE 0.05
27+
#define MAX_VIEW_SCALE 1000.0
28+
2429
QgsLayoutView::QgsLayoutView( QWidget *parent )
2530
: QGraphicsView( parent )
2631
{
@@ -74,6 +79,14 @@ void QgsLayoutView::unsetTool( QgsLayoutViewTool *tool )
7479
}
7580
}
7681

82+
void QgsLayoutView::scaleSafe( double scale )
83+
{
84+
double currentScale = transform().m11();
85+
scale *= currentScale;
86+
scale = qBound( MIN_VIEW_SCALE, scale, MAX_VIEW_SCALE );
87+
setTransform( QTransform::fromScale( scale, scale ) );
88+
}
89+
7790
void QgsLayoutView::mousePressEvent( QMouseEvent *event )
7891
{
7992
if ( mTool )
@@ -134,7 +147,10 @@ void QgsLayoutView::wheelEvent( QWheelEvent *event )
134147
}
135148

136149
if ( !mTool || !event->isAccepted() )
137-
QGraphicsView::wheelEvent( event );
150+
{
151+
event->accept();
152+
wheelZoom( event );
153+
}
138154
}
139155

140156
void QgsLayoutView::keyPressEvent( QKeyEvent *event )
@@ -158,3 +174,53 @@ void QgsLayoutView::keyReleaseEvent( QKeyEvent *event )
158174
if ( !mTool || !event->isAccepted() )
159175
QGraphicsView::keyReleaseEvent( event );
160176
}
177+
178+
void QgsLayoutView::wheelZoom( QWheelEvent *event )
179+
{
180+
//get mouse wheel zoom behavior settings
181+
QgsSettings settings;
182+
double zoomFactor = settings.value( QStringLiteral( "qgis/zoom_factor" ), 2 ).toDouble();
183+
184+
// "Normal" mouse have an angle delta of 120, precision mouses provide data faster, in smaller steps
185+
zoomFactor = 1.0 + ( zoomFactor - 1.0 ) / 120.0 * qAbs( event->angleDelta().y() );
186+
187+
if ( event->modifiers() & Qt::ControlModifier )
188+
{
189+
//holding ctrl while wheel zooming results in a finer zoom
190+
zoomFactor = 1.0 + ( zoomFactor - 1.0 ) / 20.0;
191+
}
192+
193+
//calculate zoom scale factor
194+
bool zoomIn = event->angleDelta().y() > 0;
195+
double scaleFactor = ( zoomIn ? 1 / zoomFactor : zoomFactor );
196+
197+
//get current visible part of scene
198+
QRect viewportRect( 0, 0, viewport()->width(), viewport()->height() );
199+
QgsRectangle visibleRect = QgsRectangle( mapToScene( viewportRect ).boundingRect() );
200+
201+
//transform the mouse pos to scene coordinates
202+
QPointF scenePoint = mapToScene( event->pos() );
203+
204+
//adjust view center
205+
QgsPointXY oldCenter( visibleRect.center() );
206+
QgsPointXY newCenter( scenePoint.x() + ( ( oldCenter.x() - scenePoint.x() ) * scaleFactor ),
207+
scenePoint.y() + ( ( oldCenter.y() - scenePoint.y() ) * scaleFactor ) );
208+
centerOn( newCenter.x(), newCenter.y() );
209+
210+
//zoom layout
211+
if ( zoomIn )
212+
{
213+
scaleSafe( zoomFactor );
214+
}
215+
else
216+
{
217+
scaleSafe( 1 / zoomFactor );
218+
}
219+
220+
//update layout for new zoom
221+
#if 0 // TODO
222+
emit zoomLevelChanged();
223+
updateRulers();
224+
#endif
225+
update();
226+
}

‎src/gui/layout/qgslayoutview.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,12 @@ class GUI_EXPORT QgsLayoutView: public QGraphicsView
8585
*/
8686
void unsetTool( QgsLayoutViewTool *tool );
8787

88+
/**
89+
* Scales the view in a safe way, by limiting the acceptable range
90+
* of the scale applied. The \a scale parameter specifies the zoom factor to scale the view by.
91+
*/
92+
void scaleSafe( double scale );
93+
8894
signals:
8995

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

112118
private:
113119

120+
//! Zoom layout from a mouse wheel event
121+
void wheelZoom( QWheelEvent *event );
122+
114123
QPointer< QgsLayoutViewTool > mTool;
115124

116125
friend class TestQgsLayoutView;

‎tests/src/python/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ ADD_PYTHON_TEST(PyQgsJsonUtils test_qgsjsonutils.py)
7373
ADD_PYTHON_TEST(PyQgsLayerTreeMapCanvasBridge test_qgslayertreemapcanvasbridge.py)
7474
ADD_PYTHON_TEST(PyQgsLayerTree test_qgslayertree.py)
7575
ADD_PYTHON_TEST(PyQgsLayoutManager test_qgslayoutmanager.py)
76+
ADD_PYTHON_TEST(PyQgsLayoutView test_qgslayoutview.py)
7677
ADD_PYTHON_TEST(PyQgsLineSymbolLayers test_qgslinesymbollayers.py)
7778
ADD_PYTHON_TEST(PyQgsLayerMetadata test_qgslayermetadata.py)
7879
ADD_PYTHON_TEST(PyQgsLocator test_qgslocator.py)
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# -*- coding: utf-8 -*-
2+
"""QGIS Unit tests for QgsLayoutView.
3+
4+
.. note:: This program is free software; you can redistribute it and/or modify
5+
it under the terms of the GNU General Public License as published by
6+
the Free Software Foundation; either version 2 of the License, or
7+
(at your option) any later version.
8+
"""
9+
__author__ = 'Nyall Dawson'
10+
__date__ = '05/07/2017'
11+
__copyright__ = 'Copyright 2017, The QGIS Project'
12+
# This will get replaced with a git SHA1 when you do a git archive
13+
__revision__ = '$Format:%H$'
14+
15+
import qgis # NOQA
16+
17+
from qgis.gui import QgsLayoutView
18+
from qgis.PyQt.QtCore import QRectF
19+
from qgis.PyQt.QtGui import QTransform
20+
21+
from qgis.testing import start_app, unittest
22+
23+
start_app()
24+
25+
26+
class TestQgsLayoutView(unittest.TestCase):
27+
28+
def testScaleSafe(self):
29+
""" test scaleSafe method """
30+
31+
view = QgsLayoutView()
32+
view.fitInView(QRectF(0, 0, 10, 10))
33+
scale = view.transform().m11()
34+
view.scaleSafe(2)
35+
self.assertAlmostEqual(view.transform().m11(), 2)
36+
view.scaleSafe(4)
37+
self.assertAlmostEqual(view.transform().m11(), 8)
38+
39+
# try to zoom in heaps
40+
view.scaleSafe(99999999)
41+
# assume we have hit the limit
42+
scale = view.transform().m11()
43+
view.scaleSafe(2)
44+
self.assertAlmostEqual(view.transform().m11(), scale)
45+
46+
view.setTransform(QTransform.fromScale(1, 1))
47+
self.assertAlmostEqual(view.transform().m11(), 1)
48+
# test zooming out
49+
view.scaleSafe(0.5)
50+
self.assertAlmostEqual(view.transform().m11(), 0.5)
51+
view.scaleSafe(0.1)
52+
self.assertAlmostEqual(view.transform().m11(), 0.05)
53+
54+
# try zooming out heaps
55+
view.scaleSafe(0.000000001)
56+
# assume we have hit the limit
57+
scale = view.transform().m11()
58+
view.scaleSafe(0.5)
59+
self.assertAlmostEqual(view.transform().m11(), scale)
60+
61+
62+
if __name__ == '__main__':
63+
unittest.main()

0 commit comments

Comments
 (0)
Please sign in to comment.