diff options
Diffstat (limited to 'src/widgets/widgets')
-rw-r--r-- | src/widgets/widgets/qabstractspinbox.cpp | 15 | ||||
-rw-r--r-- | src/widgets/widgets/qabstractspinbox.h | 5 | ||||
-rw-r--r-- | src/widgets/widgets/qabstractspinbox_p.h | 3 | ||||
-rw-r--r-- | src/widgets/widgets/qspinbox.cpp | 116 | ||||
-rw-r--r-- | src/widgets/widgets/qspinbox.h | 8 |
5 files changed, 146 insertions, 1 deletions
diff --git a/src/widgets/widgets/qabstractspinbox.cpp b/src/widgets/widgets/qabstractspinbox.cpp index 8dbae25dce..c5ccfac109 100644 --- a/src/widgets/widgets/qabstractspinbox.cpp +++ b/src/widgets/widgets/qabstractspinbox.cpp @@ -639,7 +639,15 @@ void QAbstractSpinBox::stepBy(int steps) e = AlwaysEmit; } if (!dontstep) { - d->setValue(d->bound(d->value + (d->singleStep * steps), old, steps), e); + QVariant singleStep; + switch (d->stepType) { + case QAbstractSpinBox::StepType::AdaptiveDecimalStepType: + singleStep = d->calculateAdaptiveDecimalStep(steps); + break; + default: + singleStep = d->singleStep; + } + d->setValue(d->bound(d->value + (singleStep * steps), old, steps), e); } else if (e == AlwaysEmit) { d->emitSignals(e, old); } @@ -1898,6 +1906,11 @@ void QAbstractSpinBoxPrivate::clearCache() const cachedState = QValidator::Acceptable; } +QVariant QAbstractSpinBoxPrivate::calculateAdaptiveDecimalStep(int steps) const +{ + Q_UNUSED(steps) + return singleStep; +} // --- QSpinBoxValidator --- diff --git a/src/widgets/widgets/qabstractspinbox.h b/src/widgets/widgets/qabstractspinbox.h index 83bf83d779..552c51fc9d 100644 --- a/src/widgets/widgets/qabstractspinbox.h +++ b/src/widgets/widgets/qabstractspinbox.h @@ -127,6 +127,11 @@ public: virtual void fixup(QString &input) const; virtual void stepBy(int steps); + + enum StepType { + DefaultStepType, + AdaptiveDecimalStepType + }; public Q_SLOTS: void stepUp(); void stepDown(); diff --git a/src/widgets/widgets/qabstractspinbox_p.h b/src/widgets/widgets/qabstractspinbox_p.h index 8f312fa900..b8bc088160 100644 --- a/src/widgets/widgets/qabstractspinbox_p.h +++ b/src/widgets/widgets/qabstractspinbox_p.h @@ -122,6 +122,8 @@ public: static int variantCompare(const QVariant &arg1, const QVariant &arg2); static QVariant variantBound(const QVariant &min, const QVariant &value, const QVariant &max); + virtual QVariant calculateAdaptiveDecimalStep(int steps) const; + QLineEdit *edit; QString prefix, suffix, specialValueText; QVariant value, minimum, maximum, singleStep; @@ -143,6 +145,7 @@ public: uint cleared : 1; uint ignoreUpdateEdit : 1; QAbstractSpinBox::CorrectionMode correctionMode; + QAbstractSpinBox::StepType stepType = QAbstractSpinBox::StepType::DefaultStepType; int acceleration; QStyle::SubControl hoverControl; QRect hoverRect; diff --git a/src/widgets/widgets/qspinbox.cpp b/src/widgets/widgets/qspinbox.cpp index 561215ec85..7f29c0c52c 100644 --- a/src/widgets/widgets/qspinbox.cpp +++ b/src/widgets/widgets/qspinbox.cpp @@ -45,6 +45,8 @@ #include <qvalidator.h> #include <qdebug.h> +#include <algorithm> +#include <cmath> #include <float.h> QT_BEGIN_NAMESPACE @@ -75,6 +77,8 @@ public: } int displayIntegerBase; + + QVariant calculateAdaptiveDecimalStep(int steps) const override; }; class QDoubleSpinBoxPrivate : public QAbstractSpinBoxPrivate @@ -100,6 +104,8 @@ public: // When fiddling with the decimals property, we may lose precision in these properties. double actualMin; double actualMax; + + QVariant calculateAdaptiveDecimalStep(int steps) const override; }; @@ -415,6 +421,41 @@ void QSpinBox::setRange(int minimum, int maximum) } /*! + Sets the step type for the spin box: single step or adaptive + decimal step. + + Adaptive decimal step means that the step size will continuously be + adjusted to one power of ten below the current \l value. So when + the value is 1100, the step is set to 100, so stepping up once + increases it to 1200. For 1200 stepping up takes it to 1300. For + negative values, stepping down from -1100 goes to -1200. + + Step direction is taken into account to handle edges cases, so + that stepping down from 100 takes the value to 99 instead of 90. + Thus a step up followed by a step down -- or vice versa -- always + lands on the starting value; 99 -> 100 -> 99. + + Setting this will cause the spin box to disregard the value of + \l singleStep, although it is preserved so that \l singleStep + comes into effect if adaptive decimal step is later turned off. + + \sa QAbstractSpinBox::groupSeparator() + \since 5.12 +*/ + +void QSpinBox::setStepType(QAbstractSpinBox::StepType stepType) +{ + Q_D(QSpinBox); + d->stepType = stepType; +} + +QAbstractSpinBox::StepType QSpinBox::stepType() const +{ + Q_D(const QSpinBox); + return d->stepType; +} + +/*! \property QSpinBox::displayIntegerBase \brief the base used to display the value of the spin box @@ -847,6 +888,44 @@ void QDoubleSpinBox::setRange(double minimum, double maximum) } /*! + Sets the step type for the spin box: single step or adaptive + decimal step. + + Adaptive decimal step means that the step size will continuously be + adjusted to one power of ten below the current \l value. So when + the value is 1100, the step is set to 100, so stepping up once + increases it to 1200. For 1200 stepping up takes it to 1300. For + negative values, stepping down from -1100 goes to -1200. + + It also works for any decimal values, 0.041 is increased to 0.042 + by stepping once. + + Step direction is taken into account to handle edges cases, so + that stepping down from 100 takes the value to 99 instead of 90. + Thus a step up followed by a step down -- or vice versa -- always + lands on the starting value; 99 -> 100 -> 99. + + Setting this will cause the spin box to disregard the value of + \l singleStep, although it is preserved so that \l singleStep + comes into effect if adaptive decimal step is later turned off. + + \sa QAbstractSpinBox::groupSeparator() + \since 5.12 +*/ + +void QDoubleSpinBox::setStepType(StepType stepType) +{ + Q_D(QDoubleSpinBox); + d->stepType = stepType; +} + +QAbstractSpinBox::StepType QDoubleSpinBox::stepType() const +{ + Q_D(const QDoubleSpinBox); + return d->stepType; +} + +/*! \property QDoubleSpinBox::decimals \brief the precision of the spin box, in decimals @@ -1078,6 +1157,22 @@ QVariant QSpinBoxPrivate::validateAndInterpret(QString &input, int &pos, return cachedValue; } +QVariant QSpinBoxPrivate::calculateAdaptiveDecimalStep(int steps) const +{ + const int intValue = value.toInt(); + const int absValue = qAbs(intValue); + + if (absValue < 100) + return 1; + + const bool valueNegative = intValue < 0; + const bool stepsNegative = steps < 0; + const int signCompensation = (valueNegative == stepsNegative) ? 0 : 1; + + const int log = static_cast<int>(std::log10(absValue - signCompensation)) - 1; + return static_cast<int>(std::pow(10, log)); +} + // --- QDoubleSpinBoxPrivate --- /*! @@ -1303,6 +1398,27 @@ QString QDoubleSpinBoxPrivate::textFromValue(const QVariant &f) const return q->textFromValue(f.toDouble()); } +QVariant QDoubleSpinBoxPrivate::calculateAdaptiveDecimalStep(int steps) const +{ + const double doubleValue = value.toDouble(); + const double minStep = std::pow(10, -decimals); + double absValue = qAbs(doubleValue); + + if (absValue < minStep) + return minStep; + + const bool valueNegative = doubleValue < 0; + const bool stepsNegative = steps < 0; + if (valueNegative != stepsNegative) + absValue /= 1.01; + + const double shift = std::pow(10, 1 - std::floor(std::log10(absValue))); + const double absRounded = round(absValue * shift) / shift; + const double log = floorf(std::log10(absRounded)) - 1; + + return std::max(minStep, std::pow(10, log)); +} + /*! \reimp */ bool QSpinBox::event(QEvent *event) { diff --git a/src/widgets/widgets/qspinbox.h b/src/widgets/widgets/qspinbox.h index 73489c9a68..d2eac903fb 100644 --- a/src/widgets/widgets/qspinbox.h +++ b/src/widgets/widgets/qspinbox.h @@ -58,6 +58,7 @@ class Q_WIDGETS_EXPORT QSpinBox : public QAbstractSpinBox Q_PROPERTY(int minimum READ minimum WRITE setMinimum) Q_PROPERTY(int maximum READ maximum WRITE setMaximum) Q_PROPERTY(int singleStep READ singleStep WRITE setSingleStep) + Q_PROPERTY(StepType stepType READ stepType WRITE setStepType) Q_PROPERTY(int value READ value WRITE setValue NOTIFY valueChanged USER true) Q_PROPERTY(int displayIntegerBase READ displayIntegerBase WRITE setDisplayIntegerBase) @@ -86,6 +87,9 @@ public: void setRange(int min, int max); + StepType stepType() const; + void setStepType(StepType stepType); + int displayIntegerBase() const; void setDisplayIntegerBase(int base); @@ -121,6 +125,7 @@ class Q_WIDGETS_EXPORT QDoubleSpinBox : public QAbstractSpinBox Q_PROPERTY(double minimum READ minimum WRITE setMinimum) Q_PROPERTY(double maximum READ maximum WRITE setMaximum) Q_PROPERTY(double singleStep READ singleStep WRITE setSingleStep) + Q_PROPERTY(StepType stepType READ stepType WRITE setStepType) Q_PROPERTY(double value READ value WRITE setValue NOTIFY valueChanged USER true) public: explicit QDoubleSpinBox(QWidget *parent = nullptr); @@ -147,6 +152,9 @@ public: void setRange(double min, double max); + StepType stepType() const; + void setStepType(StepType stepType); + int decimals() const; void setDecimals(int prec); |