Skip to content

Commit 35deef1

Browse files
committed
Add mode to QgsScaleComboBox for non-unit ratios
This allows the widget to be used for other scales (or ratios), not just map scales. Eg. it allows it to be used for entry of scale ratios like "2:3", "16:9" etc.
1 parent 959312a commit 35deef1

File tree

8 files changed

+312
-38
lines changed

8 files changed

+312
-38
lines changed
Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,22 @@
11
# The following has been generated automatically from src/gui/qgsscalecombobox.h
2+
# monkey patching scoped based enum
3+
QgsScaleComboBox.RatioMode.ForceUnitNumerator.__doc__ = "Default mode, forces the scale numerator to be 1, e.g. \"1:1000\""
4+
QgsScaleComboBox.RatioMode.Flexible.__doc__ = "Allows numerator values other than 1, e.g: \"2:3\"."
5+
QgsScaleComboBox.RatioMode.__doc__ = """Scale ratio modes.
6+
7+
.. versionadded:: 4.0
8+
9+
* ``ForceUnitNumerator``: Default mode, forces the scale numerator to be 1, e.g. \"1:1000\"
10+
* ``Flexible``: Allows numerator values other than 1, e.g: \"2:3\".
11+
12+
"""
13+
# --
14+
QgsScaleComboBox.RatioMode.baseClass = QgsScaleComboBox
215
try:
3-
QgsScaleComboBox.__attribute_docs__ = {'scaleChanged': 'Emitted when *user* has finished editing/selecting a new scale. The\n``scale`` value indicates the scale denominator, e.g. 1000.0 for a\n1:1000 map.\n'}
16+
QgsScaleComboBox.__attribute_docs__ = {'scaleChanged': 'Emitted when *user* has finished editing/selecting a new scale. The\n``scale`` value indicates the scale denominator, e.g. 1000.0 for a\n1:1000 map.\n', 'ratioModeChanged': 'Emitted when the ratio mode for the widget is changed.\n\n.. versionadded:: 4.0\n'}
417
QgsScaleComboBox.toString = staticmethod(QgsScaleComboBox.toString)
518
QgsScaleComboBox.toDouble = staticmethod(QgsScaleComboBox.toDouble)
619
QgsScaleComboBox.__overridden_methods__ = ['showPopup']
7-
QgsScaleComboBox.__signal_arguments__ = {'scaleChanged': ['scale: float']}
20+
QgsScaleComboBox.__signal_arguments__ = {'scaleChanged': ['scale: float'], 'ratioModeChanged': ['mode: QgsScaleComboBox.RatioMode']}
821
except (NameError, AttributeError):
922
pass

python/PyQt6/gui/auto_generated/qgsscalecombobox.sip.in

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,12 @@ highlights nearest to current scale value.
2020
#include "qgsscalecombobox.h"
2121
%End
2222
public:
23+
enum class RatioMode /BaseType=IntEnum/
24+
{
25+
ForceUnitNumerator,
26+
Flexible,
27+
};
28+
2329
QgsScaleComboBox( QWidget *parent /TransferThis/ = 0 );
2430
%Docstring
2531
Constructor for QgsScaleComboBox.
@@ -66,14 +72,16 @@ scale lower than the minimum scale will automatically be converted to
6672
the minimum scale. Except for 0 which is always allowed.
6773
%End
6874

69-
static QString toString( double scale );
75+
static QString toString( double scale, QgsScaleComboBox::RatioMode mode = QgsScaleComboBox::RatioMode::ForceUnitNumerator );
7076
%Docstring
71-
Helper function to convert a ``scale`` double to scale string. The
72-
``scale`` value indicates the scale denominator, e.g. 1000.0 for a
73-
1:1000 map.
77+
Helper function to convert a ``scale`` double to scale string.
7478

7579
The returned string will be rounded (e.g. 1:1000, not 1:1000.345).
7680

81+
:param scale: scale value indicating the scale denominator, e.g. 1000.0
82+
for a 1:1000 map.
83+
:param mode: ratio mode (since QGIS 4.0)
84+
7785
.. seealso:: :py:func:`toDouble`
7886
%End
7987

@@ -123,6 +131,15 @@ If ``scales`` is empty then the default user scale options will be used
123131
instead.
124132

125133
.. versionadded:: 3.38
134+
%End
135+
136+
QgsScaleComboBox::RatioMode ratioMode() const;
137+
%Docstring
138+
Returns the ratio mode for the scale.
139+
140+
.. seealso:: :py:func:`setRatioMode`
141+
142+
.. versionadded:: 4.0
126143
%End
127144

128145
signals:
@@ -132,6 +149,13 @@ instead.
132149
Emitted when *user* has finished editing/selecting a new scale. The
133150
``scale`` value indicates the scale denominator, e.g. 1000.0 for a
134151
1:1000 map.
152+
%End
153+
154+
void ratioModeChanged( QgsScaleComboBox::RatioMode mode );
155+
%Docstring
156+
Emitted when the ratio mode for the widget is changed.
157+
158+
.. versionadded:: 4.0
135159
%End
136160

137161
public slots:
@@ -171,6 +195,15 @@ This only has an effect if :py:func:`~QgsScaleComboBox.allowNull` is
171195
.. seealso:: :py:func:`isNull`
172196

173197
.. versionadded:: 3.8
198+
%End
199+
200+
void setRatioMode( QgsScaleComboBox::RatioMode mode );
201+
%Docstring
202+
Sets the ratio ``mode`` for the scale.
203+
204+
.. seealso:: :py:func:`ratioMode`
205+
206+
.. versionadded:: 4.0
174207
%End
175208

176209
protected:
Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,22 @@
11
# The following has been generated automatically from src/gui/qgsscalecombobox.h
2+
# monkey patching scoped based enum
3+
QgsScaleComboBox.RatioMode.ForceUnitNumerator.__doc__ = "Default mode, forces the scale numerator to be 1, e.g. \"1:1000\""
4+
QgsScaleComboBox.RatioMode.Flexible.__doc__ = "Allows numerator values other than 1, e.g: \"2:3\"."
5+
QgsScaleComboBox.RatioMode.__doc__ = """Scale ratio modes.
6+
7+
.. versionadded:: 4.0
8+
9+
* ``ForceUnitNumerator``: Default mode, forces the scale numerator to be 1, e.g. \"1:1000\"
10+
* ``Flexible``: Allows numerator values other than 1, e.g: \"2:3\".
11+
12+
"""
13+
# --
14+
QgsScaleComboBox.RatioMode.baseClass = QgsScaleComboBox
215
try:
3-
QgsScaleComboBox.__attribute_docs__ = {'scaleChanged': 'Emitted when *user* has finished editing/selecting a new scale. The\n``scale`` value indicates the scale denominator, e.g. 1000.0 for a\n1:1000 map.\n'}
16+
QgsScaleComboBox.__attribute_docs__ = {'scaleChanged': 'Emitted when *user* has finished editing/selecting a new scale. The\n``scale`` value indicates the scale denominator, e.g. 1000.0 for a\n1:1000 map.\n', 'ratioModeChanged': 'Emitted when the ratio mode for the widget is changed.\n\n.. versionadded:: 4.0\n'}
417
QgsScaleComboBox.toString = staticmethod(QgsScaleComboBox.toString)
518
QgsScaleComboBox.toDouble = staticmethod(QgsScaleComboBox.toDouble)
619
QgsScaleComboBox.__overridden_methods__ = ['showPopup']
7-
QgsScaleComboBox.__signal_arguments__ = {'scaleChanged': ['scale: float']}
20+
QgsScaleComboBox.__signal_arguments__ = {'scaleChanged': ['scale: float'], 'ratioModeChanged': ['mode: QgsScaleComboBox.RatioMode']}
821
except (NameError, AttributeError):
922
pass

python/gui/auto_generated/qgsscalecombobox.sip.in

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,12 @@ highlights nearest to current scale value.
2020
#include "qgsscalecombobox.h"
2121
%End
2222
public:
23+
enum class RatioMode
24+
{
25+
ForceUnitNumerator,
26+
Flexible,
27+
};
28+
2329
QgsScaleComboBox( QWidget *parent /TransferThis/ = 0 );
2430
%Docstring
2531
Constructor for QgsScaleComboBox.
@@ -66,14 +72,16 @@ scale lower than the minimum scale will automatically be converted to
6672
the minimum scale. Except for 0 which is always allowed.
6773
%End
6874

69-
static QString toString( double scale );
75+
static QString toString( double scale, QgsScaleComboBox::RatioMode mode = QgsScaleComboBox::RatioMode::ForceUnitNumerator );
7076
%Docstring
71-
Helper function to convert a ``scale`` double to scale string. The
72-
``scale`` value indicates the scale denominator, e.g. 1000.0 for a
73-
1:1000 map.
77+
Helper function to convert a ``scale`` double to scale string.
7478

7579
The returned string will be rounded (e.g. 1:1000, not 1:1000.345).
7680

81+
:param scale: scale value indicating the scale denominator, e.g. 1000.0
82+
for a 1:1000 map.
83+
:param mode: ratio mode (since QGIS 4.0)
84+
7785
.. seealso:: :py:func:`toDouble`
7886
%End
7987

@@ -123,6 +131,15 @@ If ``scales`` is empty then the default user scale options will be used
123131
instead.
124132

125133
.. versionadded:: 3.38
134+
%End
135+
136+
QgsScaleComboBox::RatioMode ratioMode() const;
137+
%Docstring
138+
Returns the ratio mode for the scale.
139+
140+
.. seealso:: :py:func:`setRatioMode`
141+
142+
.. versionadded:: 4.0
126143
%End
127144

128145
signals:
@@ -132,6 +149,13 @@ instead.
132149
Emitted when *user* has finished editing/selecting a new scale. The
133150
``scale`` value indicates the scale denominator, e.g. 1000.0 for a
134151
1:1000 map.
152+
%End
153+
154+
void ratioModeChanged( QgsScaleComboBox::RatioMode mode );
155+
%Docstring
156+
Emitted when the ratio mode for the widget is changed.
157+
158+
.. versionadded:: 4.0
135159
%End
136160

137161
public slots:
@@ -171,6 +195,15 @@ This only has an effect if :py:func:`~QgsScaleComboBox.allowNull` is
171195
.. seealso:: :py:func:`isNull`
172196

173197
.. versionadded:: 3.8
198+
%End
199+
200+
void setRatioMode( QgsScaleComboBox::RatioMode mode );
201+
%Docstring
202+
Sets the ratio ``mode`` for the scale.
203+
204+
.. seealso:: :py:func:`ratioMode`
205+
206+
.. versionadded:: 4.0
174207
%End
175208

176209
protected:

src/gui/qgsscalecombobox.cpp

Lines changed: 56 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "qgsscalecombobox.h"
2121
#include "moc_qgsscalecombobox.cpp"
2222
#include "qgssettingsentryimpl.h"
23+
#include "qgsmathutils.h"
2324

2425
#include <QAbstractItemView>
2526
#include <QLocale>
@@ -140,7 +141,7 @@ void QgsScaleComboBox::showPopup()
140141

141142
QString QgsScaleComboBox::scaleString() const
142143
{
143-
return toString( mScale );
144+
return toString( mScale, mMode );
144145
}
145146

146147
bool QgsScaleComboBox::setScaleString( const QString &string )
@@ -171,7 +172,7 @@ bool QgsScaleComboBox::setScaleString( const QString &string )
171172
else
172173
{
173174
mScale = newScale;
174-
setEditText( toString( mScale ) );
175+
setEditText( toString( mScale, mMode ) );
175176
clearFocus();
176177
if ( mScale != oldScale )
177178
{
@@ -193,7 +194,7 @@ bool QgsScaleComboBox::isNull() const
193194

194195
void QgsScaleComboBox::setScale( double scale )
195196
{
196-
setScaleString( toString( scale ) );
197+
setScaleString( toString( scale, mMode ) );
197198
}
198199

199200
void QgsScaleComboBox::fixupScale()
@@ -213,11 +214,21 @@ void QgsScaleComboBox::fixupScale()
213214
// Valid string representation
214215
if ( ok )
215216
{
216-
// if a user types scale = 2345, we transform to 1:2345
217-
if ( userSetScale && newScale < 1.0 && !qgsDoubleNear( newScale, 0.0 ) )
217+
switch ( mMode )
218218
{
219-
newScale = 1 / newScale;
219+
case RatioMode::ForceUnitNumerator:
220+
{
221+
// if a user types scale = 2345, we transform to 1:2345
222+
if ( userSetScale && newScale < 1.0 && !qgsDoubleNear( newScale, 0.0 ) )
223+
{
224+
newScale = 1 / newScale;
225+
}
226+
break;
227+
}
228+
case RatioMode::Flexible:
229+
break;
220230
}
231+
221232
setScale( newScale );
222233
}
223234
else
@@ -226,7 +237,22 @@ void QgsScaleComboBox::fixupScale()
226237
}
227238
}
228239

229-
QString QgsScaleComboBox::toString( double scale )
240+
QgsScaleComboBox::RatioMode QgsScaleComboBox::ratioMode() const
241+
{
242+
return mMode;
243+
}
244+
245+
void QgsScaleComboBox::setRatioMode( QgsScaleComboBox::RatioMode mode )
246+
{
247+
if ( mode == mMode )
248+
return;
249+
250+
mMode = mode;
251+
setScale( mScale );
252+
emit ratioModeChanged( mMode );
253+
}
254+
255+
QString QgsScaleComboBox::toString( double scale, RatioMode mode )
230256
{
231257
if ( std::isnan( scale ) )
232258
{
@@ -236,14 +262,31 @@ QString QgsScaleComboBox::toString( double scale )
236262
{
237263
return QStringLiteral( "0" );
238264
}
239-
else if ( scale <= 1 )
240-
{
241-
return QStringLiteral( "%1:1" ).arg( QLocale().toString( static_cast<int>( std::round( 1.0 / scale ) ) ) );
242-
}
243-
else
265+
266+
switch ( mode )
244267
{
245-
return QStringLiteral( "1:%1" ).arg( QLocale().toString( static_cast<float>( std::round( scale ) ), 'f', 0 ) );
268+
case RatioMode::ForceUnitNumerator:
269+
if ( scale <= 1 )
270+
{
271+
return QStringLiteral( "%1:1" ).arg( QLocale().toString( static_cast<int>( std::round( 1.0 / scale ) ) ) );
272+
}
273+
else
274+
{
275+
return QStringLiteral( "1:%1" ).arg( QLocale().toString( static_cast<float>( std::round( scale ) ), 'f', 0 ) );
276+
}
277+
278+
case RatioMode::Flexible:
279+
{
280+
qlonglong numerator = 0;
281+
qlonglong denominator = 0;
282+
QgsMathUtils::doubleToRational( 1.0 / scale, numerator, denominator, 0.01 );
283+
return QStringLiteral( "%1:%2" ).arg(
284+
QLocale().toString( numerator ),
285+
QLocale().toString( denominator )
286+
);
287+
}
246288
}
289+
return QString();
247290
}
248291

249292
double QgsScaleComboBox::toDouble( const QString &scaleString, bool *returnOk )

0 commit comments

Comments
 (0)