From 8ef5c0e91879cefc2f2c7d718b497856a4aafe22 Mon Sep 17 00:00:00 2001
From: Nyall Dawson <nyall.dawson@gmail.com>
Date: Wed, 17 Jul 2024 08:57:29 +1000
Subject: [PATCH 1/2] Add easy way for QgsMapToolAdvancedDigitizing to show
 snapping indicator

Instead of requiring all subclasses to manually implement this logic,
add QgsMapToolAdvancedDigitizing::setUseSnappingIndicator so that
the base class takes care of this for us
---
 .../qgsmaptooladvanceddigitizing.sip.in       | 31 ++++++++++++++++
 .../qgsmaptooladvanceddigitizing.sip.in       | 31 ++++++++++++++++
 src/gui/qgsmaptooladvanceddigitizing.cpp      | 27 ++++++++++++++
 src/gui/qgsmaptooladvanceddigitizing.h        | 37 +++++++++++++++++++
 4 files changed, 126 insertions(+)

diff --git a/python/PyQt6/gui/auto_generated/qgsmaptooladvanceddigitizing.sip.in b/python/PyQt6/gui/auto_generated/qgsmaptooladvanceddigitizing.sip.in
index 837d12105e77..00f1041cc28f 100644
--- a/python/PyQt6/gui/auto_generated/qgsmaptooladvanceddigitizing.sip.in
+++ b/python/PyQt6/gui/auto_generated/qgsmaptooladvanceddigitizing.sip.in
@@ -39,6 +39,7 @@ Creates an advanced digitizing maptool
 :param canvas: The map canvas on which the tool works
 :param cadDockWidget: The cad dock widget which will be used to adjust mouse events
 %End
+    ~QgsMapToolAdvancedDigitizing();
 
     virtual void canvasPressEvent( QgsMapMouseEvent *e );
 
@@ -91,6 +92,8 @@ may keep advanced digitizing allowed all the time.
 If ``True`` is returned, that does not mean that advanced digitizing is actually active,
 because it is up to the user to enable/disable it when it is allowed.
 
+The default is that advanced digitizing is allowed.
+
 .. seealso:: :py:func:`setAdvancedDigitizingAllowed`
 %End
 
@@ -101,7 +104,20 @@ Returns whether mouse events (press/move/release) should automatically try to sn
 to the tool. This may be desirable default behavior for some map tools, but not for other map tools.
 It is therefore possible to configure the behavior by the map tool.
 
+The default is that auto snapping is enabled.
+
 .. seealso:: :py:func:`isAutoSnapEnabled`
+%End
+
+    bool useSnappingIndicator() const;
+%Docstring
+Returns whether the snapping indicator should automatically be used.
+
+The default is that a snap indicator is not used.
+
+.. seealso:: :py:func:`setUseSnappingIndicator`
+
+.. versionadded:: 3.40
 %End
 
   protected:
@@ -111,6 +127,8 @@ It is therefore possible to configure the behavior by the map tool.
 Sets whether functionality of advanced digitizing dock widget is currently allowed.
 This method is protected because it should be a decision of the map tool and not from elsewhere.
 
+The default is that advanced digitizing is allowed.
+
 .. seealso:: :py:func:`isAdvancedDigitizingAllowed`
 %End
 
@@ -119,9 +137,22 @@ This method is protected because it should be a decision of the map tool and not
 Sets whether mouse events (press/move/release) should automatically try to snap mouse position
 This method is protected because it should be a decision of the map tool and not from elsewhere.
 
+The default is that auto snapping is enabled.
+
 .. seealso:: :py:func:`isAutoSnapEnabled`
 %End
 
+    void setUseSnappingIndicator( bool enabled );
+%Docstring
+Sets whether a snapping indicator should automatically be used.
+
+The default is that a snap indicator is not used.
+
+.. seealso:: :py:func:`useSnappingIndicator`
+
+.. versionadded:: 3.40
+%End
+
 
 
   public:
diff --git a/python/gui/auto_generated/qgsmaptooladvanceddigitizing.sip.in b/python/gui/auto_generated/qgsmaptooladvanceddigitizing.sip.in
index 837d12105e77..00f1041cc28f 100644
--- a/python/gui/auto_generated/qgsmaptooladvanceddigitizing.sip.in
+++ b/python/gui/auto_generated/qgsmaptooladvanceddigitizing.sip.in
@@ -39,6 +39,7 @@ Creates an advanced digitizing maptool
 :param canvas: The map canvas on which the tool works
 :param cadDockWidget: The cad dock widget which will be used to adjust mouse events
 %End
+    ~QgsMapToolAdvancedDigitizing();
 
     virtual void canvasPressEvent( QgsMapMouseEvent *e );
 
@@ -91,6 +92,8 @@ may keep advanced digitizing allowed all the time.
 If ``True`` is returned, that does not mean that advanced digitizing is actually active,
 because it is up to the user to enable/disable it when it is allowed.
 
+The default is that advanced digitizing is allowed.
+
 .. seealso:: :py:func:`setAdvancedDigitizingAllowed`
 %End
 
@@ -101,7 +104,20 @@ Returns whether mouse events (press/move/release) should automatically try to sn
 to the tool. This may be desirable default behavior for some map tools, but not for other map tools.
 It is therefore possible to configure the behavior by the map tool.
 
+The default is that auto snapping is enabled.
+
 .. seealso:: :py:func:`isAutoSnapEnabled`
+%End
+
+    bool useSnappingIndicator() const;
+%Docstring
+Returns whether the snapping indicator should automatically be used.
+
+The default is that a snap indicator is not used.
+
+.. seealso:: :py:func:`setUseSnappingIndicator`
+
+.. versionadded:: 3.40
 %End
 
   protected:
@@ -111,6 +127,8 @@ It is therefore possible to configure the behavior by the map tool.
 Sets whether functionality of advanced digitizing dock widget is currently allowed.
 This method is protected because it should be a decision of the map tool and not from elsewhere.
 
+The default is that advanced digitizing is allowed.
+
 .. seealso:: :py:func:`isAdvancedDigitizingAllowed`
 %End
 
@@ -119,9 +137,22 @@ This method is protected because it should be a decision of the map tool and not
 Sets whether mouse events (press/move/release) should automatically try to snap mouse position
 This method is protected because it should be a decision of the map tool and not from elsewhere.
 
+The default is that auto snapping is enabled.
+
 .. seealso:: :py:func:`isAutoSnapEnabled`
 %End
 
+    void setUseSnappingIndicator( bool enabled );
+%Docstring
+Sets whether a snapping indicator should automatically be used.
+
+The default is that a snap indicator is not used.
+
+.. seealso:: :py:func:`useSnappingIndicator`
+
+.. versionadded:: 3.40
+%End
+
 
 
   public:
diff --git a/src/gui/qgsmaptooladvanceddigitizing.cpp b/src/gui/qgsmaptooladvanceddigitizing.cpp
index 85fad034aa95..ae2f19dce5e2 100644
--- a/src/gui/qgsmaptooladvanceddigitizing.cpp
+++ b/src/gui/qgsmaptooladvanceddigitizing.cpp
@@ -29,6 +29,8 @@ QgsMapToolAdvancedDigitizing::QgsMapToolAdvancedDigitizing( QgsMapCanvas *canvas
   connect( canvas, &QgsMapCanvas::currentLayerChanged, this, &QgsMapToolAdvancedDigitizing::onCurrentLayerChanged );
 }
 
+QgsMapToolAdvancedDigitizing::~QgsMapToolAdvancedDigitizing() = default;
+
 void QgsMapToolAdvancedDigitizing::canvasPressEvent( QgsMapMouseEvent *e )
 {
   if ( isAdvancedDigitizingAllowed() && mCadDockWidget->cadEnabled() )
@@ -115,6 +117,11 @@ void QgsMapToolAdvancedDigitizing::canvasMoveEvent( QgsMapMouseEvent *e )
     mSnapToGridCanvasItem->setPoint( e->mapPoint() );
   }
 
+  if ( mSnapIndicator )
+  {
+    mSnapIndicator->setMatch( e->mapPointMatch() );
+  }
+
   cadCanvasMoveEvent( e );
 }
 
@@ -140,6 +147,9 @@ void QgsMapToolAdvancedDigitizing::deactivate()
   mCadDockWidget->disable();
   delete mSnapToGridCanvasItem;
   mSnapToGridCanvasItem = nullptr;
+
+  if ( mSnapIndicator )
+    mSnapIndicator->setMatch( QgsPointLocator::Match() );
 }
 
 QgsMapLayer *QgsMapToolAdvancedDigitizing::layer() const
@@ -147,6 +157,23 @@ QgsMapLayer *QgsMapToolAdvancedDigitizing::layer() const
   return canvas()->currentLayer();
 }
 
+bool QgsMapToolAdvancedDigitizing::useSnappingIndicator() const
+{
+  return static_cast< bool >( mSnapIndicator.get() );
+}
+
+void QgsMapToolAdvancedDigitizing::setUseSnappingIndicator( bool enabled )
+{
+  if ( enabled && !mSnapIndicator )
+  {
+    mSnapIndicator = std::make_unique< QgsSnapIndicator >( mCanvas );
+  }
+  else if ( !enabled && mSnapIndicator )
+  {
+    mSnapIndicator.reset();
+  }
+}
+
 void QgsMapToolAdvancedDigitizing::cadPointChanged( const QgsPointXY &point )
 {
   Q_UNUSED( point )
diff --git a/src/gui/qgsmaptooladvanceddigitizing.h b/src/gui/qgsmaptooladvanceddigitizing.h
index f20954cf7ed1..4e09ee1d2c37 100644
--- a/src/gui/qgsmaptooladvanceddigitizing.h
+++ b/src/gui/qgsmaptooladvanceddigitizing.h
@@ -19,10 +19,12 @@
 
 #include "qgsmaptooledit.h"
 #include "qgis_gui.h"
+#include <memory>
 
 class QgsMapMouseEvent;
 class QgsAdvancedDigitizingDockWidget;
 class QgsSnapToGridCanvasItem;
+class QgsSnapIndicator;
 
 /**
  * \ingroup gui
@@ -44,6 +46,7 @@ class GUI_EXPORT QgsMapToolAdvancedDigitizing : public QgsMapToolEdit
      * \param cadDockWidget  The cad dock widget which will be used to adjust mouse events
      */
     explicit QgsMapToolAdvancedDigitizing( QgsMapCanvas *canvas, QgsAdvancedDigitizingDockWidget *cadDockWidget );
+    ~QgsMapToolAdvancedDigitizing() override;
 
     //! Catch the mouse press event, filters it, transforms it to map coordinates and send it to virtual method
     void canvasPressEvent( QgsMapMouseEvent *e ) override;
@@ -83,6 +86,9 @@ class GUI_EXPORT QgsMapToolAdvancedDigitizing : public QgsMapToolEdit
      *
      * If TRUE is returned, that does not mean that advanced digitizing is actually active,
      * because it is up to the user to enable/disable it when it is allowed.
+     *
+     * The default is that advanced digitizing is allowed.
+     *
      * \see setAdvancedDigitizingAllowed()
      */
     bool isAdvancedDigitizingAllowed() const { return mAdvancedDigitizingAllowed; }
@@ -92,15 +98,31 @@ class GUI_EXPORT QgsMapToolAdvancedDigitizing : public QgsMapToolEdit
      * (according to the snapping configuration of map canvas) before passing the mouse coordinates
      * to the tool. This may be desirable default behavior for some map tools, but not for other map tools.
      * It is therefore possible to configure the behavior by the map tool.
+     *
+     * The default is that auto snapping is enabled.
+     *
      * \see isAutoSnapEnabled()
      */
     bool isAutoSnapEnabled() const { return mAutoSnapEnabled; }
 
+    /**
+     * Returns whether the snapping indicator should automatically be used.
+     *
+     * The default is that a snap indicator is not used.
+     *
+     * \see setUseSnappingIndicator()
+     * \since QGIS 3.40
+     */
+    bool useSnappingIndicator() const;
+
   protected:
 
     /**
      * Sets whether functionality of advanced digitizing dock widget is currently allowed.
      * This method is protected because it should be a decision of the map tool and not from elsewhere.
+     *
+     * The default is that advanced digitizing is allowed.
+     *
      * \see isAdvancedDigitizingAllowed()
      */
     void setAdvancedDigitizingAllowed( bool allowed ) { mAdvancedDigitizingAllowed = allowed; }
@@ -108,10 +130,23 @@ class GUI_EXPORT QgsMapToolAdvancedDigitizing : public QgsMapToolEdit
     /**
      * Sets whether mouse events (press/move/release) should automatically try to snap mouse position
      * This method is protected because it should be a decision of the map tool and not from elsewhere.
+     *
+     * The default is that auto snapping is enabled.
+     *
      * \see isAutoSnapEnabled()
      */
     void setAutoSnapEnabled( bool enabled ) { mAutoSnapEnabled = enabled; }
 
+    /**
+     * Sets whether a snapping indicator should automatically be used.
+     *
+     * The default is that a snap indicator is not used.
+     *
+     * \see useSnappingIndicator()
+     * \since QGIS 3.40
+     */
+    void setUseSnappingIndicator( bool enabled );
+
 
     QgsAdvancedDigitizingDockWidget *mCadDockWidget = nullptr;
 
@@ -188,6 +223,8 @@ class GUI_EXPORT QgsMapToolAdvancedDigitizing : public QgsMapToolEdit
     //! Whether to snap to grid before passing coordinates to cadCanvas*Event()
     bool mSnapToLayerGridEnabled = true;
     QgsSnapToGridCanvasItem *mSnapToGridCanvasItem = nullptr;
+
+    std::unique_ptr<QgsSnapIndicator> mSnapIndicator;
 };
 
 #endif // QGSMAPTOOLADVANCEDDIGITIZE_H

From 02a9a10644a40e9d3fa2c31879307fa5b1e363ff Mon Sep 17 00:00:00 2001
From: Nyall Dawson <nyall.dawson@gmail.com>
Date: Wed, 17 Jul 2024 08:58:33 +1000
Subject: [PATCH 2/2] Show snapping indicator for create point text annotation
 tool

---
 src/gui/annotations/qgscreateannotationitemmaptool_impl.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/gui/annotations/qgscreateannotationitemmaptool_impl.cpp b/src/gui/annotations/qgscreateannotationitemmaptool_impl.cpp
index 6d57ba2a8402..59b571b05bf0 100644
--- a/src/gui/annotations/qgscreateannotationitemmaptool_impl.cpp
+++ b/src/gui/annotations/qgscreateannotationitemmaptool_impl.cpp
@@ -87,7 +87,7 @@ QgsCreatePointTextItemMapTool::QgsCreatePointTextItemMapTool( QgsMapCanvas *canv
   : QgsMapToolAdvancedDigitizing( canvas, cadDockWidget )
   , mHandler( new QgsCreateAnnotationItemMapToolHandler( canvas, cadDockWidget ) )
 {
-
+  setUseSnappingIndicator( true );
 }
 
 QgsCreatePointTextItemMapTool::~QgsCreatePointTextItemMapTool() = default;