From 27f6e86e7537d650d323c827aee626b34d6e13aa Mon Sep 17 00:00:00 2001 From: Matej Bagar Date: Tue, 14 Jul 2026 18:47:47 +0200 Subject: [PATCH 1/6] Fix missaligned snapping crosshair due to broken property binding --- app/qml/map/components/MMCrosshair.qml | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/app/qml/map/components/MMCrosshair.qml b/app/qml/map/components/MMCrosshair.qml index c7755c7cd..eb58a6c98 100644 --- a/app/qml/map/components/MMCrosshair.qml +++ b/app/qml/map/components/MMCrosshair.qml @@ -21,9 +21,8 @@ Item { property point center: Qt.point( root.width / 2, root.height / 2 ) - property var recordPoint: snapUtils.recordPoint - - property point screenPoint: snapUtils.snapped && __activeLayer.vectorLayer ? __inputUtils.transformPointToScreenCoordinates(__activeLayer.vectorLayer.crs, mapSettings, recordPoint) : center + property var recordPoint + property point screenPoint property real outerSize: 60 * __dp property real innerDotSize: 10 * __dp @@ -40,6 +39,13 @@ Item { useSnapping: root.shouldUseSnapping destinationLayer: __activeLayer.vectorLayer + // We are using assignment instead of property binding here on purpose. Qt 6.10+ doesn't trigger property binding + // if tha value hasn't changed. However, if snapping is enabled recordPoint might be the same, but the screenPoint + // will be different, thus we need to trigger the recalculation. + onRecordPointChanged: { + root.recordPoint = snapUtils.recordPoint + root.screenPoint = snapUtils.snapped && __activeLayer.vectorLayer ? __inputUtils.transformPointToScreenCoordinates(__activeLayer.vectorLayer.crs, root.mapSettings, snapUtils.recordPoint) : root.center + } } Image { From b535949bdfdc3b4db5c6341a0dd92533fb67c032 Mon Sep 17 00:00:00 2001 From: Matej Bagar Date: Thu, 16 Jul 2026 13:21:00 +0200 Subject: [PATCH 2/6] Refactor snap screen point calculation --- app/qml/map/components/MMCrosshair.qml | 12 ++---------- app/snaputils.cpp | 12 ++++++++++++ app/snaputils.h | 9 +++++++++ 3 files changed, 23 insertions(+), 10 deletions(-) diff --git a/app/qml/map/components/MMCrosshair.qml b/app/qml/map/components/MMCrosshair.qml index eb58a6c98..d58364aae 100644 --- a/app/qml/map/components/MMCrosshair.qml +++ b/app/qml/map/components/MMCrosshair.qml @@ -21,8 +21,8 @@ Item { property point center: Qt.point( root.width / 2, root.height / 2 ) - property var recordPoint - property point screenPoint + property var recordPoint : snapUtils.recordPoint + property point screenPoint : snapUtils.snapped ? snapUtils.snapPoint : root.center property real outerSize: 60 * __dp property real innerDotSize: 10 * __dp @@ -38,14 +38,6 @@ Item { qgsProject: root.qgsProject useSnapping: root.shouldUseSnapping destinationLayer: __activeLayer.vectorLayer - - // We are using assignment instead of property binding here on purpose. Qt 6.10+ doesn't trigger property binding - // if tha value hasn't changed. However, if snapping is enabled recordPoint might be the same, but the screenPoint - // will be different, thus we need to trigger the recalculation. - onRecordPointChanged: { - root.recordPoint = snapUtils.recordPoint - root.screenPoint = snapUtils.snapped && __activeLayer.vectorLayer ? __inputUtils.transformPointToScreenCoordinates(__activeLayer.vectorLayer.crs, root.mapSettings, snapUtils.recordPoint) : root.center - } } Image { diff --git a/app/snaputils.cpp b/app/snaputils.cpp index 919d45f0c..fe971d52b 100644 --- a/app/snaputils.cpp +++ b/app/snaputils.cpp @@ -128,6 +128,7 @@ void SnapUtils::getsnap() } setRecordPoint( layerPoint ); + setSnapPoint( InputUtils::transformPointToScreenCoordinates( mDestinationLayer->crs(), mMapSettings, layerPoint ) ); if ( snap.hasVertex() ) { @@ -186,6 +187,17 @@ void SnapUtils::setCenterPosition( QPointF newCenterPosition ) initializeRecordPosition(); } +QPointF SnapUtils::snapPoint() const +{ + return mSnapPoint; +} + +void SnapUtils::setSnapPoint( QPointF newSnapPoint ) +{ + mSnapPoint = newSnapPoint; + emit snapPointChanged( mSnapPoint ); +} + QgsPoint SnapUtils::recordPoint() const { return mRecordPoint; diff --git a/app/snaputils.h b/app/snaputils.h index 4a98df5ea..59f526a4e 100644 --- a/app/snaputils.h +++ b/app/snaputils.h @@ -32,7 +32,10 @@ class SnapUtils : public QObject Q_PROPERTY( QgsVectorLayer *destinationLayer READ destinationLayer WRITE setDestinationLayer NOTIFY destinationLayerChanged ) Q_PROPERTY( bool snapped READ snapped WRITE setSnapped NOTIFY snappedChanged ) + // point in map CRS which will be recorded Q_PROPERTY( QgsPoint recordPoint READ recordPoint WRITE setRecordPoint NOTIFY recordPointChanged ) + // point in screen CRS where the crosshair should point if snapping is enabled + Q_PROPERTY( QPointF snapPoint READ snapPoint WRITE setSnapPoint NOTIFY snapPointChanged ) public: SnapUtils( QObject *parent = nullptr ); @@ -58,6 +61,9 @@ class SnapUtils : public QObject QPointF centerPosition() const; void setCenterPosition( QPointF newCenterPosition ); + QPointF snapPoint() const; + void setSnapPoint( QPointF newSnapPoint ); + QgsPoint recordPoint() const; void setRecordPoint( QgsPoint newRecordPoint ); @@ -84,6 +90,8 @@ class SnapUtils : public QObject void centerPositionChanged( QPointF centerPosition ); + void snapPointChanged( QPointF snapPoint ); + void recordPointChanged( QgsPoint recordPoint ); void useSnappingChanged( bool useSnapping ); @@ -105,6 +113,7 @@ class SnapUtils : public QObject QgsVectorLayer *mDestinationLayer = nullptr; // not owned QPointF mCenterPosition = QPointF( -1, -1 ); + QPointF mSnapPoint = QPointF( -1, -1 ); QgsPoint mRecordPoint = QgsPoint( -1, -1 ); bool mSnapped = false; From 69a083dfbdadedf0eda97453685eeed8c3f0fee0 Mon Sep 17 00:00:00 2001 From: Matej Bagar Date: Thu, 16 Jul 2026 13:21:29 +0200 Subject: [PATCH 3/6] Refactor SnapUtils --- app/qml/map/components/MMCrosshair.qml | 10 +++++----- app/snaputils.h | 2 ++ 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/app/qml/map/components/MMCrosshair.qml b/app/qml/map/components/MMCrosshair.qml index d58364aae..4b8d86c84 100644 --- a/app/qml/map/components/MMCrosshair.qml +++ b/app/qml/map/components/MMCrosshair.qml @@ -10,7 +10,7 @@ import QtQuick import QtQuick.Controls.impl -import mm 1.0 as MM +import MMInput Item { id: root @@ -30,7 +30,7 @@ Item { property alias crosshairForeground: crosshairForeground property alias snapUtils: snapUtils - MM.SnapUtils { + SnapUtils { id: snapUtils centerPosition: root.center @@ -164,7 +164,7 @@ Item { } } - opacity: snapUtils.snapped && ( snapUtils.snapType === MM.SnapUtils.Vertex || snapUtils.snapType === MM.SnapUtils.Other ) ? 100 : 0 + opacity: snapUtils.snapped && ( snapUtils.snapType === SnapUtils.Vertex || snapUtils.snapType === SnapUtils.Other ) ? 100 : 0 Behavior on opacity { PropertyAnimation { @@ -174,7 +174,7 @@ Item { } } - rotation: snapUtils.snapType === MM.SnapUtils.Other ? 0 : 45 + rotation: snapUtils.snapType === SnapUtils.Other ? 0 : 45 Behavior on rotation { PropertyAnimation { @@ -215,7 +215,7 @@ Item { } } - opacity: snapUtils.snapped && snapUtils.snapType === MM.SnapUtils.Segment ? 100 : 0 + opacity: snapUtils.snapped && snapUtils.snapType === SnapUtils.Segment ? 100 : 0 Behavior on opacity { PropertyAnimation { diff --git a/app/snaputils.h b/app/snaputils.h index 59f526a4e..32a5d56de 100644 --- a/app/snaputils.h +++ b/app/snaputils.h @@ -12,6 +12,7 @@ #include #include +#include #include "qgspoint.h" #include "qgsproject.h" @@ -23,6 +24,7 @@ class SnapUtils : public QObject { Q_OBJECT + QML_ELEMENT Q_PROPERTY( QgsProject *qgsProject READ qgsProject WRITE setQgsProject NOTIFY qgsProjectChanged ) Q_PROPERTY( InputMapSettings *mapSettings READ mapSettings WRITE setMapSettings NOTIFY mapSettingsChanged ) From 6027c2e9c1749e4461a1be2433e6c28b311be5b3 Mon Sep 17 00:00:00 2001 From: Matej Bagar Date: Thu, 16 Jul 2026 18:42:36 +0200 Subject: [PATCH 4/6] Expose QgsPoint as value type to QML --- app/mmtypeutils.h | 7 +++++++ app/qml/map/components/MMCrosshair.qml | 6 +++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/app/mmtypeutils.h b/app/mmtypeutils.h index 76f4da156..c53917722 100644 --- a/app/mmtypeutils.h +++ b/app/mmtypeutils.h @@ -24,4 +24,11 @@ struct ForeignGeometry QML_VALUE_TYPE( qgsGeometry ); }; +struct ForeignPoint +{ + Q_GADGET + QML_FOREIGN( QgsPoint ) + QML_VALUE_TYPE( qgsPoint ); +}; + #endif //MMTYPEUTILS_H diff --git a/app/qml/map/components/MMCrosshair.qml b/app/qml/map/components/MMCrosshair.qml index 4b8d86c84..54e460cdf 100644 --- a/app/qml/map/components/MMCrosshair.qml +++ b/app/qml/map/components/MMCrosshair.qml @@ -15,13 +15,13 @@ import MMInput Item { id: root - /*required*/ property var qgsProject - /*required*/ property var mapSettings + required property var qgsProject + required property var mapSettings property bool shouldUseSnapping: false property point center: Qt.point( root.width / 2, root.height / 2 ) - property var recordPoint : snapUtils.recordPoint + property qgsPoint recordPoint : snapUtils.recordPoint property point screenPoint : snapUtils.snapped ? snapUtils.snapPoint : root.center property real outerSize: 60 * __dp From 7745b4e2c41904ec8c7eca1ad9f56c1462ad1891 Mon Sep 17 00:00:00 2001 From: Matej Bagar Date: Mon, 20 Jul 2026 13:33:27 +0200 Subject: [PATCH 5/6] Reset snap point if snap is not used --- app/snaputils.cpp | 8 ++++++++ app/snaputils.h | 2 ++ 2 files changed, 10 insertions(+) diff --git a/app/snaputils.cpp b/app/snaputils.cpp index fe971d52b..f38024e64 100644 --- a/app/snaputils.cpp +++ b/app/snaputils.cpp @@ -218,6 +218,9 @@ void SnapUtils::setSnapped( bool newSnapped ) { if ( mSnapped == newSnapped ) return; + + if ( !newSnapped ) resetSnapPoint(); + mSnapped = newSnapped; emit snappedChanged( mSnapped ); } @@ -311,6 +314,11 @@ void SnapUtils::initializeRecordPosition() setRecordPoint( centerPoint ); } +void SnapUtils::resetSnapPoint() +{ + mSnapPoint = QPointF( -1, -1 ); +} + QgsVectorLayer *SnapUtils::destinationLayer() const { return mDestinationLayer; diff --git a/app/snaputils.h b/app/snaputils.h index 32a5d56de..fd0694082 100644 --- a/app/snaputils.h +++ b/app/snaputils.h @@ -108,6 +108,8 @@ class SnapUtils : public QObject void setupSnapping(); void initializeRecordPosition(); + void resetSnapPoint(); + QgsSnappingUtils mSnappingUtils; QgsProject *mQgsProject = nullptr; // not owned From e7a7f723dd57de7c454b5f89c8fd8ee5c40be078 Mon Sep 17 00:00:00 2001 From: Matej Bagar Date: Mon, 20 Jul 2026 13:36:46 +0200 Subject: [PATCH 6/6] Rerun astyle --- app/snaputils.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/snaputils.cpp b/app/snaputils.cpp index f38024e64..191411506 100644 --- a/app/snaputils.cpp +++ b/app/snaputils.cpp @@ -220,7 +220,7 @@ void SnapUtils::setSnapped( bool newSnapped ) return; if ( !newSnapped ) resetSnapPoint(); - + mSnapped = newSnapped; emit snappedChanged( mSnapped ); }