@@ -457,33 +457,6 @@ void QgsVertexTool::cadCanvasPressEvent( QgsMapMouseEvent *e )
457
457
if ( !mDraggingVertex && !mDraggingEdge )
458
458
mSelectionRectStartPos .reset ( new QPoint ( e->pos () ) );
459
459
}
460
-
461
- if ( e->button () == Qt::RightButton )
462
- {
463
- if ( !mSelectionRect && !mDraggingVertex && !mDraggingEdge )
464
- {
465
- QgsPointLocator::Match m = snapToEditableLayer ( e );
466
- if ( !m.isValid () )
467
- {
468
- // as the last resort check if we are on top of a feature if there is no vertex or edge snap
469
- m = snapToPolygonInterior ( e );
470
- }
471
-
472
- if ( m.isValid () && m.layer () )
473
- {
474
- updateVertexEditor ( m.layer (), m.featureId () );
475
- }
476
- else
477
- {
478
- // there's really nothing under the cursor - let's deselect any feature we may have
479
- mSelectedFeature .reset ();
480
- if ( mVertexEditor )
481
- {
482
- mVertexEditor ->updateEditor ( nullptr );
483
- }
484
- }
485
- }
486
- }
487
460
}
488
461
489
462
void QgsVertexTool::cadCanvasReleaseEvent ( QgsMapMouseEvent *e )
@@ -593,8 +566,17 @@ void QgsVertexTool::cadCanvasReleaseEvent( QgsMapMouseEvent *e )
593
566
}
594
567
else if ( e->button () == Qt::RightButton )
595
568
{
596
- // cancel action
597
- stopDragging ();
569
+ if ( mDraggingVertex || mDraggingEdge )
570
+ {
571
+ // cancel action
572
+ stopDragging ();
573
+ }
574
+ else if ( !mSelectionRect )
575
+ {
576
+ // Right-click to select/delect a feature for editing (also gets selected in vertex editor).
577
+ // If there are multiple features at one location, cycle through them with subsequent right clicks.
578
+ tryToSelectFeature ( e );
579
+ }
598
580
}
599
581
}
600
582
@@ -603,6 +585,13 @@ void QgsVertexTool::cadCanvasReleaseEvent( QgsMapMouseEvent *e )
603
585
604
586
void QgsVertexTool::cadCanvasMoveEvent ( QgsMapMouseEvent *e )
605
587
{
588
+ if ( mSelectedFeatureAlternatives && ( e->pos () - mSelectedFeatureAlternatives ->screenPoint ).manhattanLength () >= QApplication::startDragDistance () )
589
+ {
590
+ // as soon as the mouse moves more than just a tiny bit, previously stored alternatives info
591
+ // is probably not valid anymore and will need to be re-calculated
592
+ mSelectedFeatureAlternatives .reset ();
593
+ }
594
+
606
595
if ( mSelectionMethod == SelectionRange )
607
596
{
608
597
rangeMethodMoveEvent ( e );
@@ -684,6 +673,9 @@ void QgsVertexTool::mouseMoveDraggingEdge( QgsMapMouseEvent *e )
684
673
685
674
void QgsVertexTool::canvasDoubleClickEvent ( QgsMapMouseEvent *e )
686
675
{
676
+ if ( e->button () != Qt::LeftButton )
677
+ return ;
678
+
687
679
QgsPointLocator::Match m = snapToEditableLayer ( e );
688
680
if ( !m.hasEdge () )
689
681
return ;
@@ -852,6 +844,126 @@ QgsPointLocator::Match QgsVertexTool::snapToPolygonInterior( QgsMapMouseEvent *e
852
844
}
853
845
854
846
847
+ QList<QgsPointLocator::Match> QgsVertexTool::findEditableLayerMatches ( const QgsPointXY &mapPoint, QgsVectorLayer *layer )
848
+ {
849
+ QgsPointLocator::MatchList matchList;
850
+
851
+ if ( !layer->isEditable () )
852
+ return matchList;
853
+
854
+ QgsSnappingUtils *snapUtils = canvas ()->snappingUtils ();
855
+ QgsPointLocator *locator = snapUtils->locatorForLayer ( layer );
856
+
857
+ if ( layer->geometryType () == QgsWkbTypes::PolygonGeometry )
858
+ {
859
+ matchList << locator->pointInPolygon ( mapPoint );
860
+ }
861
+
862
+ double tolerance = QgsTolerance::vertexSearchRadius ( canvas ()->mapSettings () );
863
+ matchList << locator->edgesInRect ( mapPoint, tolerance );
864
+ matchList << locator->verticesInRect ( mapPoint, tolerance );
865
+
866
+ return matchList;
867
+ }
868
+
869
+
870
+ QSet<QPair<QgsVectorLayer *, QgsFeatureId> > QgsVertexTool::findAllEditableFeatures ( const QgsPointXY &mapPoint )
871
+ {
872
+ QSet< QPair<QgsVectorLayer *, QgsFeatureId> > alternatives;
873
+
874
+ // if there is a current layer, it should have priority over other layers
875
+ // because sometimes there may be match from multiple layers at one location
876
+ // and selecting current layer is an easy way for the user to prioritize a layer
877
+ if ( QgsVectorLayer *currentVlayer = currentVectorLayer () )
878
+ {
879
+ for ( const QgsPointLocator::Match &m : findEditableLayerMatches ( mapPoint, currentVlayer ) )
880
+ {
881
+ alternatives.insert ( qMakePair ( m.layer (), m.featureId () ) );
882
+ }
883
+ }
884
+
885
+ if ( mMode == AllLayers )
886
+ {
887
+ const auto layers = canvas ()->layers ();
888
+ for ( QgsMapLayer *layer : layers )
889
+ {
890
+ QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( layer );
891
+ if ( !vlayer )
892
+ continue ;
893
+
894
+ for ( const QgsPointLocator::Match &m : findEditableLayerMatches ( mapPoint, vlayer ) )
895
+ {
896
+ alternatives.insert ( qMakePair ( m.layer (), m.featureId () ) );
897
+ }
898
+ }
899
+ }
900
+
901
+ return alternatives;
902
+ }
903
+
904
+
905
+ void QgsVertexTool::tryToSelectFeature ( QgsMapMouseEvent *e )
906
+ {
907
+ if ( !mSelectedFeatureAlternatives )
908
+ {
909
+ // this is the first right-click on this location so we currently do not have information
910
+ // about editable features at this mouse location - let's build the alternatives info
911
+ QSet< QPair<QgsVectorLayer *, QgsFeatureId> > alternatives = findAllEditableFeatures ( toMapCoordinates ( e->pos () ) );
912
+ if ( !alternatives.isEmpty () )
913
+ {
914
+ QgsPointLocator::Match m = snapToEditableLayer ( e );
915
+ if ( !m.isValid () )
916
+ {
917
+ // as the last resort check if we are on top of a feature if there is no vertex or edge snap
918
+ m = snapToPolygonInterior ( e );
919
+ }
920
+
921
+ mSelectedFeatureAlternatives .reset ( new SelectedFeatureAlternatives );
922
+ mSelectedFeatureAlternatives ->screenPoint = e->pos ();
923
+ mSelectedFeatureAlternatives ->index = 0 ;
924
+ if ( m.isValid () )
925
+ {
926
+ // ideally the feature that would get normally highlighted should be also the first choice
927
+ // because as user moves mouse, different features are highlighted, so the highlighted feature
928
+ // should be first to get selected
929
+ QPair<QgsVectorLayer *, QgsFeatureId> firstChoice ( m.layer (), m.featureId () );
930
+ mSelectedFeatureAlternatives ->alternatives .append ( firstChoice );
931
+ alternatives.remove ( firstChoice );
932
+ }
933
+ mSelectedFeatureAlternatives ->alternatives .append ( alternatives.toList () );
934
+ }
935
+ }
936
+ else
937
+ {
938
+ // we have had right-click before on this mouse location - so let's just cycle in our alternatives
939
+ // move to the next alternative
940
+ if ( mSelectedFeatureAlternatives ->index < mSelectedFeatureAlternatives ->alternatives .count () - 1 )
941
+ ++mSelectedFeatureAlternatives ->index ;
942
+ else
943
+ mSelectedFeatureAlternatives ->index = -1 ;
944
+ }
945
+
946
+ if ( mSelectedFeatureAlternatives && mSelectedFeatureAlternatives ->index != -1 )
947
+ {
948
+ // we have a feature to select
949
+ QPair<QgsVectorLayer *, QgsFeatureId> alternative = mSelectedFeatureAlternatives ->alternatives .at ( mSelectedFeatureAlternatives ->index );
950
+ updateVertexEditor ( alternative.first , alternative.second );
951
+ updateFeatureBand ( QgsPointLocator::Match ( QgsPointLocator::Area, alternative.first , alternative.second , 0 , QgsPointXY () ) );
952
+ }
953
+ else
954
+ {
955
+ // there's really nothing under the cursor or while cycling through the list of available features
956
+ // we got to the end of the list - let's deselect any feature we may have had selected
957
+ mSelectedFeature .reset ();
958
+ if ( mVertexEditor )
959
+ {
960
+ mVertexEditor ->updateEditor ( nullptr );
961
+ }
962
+ updateFeatureBand ( QgsPointLocator::Match () );
963
+ }
964
+ }
965
+
966
+
855
967
bool QgsVertexTool::isNearEndpointMarker ( const QgsPointXY &mapPoint )
856
968
{
857
969
if ( !mEndpointMarkerCenter )
0 commit comments