26#include <QApplication>
32#include "moc_qgsmaptoolselectionhandler.cpp"
34using namespace Qt::StringLiterals;
38QgsDistanceWidget::QgsDistanceWidget(
const QString &label, QWidget *parent )
41 mLayout =
new QHBoxLayout(
this );
42 mLayout->setContentsMargins( 0, 0, 0, 0 );
43 mLayout->setAlignment( Qt::AlignLeft );
46 if ( !label.isEmpty() )
48 QLabel *lbl =
new QLabel( label,
this );
49 lbl->setAlignment( Qt::AlignRight | Qt::AlignCenter );
50 mLayout->addWidget( lbl );
54 mDistanceSpinBox->setSingleStep( 1 );
55 mDistanceSpinBox->setValue( 0 );
56 mDistanceSpinBox->setMinimum( 0 );
57 mDistanceSpinBox->setMaximum( 1000000000 );
58 mDistanceSpinBox->setDecimals( 6 );
59 mDistanceSpinBox->setShowClearButton(
false );
60 mDistanceSpinBox->setSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::Preferred );
61 mLayout->addWidget( mDistanceSpinBox );
64 mDistanceSpinBox->installEventFilter(
this );
65 connect( mDistanceSpinBox,
static_cast<void (
QgsDoubleSpinBox::* )(
double )
>( &QgsDoubleSpinBox::valueChanged ),
this, &QgsDistanceWidget::distanceChanged );
68 setFocusProxy( mDistanceSpinBox );
71void QgsDistanceWidget::setDistance(
double distance )
73 mDistanceSpinBox->setValue( distance );
74 mDistanceSpinBox->selectAll();
77double QgsDistanceWidget::distance()
79 return mDistanceSpinBox->value();
82bool QgsDistanceWidget::eventFilter( QObject *obj, QEvent *ev )
84 if ( obj == mDistanceSpinBox && ev->type() == QEvent::KeyPress )
86 QKeyEvent *
event =
static_cast<QKeyEvent *
>( ev );
87 if ( event->key() == Qt::Key_Escape )
89 emit distanceEditingCanceled();
92 if ( event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return )
94 emit distanceEditingFinished( distance(), event->modifiers() );
111 mIdentifyMenu->setAllowMultipleReturn(
false );
112 mIdentifyMenu->setExecWithSingleResult(
true );
122 switch ( mSelectionMode )
126 selectFeaturesReleaseEvent( e );
131 selectFreehandReleaseEvent( e );
134 selectRadiusReleaseEvent( e );
142 switch ( mSelectionMode )
146 selectFeaturesMoveEvent( e );
149 selectPolygonMoveEvent( e );
152 selectFreehandMoveEvent( e );
155 selectRadiusMoveEvent( e );
162 switch ( mSelectionMode )
166 selectFeaturesPressEvent( e );
169 selectPolygonPressEvent( e );
180 if ( mSelectionActive && e->key() == Qt::Key_Escape )
193void QgsMapToolSelectionHandler::selectFeaturesPressEvent(
QgsMapMouseEvent *e )
195 if ( !mSelectionRubberBand )
198 mInitDragPos = e->pos();
201void QgsMapToolSelectionHandler::selectFeaturesMoveEvent(
QgsMapMouseEvent *e )
205 mMoveLastCursorPos = e->pos();
209#ifndef __clang_analyzer__
210 if ( !mOnMouseMoveDelayTimer || !mOnMouseMoveDelayTimer->isActive() )
213 mOnMouseMoveDelayTimer = std::make_unique<QTimer>();
214 mOnMouseMoveDelayTimer->setSingleShot(
true );
215 connect( mOnMouseMoveDelayTimer.get(), &QTimer::timeout,
this, [
this, e] {
216 if ( !mMoveLastCursorPos.isNull() )
218 setSelectedGeometry( QgsGeometry::fromPointXY( toMapCoordinates( mMoveLastCursorPos ) ), e->modifiers() );
221 mOnMouseMoveDelayTimer->start( 300 );
227 if ( e->buttons() != Qt::LeftButton )
231 if ( !mSelectionActive )
233 mSelectionActive =
true;
234 rect = QRect( e->pos(), e->pos() );
238 rect = QRect( e->pos(), mInitDragPos );
241 if ( mSelectionRubberBand )
242 mSelectionRubberBand->setToCanvasRectangle( rect );
245void QgsMapToolSelectionHandler::selectFeaturesReleaseEvent(
QgsMapMouseEvent *e )
247 const QPoint point = e->pos() - mInitDragPos;
248 if ( !mSelectionActive || ( point.manhattanLength() < QApplication::startDragDistance() ) )
250 mSelectionActive =
false;
254 if ( mSelectionRubberBand && mSelectionActive )
256 if ( mSelectionRubberBand )
257 mSelectionRubberBand.reset();
259 mSelectionActive =
false;
262QgsPointXY QgsMapToolSelectionHandler::toMapCoordinates( QPoint point )
264 return mCanvas->getCoordinateTransform()->toMapCoordinates( point );
267void QgsMapToolSelectionHandler::selectPolygonMoveEvent(
QgsMapMouseEvent *e )
269 if ( !mSelectionRubberBand )
272 if ( mSelectionRubberBand->numberOfVertices() > 0 )
274 mSelectionRubberBand->movePoint( toMapCoordinates( e->pos() ) );
278void QgsMapToolSelectionHandler::selectPolygonPressEvent(
QgsMapMouseEvent *e )
281 if ( !mSelectionRubberBand && ( e->button() == Qt::RightButton ) )
285 const QPoint globalPos = mCanvas->mapToGlobal( QPoint( e->pos().x() + 5, e->pos().y() + 5 ) );
286 const QList<QgsMapToolIdentify::IdentifyResult> selectedFeatures = mIdentifyMenu->exec( results, globalPos );
287 if ( !selectedFeatures.empty() && selectedFeatures[0].mFeature.hasGeometry() )
289 QgsCoordinateTransform transform = mCanvas->mapSettings().layerTransform( selectedFeatures.at( 0 ).mLayer );
290 QgsGeometry geom = selectedFeatures[0].mFeature.geometry();
295 catch ( QgsCsException & )
297 QgsDebugError( u
"Could not transform geometry to map CRS"_s );
307 if ( !mSelectionRubberBand )
310 if ( e->button() == Qt::LeftButton )
312 mSelectionRubberBand->addPoint( toMapCoordinates( e->pos() ) );
313 mSelectionActive =
true;
317 if ( mSelectionRubberBand->numberOfVertices() > 2 )
321 mSelectionRubberBand.reset();
322 mSelectionActive =
false;
326void QgsMapToolSelectionHandler::selectFreehandMoveEvent(
QgsMapMouseEvent *e )
328 if ( !mSelectionActive || !mSelectionRubberBand )
331 mSelectionRubberBand->addPoint( toMapCoordinates( e->pos() ) );
334void QgsMapToolSelectionHandler::selectFreehandReleaseEvent(
QgsMapMouseEvent *e )
336 if ( !mSelectionActive )
338 if ( e->button() != Qt::LeftButton )
341 if ( !mSelectionRubberBand )
344 mSelectionRubberBand->addPoint( toMapCoordinates( e->pos() ) );
345 mSelectionActive =
true;
349 if ( e->button() == Qt::LeftButton )
351 if ( mSelectionRubberBand && mSelectionRubberBand->numberOfVertices() > 2 )
357 mSelectionRubberBand.reset();
358 mSelectionActive =
false;
362void QgsMapToolSelectionHandler::selectRadiusMoveEvent(
QgsMapMouseEvent *e )
368 if ( !mSelectionActive )
373 if ( !mSelectionRubberBand )
378 updateRadiusFromEdge( radiusEdge );
381void QgsMapToolSelectionHandler::selectRadiusReleaseEvent(
QgsMapMouseEvent *e )
383 if ( e->button() == Qt::RightButton )
389 if ( e->button() != Qt::LeftButton )
392 if ( !mSelectionActive )
394 mSelectionActive =
true;
396 createDistanceWidget();
400 if ( mSelectionRubberBand )
409void QgsMapToolSelectionHandler::initRubberBand()
412 mSelectionRubberBand->setFillColor( mFillColor );
413 mSelectionRubberBand->setStrokeColor( mStrokeColor );
416void QgsMapToolSelectionHandler::createDistanceWidget()
423 deleteDistanceWidget();
425 mDistanceWidget =
new QgsDistanceWidget( tr(
"Selection radius:" ) );
426 if ( QgsUserInputWidget *userInputWidget = mCanvas->userInputWidget() )
428 userInputWidget->addUserInputWidget( mDistanceWidget );
430 mDistanceWidget->setFocus( Qt::TabFocusReason );
432 connect( mDistanceWidget, &QgsDistanceWidget::distanceChanged,
this, &QgsMapToolSelectionHandler::updateRadiusRubberband );
433 connect( mDistanceWidget, &QgsDistanceWidget::distanceEditingFinished,
this, &QgsMapToolSelectionHandler::radiusValueEntered );
434 connect( mDistanceWidget, &QgsDistanceWidget::distanceEditingCanceled,
this, &QgsMapToolSelectionHandler::cancel );
437void QgsMapToolSelectionHandler::deleteDistanceWidget()
439 if ( mDistanceWidget )
441 mDistanceWidget->releaseKeyboard();
442 mDistanceWidget->deleteLater();
444 mDistanceWidget =
nullptr;
447void QgsMapToolSelectionHandler::radiusValueEntered(
double radius, Qt::KeyboardModifiers modifiers )
449 if ( !mSelectionRubberBand )
452 updateRadiusRubberband( radius );
457void QgsMapToolSelectionHandler::cancel()
459 deleteDistanceWidget();
460 mSnapIndicator->setMatch( QgsPointLocator::Match() );
461 mSelectionRubberBand.reset();
462 mSelectionActive =
false;
465void QgsMapToolSelectionHandler::updateRadiusRubberband(
double radius )
467 if ( !mSelectionRubberBand )
470 const int RADIUS_SEGMENTS = 80;
473 for (
int i = 0; i <= RADIUS_SEGMENTS; ++i )
475 const double theta = i * ( 2.0 * M_PI / RADIUS_SEGMENTS );
476 const QgsPointXY radiusPoint( mRadiusCenter.x() + radius * std::cos( theta ), mRadiusCenter.y() + radius * std::sin( theta ) );
477 mSelectionRubberBand->addPoint( radiusPoint,
false );
479 mSelectionRubberBand->closePoints(
true );
482void QgsMapToolSelectionHandler::updateRadiusFromEdge(
QgsPointXY &radiusEdge )
484 const double radius = std::sqrt( mRadiusCenter.sqrDist( radiusEdge ) );
485 if ( mDistanceWidget )
487 mDistanceWidget->setDistance( radius );
488 mDistanceWidget->setFocus( Qt::TabFocusReason );
492 updateRadiusRubberband( radius );
498 return mSelectionGeometry;
503 mSelectionGeometry = geometry;
504 mMoveLastCursorPos = QPoint();
510 mSelectionMode = mode;
515 return mSelectionMode;
The QgsSpinBox is a spin box with a clear button that will set the value to the defined clear value.
A geometry is the spatial representation of a feature.
Qgis::GeometryOperationResult transform(const QgsCoordinateTransform &ct, Qgis::TransformDirection direction=Qgis::TransformDirection::Forward, bool transformZ=false)
Transforms this geometry as described by the coordinate transform ct.
static QgsGeometry fromPointXY(const QgsPointXY &point)
Creates a new geometry from a QgsPointXY object.
Map canvas is a class for displaying all GIS data types on a canvas.
A mouse event which is the result of a user interaction with a QgsMapCanvas.
QgsPointLocator::Match mapPointMatch() const
Returns the matching data from the most recently snapped point.
QgsPointXY snapPoint()
snapPoint will snap the points using the map canvas snapping utils configuration
Shows a snapping marker on map canvas for the current snapping match.
#define QgsDebugError(str)