Skip to content

Commit

Permalink
Add framework to allow for flexible interaction blocking with map canvas
Browse files Browse the repository at this point in the history
  • Loading branch information
nyalldawson committed May 21, 2020
1 parent baec06c commit 3ebd097
Show file tree
Hide file tree
Showing 9 changed files with 201 additions and 12 deletions.
5 changes: 5 additions & 0 deletions python/gui/auto_additions/qgsmapcanvasinteractionblocker.py
@@ -0,0 +1,5 @@
# The following has been generated automatically from src/gui/qgsmapcanvasinteractionblocker.h
# monkey patching scoped based enum
QgsMapCanvasInteractionBlocker.Interaction.MapPanOnSingleClick.__doc__ = "A map pan interaction caused by a single click and release on the map canvas"
QgsMapCanvasInteractionBlocker.Interaction.__doc__ = '\n\n' + '* ``MapPanOnSingleClick``: ' + QgsMapCanvasInteractionBlocker.Interaction.MapPanOnSingleClick.__doc__
# --
36 changes: 35 additions & 1 deletion python/gui/auto_generated/qgsmapcanvas.sip.in
Expand Up @@ -19,6 +19,7 @@




class QgsMapCanvas : QGraphicsView
{
%Docstring
Expand Down Expand Up @@ -75,7 +76,7 @@ Gets access to properties used for map rendering

void setTemporalController( QgsTemporalController *controller );
%Docstring
Sets the temporal controller, this controller will be used to
Sets the temporal controller, tQgsMapCanvasInteractionBlockerhis controller will be used to
update the canvas temporal range.

.. versionadded:: 3.14
Expand Down Expand Up @@ -784,6 +785,39 @@ Returns map canvas datetime range.

.. seealso:: :py:func:`setTemporalRange`

.. versionadded:: 3.14
%End

void installInteractionBlocker( QgsMapCanvasInteractionBlocker *blocker );
%Docstring
Installs an interaction ``blocker`` onto the canvas, which may prevent certain map canvas
interactions from occurring.

The caller retains ownership of ``blocker``, and must correctly call removeInteractionBlocker()
before deleting the object.

.. seealso:: :py:func:`allowInteraction`

.. seealso:: :py:func:`removeInteractionBlocker`

.. versionadded:: 3.14
%End

void removeInteractionBlocker( QgsMapCanvasInteractionBlocker *blocker );
%Docstring
Removes an interaction ``blocker`` from the canvas.

.. seealso:: :py:func:`allowInteraction`

.. seealso:: :py:func:`installInteractionBlocker`

.. versionadded:: 3.14
%End

bool allowInteraction( QgsMapCanvasInteractionBlocker::Interaction interaction ) const;
%Docstring
Returns ``True`` if the specified ``interaction`` is currently permitted on the canvas.

.. versionadded:: 3.14
%End

Expand Down
45 changes: 45 additions & 0 deletions python/gui/auto_generated/qgsmapcanvasinteractionblocker.sip.in
@@ -0,0 +1,45 @@
/************************************************************************
* This file has been generated automatically from *
* *
* src/gui/qgsmapcanvasinteractionblocker.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/




class QgsMapCanvasInteractionBlocker
{
%Docstring
An interface for objects which block interactions with a QgsMapCanvas.

.. versionadded:: 3.14
%End

%TypeHeaderCode
#include "qgsmapcanvasinteractionblocker.h"
%End
public:

enum class Interaction
{
MapPanOnSingleClick,
};

virtual ~QgsMapCanvasInteractionBlocker();

virtual bool blockCanvasInteraction( Interaction interaction ) const = 0;
%Docstring
Returns ``True`` if the specified ``interaction`` should be blocked.
%End

};

/************************************************************************
* This file has been generated automatically from *
* *
* src/gui/qgsmapcanvasinteractionblocker.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/
1 change: 1 addition & 0 deletions python/gui/gui_auto.sip
Expand Up @@ -119,6 +119,7 @@
%Include auto_generated/qgsmanageconnectionsdialog.sip
%Include auto_generated/qgsmapcanvas.sip
%Include auto_generated/qgsmapcanvasannotationitem.sip
%Include auto_generated/qgsmapcanvasinteractionblocker.sip
%Include auto_generated/qgsmapcanvasitem.sip
%Include auto_generated/qgsmapcanvassnappingutils.sip
%Include auto_generated/qgsmapcanvastracer.sip
Expand Down
1 change: 1 addition & 0 deletions src/gui/CMakeLists.txt
Expand Up @@ -674,6 +674,7 @@ SET(QGIS_GUI_HDRS
qgsmanageconnectionsdialog.h
qgsmapcanvas.h
qgsmapcanvasannotationitem.h
qgsmapcanvasinteractionblocker.h
qgsmapcanvasitem.h
qgsmapcanvasmap.h
qgsmapcanvassnappingutils.h
Expand Down
20 changes: 20 additions & 0 deletions src/gui/qgsmapcanvas.cpp
Expand Up @@ -818,6 +818,26 @@ const QgsDateTimeRange &QgsMapCanvas::temporalRange() const
return mSettings.temporalRange();
}

void QgsMapCanvas::installInteractionBlocker( QgsMapCanvasInteractionBlocker *blocker )
{
mInteractionBlockers.append( blocker );
}

void QgsMapCanvas::removeInteractionBlocker( QgsMapCanvasInteractionBlocker *blocker )
{
mInteractionBlockers.removeAll( blocker );
}

bool QgsMapCanvas::allowInteraction( QgsMapCanvasInteractionBlocker::Interaction interaction ) const
{
for ( const QgsMapCanvasInteractionBlocker *block : mInteractionBlockers )
{
if ( block->blockCanvasInteraction( interaction ) )
return false;
}
return true;
}

void QgsMapCanvas::mapUpdateTimeout()
{
if ( mJob )
Expand Down
35 changes: 34 additions & 1 deletion src/gui/qgsmapcanvas.h
Expand Up @@ -27,6 +27,7 @@
#include "qgsgeometry.h"
#include "qgscustomdrophandler.h"
#include "qgstemporalrangeobject.h"
#include "qgsmapcanvasinteractionblocker.h"

#include <QDomDocument>
#include <QGraphicsView>
Expand Down Expand Up @@ -70,6 +71,7 @@ class QgsReferencedRectangle;

class QgsTemporalController;


/**
* \ingroup gui
* Map canvas is a class for displaying all GIS data types on a canvas.
Expand Down Expand Up @@ -126,7 +128,7 @@ class GUI_EXPORT QgsMapCanvas : public QGraphicsView
const QgsMapSettings &mapSettings() const SIP_KEEPREFERENCE;

/**
* Sets the temporal controller, this controller will be used to
* Sets the temporal controller, tQgsMapCanvasInteractionBlockerhis controller will be used to
* update the canvas temporal range.
*
* \since QGIS 3.14
Expand Down Expand Up @@ -723,6 +725,35 @@ class GUI_EXPORT QgsMapCanvas : public QGraphicsView
*/
const QgsDateTimeRange &temporalRange() const;

/**
* Installs an interaction \a blocker onto the canvas, which may prevent certain map canvas
* interactions from occurring.
*
* The caller retains ownership of \a blocker, and must correctly call removeInteractionBlocker()
* before deleting the object.
*
* \see allowInteraction()
* \see removeInteractionBlocker()
* \since QGIS 3.14
*/
void installInteractionBlocker( QgsMapCanvasInteractionBlocker *blocker );

/**
* Removes an interaction \a blocker from the canvas.
*
* \see allowInteraction()
* \see installInteractionBlocker()
* \since QGIS 3.14
*/
void removeInteractionBlocker( QgsMapCanvasInteractionBlocker *blocker );

/**
* Returns TRUE if the specified \a interaction is currently permitted on the canvas.
*
* \since QGIS 3.14
*/
bool allowInteraction( QgsMapCanvasInteractionBlocker::Interaction interaction ) const;

public slots:

//! Repaints the canvas map
Expand Down Expand Up @@ -1150,6 +1181,8 @@ class GUI_EXPORT QgsMapCanvas : public QGraphicsView
QgsDistanceArea mDa;
QList<double> mZoomResolutions;

QList< QgsMapCanvasInteractionBlocker * > mInteractionBlockers;

/**
* Returns the last cursor position on the canvas in geographical coordinates
* \since QGIS 3.4
Expand Down
47 changes: 47 additions & 0 deletions src/gui/qgsmapcanvasinteractionblocker.h
@@ -0,0 +1,47 @@
/***************************************************************************
qgsmapcanvasinteractionblocker.h
--------------------------------
begin : May 2020
copyright : (C) 2020 by Nyall Dawson
email : nyall dot dawson at gmail dot com
***************************************************************************/

/***************************************************************************
* *
* 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. *
* *
***************************************************************************/

#ifndef QGSMAPCANVASINTERACTIONBLOCKER_H
#define QGSMAPCANVASINTERACTIONBLOCKER_H

#include "qgis_gui.h"

/**
* \class QgsMapCanvasInteractionBlocker
* \ingroup gui
* An interface for objects which block interactions with a QgsMapCanvas.
* \since QGIS 3.14
*/
class GUI_EXPORT QgsMapCanvasInteractionBlocker
{
public:

enum class Interaction : int
{
MapPanOnSingleClick = 1 << 0, //!< A map pan interaction caused by a single click and release on the map canvas
};

virtual ~QgsMapCanvasInteractionBlocker() = default;

/**
* Returns TRUE if the specified \a interaction should be blocked.
*/
virtual bool blockCanvasInteraction( Interaction interaction ) const = 0;

};

#endif // QGSMAPCANVASINTERACTIONBLOCKER_H
23 changes: 13 additions & 10 deletions src/gui/qgsmaptoolpan.cpp
Expand Up @@ -86,16 +86,19 @@ void QgsMapToolPan::canvasReleaseEvent( QgsMapMouseEvent *e )
}
else // add pan to mouse cursor
{
// transform the mouse pos to map coordinates
const QgsPointXY prevCenter = mCanvas->center();
QgsPointXY center = mCanvas->getCoordinateTransform()->toMapCoordinates( e->x(), e->y() );
mCanvas->setCenter( center );
mCanvas->refresh();

QgsDistanceArea da;
da.setEllipsoid( QgsProject::instance()->ellipsoid() );
da.setSourceCrs( mCanvas->mapSettings().destinationCrs(), QgsProject::instance()->transformContext() );
emit panDistanceBearingChanged( da.measureLine( center, prevCenter ), da.lengthUnits(), da.bearing( center, prevCenter ) * 180 / M_PI );
if ( mCanvas->allowInteraction( QgsMapCanvasInteractionBlocker::Interaction::MapPanOnSingleClick ) )
{
// transform the mouse pos to map coordinates
const QgsPointXY prevCenter = mCanvas->center();
QgsPointXY center = mCanvas->getCoordinateTransform()->toMapCoordinates( e->x(), e->y() );
mCanvas->setCenter( center );
mCanvas->refresh();

QgsDistanceArea da;
da.setEllipsoid( QgsProject::instance()->ellipsoid() );
da.setSourceCrs( mCanvas->mapSettings().destinationCrs(), QgsProject::instance()->transformContext() );
emit panDistanceBearingChanged( da.measureLine( center, prevCenter ), da.lengthUnits(), da.bearing( center, prevCenter ) * 180 / M_PI );
}
}
}
}
Expand Down

0 comments on commit 3ebd097

Please sign in to comment.