Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Snapping enabled on a configurable scale range #35110

Merged
merged 25 commits into from Apr 7, 2020

Conversation

obrix
Copy link

@obrix obrix commented Mar 16, 2020

Description

This pull request follows the qgis enhancement proposal 167 described in details here : Snapping enabled on a configurable scale range

The goal is to provide a way to optimizing the snapping feature by allowing the user to enable it only on specified scale range. A global setting and a per layer setting are available.

For more details please refer to the qgis enhancement proposal description and discussion.

@github-actions github-actions bot added this to the 3.14.0 milestone Mar 16, 2020
@obrix obrix requested review from troopa81 and 3nids March 24, 2020 14:37
Copy link
Contributor

@troopa81 troopa81 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not clear to me how the scale limit apply:

  • If global limit to scale is disabled, no scale range (global nor per layer) are applied
  • Else we use global range only if per layer one hasn't been defined

As a user, I would have expected

  • If global limit to scale is disable, per layer scale range are applied
  • Else we check global scale range AND per layer scale range before snapping on this layer

But maybe, I'm a weird user :)

{
if ( ls.minScale() <= 0.0 )
{
return QString( "not set" );
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it should be translated

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes

{
if ( ls.maxScale() <= 0.0 )
{
return QString( "not set" );
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

translation

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes

* \deprecated since QGIS 3.12 use the method with SnappingTypeFlag instead.
*/
Q_DECL_DEPRECATED IndividualLayerSettings( bool enabled, SnappingType type, double tolerance, QgsTolerance::UnitType units ) SIP_DEPRECATED;
Q_DECL_DEPRECATED IndividualLayerSettings( bool enabled, SnappingType type, double tolerance, QgsTolerance::UnitType units, double minScale, double maxScale ) SIP_DEPRECATED;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wondering if it's usefull/needed to update this method signature while it has been deprecated.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably not.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

QList<LayerAndAreaOfInterest> layers;
for ( const LayerConfig &layerConfig : qgis::as_const( mLayers ) )
QList<LayerConfigIterator> filteredConfigs;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you store a list of iterator instead of LayerConfig? to avoid LayerConfig copy?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes

@obrix
Copy link
Author

obrix commented Mar 24, 2020

@troopa81 Yes you got it the global boolean disable the feature globally (including the per layer configuration). The layer specific setting applies if specified, otherwise the global setting applies.

I think it is useful to have a simple way to completely disable the feature. Your expectation give no way to disable the optimization except resetting manually all settings which might be a pain I think.

@troopa81
Copy link
Contributor

I think it is useful to have a simple way to completely disable the feature.

I understand your point, so OK for a button which disable all limit scale range. Maybe it would be good to disable (grayed) per layer min/max configuration when the button is disable, as it is done for the global min/max. This way, the user understand it applies to both global and per layer configuration.

Copy link
Member

@3nids 3nids left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • could you provide a small screencast of the config widget + toolbar
  • would it make sense to add some tests to this?
  • small thing but rather than talking about "Limit on scale snapping" I would rather use "Scale dependent snapping". (to be approved by better english speakers)

@@ -173,6 +175,23 @@ QgsSnappingWidget::QgsSnappingWidget( QgsProject *project, QgsMapCanvas *canvas,
mToleranceSpinBox->setObjectName( QStringLiteral( "SnappingToleranceSpinBox" ) );
connect( mToleranceSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsSnappingWidget::changeTolerance );

mMinScaleWidget = new QgsScaleWidget();
mMinScaleWidget->setToolTip( tr( "Min scale on which snapping is enabled" ) );
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
mMinScaleWidget->setToolTip( tr( "Min scale on which snapping is enabled" ) );
mMinScaleWidget->setToolTip( tr( "Minimum scale from which snapping is enabled" ) );

maybe some native speaker can come up with something better

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if no ones comes up with something better, I would recommend to accept this one

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I went with it.

connect( mMinScaleWidget, &QgsScaleWidget::scaleChanged, this, &QgsSnappingWidget::changeMinScale );

mMaxScaleWidget = new QgsScaleWidget();
mMaxScaleWidget->setToolTip( tr( "Max scale on which snapping is enabled" ) );
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
mMaxScaleWidget->setToolTip( tr( "Max scale on which snapping is enabled" ) );
mMaxScaleWidget->setToolTip( tr( "Maximum scale up to which snapping is enabled" ) );

...not so sure

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

src/app/qgssnappingwidget.cpp Outdated Show resolved Hide resolved
src/app/qgssnappingwidget.cpp Outdated Show resolved Hide resolved
* \deprecated since QGIS 3.12 use the method with SnappingTypeFlag instead.
*/
Q_DECL_DEPRECATED IndividualLayerSettings( bool enabled, SnappingType type, double tolerance, QgsTolerance::UnitType units ) SIP_DEPRECATED;
Q_DECL_DEPRECATED IndividualLayerSettings( bool enabled, SnappingType type, double tolerance, QgsTolerance::UnitType units, double minScale, double maxScale ) SIP_DEPRECATED;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

src/core/qgssnappingconfig.h Outdated Show resolved Hide resolved
src/core/qgssnappingutils.cpp Outdated Show resolved Hide resolved
src/core/qgssnappingutils.cpp Outdated Show resolved Hide resolved
tests/src/core/testqgssnappingutils.cpp Outdated Show resolved Hide resolved
@3nids
Copy link
Member

3nids commented Mar 25, 2020

Yes you got it the global boolean disable the feature globally (including the per layer configuration). The layer specific setting applies if specified, otherwise the global setting applies.

good idea!

@troopa81
Copy link
Contributor

@obrix As soon as you define a per layer min, both per layer min/max applies even if you define a global max and your per layer max is not set. I find it a little bit confusing. Wouldn't be better to separate min et max ? Or at least, make the current behavior more explicit (tooltip?)

@obrix
Copy link
Author

obrix commented Mar 25, 2020

@troopa81

I understand your point, so OK for a button which disable all limit scale range. Maybe it would be good to disable (grayed) per layer min/max configuration when the button is disable, as it is done for the global min/max. This way, the user understand it applies to both global and per layer configuration.

Yes good idea to also explicitly grey out the per layer configuration when the feature is disabled.

As soon as you define a per layer min, both per layer min/max applies even if you define a global max and your per layer max is not set. I find it a little bit confusing. Wouldn't be better to separate min et max ? Or at least, make the current behavior more explicit (tooltip?)

Yes this is a deliberate choice, from my point of view mixing some configuration from the global settings and some configuration from the per layer settings was confusing. I wanted to avoid that but I am not really satisfied by the way it is presented to the user though. If this is confusing for you I should probably separate min/max and use global setting when one is not set.

@3nids

would it make sense to add some tests to this?
small thing but rather than talking about "Limit on scale snapping" I would rather use "Scale dependent snapping". (to be approved by better english speakers)

Not sure about a test. I can take a look. I Agree with "Scale dependent snapping".

Coming back to you with some new commits soon.

@troopa81
Copy link
Contributor

troopa81 commented Mar 25, 2020 via email

@obrix
Copy link
Author

obrix commented Mar 26, 2020

@troopa81 If I handle separately min and max range for layer specific settings (ie if not set -> use global configuration), it makes it impossible for the user to specify a global setting and disable completely snapping optimization on a specific layer. This is also the case for the current implementation (ie if I unset both min and max, it will be replaced by global settings).

A solution I can think of is to re add a check box to specifically enable/disable the custom setting on a specific layer. I think it makes more sense and is more explicit for the user.

So we would have

  • Global checkbox button to enable/disable the feature globally, with global min max range applied to all layer
  • A checkbox per layer to enable/disable a specific layer setting with min and max (with tooltip "Use layer specific snapping range")

I think this way the user will not have to guess which min max is used, it is explicit.

@troopa81
Copy link
Contributor

@obrix I'm concerned that it will make it even more complicated. I'd prefer to keep it simple

  • a default (global) config min/max
  • a per layer config min/max
  • a button to disable scale dependent snapping

if both global and per layer min (resp. max) are defined (different from "not set"), we check only the per layer one.

@troopa81
Copy link
Contributor

So we would have

Global checkbox button to enable/disable the feature globally, with global min max range applied to all layer
A checkbox per layer to enable/disable a specific layer setting with min and max (with tooltip "Use layer specific snapping range")

I think this way the user will not have to guess which min max is used, it is explicit.

After a second thoughts, it may be in fact better to do it this way so it removes any ambiguity. @3nids do you agree?

@3nids
Copy link
Member

3nids commented Mar 26, 2020

A maybe simpler alternative would be a tri-state for the main one:

  • inactive
  • active - global
  • active - advanced / per layer

So, if we are in active global we can hide the columns in the table.

I think this feature is very very specific and even more when going per layer. So we should try not to complexify too much the UI.
I think the approach proposed above has both the advantage of the lightest possible UX and the clarity (at a small cost of not being able to fine tune the global setting per layer, but it sounds acceptable to me)

@obrix
Copy link
Author

obrix commented Mar 26, 2020

The tri-state approach is okay for me as it also remove any ambiguity.

@3nids
Copy link
Member

3nids commented Apr 6, 2020

ready to re-review / merge?

* \since QGIS 3.12
*/
IndividualLayerSettings( bool enabled, SnappingTypeFlag type, double tolerance, QgsTolerance::UnitType units );
IndividualLayerSettings( bool enabled, SnappingTypeFlag type, double tolerance, QgsTolerance::UnitType units, double minScale, double maxScale );
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is an API break, can you use default values?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

/**
* !
* Returns the tolerance
* \since QGIS 3.12
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this method and the following were added in 3.12
https://github.com/qgis/QGIS/blame/master/src/core/qgssnappingconfig.h#L172

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes I think I went too fast with some doc modification.

* Returns min scale on which snapping is limited
* \since QGIS 3.14
*/
double minScale() const;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

both in the docstring and the method names can you use minimum and maximum in whole words rather than min/max?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

src/app/qgssnappingwidget.h Outdated Show resolved Hide resolved
src/app/qgssnappingwidget.h Outdated Show resolved Hide resolved
obrix added 5 commits April 7, 2020 09:27
- LimitToScaleRange : Allows to enable snapping only when current scale on the canvas is in a specified range. This range is controled by the two parameters scale min and scale max.
- MinScale : Minimum scale in which the snapping is enabled
- MaxScale : Maximum scale in which the snapping is enabled

When LimitToScaleRange is set to true, snapping is disabled if the current scale out of [MinScale, MaxScale].
When LimitToScaleRange is set to false, the behavior remain unchanged and snapping is enabled whatever the scale.

This allows to limit the costly cache refresh for some heavy layers when panning said layer at a level where the snapping is not useful.
obrix added 20 commits April 7, 2020 09:27
…o enable). Also use 0.0 for disabling value and display NULL to be more explicit.
* better documentation
* translation on non translated string
* Grey out column min and max of individual layer snapping settings when snapping limit on scale is disabled.
  Force the refresh when rowChanged is called even if the individual settings are the same to enable/disable immediately the columns when the snapping limit on scale button is pushed.
… and max. Add default value for min and max in IndividualLayerSettings as the two new parameters break compatibility.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants