Skip to content

Commit 0050262

Browse files
committed
[FEATURE] Allow web map style shift-drag zoom
When certain map tools are active, you can hold down shift and drag a rectangle on the map to zoom to that area. This is enabled for the map tools which are not selection tools (since they use shift for adding to selection), and edit tools. Gracias a Girona!
1 parent 8628f21 commit 0050262

16 files changed

+209
-8
lines changed

python/gui/qgsmaptool.sip

+4
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ class QgsMapTool : QObject
3838
If it does, the tool can be operated once and then a previous map
3939
tool automatically restored. */
4040
EditTool, /*!< Map tool is an edit tool, which can only be used when layer is editable*/
41+
AllowZoomRect, /*!< Allow zooming by rectangle (by holding shift and dragging) while the tool is active*/
4142
};
4243
typedef QFlags<QgsMapTool::Flag> Flags;
4344

@@ -183,3 +184,6 @@ class QgsMapTool : QObject
183184

184185

185186
};
187+
188+
189+
QFlags<QgsMapTool::Flag> operator|(QgsMapTool::Flag f1, QFlags<QgsMapTool::Flag> f2);

python/gui/qgsmaptoolemitpoint.sip

+2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ class QgsMapToolEmitPoint : QgsMapTool
99
//! constructor
1010
QgsMapToolEmitPoint( QgsMapCanvas* canvas );
1111

12+
virtual Flags flags() const;
13+
1214
//! Overridden mouse move event
1315
virtual void canvasMoveEvent( QgsMapMouseEvent * e );
1416

python/gui/qgsmaptoolidentify.sip

+2
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ class QgsMapToolIdentify : QgsMapTool
4747

4848
virtual ~QgsMapToolIdentify();
4949

50+
virtual Flags flags() const;
51+
5052
//! Overridden mouse move event
5153
virtual void canvasMoveEvent( QgsMapMouseEvent * e );
5254

src/app/qgsmaptoolfeatureaction.h

+2
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ class APP_EXPORT QgsMapToolFeatureAction : public QgsMapTool
3636

3737
~QgsMapToolFeatureAction();
3838

39+
virtual Flags flags() const override { return QgsMapTool::AllowZoomRect; }
40+
3941
//! Overridden mouse move event
4042
virtual void canvasMoveEvent( QgsMapMouseEvent* e ) override;
4143

src/app/qgsmaptoolmeasureangle.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,9 @@ class APP_EXPORT QgsMapToolMeasureAngle: public QgsMapTool
3131
QgsMapToolMeasureAngle( QgsMapCanvas* canvas );
3232
~QgsMapToolMeasureAngle();
3333

34-
//! Mouse move event for overridingqgs
34+
virtual Flags flags() const override { return QgsMapTool::AllowZoomRect; }
35+
36+
//! Mouse move event for overriding
3537
void canvasMoveEvent( QgsMapMouseEvent* e ) override;
3638

3739
//! Mouse release event for overriding

src/app/qgsmaptoolpointsymbol.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ class APP_EXPORT QgsMapToolPointSymbol: public QgsMapToolEdit
3434
public:
3535
QgsMapToolPointSymbol( QgsMapCanvas* canvas );
3636

37-
virtual Flags flags() const { return QgsMapTool::EditTool; }
37+
virtual Flags flags() const override { return QgsMapTool::EditTool; }
3838

3939
void canvasPressEvent( QgsMapMouseEvent* e ) override;
4040

src/app/qgsmeasuretool.h

+2
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ class APP_EXPORT QgsMeasureTool : public QgsMapTool
3636

3737
~QgsMeasureTool();
3838

39+
virtual Flags flags() const override { return QgsMapTool::AllowZoomRect; }
40+
3941
//! returns whether measuring distance or area
4042
bool measureArea() { return mMeasureArea; }
4143

src/gui/qgsmapcanvas.cpp

+72-3
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ email : sherman at mrcc.com
6262
#include "qgsproject.h"
6363
#include "qgsrubberband.h"
6464
#include "qgsvectorlayer.h"
65+
#include "qgscursors.h"
6566
#include <math.h>
6667

6768

@@ -212,6 +213,7 @@ QgsMapCanvas::QgsMapCanvas( QWidget * parent, const char *name )
212213
, mSnappingUtils( nullptr )
213214
, mScaleLocked( false )
214215
, mExpressionContextScope( tr( "Map Canvas" ) )
216+
, mZoomDragging( false )
215217
{
216218
setObjectName( name );
217219
mScene = new QGraphicsScene();
@@ -273,6 +275,9 @@ QgsMapCanvas::QgsMapCanvas( QWidget * parent, const char *name )
273275
mPreviewEffect = new QgsPreviewEffect( this );
274276
viewport()->setGraphicsEffect( mPreviewEffect );
275277

278+
QPixmap zoomPixmap = QPixmap(( const char ** )( zoom_in ) );
279+
mZoomCursor = QCursor( zoomPixmap, 7, 7 );
280+
276281
setInteractive( false );
277282

278283
refresh();
@@ -1342,6 +1347,50 @@ void QgsMapCanvas::mouseDoubleClickEvent( QMouseEvent* e )
13421347
}// mouseDoubleClickEvent
13431348

13441349

1350+
void QgsMapCanvas::beginZoomRect( QPoint pos )
1351+
{
1352+
mZoomRect.setRect( 0, 0, 0, 0 );
1353+
QApplication::setOverrideCursor( mZoomCursor );
1354+
mZoomDragging = true;
1355+
mZoomRubberBand.reset( new QgsRubberBand( this, QGis::Polygon ) );
1356+
QColor color( Qt::blue );
1357+
color.setAlpha( 63 );
1358+
mZoomRubberBand->setColor( color );
1359+
mZoomRect.setTopLeft( pos );
1360+
}
1361+
1362+
void QgsMapCanvas::endZoomRect( QPoint pos )
1363+
{
1364+
mZoomDragging = false;
1365+
mZoomRubberBand.reset( nullptr );
1366+
QApplication::restoreOverrideCursor();
1367+
1368+
// store the rectangle
1369+
mZoomRect.setRight( pos.x() );
1370+
mZoomRect.setBottom( pos.y() );
1371+
1372+
if ( mZoomRect.width() < 5 && mZoomRect.height() < 5 )
1373+
{
1374+
//probably a mistake - would result in huge zoom!
1375+
return;
1376+
}
1377+
1378+
//account for bottom right -> top left dragging
1379+
mZoomRect = mZoomRect.normalized();
1380+
1381+
// set center and zoom
1382+
const QSize& zoomRectSize = mZoomRect.size();
1383+
const QSize& canvasSize = mSettings.outputSize();
1384+
double sfx = ( double )zoomRectSize.width() / canvasSize.width();
1385+
double sfy = ( double )zoomRectSize.height() / canvasSize.height();
1386+
double sf = qMax( sfx, sfy );
1387+
1388+
QgsPoint c = mSettings.mapToPixel().toMapCoordinates( mZoomRect.center() );
1389+
1390+
zoomByFactor( sf, &c );
1391+
refresh();
1392+
}
1393+
13451394
void QgsMapCanvas::mousePressEvent( QMouseEvent* e )
13461395
{
13471396
//use middle mouse button for panning, map tools won't receive any events in that case
@@ -1352,12 +1401,20 @@ void QgsMapCanvas::mousePressEvent( QMouseEvent* e )
13521401
}
13531402
else
13541403
{
1355-
13561404
// call handler of current map tool
13571405
if ( mMapTool )
13581406
{
1359-
QScopedPointer<QgsMapMouseEvent> me( new QgsMapMouseEvent( this, e ) );
1360-
mMapTool->canvasPressEvent( me.data() );
1407+
if ( mMapTool->flags() & QgsMapTool::AllowZoomRect && e->button() == Qt::LeftButton
1408+
&& e->modifiers() & Qt::ShiftModifier )
1409+
{
1410+
beginZoomRect( e->pos() );
1411+
return;
1412+
}
1413+
else
1414+
{
1415+
QScopedPointer<QgsMapMouseEvent> me( new QgsMapMouseEvent( this, e ) );
1416+
mMapTool->canvasPressEvent( me.data() );
1417+
}
13611418
}
13621419
}
13631420

@@ -1382,6 +1439,12 @@ void QgsMapCanvas::mouseReleaseEvent( QMouseEvent* e )
13821439
}
13831440
else
13841441
{
1442+
if ( mZoomDragging && e->button() == Qt::LeftButton )
1443+
{
1444+
endZoomRect( e->pos() );
1445+
return;
1446+
}
1447+
13851448
// call handler of current map tool
13861449
if ( mMapTool )
13871450
{
@@ -1572,6 +1635,12 @@ void QgsMapCanvas::mouseMoveEvent( QMouseEvent * e )
15721635
{
15731636
panAction( e );
15741637
}
1638+
else if ( mZoomDragging )
1639+
{
1640+
mZoomRect.setBottomRight( e->pos() );
1641+
mZoomRubberBand->setToCanvasRectangle( mZoomRect );
1642+
mZoomRubberBand->show();
1643+
}
15751644
else
15761645
{
15771646
// call handler of current map tool

src/gui/qgsmapcanvas.h

+24
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ class QgsMapCanvasMap;
6565
class QgsMapOverviewCanvas;
6666
class QgsMapTool;
6767
class QgsSnappingUtils;
68+
class QgsRubberBand;
6869

6970
/** \ingroup gui
7071
* A class that stores visibility and presence in overview flags together
@@ -785,10 +786,33 @@ class GUI_EXPORT QgsMapCanvas : public QGraphicsView
785786

786787
QgsExpressionContextScope mExpressionContextScope;
787788

789+
//! Stores zoom rect
790+
QRect mZoomRect;
791+
792+
//! Flag to indicate a zoom by rectangle operation is taking place
793+
bool mZoomDragging;
794+
795+
//! Zoom by rectangle rubber band
796+
QScopedPointer< QgsRubberBand > mZoomRubberBand;
797+
798+
QCursor mZoomCursor;
799+
788800
//! Force a resize of the map canvas item
789801
//! @note added in 2.16
790802
void updateMapSize();
791803

804+
/** Starts zooming via rectangle
805+
* @param pos start position for rectangle
806+
* @note added in QGIS 2.16
807+
*/
808+
void beginZoomRect( QPoint pos );
809+
810+
/** Ends zooming via rectangle
811+
* @param pos end position for rectangle
812+
* @note added in QGIS 2.16
813+
*/
814+
void endZoomRect( QPoint pos );
815+
792816
friend class TestQgsMapCanvas;
793817

794818
}; // class QgsMapCanvas

src/gui/qgsmaptool.h

+4
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ class GUI_EXPORT QgsMapTool : public QObject
6262
If it does, the tool can be operated once and then a previous map
6363
tool automatically restored. */
6464
EditTool = 1 << 2, /*!< Map tool is an edit tool, which can only be used when layer is editable*/
65+
AllowZoomRect = 1 << 3, /*!< Allow zooming by rectangle (by holding shift and dragging) while the tool is active*/
6566
};
6667
Q_DECLARE_FLAGS( Flags, Flag )
6768

@@ -224,6 +225,9 @@ class GUI_EXPORT QgsMapTool : public QObject
224225

225226
//! translated name of the map tool
226227
QString mToolName;
228+
227229
};
228230

231+
Q_DECLARE_OPERATORS_FOR_FLAGS( QgsMapTool::Flags )
232+
229233
#endif

src/gui/qgsmaptooledit.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ class GUI_EXPORT QgsMapToolEdit: public QgsMapTool
3333
QgsMapToolEdit( QgsMapCanvas* canvas );
3434
virtual ~QgsMapToolEdit();
3535

36-
virtual Flags flags() const { return QgsMapTool::EditTool; }
36+
virtual Flags flags() const override { return QgsMapTool::EditTool; }
3737

3838
protected:
3939

src/gui/qgsmaptoolemitpoint.h

+2
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ class GUI_EXPORT QgsMapToolEmitPoint : public QgsMapTool
3434
//! constructor
3535
QgsMapToolEmitPoint( QgsMapCanvas* canvas );
3636

37+
virtual Flags flags() const override { return QgsMapTool::AllowZoomRect; }
38+
3739
//! Overridden mouse move event
3840
virtual void canvasMoveEvent( QgsMapMouseEvent* e ) override;
3941

src/gui/qgsmaptoolidentify.h

+2
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,8 @@ class GUI_EXPORT QgsMapToolIdentify : public QgsMapTool
9292

9393
virtual ~QgsMapToolIdentify();
9494

95+
virtual Flags flags() const override { return QgsMapTool::AllowZoomRect; }
96+
9597
//! Overridden mouse move event
9698
virtual void canvasMoveEvent( QgsMapMouseEvent* e ) override;
9799

src/gui/qgsmaptoolpan.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ class GUI_EXPORT QgsMapToolPan : public QgsMapTool
3232
//! constructor
3333
QgsMapToolPan( QgsMapCanvas* canvas );
3434

35-
virtual Flags flags() const { return QgsMapTool::Transient; }
35+
virtual Flags flags() const override { return QgsMapTool::Transient | QgsMapTool::AllowZoomRect; }
3636

3737
//! Mouse press event
3838
virtual void canvasPressEvent( QgsMapMouseEvent* e ) override;

src/gui/qgsmaptoolzoom.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ class GUI_EXPORT QgsMapToolZoom : public QgsMapTool
3535

3636
~QgsMapToolZoom();
3737

38-
virtual Flags flags() const { return QgsMapTool::Transient; }
38+
virtual Flags flags() const override { return QgsMapTool::Transient; }
3939

4040
//! Overridden mouse move event
4141
virtual void canvasMoveEvent( QgsMapMouseEvent* e ) override;

0 commit comments

Comments
 (0)