@@ -13,22 +13,91 @@ email : jpalmer at linz dot govt dot nz
* *
***************************************************************************/
#include < cmath>
#include < QMouseEvent>
#include < QHBoxLayout>
#include < QKeyEvent>
#include < QLabel>
#include " qgisapp.h"
#include " qgsmaptoolselectradius.h"
#include " qgsmaptoolselectutils.h"
#include " qgsgeometry.h"
#include " qgsrubberband.h"
#include " qgsmapcanvas.h"
#include " qgis.h"
#include " qgslogger.h"
#include " qgsdoublespinbox.h"
#include < cmath>
#include < QMouseEvent>
const int RADIUS_SEGMENTS = 40 ;
QgsDistanceWidget::QgsDistanceWidget ( const QString &label, QWidget *parent )
: QWidget( parent )
{
mLayout = new QHBoxLayout ( this );
mLayout ->setContentsMargins ( 0 , 0 , 0 , 0 );
// mLayout->setAlignment( Qt::AlignLeft );
setLayout ( mLayout );
if ( !label.isEmpty () )
{
QLabel *lbl = new QLabel ( label, this );
lbl->setAlignment ( Qt::AlignRight | Qt::AlignCenter );
mLayout ->addWidget ( lbl );
}
mDistanceSpinBox = new QgsDoubleSpinBox ( this );
mDistanceSpinBox ->setSingleStep ( 1 );
mDistanceSpinBox ->setValue ( 0 );
mDistanceSpinBox ->setMinimum ( 0 );
mDistanceSpinBox ->setMaximum ( 1000000000 );
mDistanceSpinBox ->setShowClearButton ( false );
mDistanceSpinBox ->setSizePolicy ( QSizePolicy::MinimumExpanding, QSizePolicy::Preferred );
mLayout ->addWidget ( mDistanceSpinBox );
// connect signals
mDistanceSpinBox ->installEventFilter ( this );
connect ( mDistanceSpinBox , static_cast < void ( QgsDoubleSpinBox::* )( double ) > ( &QgsDoubleSpinBox::valueChanged ), this , &QgsDistanceWidget::distanceSpinBoxValueChanged );
// config focus
setFocusProxy ( mDistanceSpinBox );
}
void QgsDistanceWidget::setDistance ( double distance )
{
mDistanceSpinBox ->setValue ( distance );
}
double QgsDistanceWidget::distance ()
{
return mDistanceSpinBox ->value ();
}
bool QgsDistanceWidget::eventFilter ( QObject *obj, QEvent *ev )
{
if ( obj == mDistanceSpinBox && ev->type () == QEvent::KeyPress )
{
QKeyEvent *event = static_cast <QKeyEvent *>( ev );
if ( event->key () == Qt::Key_Enter || event->key () == Qt::Key_Return )
{
emit distanceEditingFinished ( distance (), event->modifiers () );
return true ;
}
}
return false ;
}
void QgsDistanceWidget::distanceSpinBoxValueChanged ( double distance )
{
emit distanceChanged ( distance );
}
QgsMapToolSelectRadius::QgsMapToolSelectRadius ( QgsMapCanvas *canvas )
: QgsMapTool( canvas )
, mDragging( false )
{
mRubberBand = nullptr ;
mCursor = Qt::ArrowCursor;
@@ -38,74 +107,145 @@ QgsMapToolSelectRadius::QgsMapToolSelectRadius( QgsMapCanvas *canvas )
QgsMapToolSelectRadius::~QgsMapToolSelectRadius ()
{
delete mRubberBand ;
}
void QgsMapToolSelectRadius::canvasPressEvent ( QgsMapMouseEvent *e )
{
if ( e->button () != Qt::LeftButton )
return ;
mRadiusCenter = toMapCoordinates ( e->pos () );
deleteRotationWidget ();
deleteRubberband ();
}
void QgsMapToolSelectRadius::canvasMoveEvent ( QgsMapMouseEvent *e )
{
if ( e-> buttons () != Qt::LeftButton )
if ( ! mActive )
return ;
if ( !mDragging )
if ( !mRubberBand )
{
if ( !mRubberBand )
{
mRubberBand = new QgsRubberBand ( mCanvas , QgsWkbTypes::PolygonGeometry );
mRubberBand ->setFillColor ( mFillColor );
mRubberBand ->setStrokeColor ( mStrokeColor );
}
mDragging = true ;
mRubberBand = new QgsRubberBand ( mCanvas , QgsWkbTypes::PolygonGeometry );
mRubberBand ->setFillColor ( mFillColor );
mRubberBand ->setStrokeColor ( mStrokeColor );
}
QgsPointXY radiusEdge = toMapCoordinates ( e->pos () );
setRadiusRubberBand ( radiusEdge );
updateRadiusFromEdge ( radiusEdge );
}
void QgsMapToolSelectRadius::canvasReleaseEvent ( QgsMapMouseEvent *e )
{
if ( e->button () == Qt::RightButton )
{
deleteRotationWidget ();
deleteRubberband ();
mActive = false ;
return ;
}
if ( e->button () != Qt::LeftButton )
return ;
if ( !mDragging )
if ( !mActive )
{
mActive = true ;
mRadiusCenter = toMapCoordinates ( e->pos () );
createRotationWidget ();
}
else
{
if ( !mRubberBand )
{
mRubberBand = new QgsRubberBand ( mCanvas , QgsWkbTypes::PolygonGeometry );
mRubberBand ->setFillColor ( mFillColor );
mRubberBand ->setStrokeColor ( mStrokeColor );
}
mRadiusCenter = toMapCoordinates ( e->pos () );
QgsPointXY radiusEdge = toMapCoordinates ( QPoint ( e->pos ().x () + 1 , e->pos ().y () + 1 ) );
setRadiusRubberBand ( radiusEdge );
updateRadiusFromEdge ( radiusEdge );
selectFromRubberband ( e->modifiers () );
}
QgsGeometry radiusGeometry = mRubberBand ->asGeometry ();
QgsMapToolSelectUtils::selectMultipleFeatures ( mCanvas , radiusGeometry, e );
mRubberBand ->reset ( QgsWkbTypes::PolygonGeometry );
delete mRubberBand ;
mRubberBand = nullptr ;
mDragging = false ;
}
void QgsMapToolSelectRadius::setRadiusRubberBand ( QgsPointXY &radiusEdge )
void QgsMapToolSelectRadius::updateRadiusFromEdge ( QgsPointXY &radiusEdge )
{
double radius = std::sqrt ( mRadiusCenter .sqrDist ( radiusEdge ) );
if ( mDistanceWidget )
{
mDistanceWidget ->setDistance ( radius );
mDistanceWidget ->setFocus ( Qt::TabFocusReason );
mDistanceWidget ->editor ()->selectAll ();
}
else
{
updateRubberband ( radius );
}
}
void QgsMapToolSelectRadius::deactivate ()
{
deleteRotationWidget ();
deleteRubberband ();
mActive = false ;
QgsMapTool::deactivate ();
}
void QgsMapToolSelectRadius::updateRubberband ( const double &radius )
{
double r = std::sqrt ( mRadiusCenter .sqrDist ( radiusEdge ) );
mRubberBand ->reset ( QgsWkbTypes::PolygonGeometry );
for ( int i = 0 ; i <= RADIUS_SEGMENTS; ++i )
{
double theta = i * ( 2.0 * M_PI / RADIUS_SEGMENTS );
QgsPointXY radiusPoint ( mRadiusCenter .x () + r * std::cos ( theta ),
mRadiusCenter .y () + r * std::sin ( theta ) );
QgsPointXY radiusPoint ( mRadiusCenter .x () + radius * std::cos ( theta ),
mRadiusCenter .y () + radius * std::sin ( theta ) );
mRubberBand ->addPoint ( radiusPoint, false );
}
mRubberBand ->closePoints ( true );
}
void QgsMapToolSelectRadius::selectFromRubberband ( const Qt::KeyboardModifiers &modifiers )
{
QgsGeometry radiusGeometry = mRubberBand ->asGeometry ();
QgsMapToolSelectUtils::selectMultipleFeatures ( mCanvas , radiusGeometry, modifiers );
mRubberBand ->reset ( QgsWkbTypes::PolygonGeometry );
deleteRotationWidget ();
deleteRubberband ();
mActive = false ;
}
void QgsMapToolSelectRadius::radiusValueEntered ( const double &radius, const Qt::KeyboardModifiers &modifiers )
{
updateRubberband ( radius );
selectFromRubberband ( modifiers );
}
void QgsMapToolSelectRadius::deleteRubberband ()
{
delete mRubberBand ;
mRubberBand = nullptr ;
}
void QgsMapToolSelectRadius::createRotationWidget ()
{
if ( !mCanvas )
{
return ;
}
deleteRotationWidget ();
mDistanceWidget = new QgsDistanceWidget ( QStringLiteral ( " Selection radius:" ) );
QgisApp::instance ()->addUserInputWidget ( mDistanceWidget );
mDistanceWidget ->setFocus ( Qt::TabFocusReason );
connect ( mDistanceWidget , &QgsDistanceWidget::distanceChanged, this , &QgsMapToolSelectRadius::updateRubberband );
connect ( mDistanceWidget , &QgsDistanceWidget::distanceEditingFinished, this , &QgsMapToolSelectRadius::radiusValueEntered );
}
void QgsMapToolSelectRadius::deleteRotationWidget ()
{
if ( mDistanceWidget )
{
disconnect ( mDistanceWidget , &QgsDistanceWidget::distanceChanged, this , &QgsMapToolSelectRadius::updateRubberband );
disconnect ( mDistanceWidget , &QgsDistanceWidget::distanceEditingFinished, this , &QgsMapToolSelectRadius::radiusValueEntered );
mDistanceWidget ->releaseKeyboard ();
mDistanceWidget ->deleteLater ();
}
mDistanceWidget = nullptr ;
}