1 /***************************************************************************
2     qgsmaptoolpan.h  -  map tool for panning in map canvas
3     ---------------------
4     begin                : January 2006
5     copyright            : (C) 2006 by Martin Dobias
6     email                : wonder.sk at gmail dot com
7  ***************************************************************************
8  *                                                                         *
9  *   This program is free software; you can redistribute it and/or modify  *
10  *   it under the terms of the GNU General Public License as published by  *
11  *   the Free Software Foundation; either version 2 of the License, or     *
12  *   (at your option) any later version.                                   *
13  *                                                                         *
14  ***************************************************************************/
15 
16 #include <QBitmap>
17 #include <QCursor>
18 #include "qgsmaptoolpan.h"
19 #include "qgsmapcanvas.h"
20 #include "qgsmaptopixel.h"
21 #include "qgsmapmouseevent.h"
22 #include "qgsproject.h"
23 #include "qgslogger.h"
24 
25 
QgsMapToolPan(QgsMapCanvas * canvas)26 QgsMapToolPan::QgsMapToolPan( QgsMapCanvas *canvas )
27   : QgsMapTool( canvas )
28   , mDragging( false )
29 {
30   mToolName = tr( "Pan" );
31   // set cursor
32   mCursor = QCursor( Qt::OpenHandCursor );
33 }
34 
~QgsMapToolPan()35 QgsMapToolPan::~QgsMapToolPan()
36 {
37   mCanvas->ungrabGesture( Qt::PinchGesture );
38 }
39 
activate()40 void QgsMapToolPan::activate()
41 {
42   mCanvas->grabGesture( Qt::PinchGesture );
43   QgsMapTool::activate();
44 }
45 
deactivate()46 void QgsMapToolPan::deactivate()
47 {
48   mCanvas->ungrabGesture( Qt::PinchGesture );
49   QgsMapTool::deactivate();
50 }
51 
flags() const52 QgsMapTool::Flags QgsMapToolPan::flags() const
53 {
54   return QgsMapTool::Transient | QgsMapTool::AllowZoomRect | QgsMapTool::ShowContextMenu;
55 }
56 
canvasPressEvent(QgsMapMouseEvent * e)57 void QgsMapToolPan::canvasPressEvent( QgsMapMouseEvent *e )
58 {
59   if ( e->button() == Qt::LeftButton )
60   {
61     mCanvas->setCursor( QCursor( Qt::ClosedHandCursor ) );
62     mCanvas->panActionStart( e->pos() );
63   }
64 }
65 
66 
canvasMoveEvent(QgsMapMouseEvent * e)67 void QgsMapToolPan::canvasMoveEvent( QgsMapMouseEvent *e )
68 {
69   if ( !mPinching )
70   {
71     if ( ( e->buttons() & Qt::LeftButton ) )
72     {
73       mDragging = true;
74       // move map and other canvas items
75       mCanvas->panAction( e );
76     }
77   }
78 }
79 
canvasReleaseEvent(QgsMapMouseEvent * e)80 void QgsMapToolPan::canvasReleaseEvent( QgsMapMouseEvent *e )
81 {
82   if ( !mPinching )
83   {
84     if ( e->button() == Qt::LeftButton )
85     {
86       if ( mDragging )
87       {
88         mCanvas->panActionEnd( e->pos() );
89         mDragging = false;
90       }
91       else // add pan to mouse cursor
92       {
93         if ( mCanvas->allowInteraction( QgsMapCanvasInteractionBlocker::Interaction::MapPanOnSingleClick ) )
94         {
95           // transform the mouse pos to map coordinates
96           const QgsPointXY prevCenter = mCanvas->center();
97           QgsPointXY center = mCanvas->getCoordinateTransform()->toMapCoordinates( e->x(), e->y() );
98           mCanvas->setCenter( center );
99           mCanvas->refresh();
100 
101           QgsDistanceArea da;
102           da.setEllipsoid( QgsProject::instance()->ellipsoid() );
103           da.setSourceCrs( mCanvas->mapSettings().destinationCrs(), QgsProject::instance()->transformContext() );
104           emit panDistanceBearingChanged( da.measureLine( center, prevCenter ), da.lengthUnits(), da.bearing( center, prevCenter ) * 180 / M_PI );
105         }
106       }
107     }
108   }
109   mCanvas->setCursor( mCursor );
110 }
111 
canvasDoubleClickEvent(QgsMapMouseEvent * e)112 void QgsMapToolPan::canvasDoubleClickEvent( QgsMapMouseEvent *e )
113 {
114   if ( !QTouchDevice::devices().isEmpty() && !mPinching )
115   {
116     mCanvas->zoomWithCenter( e->x(), e->y(), true );
117   }
118 }
119 
gestureEvent(QGestureEvent * event)120 bool QgsMapToolPan::gestureEvent( QGestureEvent *event )
121 {
122   if ( QTouchDevice::devices().isEmpty() )
123     return true; // no touch support
124 
125   if ( QGesture *gesture = event->gesture( Qt::PinchGesture ) )
126   {
127     mPinching = true;
128     pinchTriggered( static_cast<QPinchGesture *>( gesture ) );
129   }
130   return true;
131 }
132 
pinchTriggered(QPinchGesture * gesture)133 void QgsMapToolPan::pinchTriggered( QPinchGesture *gesture )
134 {
135   if ( gesture->state() == Qt::GestureFinished )
136   {
137     //a very small totalScaleFactor indicates a two finger tap (pinch gesture without pinching)
138     if ( 0.98 < gesture->totalScaleFactor()  && gesture->totalScaleFactor() < 1.02 )
139     {
140       mCanvas->zoomOut();
141     }
142     else
143     {
144       //Transfor global coordinates to widget coordinates
145       QPoint pos = gesture->centerPoint().toPoint();
146       pos = mCanvas->mapFromGlobal( pos );
147       // transform the mouse pos to map coordinates
148       QgsPointXY center  = mCanvas->getCoordinateTransform()->toMapCoordinates( pos.x(), pos.y() );
149       QgsRectangle r = mCanvas->extent();
150       r.scale( 1 / gesture->totalScaleFactor(), &center );
151       mCanvas->setExtent( r );
152       mCanvas->refresh();
153     }
154     mPinching = false;
155   }
156 }
157