From 03c522a9578435851985e391af61e9e028e70d2b Mon Sep 17 00:00:00 2001 From: obrix Date: Mon, 30 Mar 2020 17:32:24 +0200 Subject: [PATCH] Use a tri state button to configure snapping limit : disable, global and per layer. --- .../auto_generated/qgssnappingconfig.sip.in | 46 +++++++++-- src/app/qgssnappinglayertreemodel.cpp | 4 +- src/app/qgssnappingwidget.cpp | 80 ++++++++++++++----- src/app/qgssnappingwidget.h | 9 ++- src/core/qgssnappingconfig.cpp | 21 ++--- src/core/qgssnappingconfig.h | 20 +++-- src/core/qgssnappingutils.cpp | 10 +-- 7 files changed, 136 insertions(+), 54 deletions(-) diff --git a/python/core/auto_generated/qgssnappingconfig.sip.in b/python/core/auto_generated/qgssnappingconfig.sip.in index 9ff2bd0a024..d3333949e3f 100644 --- a/python/core/auto_generated/qgssnappingconfig.sip.in +++ b/python/core/auto_generated/qgssnappingconfig.sip.in @@ -51,6 +51,13 @@ This is a container for configuration of the snapping of the project typedef QFlags SnappingTypeFlag; + enum ScaleDependencyMode + { + Disabled, + ScaleDependentGlobal, + ScaleDependentPerLayer + }; + static const QString snappingTypeFlagToString( SnappingTypeFlag type ); %Docstring Convenient method to returns the translated name of the enum type @@ -154,42 +161,59 @@ define the type of snapping double tolerance() const; %Docstring +! Returns the tolerance + +.. versionadded:: 3.12 %End void setTolerance( double tolerance ); %Docstring Sets the tolerance + +.. versionadded:: 3.12 %End QgsTolerance::UnitType units() const; %Docstring Returns the type of units + +.. versionadded:: 3.12 %End void setUnits( QgsTolerance::UnitType units ); %Docstring Sets the type of units + +.. versionadded:: 3.12 %End double minScale() const; %Docstring Returns min scale on which snapping is limited + +.. versionadded:: 3.14 %End void setMinScale( double p_minScale ); %Docstring Sets the min scale value on which snapping is used, 0.0 disable scale limit + +.. versionadded:: 3.14 %End double maxScale() const; %Docstring -Returns max scale on which snapping is limite +Returns max scale on which snapping is limited + +.. versionadded:: 3.14 %End void setMaxScale( double p_maxScale ); %Docstring Sets the max scale value on which snapping is used, 0.0 disable scale limit + +.. versionadded:: 3.14 %End bool operator!= ( const QgsSnappingConfig::IndividualLayerSettings &other ) const; @@ -273,31 +297,43 @@ Sets the tolerance double minScale() const; %Docstring Returns the min scale + +.. versionadded:: 3.14 %End void setMinScale( double pMinScale ); %Docstring Sets the min scale on which snapping is enabled, 0.0 disable scale limit + +.. versionadded:: 3.14 %End double maxScale() const; %Docstring Returns the max scale + +.. versionadded:: 3.14 %End void setMaxScale( double pMaxScale ); %Docstring Set the max scale on which snapping is enabled, 0.0 disable scale limit + +.. versionadded:: 3.14 %End - bool limitToScale() const; + void setScaleDependencyMode( ScaleDependencyMode mode ); %Docstring -Returns limit to scale +Set the scale dependency mode + +.. versionadded:: 3.14 %End - void setLimitToScale( bool pLimitSnapping ); + ScaleDependencyMode scaleDependencyMode() const; %Docstring -Set limit to scale, true means snapping will be limited to the [minScale, maxScale] range +Returns the scale dependency mode + +.. versionadded:: 3.14 %End QgsTolerance::UnitType units() const; diff --git a/src/app/qgssnappinglayertreemodel.cpp b/src/app/qgssnappinglayertreemodel.cpp index bc3843b5a6f..64747dcb23f 100644 --- a/src/app/qgssnappinglayertreemodel.cpp +++ b/src/app/qgssnappinglayertreemodel.cpp @@ -238,7 +238,7 @@ QgsSnappingLayerTreeModel::QgsSnappingLayerTreeModel( QgsProject *project, QgsMa , mProject( project ) , mCanvas( canvas ) , mIndividualLayerSettings( project->snappingConfig().individualLayerSettings() ) - , mEnableMinMaxColumn( project->snappingConfig().limitToScale() ) + , mEnableMinMaxColumn( project->snappingConfig().scaleDependencyMode() == QgsSnappingConfig::ScaleDependentPerLayer ) { connect( project, &QgsProject::snappingConfigChanged, this, &QgsSnappingLayerTreeModel::onSnappingSettingsChanged ); @@ -369,7 +369,7 @@ void QgsSnappingLayerTreeModel::onSnappingSettingsChanged() } } - mEnableMinMaxColumn = mProject->snappingConfig().limitToScale(); + mEnableMinMaxColumn = ( mProject->snappingConfig().scaleDependencyMode() == QgsSnappingConfig::ScaleDependentPerLayer ); hasRowchanged( mLayerTreeModel->rootGroup(), oldSettings, wasMinMaxEnabled != mEnableMinMaxColumn ); } diff --git a/src/app/qgssnappingwidget.cpp b/src/app/qgssnappingwidget.cpp index d5c4fdd4dae..c9b9f50e700 100644 --- a/src/app/qgssnappingwidget.cpp +++ b/src/app/qgssnappingwidget.cpp @@ -186,11 +186,23 @@ QgsSnappingWidget::QgsSnappingWidget( QgsProject *project, QgsMapCanvas *canvas, connect( mMaxScaleWidget, &QgsScaleWidget::scaleChanged, this, &QgsSnappingWidget::changeMaxScale ); - mLimitToScale = new QAction( tr( "Toggle scale dependent snapping" ), this ); - mLimitToScale->setCheckable( true ); - mLimitToScale->setIcon( QIcon( QgsApplication::getThemeIcon( "/mIconSnappingOnScale.svg" ) ) ); - mLimitToScale->setObjectName( QStringLiteral( "EnableSnappingLimitOnScaleAction" ) ); - connect( mLimitToScale, &QAction::toggled, this, &QgsSnappingWidget::changeLimitToScale ); + mSnappingScaleModeButton = new QToolButton(); + mSnappingScaleModeButton->setToolTip( tr( "Snapping scale mode" ) ); + mSnappingScaleModeButton->setPopupMode( QToolButton::InstantPopup ); + QMenu *scaleModeMenu = new QMenu( tr( "Set snapping scale mode" ), this ); + mDefaultSnappingScaleAct = new QAction( QIcon( QgsApplication::getThemeIcon( "/mIconSnappingOnScale.svg" ) ), tr( "Disabled" ), scaleModeMenu ); + mDefaultSnappingScaleAct->setToolTip( tr( "Scale dependency disabled" ) ); + mGlobalSnappingScaleAct = new QAction( QIcon( QgsApplication::getThemeIcon( "/mIconSnappingOnScale.svg" ) ), tr( "Global" ), scaleModeMenu ); + mGlobalSnappingScaleAct->setToolTip( tr( "Scale dependency global" ) ); + mPerLayerSnappingScaleAct = new QAction( QIcon( QgsApplication::getThemeIcon( "/mIconSnappingOnScale.svg" ) ), tr( "Per layer" ), scaleModeMenu ); + mPerLayerSnappingScaleAct->setToolTip( tr( "Scale dependency per layer" ) ); + scaleModeMenu->addAction( mDefaultSnappingScaleAct ); + scaleModeMenu->addAction( mGlobalSnappingScaleAct ); + scaleModeMenu->addAction( mPerLayerSnappingScaleAct ); + mSnappingScaleModeButton->setMenu( scaleModeMenu ); + mSnappingScaleModeButton->setObjectName( QStringLiteral( "SnappingScaleModeButton" ) ); + mSnappingScaleModeButton->setToolButtonStyle( Qt::ToolButtonTextBesideIcon ); + connect( mSnappingScaleModeButton, &QToolButton::triggered, this, &QgsSnappingWidget::snappingScaleModeTriggered ); // units mUnitsComboBox = new QComboBox(); @@ -299,10 +311,8 @@ QgsSnappingWidget::QgsSnappingWidget( QgsProject *project, QgsMapCanvas *canvas, layout->addWidget( mTypeButton ); layout->addWidget( mToleranceSpinBox ); layout->addWidget( mUnitsComboBox ); - QToolButton *limitToScaleButton = new QToolButton(); - limitToScaleButton->addAction( mLimitToScale ); - limitToScaleButton->setDefaultAction( mLimitToScale ); - layout->addWidget( limitToScaleButton ); + mSnappingScaleModeButton->setDefaultAction( mDefaultSnappingScaleAct ); + layout->addWidget( mSnappingScaleModeButton ); layout->addWidget( mMinScaleWidget ); layout->addWidget( mMaxScaleWidget ); @@ -437,7 +447,18 @@ void QgsSnappingWidget::projectSnapSettingsChanged() mMaxScaleWidget->setScale( config.maxScale() ); } - mLimitToScale->setChecked( config.limitToScale() ); + if ( config.scaleDependencyMode() == QgsSnappingConfig::Disabled ) + { + mSnappingScaleModeButton->setDefaultAction( mDefaultSnappingScaleAct ); + } + else if ( config.scaleDependencyMode() == QgsSnappingConfig::ScaleDependentGlobal ) + { + mSnappingScaleModeButton->setDefaultAction( mGlobalSnappingScaleAct ); + } + else if ( config.scaleDependencyMode() == QgsSnappingConfig::ScaleDependentPerLayer ) + { + mSnappingScaleModeButton->setDefaultAction( mPerLayerSnappingScaleAct ); + } if ( config.intersectionSnapping() != mIntersectionSnappingAction->isChecked() ) { @@ -468,9 +489,9 @@ void QgsSnappingWidget::toggleSnappingWidgets( bool enabled ) mModeButton->setEnabled( enabled ); mTypeButton->setEnabled( enabled ); mToleranceSpinBox->setEnabled( enabled ); - mLimitToScale->setEnabled( enabled ); - mMinScaleWidget->setEnabled( enabled && mConfig.limitToScale() ); - mMaxScaleWidget->setEnabled( enabled && mConfig.limitToScale() ); + mSnappingScaleModeButton->setEnabled( enabled ); + mMinScaleWidget->setEnabled( enabled && mConfig.scaleDependencyMode() == QgsSnappingConfig::ScaleDependentGlobal ); + mMaxScaleWidget->setEnabled( enabled && mConfig.scaleDependencyMode() == QgsSnappingConfig::ScaleDependentGlobal ); mUnitsComboBox->setEnabled( enabled ); if ( mEditAdvancedConfigAction ) @@ -504,14 +525,6 @@ void QgsSnappingWidget::changeMaxScale( double pMaxScale ) mProject->setSnappingConfig( mConfig ); } -void QgsSnappingWidget::changeLimitToScale( bool enabled ) -{ - mConfig.setLimitToScale( enabled ); - mMinScaleWidget->setEnabled( mConfig.limitToScale() ); - mMaxScaleWidget->setEnabled( mConfig.limitToScale() ); - mProject->setSnappingConfig( mConfig ); -} - void QgsSnappingWidget::changeUnit( int idx ) { QgsTolerance::UnitType unit = static_cast( mUnitsComboBox->itemData( idx ).toInt() ); @@ -597,6 +610,29 @@ void QgsSnappingWidget::typeButtonTriggered( QAction *action ) mProject->setSnappingConfig( mConfig ); } +void QgsSnappingWidget::snappingScaleModeTriggered( QAction *action ) +{ + mSnappingScaleModeButton->setDefaultAction( action ); + QgsSnappingConfig::ScaleDependencyMode mode; + if ( action == mDefaultSnappingScaleAct ) + { + mode = QgsSnappingConfig::Disabled; + } + else if ( action == mGlobalSnappingScaleAct ) + { + mode = QgsSnappingConfig::ScaleDependentGlobal; + } + else if ( action == mPerLayerSnappingScaleAct ) + { + mode = QgsSnappingConfig::ScaleDependentPerLayer; + } + + mMinScaleWidget->setEnabled( mode == QgsSnappingConfig::ScaleDependentGlobal ); + mMaxScaleWidget->setEnabled( mode == QgsSnappingConfig::ScaleDependentGlobal ); + mConfig.setScaleDependencyMode( mode ); + mProject->setSnappingConfig( mConfig ); +} + void QgsSnappingWidget::updateToleranceDecimals() { if ( mConfig.units() == QgsTolerance::Pixels ) @@ -638,9 +674,9 @@ void QgsSnappingWidget::modeChanged() { mAdvancedConfigWidget->setVisible( advanced ); } + mSnappingScaleModeButton->setVisible( advanced ); mMinScaleWidget->setVisible( advanced ); mMaxScaleWidget->setVisible( advanced ); - mLimitToScale->setVisible( advanced ); } } diff --git a/src/app/qgssnappingwidget.h b/src/app/qgssnappingwidget.h index 4fec63c0295..5013e12ca69 100644 --- a/src/app/qgssnappingwidget.h +++ b/src/app/qgssnappingwidget.h @@ -106,8 +106,6 @@ class APP_EXPORT QgsSnappingWidget : public QWidget void changeMaxScale( double pMaxScale ); - void changeLimitToScale( bool enabled ); - void changeUnit( int idx ); void enableTopologicalEditing( bool enabled ); @@ -116,6 +114,7 @@ class APP_EXPORT QgsSnappingWidget : public QWidget void modeButtonTriggered( QAction *action ); void typeButtonTriggered( QAction *action ); + void snappingScaleModeTriggered( QAction *action ); //! number of decimals of the tolerance spin box depends on map units void updateToleranceDecimals(); @@ -152,11 +151,13 @@ class APP_EXPORT QgsSnappingWidget : public QWidget QAction *mCentroidAction = nullptr; QAction *mMiddleAction = nullptr; QDoubleSpinBox *mToleranceSpinBox = nullptr; - QAction *mLimitToScale = nullptr; QgsScaleWidget *mMinScaleWidget = nullptr; QgsScaleWidget *mMaxScaleWidget = nullptr; QAction *mToleranceAction = nullptr; // hide widget does not work on toolbar, action needed - QAction *mLimitToScaleAction = nullptr; + QToolButton *mSnappingScaleModeButton = nullptr; + QAction *mDefaultSnappingScaleAct = nullptr; + QAction *mGlobalSnappingScaleAct = nullptr; + QAction *mPerLayerSnappingScaleAct = nullptr; QComboBox *mUnitsComboBox = nullptr; QAction *mUnitAction = nullptr; // hide widget does not work on toolbar, action needed QAction *mTopologicalEditingAction = nullptr; diff --git a/src/core/qgssnappingconfig.cpp b/src/core/qgssnappingconfig.cpp index 5e34edb3e3a..92958ad5bcb 100644 --- a/src/core/qgssnappingconfig.cpp +++ b/src/core/qgssnappingconfig.cpp @@ -180,7 +180,7 @@ bool QgsSnappingConfig::operator==( const QgsSnappingConfig &other ) const && mUnits == other.mUnits && mIntersectionSnapping == other.mIntersectionSnapping && mIndividualLayerSettings == other.mIndividualLayerSettings - && mLimitToScale == other.mLimitToScale + && mScaleDependencyMode == other.mScaleDependencyMode && mMinScale == other.mMinScale && mMaxScale == other.mMaxScale; } @@ -205,7 +205,7 @@ void QgsSnappingConfig::reset() mMode = mode; mType = type; mTolerance = tolerance; - mLimitToScale = false; + mScaleDependencyMode = Disabled; mMinScale = 0.0; mMaxScale = 0.0; // do not allow unit to be "layer" if not in advanced configuration @@ -378,7 +378,7 @@ bool QgsSnappingConfig::operator!=( const QgsSnappingConfig &other ) const || mTolerance != other.mTolerance || mUnits != other.mUnits || mIndividualLayerSettings != other.mIndividualLayerSettings - || mLimitToScale != other.mLimitToScale + || mScaleDependencyMode != other.mScaleDependencyMode || mMinScale != other.mMinScale || mMaxScale != other.mMaxScale; } @@ -444,8 +444,8 @@ void QgsSnappingConfig::readProject( const QDomDocument &doc ) if ( snapSettingsElem.hasAttribute( QStringLiteral( "tolerance" ) ) ) mTolerance = snapSettingsElem.attribute( QStringLiteral( "tolerance" ) ).toDouble(); - if ( snapSettingsElem.hasAttribute( QStringLiteral( "limitToScale" ) ) ) - mLimitToScale = snapSettingsElem.attribute( QStringLiteral( "limitToScale" ) ) == QLatin1String( "1" ); + if ( snapSettingsElem.hasAttribute( QStringLiteral( "scaleDependencyMode" ) ) ) + mScaleDependencyMode = static_cast( snapSettingsElem.attribute( QStringLiteral( "scaleDependencyMode" ) ).toInt() ); if ( snapSettingsElem.hasAttribute( QStringLiteral( "minScale" ) ) ) mMinScale = snapSettingsElem.attribute( QStringLiteral( "minScale" ) ).toDouble(); @@ -504,7 +504,7 @@ void QgsSnappingConfig::writeProject( QDomDocument &doc ) snapSettingsElem.setAttribute( QStringLiteral( "tolerance" ), mTolerance ); snapSettingsElem.setAttribute( QStringLiteral( "unit" ), static_cast( mUnits ) ); snapSettingsElem.setAttribute( QStringLiteral( "intersection-snapping" ), QString::number( mIntersectionSnapping ) ); - snapSettingsElem.setAttribute( QStringLiteral( "limitToScale" ), QString::number( mLimitToScale ) ); + snapSettingsElem.setAttribute( QStringLiteral( "scaleDependencyMode" ), QString::number( mScaleDependencyMode ) ); snapSettingsElem.setAttribute( QStringLiteral( "minScale" ), mMinScale ); snapSettingsElem.setAttribute( QStringLiteral( "maxScale" ), mMaxScale ); @@ -668,16 +668,17 @@ void QgsSnappingConfig::setMaxScale( double pMaxScale ) mMaxScale = pMaxScale; } -bool QgsSnappingConfig::limitToScale() const +void QgsSnappingConfig::setScaleDependencyMode( QgsSnappingConfig::ScaleDependencyMode mode ) { - return mLimitToScale; + mScaleDependencyMode = mode; } -void QgsSnappingConfig::setLimitToScale( bool pLimitSnapping ) +QgsSnappingConfig::ScaleDependencyMode QgsSnappingConfig::scaleDependencyMode() const { - mLimitToScale = pLimitSnapping; + return mScaleDependencyMode; } + diff --git a/src/core/qgssnappingconfig.h b/src/core/qgssnappingconfig.h index a1bb8612c5f..0321be359d7 100644 --- a/src/core/qgssnappingconfig.h +++ b/src/core/qgssnappingconfig.h @@ -80,6 +80,13 @@ class CORE_EXPORT QgsSnappingConfig Q_DECLARE_FLAGS( SnappingTypeFlag, SnappingTypes ) Q_FLAG( SnappingTypeFlag ) + enum ScaleDependencyMode + { + Disabled = 0, + ScaleDependentGlobal, + ScaleDependentPerLayer + }; + /** * Convenient method to returns the translated name of the enum type * QgsSnappingConfig::SnappingTypeFlag @@ -172,7 +179,8 @@ class CORE_EXPORT QgsSnappingConfig */ void setTypeFlag( QgsSnappingConfig::SnappingTypeFlag type ); - /**! + /** + * ! * Returns the tolerance * \since QGIS 3.12 */ @@ -314,16 +322,16 @@ class CORE_EXPORT QgsSnappingConfig void setMaxScale( double pMaxScale ); /** - * Returns limit to scale + * Set the scale dependency mode * \since QGIS 3.14 */ - bool limitToScale() const; + void setScaleDependencyMode( ScaleDependencyMode mode ); /** - * Set limit to scale, true means snapping will be limited to the [minScale, maxScale] range + * Returns the scale dependency mode * \since QGIS 3.14 */ - void setLimitToScale( bool pLimitSnapping ); + ScaleDependencyMode scaleDependencyMode() const; //! Returns the type of units QgsTolerance::UnitType units() const; @@ -455,7 +463,7 @@ class CORE_EXPORT QgsSnappingConfig SnappingMode mMode = ActiveLayer; SnappingTypeFlag mType = VertexFlag; double mTolerance = 0.0; - bool mLimitToScale = false; + ScaleDependencyMode mScaleDependencyMode = Disabled; double mMinScale = 0.0; double mMaxScale = 0.0; QgsTolerance::UnitType mUnits = QgsTolerance::ProjectUnits; diff --git a/src/core/qgssnappingutils.cpp b/src/core/qgssnappingutils.cpp index d283434f253..bb03e594b20 100644 --- a/src/core/qgssnappingutils.cpp +++ b/src/core/qgssnappingutils.cpp @@ -297,17 +297,17 @@ QgsPointLocator::Match QgsSnappingUtils::snapToMap( const QgsPointXY &pointMap, bool inRangeGlobal = ( mSnappingConfig.minScale() <= 0.0 || mMapSettings.scale() >= mSnappingConfig.minScale() ) && ( mSnappingConfig.maxScale() <= 0.0 || mMapSettings.scale() <= mSnappingConfig.maxScale() ); - for ( const LayerConfig &layerConfig : qgis::as_const( mLayers )) + for ( const LayerConfig &layerConfig : qgis::as_const( mLayers ) ) { QgsSnappingConfig::IndividualLayerSettings layerSettings = mSnappingConfig.individualLayerSettings( layerConfig.layer ); - //Default value for layer config means it is not set ( appears NULL ) layerSpecificRange <- false - bool layerSpecificRange = layerSettings.minScale() > 0.0 || layerSettings.maxScale() > 0.0; - bool inRangeLayer = ( layerSettings.minScale() < 0.0 || mMapSettings.scale() >= layerSettings.minScale() ) && ( layerSettings.maxScale() < 0.0 || mMapSettings.scale() <= layerSettings.maxScale() ); + bool inRangeLayer = ( layerSettings.minScale() <= 0.0 || mMapSettings.scale() >= layerSettings.minScale() ) && ( layerSettings.maxScale() <= 0.0 || mMapSettings.scale() <= layerSettings.maxScale() ); //If limit to scale is disabled, snapping activated on all layer //If no per layer config is set use the global one, otherwise use the layer config - if ( !mSnappingConfig.limitToScale() || ( ( !layerSpecificRange && inRangeGlobal ) || ( layerSpecificRange && inRangeLayer ) ) ) + if ( mSnappingConfig.scaleDependencyMode() == QgsSnappingConfig::Disabled + || ( mSnappingConfig.scaleDependencyMode() == QgsSnappingConfig::ScaleDependentGlobal && inRangeGlobal ) + || ( mSnappingConfig.scaleDependencyMode() == QgsSnappingConfig::ScaleDependentPerLayer && inRangeLayer ) ) { double tolerance = QgsTolerance::toleranceInProjectUnits( layerConfig.tolerance, layerConfig.layer, mMapSettings, layerConfig.unit ); layers << qMakePair( layerConfig.layer, _areaOfInterest( pointMap, tolerance ) );