@@ -457,33 +457,6 @@ void QgsVertexTool::cadCanvasPressEvent( QgsMapMouseEvent *e )
457457 if ( !mDraggingVertex && !mDraggingEdge )
458458 mSelectionRectStartPos .reset ( new QPoint ( e->pos () ) );
459459 }
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- }
487460}
488461
489462void QgsVertexTool::cadCanvasReleaseEvent ( QgsMapMouseEvent *e )
@@ -593,8 +566,17 @@ void QgsVertexTool::cadCanvasReleaseEvent( QgsMapMouseEvent *e )
593566 }
594567 else if ( e->button () == Qt::RightButton )
595568 {
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+ }
598580 }
599581 }
600582
@@ -603,6 +585,13 @@ void QgsVertexTool::cadCanvasReleaseEvent( QgsMapMouseEvent *e )
603585
604586void QgsVertexTool::cadCanvasMoveEvent ( QgsMapMouseEvent *e )
605587{
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+
606595 if ( mSelectionMethod == SelectionRange )
607596 {
608597 rangeMethodMoveEvent ( e );
@@ -684,6 +673,9 @@ void QgsVertexTool::mouseMoveDraggingEdge( QgsMapMouseEvent *e )
684673
685674void QgsVertexTool::canvasDoubleClickEvent ( QgsMapMouseEvent *e )
686675{
676+ if ( e->button () != Qt::LeftButton )
677+ return ;
678+
687679 QgsPointLocator::Match m = snapToEditableLayer ( e );
688680 if ( !m.hasEdge () )
689681 return ;
@@ -852,6 +844,126 @@ QgsPointLocator::Match QgsVertexTool::snapToPolygonInterior( QgsMapMouseEvent *e
852844}
853845
854846
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+
855967bool QgsVertexTool::isNearEndpointMarker ( const QgsPointXY &mapPoint )
856968{
857969 if ( !mEndpointMarkerCenter )
0 commit comments