25#include <QAbstractItemView>
29#include "moc_qgsscalecombobox.cpp"
37 setInsertPolicy( QComboBox::NoInsert );
38 setCompleter(
nullptr );
39 connect(
this, qOverload<int>( &QComboBox::activated ),
this, &QgsScaleComboBox::fixupScale );
40 connect( lineEdit(), &QLineEdit::editingFinished,
this, &QgsScaleComboBox::fixupScale );
46 QStringList scalesList;
47 const QString oldScale = currentText();
49 if ( scales.isEmpty() )
58 QStringList cleanedScalesList;
59 for (
const QString &
scale : std::as_const( scalesList ) )
61 const QStringList parts =
scale.split(
':' );
62 if ( parts.size() < 2 )
66 const double denominator = QLocale().toDouble( parts[1], &ok );
69 cleanedScalesList.push_back(
toString( denominator ) );
73 const double denominator = parts[1].toDouble( &ok );
76 cleanedScalesList.push_back(
toString( denominator ) );
83 addItems( cleanedScalesList );
85 blockSignals(
false );
90 if ( scales.isEmpty() )
96 const QString oldScale = currentText();
98 QStringList scalesStringList;
99 scalesStringList.reserve( scales.size() );
100 for (
double denominator : scales )
102 scalesStringList.push_back(
toString( denominator ) );
105 blockSignals(
true );
107 addItems( scalesStringList );
109 blockSignals(
false );
114 QComboBox::showPopup();
116 if ( !currentText().contains(
':' ) )
120 QStringList parts = currentText().split(
':' );
124 const long currScale = parts.at( 1 ).toLong( &ok );
125 long nextScale, delta;
126 for (
int i = 0; i < count(); i++ )
128 parts = itemText( i ).split(
':' );
129 nextScale = parts.at( 1 ).toLong( &ok );
130 delta = std::labs( currScale - nextScale );
138 blockSignals(
true );
139 view()->setCurrentIndex( model()->index( idx, 0 ) );
140 blockSignals(
false );
141 view()->setMinimumWidth( view()->sizeHintForColumn( 0 ) );
151 const double oldScale = mScale;
152 if ( mAllowNull &&
string.trimmed().isEmpty() )
154 mScale = std::numeric_limits<double>::quiet_NaN();
157 if ( !std::isnan( oldScale ) )
165 double newScale =
toDouble(
string, &ok );
166 if ( newScale > mMinScale && newScale != 0 && mMinScale != 0 )
168 newScale = mMinScale;
177 setEditText(
toString( mScale, mMode ) );
179 if ( mScale != oldScale )
194 return std::isnan( mScale );
202void QgsScaleComboBox::fixupScale()
204 if ( mAllowNull && currentText().trimmed().isEmpty() )
206 setScale( std::numeric_limits<double>::quiet_NaN() );
210 const QStringList txtList = currentText().split(
':' );
211 const bool userSetScale = txtList.size() != 2;
214 double newScale =
toDouble( currentText(), &ok );
224 if ( userSetScale && newScale < 1.0 && !
qgsDoubleNear( newScale, 0.0 ) )
226 newScale = 1 / newScale;
259 if ( std::isnan(
scale ) )
265 return QStringLiteral(
"0" );
273 return QStringLiteral(
"%1:1" ).arg( QLocale().
toString(
static_cast<int>( std::round( 1.0 /
scale ) ) ) );
277 return QStringLiteral(
"1:%1" ).arg( QLocale().
toString(
static_cast<float>( std::round(
scale ) ),
'f', 0 ) );
282 qlonglong numerator = 0;
283 qlonglong denominator = 0;
285 return QStringLiteral(
"%1:%2" ).arg(
310 QStringList txtList = scaleTxt.split(
':' );
311 if ( 2 == txtList.size() )
317 if ( okX && okY && x != 0 )
320 scale =
static_cast<double>( y ) /
static_cast<double>( x );
337 lineEdit()->setClearButtonEnabled(
allowNull );
349 if ( mScale > mMinScale && mScale != 0 && mMinScale != 0 )
358 setScale( std::numeric_limits<double>::quiet_NaN() );
static Q_INVOKABLE void doubleToRational(double value, qlonglong &numerator, qlonglong &denominator, double tolerance=1.0e-9, int maxIterations=100)
Converts a double value to a rational fraction.
void setPredefinedScales(const QVector< double > &scales)
Sets the list of predefined scales to show in the combobox.
void updateScales(const QStringList &scales=QStringList())
Sets the list of predefined scales to show in the combobox.
QString scaleString() const
Returns the selected scale as a string, e.g.
bool setScaleString(const QString &string)
Set the selected scale from a string, e.g.
void setAllowNull(bool allowNull)
Sets whether the scale combobox can be set to a NULL value.
QgsScaleComboBox(QWidget *parent=nullptr)
Constructor for QgsScaleComboBox.
bool isNull() const
Returns true if the combo box is currently set to a "null" value.
bool allowNull() const
Returns true if the combobox can be set to a NULL value.
static double toDouble(const QString &string, bool *ok=nullptr)
Helper function to convert a scale string to double.
void setScale(double scale)
Set the selected scale from a double.
void ratioModeChanged(QgsScaleComboBox::RatioMode mode)
Emitted when the ratio mode for the widget is changed.
void showPopup() override
void setNull()
Sets the combo box to the null value.
RatioMode
Scale ratio modes.
@ Flexible
Allows numerator values other than 1, e.g: "2:3".
@ ForceUnitNumerator
Default mode, forces the scale numerator to be 1, e.g. "1:1000".
void setRatioMode(QgsScaleComboBox::RatioMode mode)
Sets the ratio mode for the scale.
void setMinScale(double scale)
Set the minimum allowed scale.
static QString toString(double scale, QgsScaleComboBox::RatioMode mode=QgsScaleComboBox::RatioMode::ForceUnitNumerator)
Helper function to convert a scale double to scale string.
void scaleChanged(double scale)
Emitted when user has finished editing/selecting a new scale.
static const QgsSettingsEntryStringList * settingsMapScales
double qgsPermissiveToDouble(QString string, bool &ok)
Converts a string to a double in a permissive way, e.g., allowing for incorrect numbers of digits bet...
int qgsPermissiveToInt(QString string, bool &ok)
Converts a string to an integer in a permissive way, e.g., allowing for incorrect numbers of digits b...
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference).