1 /****************************************************************************
2 **
3 ** Copyright (C) 2020 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtWidgets module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 #include <private/qabstractspinbox_p.h>
41 #include <qspinbox.h>
42 
43 #include <qlineedit.h>
44 #include <qlocale.h>
45 #include <qvalidator.h>
46 #include <qdebug.h>
47 
48 #include <algorithm>
49 #include <cmath>
50 #include <float.h>
51 
52 QT_BEGIN_NAMESPACE
53 
54 //#define QSPINBOX_QSBDEBUG
55 #ifdef QSPINBOX_QSBDEBUG
56 #  define QSBDEBUG qDebug
57 #else
58 #  define QSBDEBUG if (false) qDebug
59 #endif
60 
61 class QSpinBoxPrivate : public QAbstractSpinBoxPrivate
62 {
63     Q_DECLARE_PUBLIC(QSpinBox)
64 public:
65     QSpinBoxPrivate();
66     void emitSignals(EmitPolicy ep, const QVariant &) override;
67 
68     virtual QVariant valueFromText(const QString &n) const override;
69     virtual QString textFromValue(const QVariant &n) const override;
70     QVariant validateAndInterpret(QString &input, int &pos,
71                                   QValidator::State &state) const;
72 
init()73     inline void init() {
74         Q_Q(QSpinBox);
75         q->setInputMethodHints(Qt::ImhDigitsOnly);
76         setLayoutItemMargins(QStyle::SE_SpinBoxLayoutItem);
77     }
78 
79     int displayIntegerBase;
80 
81     QVariant calculateAdaptiveDecimalStep(int steps) const override;
82 };
83 
84 class QDoubleSpinBoxPrivate : public QAbstractSpinBoxPrivate
85 {
86     Q_DECLARE_PUBLIC(QDoubleSpinBox)
87 public:
88     QDoubleSpinBoxPrivate();
89     void emitSignals(EmitPolicy ep, const QVariant &) override;
90 
91     virtual QVariant valueFromText(const QString &n) const override;
92     virtual QString textFromValue(const QVariant &n) const override;
93     QVariant validateAndInterpret(QString &input, int &pos,
94                                   QValidator::State &state) const;
95     double round(double input) const;
96     // variables
97     int decimals;
98 
init()99     inline void init() {
100         Q_Q(QDoubleSpinBox);
101         q->setInputMethodHints(Qt::ImhFormattedNumbersOnly);
102     }
103 
104     // When fiddling with the decimals property, we may lose precision in these properties.
105     double actualMin;
106     double actualMax;
107 
108     QVariant calculateAdaptiveDecimalStep(int steps) const override;
109 };
110 
111 
112 /*!
113     \class QSpinBox
114     \brief The QSpinBox class provides a spin box widget.
115 
116     \ingroup basicwidgets
117     \inmodule QtWidgets
118 
119     \image windows-spinbox.png
120 
121     QSpinBox is designed to handle integers and discrete sets of
122     values (e.g., month names); use QDoubleSpinBox for floating point
123     values.
124 
125     QSpinBox allows the user to choose a value by clicking the up/down
126     buttons or pressing up/down on the keyboard to increase/decrease
127     the value currently displayed. The user can also type the value in
128     manually. The spin box supports integer values but can be extended to
129     use different strings with validate(), textFromValue() and valueFromText().
130 
131     Every time the value changes QSpinBox emits valueChanged() and
132     textChanged() signals, the former providing a int and the latter
133     a QString. The textChanged() signal provides the value with both
134     prefix() and suffix().
135     The current value can be fetched with value() and set with setValue().
136 
137     Clicking the up/down buttons or using the keyboard accelerator's
138     up and down arrows will increase or decrease the current value in
139     steps of size singleStep(). If you want to change this behaviour you
140     can reimplement the virtual function stepBy(). The minimum and
141     maximum value and the step size can be set using one of the
142     constructors, and can be changed later with setMinimum(),
143     setMaximum() and setSingleStep().
144 
145     Most spin boxes are directional, but QSpinBox can also operate as
146     a circular spin box, i.e. if the range is 0-99 and the current
147     value is 99, clicking "up" will give 0 if wrapping() is set to
148     true. Use setWrapping() if you want circular behavior.
149 
150     The displayed value can be prepended and appended with arbitrary
151     strings indicating, for example, currency or the unit of
152     measurement. See setPrefix() and setSuffix(). The text in the spin
153     box is retrieved with text() (which includes any prefix() and
154     suffix()), or with cleanText() (which has no prefix(), no suffix()
155     and no leading or trailing whitespace).
156 
157     It is often desirable to give the user a special (often default)
158     choice in addition to the range of numeric values. See
159     setSpecialValueText() for how to do this with QSpinBox.
160 
161     \section1 Subclassing QSpinBox
162 
163     If using prefix(), suffix(), and specialValueText() don't provide
164     enough control, you subclass QSpinBox and reimplement
165     valueFromText() and textFromValue(). For example, here's the code
166     for a custom spin box that allows the user to enter icon sizes
167     (e.g., "32 x 32"):
168 
169     \snippet widgets/icons/iconsizespinbox.cpp 1
170     \codeline
171     \snippet widgets/icons/iconsizespinbox.cpp 2
172 
173     See the \l{widgets/icons}{Icons} example for the full source
174     code.
175 
176     \sa QDoubleSpinBox, QDateTimeEdit, QSlider, {Spin Boxes Example}
177 */
178 
179 /*!
180     \fn void QSpinBox::valueChanged(int i)
181 
182     This signal is emitted whenever the spin box's value is changed.
183     The new value's integer value is passed in \a i.
184 */
185 
186 /*!
187     \fn void QSpinBox::textChanged(const QString &text)
188     \since 5.14
189 
190     This signal is emitted whenever the spin box's text is changed.
191     The new text is passed in \a text with prefix() and suffix().
192 */
193 
194 #if QT_DEPRECATED_SINCE(5, 14)
195 /*!
196     \fn void QSpinBox::valueChanged(const QString &text)
197 
198     \overload
199     \obsolete Use textChanged(QString) instead
200 
201     The new value is passed in \a text with prefix() and suffix().
202 */
203 #endif
204 
205 /*!
206     Constructs a spin box with 0 as minimum value and 99 as maximum value, a
207     step value of 1. The value is initially set to 0. It is parented to \a
208     parent.
209 
210     \sa setMinimum(), setMaximum(), setSingleStep()
211 */
212 
QSpinBox(QWidget * parent)213 QSpinBox::QSpinBox(QWidget *parent)
214     : QAbstractSpinBox(*new QSpinBoxPrivate, parent)
215 {
216     Q_D(QSpinBox);
217     d->init();
218 }
219 
220 /*!
221     Destructor.
222 */
~QSpinBox()223 QSpinBox::~QSpinBox() {}
224 
225 /*!
226     \property QSpinBox::value
227     \brief the value of the spin box
228 
229     setValue() will emit valueChanged() if the new value is different
230     from the old one. The value property has a second notifier
231     signal which includes the spin box's prefix and suffix.
232 */
233 
value() const234 int QSpinBox::value() const
235 {
236     Q_D(const QSpinBox);
237     return d->value.toInt();
238 }
239 
setValue(int value)240 void QSpinBox::setValue(int value)
241 {
242     Q_D(QSpinBox);
243     d->setValue(QVariant(value), EmitIfChanged);
244 }
245 
246 /*!
247     \property QSpinBox::prefix
248     \brief the spin box's prefix
249 
250     The prefix is prepended to the start of the displayed value.
251     Typical use is to display a unit of measurement or a currency
252     symbol. For example:
253 
254     \snippet code/src_gui_widgets_qspinbox.cpp 0
255 
256     To turn off the prefix display, set this property to an empty
257     string. The default is no prefix. The prefix is not displayed when
258     value() == minimum() and specialValueText() is set.
259 
260     If no prefix is set, prefix() returns an empty string.
261 
262     \sa suffix(), setSuffix(), specialValueText(), setSpecialValueText()
263 */
264 
prefix() const265 QString QSpinBox::prefix() const
266 {
267     Q_D(const QSpinBox);
268     return d->prefix;
269 }
270 
setPrefix(const QString & prefix)271 void QSpinBox::setPrefix(const QString &prefix)
272 {
273     Q_D(QSpinBox);
274 
275     d->prefix = prefix;
276     d->updateEdit();
277 
278     d->cachedSizeHint = QSize();
279     d->cachedMinimumSizeHint = QSize(); // minimumSizeHint cares about the prefix
280     updateGeometry();
281 }
282 
283 /*!
284     \property QSpinBox::suffix
285     \brief the suffix of the spin box
286 
287     The suffix is appended to the end of the displayed value. Typical
288     use is to display a unit of measurement or a currency symbol. For
289     example:
290 
291     \snippet code/src_gui_widgets_qspinbox.cpp 1
292 
293     To turn off the suffix display, set this property to an empty
294     string. The default is no suffix. The suffix is not displayed for
295     the minimum() if specialValueText() is set.
296 
297     If no suffix is set, suffix() returns an empty string.
298 
299     \sa prefix(), setPrefix(), specialValueText(), setSpecialValueText()
300 */
301 
suffix() const302 QString QSpinBox::suffix() const
303 {
304     Q_D(const QSpinBox);
305 
306     return d->suffix;
307 }
308 
setSuffix(const QString & suffix)309 void QSpinBox::setSuffix(const QString &suffix)
310 {
311     Q_D(QSpinBox);
312 
313     d->suffix = suffix;
314     d->updateEdit();
315 
316     d->cachedSizeHint = QSize();
317     updateGeometry();
318 }
319 
320 /*!
321     \property QSpinBox::cleanText
322 
323     \brief the text of the spin box excluding any prefix, suffix,
324     or leading or trailing whitespace.
325 
326     \sa text, QSpinBox::prefix, QSpinBox::suffix
327 */
328 
cleanText() const329 QString QSpinBox::cleanText() const
330 {
331     Q_D(const QSpinBox);
332 
333     return d->stripped(d->edit->displayText());
334 }
335 
336 
337 /*!
338     \property QSpinBox::singleStep
339     \brief the step value
340 
341     When the user uses the arrows to change the spin box's value the
342     value will be incremented/decremented by the amount of the
343     singleStep. The default value is 1. Setting a singleStep value of
344     less than 0 does nothing.
345 */
346 
singleStep() const347 int QSpinBox::singleStep() const
348 {
349     Q_D(const QSpinBox);
350 
351     return d->singleStep.toInt();
352 }
353 
setSingleStep(int value)354 void QSpinBox::setSingleStep(int value)
355 {
356     Q_D(QSpinBox);
357     if (value >= 0) {
358         d->singleStep = QVariant(value);
359         d->updateEdit();
360     }
361 }
362 
363 /*!
364     \property QSpinBox::minimum
365 
366     \brief the minimum value of the spin box
367 
368     When setting this property the \l maximum is adjusted
369     if necessary to ensure that the range remains valid.
370 
371     The default minimum value is 0.
372 
373     \sa setRange(), specialValueText
374 */
375 
minimum() const376 int QSpinBox::minimum() const
377 {
378     Q_D(const QSpinBox);
379 
380     return d->minimum.toInt();
381 }
382 
setMinimum(int minimum)383 void QSpinBox::setMinimum(int minimum)
384 {
385     Q_D(QSpinBox);
386     const QVariant m(minimum);
387     d->setRange(m, (QSpinBoxPrivate::variantCompare(d->maximum, m) > 0 ? d->maximum : m));
388 }
389 
390 /*!
391     \property QSpinBox::maximum
392 
393     \brief the maximum value of the spin box
394 
395     When setting this property the minimum is adjusted
396     if necessary, to ensure that the range remains valid.
397 
398     The default maximum value is 99.
399 
400     \sa setRange(), specialValueText
401 
402 */
403 
maximum() const404 int QSpinBox::maximum() const
405 {
406     Q_D(const QSpinBox);
407 
408     return d->maximum.toInt();
409 }
410 
setMaximum(int maximum)411 void QSpinBox::setMaximum(int maximum)
412 {
413     Q_D(QSpinBox);
414     const QVariant m(maximum);
415     d->setRange((QSpinBoxPrivate::variantCompare(d->minimum, m) < 0 ? d->minimum : m), m);
416 }
417 
418 /*!
419     Convenience function to set the \a minimum, and \a maximum values
420     with a single function call.
421 
422     \snippet code/src_gui_widgets_qspinbox.cpp 2
423     is equivalent to:
424     \snippet code/src_gui_widgets_qspinbox.cpp 3
425 
426     \sa minimum, maximum
427 */
428 
setRange(int minimum,int maximum)429 void QSpinBox::setRange(int minimum, int maximum)
430 {
431     Q_D(QSpinBox);
432     d->setRange(QVariant(minimum), QVariant(maximum));
433 }
434 
435 /*!
436     Sets the step type for the spin box to \a stepType, which is single
437     step or adaptive decimal step.
438 
439     Adaptive decimal step means that the step size will continuously be
440     adjusted to one power of ten below the current \l value. So when
441     the value is 1100, the step is set to 100, so stepping up once
442     increases it to 1200. For 1200 stepping up takes it to 1300. For
443     negative values, stepping down from -1100 goes to -1200.
444 
445     Step direction is taken into account to handle edges cases, so
446     that stepping down from 100 takes the value to 99 instead of 90.
447     Thus a step up followed by a step down -- or vice versa -- always
448     lands on the starting value; 99 -> 100 -> 99.
449 
450     Setting this will cause the spin box to disregard the value of
451     \l singleStep, although it is preserved so that \l singleStep
452     comes into effect if adaptive decimal step is later turned off.
453 
454     \since 5.12
455 */
456 
setStepType(QAbstractSpinBox::StepType stepType)457 void QSpinBox::setStepType(QAbstractSpinBox::StepType stepType)
458 {
459     Q_D(QSpinBox);
460     d->stepType = stepType;
461 }
462 
463 /*!
464     \property QSpinBox::stepType
465     \brief The step type.
466 
467     The step type can be single step or adaptive decimal step.
468 */
469 
stepType() const470 QAbstractSpinBox::StepType QSpinBox::stepType() const
471 {
472     Q_D(const QSpinBox);
473     return d->stepType;
474 }
475 
476 /*!
477     \property QSpinBox::displayIntegerBase
478 
479     \brief the base used to display the value of the spin box
480 
481     The default displayIntegerBase value is 10.
482 
483     \sa textFromValue(), valueFromText()
484     \since 5.2
485 */
486 
displayIntegerBase() const487 int QSpinBox::displayIntegerBase() const
488 {
489     Q_D(const QSpinBox);
490     return d->displayIntegerBase;
491 }
492 
setDisplayIntegerBase(int base)493 void QSpinBox::setDisplayIntegerBase(int base)
494 {
495     Q_D(QSpinBox);
496     // Falls back to base 10 on invalid bases (like QString)
497     if (Q_UNLIKELY(base < 2 || base > 36)) {
498         qWarning("QSpinBox::setDisplayIntegerBase: Invalid base (%d)", base);
499         base = 10;
500     }
501 
502     if (base != d->displayIntegerBase) {
503         d->displayIntegerBase = base;
504         d->updateEdit();
505     }
506 }
507 
508 /*!
509     This virtual function is used by the spin box whenever it needs to
510     display the given \a value. The default implementation returns a
511     string containing \a value printed in the standard way using
512     QWidget::locale().toString(), but with the thousand separator
513     removed unless setGroupSeparatorShown() is set. Reimplementations may
514     return anything. (See the example in the detailed description.)
515 
516     Note: QSpinBox does not call this function for specialValueText()
517     and that neither prefix() nor suffix() should be included in the
518     return value.
519 
520     If you reimplement this, you may also need to reimplement
521     valueFromText() and validate()
522 
523     \sa valueFromText(), validate(), QLocale::groupSeparator()
524 */
525 
textFromValue(int value) const526 QString QSpinBox::textFromValue(int value) const
527 {
528     Q_D(const QSpinBox);
529     QString str;
530 
531     if (d->displayIntegerBase != 10) {
532         const QLatin1String prefix = value < 0 ? QLatin1String("-") : QLatin1String();
533         str = prefix + QString::number(qAbs(value), d->displayIntegerBase);
534     } else {
535         str = locale().toString(value);
536         if (!d->showGroupSeparator && (qAbs(value) >= 1000 || value == INT_MIN)) {
537             str.remove(locale().groupSeparator());
538         }
539     }
540 
541     return str;
542 }
543 
544 /*!
545     \fn int QSpinBox::valueFromText(const QString &text) const
546 
547     This virtual function is used by the spin box whenever it needs to
548     interpret \a text entered by the user as a value.
549 
550     Subclasses that need to display spin box values in a non-numeric
551     way need to reimplement this function.
552 
553     Note: QSpinBox handles specialValueText() separately; this
554     function is only concerned with the other values.
555 
556     \sa textFromValue(), validate()
557 */
558 
valueFromText(const QString & text) const559 int QSpinBox::valueFromText(const QString &text) const
560 {
561     Q_D(const QSpinBox);
562 
563     QString copy = text;
564     int pos = d->edit->cursorPosition();
565     QValidator::State state = QValidator::Acceptable;
566     return d->validateAndInterpret(copy, pos, state).toInt();
567 }
568 
569 /*!
570   \reimp
571 */
validate(QString & text,int & pos) const572 QValidator::State QSpinBox::validate(QString &text, int &pos) const
573 {
574     Q_D(const QSpinBox);
575 
576     QValidator::State state;
577     d->validateAndInterpret(text, pos, state);
578     return state;
579 }
580 
581 
582 /*!
583   \reimp
584 */
fixup(QString & input) const585 void QSpinBox::fixup(QString &input) const
586 {
587     if (!isGroupSeparatorShown())
588         input.remove(locale().groupSeparator());
589 }
590 
591 
592 // --- QDoubleSpinBox ---
593 
594 /*!
595     \class QDoubleSpinBox
596     \brief The QDoubleSpinBox class provides a spin box widget that
597     takes doubles.
598 
599     \ingroup basicwidgets
600     \inmodule QtWidgets
601 
602     QDoubleSpinBox allows the user to choose a value by clicking the
603     up and down buttons or by pressing Up or Down on the keyboard to
604     increase or decrease the value currently displayed. The user can
605     also type the value in manually. The spin box supports double
606     values but can be extended to use different strings with
607     validate(), textFromValue() and valueFromText().
608 
609     Every time the value changes QDoubleSpinBox emits valueChanged() and
610     textChanged() signals, the former providing a double and the latter
611     a QString. The textChanged() signal provides the value with both
612     prefix() and suffix(). The current value can be fetched with
613     value() and set with setValue().
614 
615     Note: QDoubleSpinBox will round numbers so they can be displayed
616     with the current precision. In a QDoubleSpinBox with decimals set
617     to 2, calling setValue(2.555) will cause value() to return 2.56.
618 
619     Clicking the up and down buttons or using the keyboard accelerator's
620     Up and Down arrows will increase or decrease the current value in
621     steps of size singleStep(). If you want to change this behavior you
622     can reimplement the virtual function stepBy(). The minimum and
623     maximum value and the step size can be set using one of the
624     constructors, and can be changed later with setMinimum(),
625     setMaximum() and setSingleStep(). The spinbox has a default
626     precision of 2 decimal places but this can be changed using
627     setDecimals().
628 
629     Most spin boxes are directional, but QDoubleSpinBox can also
630     operate as a circular spin box, i.e. if the range is 0.0-99.9 and
631     the current value is 99.9, clicking "up" will give 0 if wrapping()
632     is set to true. Use setWrapping() if you want circular behavior.
633 
634     The displayed value can be prepended and appended with arbitrary
635     strings indicating, for example, currency or the unit of
636     measurement. See setPrefix() and setSuffix(). The text in the spin
637     box is retrieved with text() (which includes any prefix() and
638     suffix()), or with cleanText() (which has no prefix(), no suffix()
639     and no leading or trailing whitespace).
640 
641     It is often desirable to give the user a special (often default)
642     choice in addition to the range of numeric values. See
643     setSpecialValueText() for how to do this with QDoubleSpinBox.
644 
645     \note The displayed value of the QDoubleSpinBox is limited to 18 characters
646     in addition to eventual prefix and suffix content. This limitation is used
647     to keep the double spin box usable even with extremely large values.
648     \sa QSpinBox, QDateTimeEdit, QSlider, {Spin Boxes Example}
649 */
650 
651 /*!
652     \fn void QDoubleSpinBox::valueChanged(double d);
653 
654     This signal is emitted whenever the spin box's value is changed.
655     The new value is passed in \a d.
656 */
657 
658 /*!
659     \fn void QDoubleSpinBox::textChanged(const QString &text)
660     \since 5.14
661 
662     This signal is emitted whenever the spin box's text is changed.
663     The new text is passed in \a text with prefix() and suffix().
664 */
665 
666 #if QT_DEPRECATED_SINCE(5, 14)
667 /*!
668     \fn void QDoubleSpinBox::valueChanged(const QString &text);
669 
670     \overload
671     \obsolete Use textChanged(QString) instead
672 
673     The new value is passed in \a text with prefix() and suffix().
674 */
675 #endif
676 
677 /*!
678     Constructs a spin box with 0.0 as minimum value and 99.99 as maximum value,
679     a step value of 1.0 and a precision of 2 decimal places. The value is
680     initially set to 0.00. The spin box has the given \a parent.
681 
682     \sa setMinimum(), setMaximum(), setSingleStep()
683 */
QDoubleSpinBox(QWidget * parent)684 QDoubleSpinBox::QDoubleSpinBox(QWidget *parent)
685     : QAbstractSpinBox(*new QDoubleSpinBoxPrivate, parent)
686 {
687     Q_D(QDoubleSpinBox);
688     d->init();
689 }
690 
691 /*!
692     Destructor.
693 */
~QDoubleSpinBox()694 QDoubleSpinBox::~QDoubleSpinBox() {}
695 
696 /*!
697     \property QDoubleSpinBox::value
698     \brief the value of the spin box
699 
700     setValue() will emit valueChanged() if the new value is different
701     from the old one. The value property has a second notifier
702     signal which includes the spin box's prefix and suffix.
703 
704     Note: The value will be rounded so it can be displayed with the
705     current setting of decimals.
706 
707     \sa decimals
708 */
value() const709 double QDoubleSpinBox::value() const
710 {
711     Q_D(const QDoubleSpinBox);
712 
713     return d->value.toDouble();
714 }
715 
setValue(double value)716 void QDoubleSpinBox::setValue(double value)
717 {
718     Q_D(QDoubleSpinBox);
719     QVariant v(d->round(value));
720     d->setValue(v, EmitIfChanged);
721 }
722 /*!
723     \property QDoubleSpinBox::prefix
724     \brief the spin box's prefix
725 
726     The prefix is prepended to the start of the displayed value.
727     Typical use is to display a unit of measurement or a currency
728     symbol. For example:
729 
730     \snippet code/src_gui_widgets_qspinbox.cpp 4
731 
732     To turn off the prefix display, set this property to an empty
733     string. The default is no prefix. The prefix is not displayed when
734     value() == minimum() and specialValueText() is set.
735 
736     If no prefix is set, prefix() returns an empty string.
737 
738     \sa suffix(), setSuffix(), specialValueText(), setSpecialValueText()
739 */
740 
prefix() const741 QString QDoubleSpinBox::prefix() const
742 {
743     Q_D(const QDoubleSpinBox);
744 
745     return d->prefix;
746 }
747 
setPrefix(const QString & prefix)748 void QDoubleSpinBox::setPrefix(const QString &prefix)
749 {
750     Q_D(QDoubleSpinBox);
751 
752     d->prefix = prefix;
753     d->updateEdit();
754 
755     d->cachedSizeHint = QSize();
756     d->cachedMinimumSizeHint = QSize(); // minimumSizeHint cares about the prefix
757     updateGeometry();
758 }
759 
760 /*!
761     \property QDoubleSpinBox::suffix
762     \brief the suffix of the spin box
763 
764     The suffix is appended to the end of the displayed value. Typical
765     use is to display a unit of measurement or a currency symbol. For
766     example:
767 
768     \snippet code/src_gui_widgets_qspinbox.cpp 5
769 
770     To turn off the suffix display, set this property to an empty
771     string. The default is no suffix. The suffix is not displayed for
772     the minimum() if specialValueText() is set.
773 
774     If no suffix is set, suffix() returns an empty string.
775 
776     \sa prefix(), setPrefix(), specialValueText(), setSpecialValueText()
777 */
778 
suffix() const779 QString QDoubleSpinBox::suffix() const
780 {
781     Q_D(const QDoubleSpinBox);
782 
783     return d->suffix;
784 }
785 
setSuffix(const QString & suffix)786 void QDoubleSpinBox::setSuffix(const QString &suffix)
787 {
788     Q_D(QDoubleSpinBox);
789 
790     d->suffix = suffix;
791     d->updateEdit();
792 
793     d->cachedSizeHint = QSize();
794     updateGeometry();
795 }
796 
797 /*!
798     \property QDoubleSpinBox::cleanText
799 
800     \brief the text of the spin box excluding any prefix, suffix,
801     or leading or trailing whitespace.
802 
803     \sa text, QDoubleSpinBox::prefix, QDoubleSpinBox::suffix
804 */
805 
cleanText() const806 QString QDoubleSpinBox::cleanText() const
807 {
808     Q_D(const QDoubleSpinBox);
809 
810     return d->stripped(d->edit->displayText());
811 }
812 
813 /*!
814     \property QDoubleSpinBox::singleStep
815     \brief the step value
816 
817     When the user uses the arrows to change the spin box's value the
818     value will be incremented/decremented by the amount of the
819     singleStep. The default value is 1.0. Setting a singleStep value
820     of less than 0 does nothing.
821 */
singleStep() const822 double QDoubleSpinBox::singleStep() const
823 {
824     Q_D(const QDoubleSpinBox);
825 
826     return d->singleStep.toDouble();
827 }
828 
setSingleStep(double value)829 void QDoubleSpinBox::setSingleStep(double value)
830 {
831     Q_D(QDoubleSpinBox);
832 
833     if (value >= 0) {
834         d->singleStep = value;
835         d->updateEdit();
836     }
837 }
838 
839 /*!
840     \property QDoubleSpinBox::minimum
841 
842     \brief the minimum value of the spin box
843 
844     When setting this property the \l maximum is adjusted
845     if necessary to ensure that the range remains valid.
846 
847     The default minimum value is 0.0.
848 
849     Note: The minimum value will be rounded to match the decimals
850     property.
851 
852     \sa decimals, setRange(), specialValueText
853 */
854 
minimum() const855 double QDoubleSpinBox::minimum() const
856 {
857     Q_D(const QDoubleSpinBox);
858 
859     return d->minimum.toDouble();
860 }
861 
setMinimum(double minimum)862 void QDoubleSpinBox::setMinimum(double minimum)
863 {
864     Q_D(QDoubleSpinBox);
865     d->actualMin = minimum;
866     const QVariant m(d->round(minimum));
867     d->setRange(m, (QDoubleSpinBoxPrivate::variantCompare(d->maximum, m) > 0 ? d->maximum : m));
868 }
869 
870 /*!
871     \property QDoubleSpinBox::maximum
872 
873     \brief the maximum value of the spin box
874 
875     When setting this property the \l minimum is adjusted
876     if necessary, to ensure that the range remains valid.
877 
878     The default maximum value is 99.99.
879 
880     Note: The maximum value will be rounded to match the decimals
881     property.
882 
883     \sa decimals, setRange()
884 */
885 
maximum() const886 double QDoubleSpinBox::maximum() const
887 {
888     Q_D(const QDoubleSpinBox);
889 
890     return d->maximum.toDouble();
891 }
892 
setMaximum(double maximum)893 void QDoubleSpinBox::setMaximum(double maximum)
894 {
895     Q_D(QDoubleSpinBox);
896     d->actualMax = maximum;
897     const QVariant m(d->round(maximum));
898     d->setRange((QDoubleSpinBoxPrivate::variantCompare(d->minimum, m) < 0 ? d->minimum : m), m);
899 }
900 
901 /*!
902     Convenience function to set the \a minimum and \a maximum values
903     with a single function call.
904 
905     Note: The maximum and minimum values will be rounded to match the
906     decimals property.
907 
908     \snippet code/src_gui_widgets_qspinbox.cpp 6
909     is equivalent to:
910     \snippet code/src_gui_widgets_qspinbox.cpp 7
911 
912     \sa minimum, maximum
913 */
914 
setRange(double minimum,double maximum)915 void QDoubleSpinBox::setRange(double minimum, double maximum)
916 {
917     Q_D(QDoubleSpinBox);
918     d->actualMin = minimum;
919     d->actualMax = maximum;
920     d->setRange(QVariant(d->round(minimum)), QVariant(d->round(maximum)));
921 }
922 
923 /*!
924     Sets the step type for the spin box to \a stepType, which is single
925     step or adaptive decimal step.
926 
927     Adaptive decimal step means that the step size will continuously be
928     adjusted to one power of ten below the current \l value. So when
929     the value is 1100, the step is set to 100, so stepping up once
930     increases it to 1200. For 1200 stepping up takes it to 1300. For
931     negative values, stepping down from -1100 goes to -1200.
932 
933     It also works for any decimal values, 0.041 is increased to 0.042
934     by stepping once.
935 
936     Step direction is taken into account to handle edges cases, so
937     that stepping down from 100 takes the value to 99 instead of 90.
938     Thus a step up followed by a step down -- or vice versa -- always
939     lands on the starting value; 99 -> 100 -> 99.
940 
941     Setting this will cause the spin box to disregard the value of
942     \l singleStep, although it is preserved so that \l singleStep
943     comes into effect if adaptive decimal step is later turned off.
944 
945     \since 5.12
946 */
947 
setStepType(StepType stepType)948 void QDoubleSpinBox::setStepType(StepType stepType)
949 {
950     Q_D(QDoubleSpinBox);
951     d->stepType = stepType;
952 }
953 
954 /*!
955     \property QDoubleSpinBox::stepType
956     \brief The step type.
957 
958     The step type can be single step or adaptive decimal step.
959 */
960 
stepType() const961 QAbstractSpinBox::StepType QDoubleSpinBox::stepType() const
962 {
963     Q_D(const QDoubleSpinBox);
964     return d->stepType;
965 }
966 
967 /*!
968      \property QDoubleSpinBox::decimals
969 
970      \brief the precision of the spin box, in decimals
971 
972      Sets how many decimals the spinbox will use for displaying and
973      interpreting doubles.
974 
975      \warning The maximum value for \a decimals is DBL_MAX_10_EXP +
976      DBL_DIG (ie. 323) because of the limitations of the double type.
977 
978      Note: The maximum, minimum and value might change as a result of
979      changing this property.
980 */
981 
decimals() const982 int QDoubleSpinBox::decimals() const
983 {
984     Q_D(const QDoubleSpinBox);
985 
986     return d->decimals;
987 }
988 
setDecimals(int decimals)989 void QDoubleSpinBox::setDecimals(int decimals)
990 {
991     Q_D(QDoubleSpinBox);
992     d->decimals = qBound(0, decimals, DBL_MAX_10_EXP + DBL_DIG);
993 
994     setRange(d->actualMin, d->actualMax); // make sure values are rounded
995     setValue(value());
996 }
997 
998 /*!
999     This virtual function is used by the spin box whenever it needs to
1000     display the given \a value. The default implementation returns a string
1001     containing \a value printed using QWidget::locale().toString(\a value,
1002     QLatin1Char('f'), decimals()) and will remove the thousand
1003     separator unless setGroupSeparatorShown() is set. Reimplementations may
1004     return anything.
1005 
1006     Note: QDoubleSpinBox does not call this function for
1007     specialValueText() and that neither prefix() nor suffix() should
1008     be included in the return value.
1009 
1010     If you reimplement this, you may also need to reimplement
1011     valueFromText().
1012 
1013     \sa valueFromText(), QLocale::groupSeparator()
1014 */
1015 
1016 
textFromValue(double value) const1017 QString QDoubleSpinBox::textFromValue(double value) const
1018 {
1019     Q_D(const QDoubleSpinBox);
1020     QString str = locale().toString(value, 'f', d->decimals);
1021     if (!d->showGroupSeparator && qAbs(value) >= 1000.0)
1022         str.remove(locale().groupSeparator());
1023 
1024     return str;
1025 }
1026 
1027 /*!
1028     This virtual function is used by the spin box whenever it needs to
1029     interpret \a text entered by the user as a value.
1030 
1031     Subclasses that need to display spin box values in a non-numeric
1032     way need to reimplement this function.
1033 
1034     Note: QDoubleSpinBox handles specialValueText() separately; this
1035     function is only concerned with the other values.
1036 
1037     \sa textFromValue(), validate()
1038 */
valueFromText(const QString & text) const1039 double QDoubleSpinBox::valueFromText(const QString &text) const
1040 {
1041     Q_D(const QDoubleSpinBox);
1042 
1043     QString copy = text;
1044     int pos = d->edit->cursorPosition();
1045     QValidator::State state = QValidator::Acceptable;
1046     return d->validateAndInterpret(copy, pos, state).toDouble();
1047 }
1048 
1049 /*!
1050   \reimp
1051 */
validate(QString & text,int & pos) const1052 QValidator::State QDoubleSpinBox::validate(QString &text, int &pos) const
1053 {
1054     Q_D(const QDoubleSpinBox);
1055 
1056     QValidator::State state;
1057     d->validateAndInterpret(text, pos, state);
1058     return state;
1059 }
1060 
1061 
1062 /*!
1063   \reimp
1064 */
fixup(QString & input) const1065 void QDoubleSpinBox::fixup(QString &input) const
1066 {
1067     input.remove(locale().groupSeparator());
1068 }
1069 
1070 // --- QSpinBoxPrivate ---
1071 
1072 /*!
1073     \internal
1074     Constructs a QSpinBoxPrivate object
1075 */
1076 
QSpinBoxPrivate()1077 QSpinBoxPrivate::QSpinBoxPrivate()
1078 {
1079     minimum = QVariant((int)0);
1080     maximum = QVariant((int)99);
1081     value = minimum;
1082     displayIntegerBase = 10;
1083     singleStep = QVariant((int)1);
1084     type = QMetaType::Int;
1085 }
1086 
1087 /*!
1088     \internal
1089     \reimp
1090 */
1091 
emitSignals(EmitPolicy ep,const QVariant & old)1092 void QSpinBoxPrivate::emitSignals(EmitPolicy ep, const QVariant &old)
1093 {
1094     Q_Q(QSpinBox);
1095     if (ep != NeverEmit) {
1096         pendingEmit = false;
1097         if (ep == AlwaysEmit || value != old) {
1098 #if QT_DEPRECATED_SINCE(5, 14)
1099 QT_WARNING_PUSH
1100 QT_WARNING_DISABLE_DEPRECATED
1101             emit q->valueChanged(edit->displayText());
1102 QT_WARNING_POP
1103 #endif
1104             emit q->textChanged(edit->displayText());
1105             emit q->valueChanged(value.toInt());
1106         }
1107     }
1108 }
1109 
1110 /*!
1111     \internal
1112     \reimp
1113 */
1114 
textFromValue(const QVariant & value) const1115 QString QSpinBoxPrivate::textFromValue(const QVariant &value) const
1116 {
1117     Q_Q(const QSpinBox);
1118     return q->textFromValue(value.toInt());
1119 }
1120 /*!
1121     \internal
1122     \reimp
1123 */
1124 
valueFromText(const QString & text) const1125 QVariant QSpinBoxPrivate::valueFromText(const QString &text) const
1126 {
1127     Q_Q(const QSpinBox);
1128 
1129     return QVariant(q->valueFromText(text));
1130 }
1131 
1132 
1133 /*!
1134     \internal Multi purpose function that parses input, sets state to
1135     the appropriate state and returns the value it will be interpreted
1136     as.
1137 */
1138 
validateAndInterpret(QString & input,int & pos,QValidator::State & state) const1139 QVariant QSpinBoxPrivate::validateAndInterpret(QString &input, int &pos,
1140                                                QValidator::State &state) const
1141 {
1142     if (cachedText == input && !input.isEmpty()) {
1143         state = cachedState;
1144         QSBDEBUG() << "cachedText was '" << cachedText << "' state was "
1145                    << state << " and value was " << cachedValue;
1146 
1147         return cachedValue;
1148     }
1149     const int max = maximum.toInt();
1150     const int min = minimum.toInt();
1151 
1152     QString copy = stripped(input, &pos);
1153     QSBDEBUG() << "input" << input << "copy" << copy;
1154     state = QValidator::Acceptable;
1155     int num = min;
1156 
1157     if (max != min && (copy.isEmpty()
1158                        || (min < 0 && copy == QLatin1String("-"))
1159                        || (max >= 0 && copy == QLatin1String("+")))) {
1160         state = QValidator::Intermediate;
1161         QSBDEBUG() << __FILE__ << __LINE__<< "num is set to" << num;
1162     } else if (copy.startsWith(QLatin1Char('-')) && min >= 0) {
1163         state = QValidator::Invalid; // special-case -0 will be interpreted as 0 and thus not be invalid with a range from 0-100
1164     } else {
1165         bool ok = false;
1166         if (displayIntegerBase != 10) {
1167             num = copy.toInt(&ok, displayIntegerBase);
1168         } else {
1169             num = locale.toInt(copy, &ok);
1170             if (!ok && (max >= 1000 || min <= -1000)) {
1171                 const QString sep(locale.groupSeparator());
1172                 const QString doubleSep = sep + sep;
1173                 if (copy.contains(sep) && !copy.contains(doubleSep)) {
1174                     QString copy2 = copy;
1175                     copy2.remove(sep);
1176                     num = locale.toInt(copy2, &ok);
1177                 }
1178             }
1179         }
1180         QSBDEBUG() << __FILE__ << __LINE__<< "num is set to" << num;
1181         if (!ok) {
1182             state = QValidator::Invalid;
1183         } else if (num >= min && num <= max) {
1184             state = QValidator::Acceptable;
1185         } else if (max == min) {
1186             state = QValidator::Invalid;
1187         } else {
1188             if ((num >= 0 && num > max) || (num < 0 && num < min)) {
1189                 state = QValidator::Invalid;
1190                 QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Invalid";
1191             } else {
1192                 state = QValidator::Intermediate;
1193                 QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Intermediate";
1194             }
1195         }
1196     }
1197     if (state != QValidator::Acceptable)
1198         num = max > 0 ? min : max;
1199     input = prefix + copy + suffix;
1200     cachedText = input;
1201     cachedState = state;
1202     cachedValue = QVariant((int)num);
1203 
1204     QSBDEBUG() << "cachedText is set to '" << cachedText << "' state is set to "
1205                << state << " and value is set to " << cachedValue;
1206     return cachedValue;
1207 }
1208 
calculateAdaptiveDecimalStep(int steps) const1209 QVariant QSpinBoxPrivate::calculateAdaptiveDecimalStep(int steps) const
1210 {
1211     const int intValue = value.toInt();
1212     const int absValue = qAbs(intValue);
1213 
1214     if (absValue < 100)
1215         return 1;
1216 
1217     const bool valueNegative = intValue < 0;
1218     const bool stepsNegative = steps < 0;
1219     const int signCompensation = (valueNegative == stepsNegative) ? 0 : 1;
1220 
1221     const int log = static_cast<int>(std::log10(absValue - signCompensation)) - 1;
1222     return static_cast<int>(std::pow(10, log));
1223 }
1224 
1225 // --- QDoubleSpinBoxPrivate ---
1226 
1227 /*!
1228     \internal
1229     Constructs a QSpinBoxPrivate object
1230 */
1231 
QDoubleSpinBoxPrivate()1232 QDoubleSpinBoxPrivate::QDoubleSpinBoxPrivate()
1233 {
1234     actualMin = 0.0;
1235     actualMax = 99.99;
1236     minimum = QVariant(actualMin);
1237     maximum = QVariant(actualMax);
1238     value = minimum;
1239     singleStep = QVariant(1.0);
1240     decimals = 2;
1241     type = QMetaType::Double;
1242 }
1243 
1244 /*!
1245     \internal
1246     \reimp
1247 */
1248 
emitSignals(EmitPolicy ep,const QVariant & old)1249 void QDoubleSpinBoxPrivate::emitSignals(EmitPolicy ep, const QVariant &old)
1250 {
1251     Q_Q(QDoubleSpinBox);
1252     if (ep != NeverEmit) {
1253         pendingEmit = false;
1254         if (ep == AlwaysEmit || value != old) {
1255 #if QT_DEPRECATED_SINCE(5, 14)
1256 QT_WARNING_PUSH
1257 QT_WARNING_DISABLE_DEPRECATED
1258             emit q->valueChanged(edit->displayText());
1259 QT_WARNING_POP
1260 #endif
1261             emit q->textChanged(edit->displayText());
1262             emit q->valueChanged(value.toDouble());
1263         }
1264     }
1265 }
1266 
1267 
1268 /*!
1269     \internal
1270     \reimp
1271 */
valueFromText(const QString & f) const1272 QVariant QDoubleSpinBoxPrivate::valueFromText(const QString &f) const
1273 {
1274     Q_Q(const QDoubleSpinBox);
1275     return QVariant(q->valueFromText(f));
1276 }
1277 
1278 /*!
1279     \internal
1280     Rounds to a double value that is restricted to decimals.
1281     E.g. // decimals = 2
1282 
1283     round(5.555) => 5.56
1284     */
1285 
round(double value) const1286 double QDoubleSpinBoxPrivate::round(double value) const
1287 {
1288     return QString::number(value, 'f', decimals).toDouble();
1289 }
1290 
1291 
1292 /*!
1293     \internal Multi purpose function that parses input, sets state to
1294     the appropriate state and returns the value it will be interpreted
1295     as.
1296 */
1297 
validateAndInterpret(QString & input,int & pos,QValidator::State & state) const1298 QVariant QDoubleSpinBoxPrivate::validateAndInterpret(QString &input, int &pos,
1299                                                      QValidator::State &state) const
1300 {
1301     if (cachedText == input && !input.isEmpty()) {
1302         state = cachedState;
1303         QSBDEBUG() << "cachedText was '" << cachedText << "' state was "
1304                    << state << " and value was " << cachedValue;
1305         return cachedValue;
1306     }
1307     const double max = maximum.toDouble();
1308     const double min = minimum.toDouble();
1309 
1310     QString copy = stripped(input, &pos);
1311     QSBDEBUG() << "input" << input << "copy" << copy;
1312     int len = copy.size();
1313     double num = min;
1314     const bool plus = max >= 0;
1315     const bool minus = min <= 0;
1316 
1317     const QString group(locale.groupSeparator());
1318     const uint groupUcs = (group.size() > 1 && group.at(0).isHighSurrogate()
1319                            ? QChar::surrogateToUcs4(group.at(0), group.at(1))
1320                            : group.at(0).unicode());
1321     switch (len) {
1322     case 0:
1323         state = max != min ? QValidator::Intermediate : QValidator::Invalid;
1324         goto end;
1325     case 1:
1326         if (copy.at(0) == locale.decimalPoint()
1327             || (plus && copy.at(0) == QLatin1Char('+'))
1328             || (minus && copy.at(0) == QLatin1Char('-'))) {
1329             state = QValidator::Intermediate;
1330             goto end;
1331         }
1332         break;
1333     case 2:
1334         if (copy.at(1) == locale.decimalPoint()
1335             && ((plus && copy.at(0) == QLatin1Char('+')) || (minus && copy.at(0) == QLatin1Char('-')))) {
1336             state = QValidator::Intermediate;
1337             goto end;
1338         }
1339         break;
1340     default: break;
1341     }
1342 
1343     if (copy.at(0) == locale.groupSeparator()) {
1344         QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Invalid";
1345         state = QValidator::Invalid;
1346         goto end;
1347     } else if (len > 1) {
1348         const int dec = copy.indexOf(locale.decimalPoint());
1349         if (dec != -1) {
1350             if (dec + 1 < copy.size() && copy.at(dec + 1) == locale.decimalPoint() && pos == dec + 1) {
1351                 copy.remove(dec + 1, 1); // typing a delimiter when you are on the delimiter
1352             } // should be treated as typing right arrow
1353 
1354             if (copy.size() - dec > decimals + 1) {
1355                 QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Invalid";
1356                 state = QValidator::Invalid;
1357                 goto end;
1358             }
1359             for (int i=dec + 1; i<copy.size(); ++i) {
1360                 if (copy.at(i).isSpace() || copy.at(i) == locale.groupSeparator()) {
1361                     QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Invalid";
1362                     state = QValidator::Invalid;
1363                     goto end;
1364                 }
1365             }
1366         } else {
1367             const QChar last = copy.back();
1368             const bool groupEnd = copy.endsWith(group);
1369             const QStringView head(copy.constData(), groupEnd ? len - group.size() : len - 1);
1370             const QChar secondLast = head.back();
1371             if ((groupEnd || last.isSpace()) && (head.endsWith(group) || secondLast.isSpace())) {
1372                 state = QValidator::Invalid;
1373                 QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Invalid";
1374                 goto end;
1375             } else if (last.isSpace() && (!QChar::isSpace(groupUcs) || secondLast.isSpace())) {
1376                 state = QValidator::Invalid;
1377                 QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Invalid";
1378                 goto end;
1379             }
1380         }
1381     }
1382 
1383     {
1384         bool ok = false;
1385         num = locale.toDouble(copy, &ok);
1386         QSBDEBUG() << __FILE__ << __LINE__ << locale << copy << num << ok;
1387 
1388         if (!ok) {
1389             if (QChar::isPrint(groupUcs)) {
1390                 if (max < 1000 && min > -1000 && copy.contains(group)) {
1391                     state = QValidator::Invalid;
1392                     QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Invalid";
1393                     goto end;
1394                 }
1395 
1396                 const int len = copy.size();
1397                 for (int i = 0; i < len - 1;) {
1398                     if (QStringView(copy).mid(i).startsWith(group)) {
1399                         if (QStringView(copy).mid(i + group.size()).startsWith(group)) {
1400                             QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Invalid";
1401                             state = QValidator::Invalid;
1402                             goto end;
1403                         }
1404                         i += group.size();
1405                     } else {
1406                         i++;
1407                     }
1408                 }
1409 
1410                 QString copy2 = copy;
1411                 copy2.remove(group);
1412                 num = locale.toDouble(copy2, &ok);
1413                 QSBDEBUG() << group << num << copy2 << ok;
1414 
1415                 if (!ok) {
1416                     state = QValidator::Invalid;
1417                     QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Invalid";
1418                     goto end;
1419                 }
1420             }
1421         }
1422 
1423         if (!ok) {
1424             state = QValidator::Invalid;
1425             QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Invalid";
1426         } else if (num >= min && num <= max) {
1427             state = QValidator::Acceptable;
1428             QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Acceptable";
1429         } else if (max == min) { // when max and min is the same the only non-Invalid input is max (or min)
1430             state = QValidator::Invalid;
1431             QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Invalid";
1432         } else {
1433             if ((num >= 0 && num > max) || (num < 0 && num < min)) {
1434                 state = QValidator::Invalid;
1435                 QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Invalid";
1436             } else {
1437                 state = QValidator::Intermediate;
1438                 QSBDEBUG() << __FILE__ << __LINE__<< "state is set to Intermediate";
1439             }
1440         }
1441     }
1442 
1443 end:
1444     if (state != QValidator::Acceptable) {
1445         num = max > 0 ? min : max;
1446     }
1447 
1448     input = prefix + copy + suffix;
1449     cachedText = input;
1450     cachedState = state;
1451     cachedValue = QVariant(num);
1452     return QVariant(num);
1453 }
1454 
1455 /*
1456     \internal
1457     \reimp
1458 */
1459 
textFromValue(const QVariant & f) const1460 QString QDoubleSpinBoxPrivate::textFromValue(const QVariant &f) const
1461 {
1462     Q_Q(const QDoubleSpinBox);
1463     return q->textFromValue(f.toDouble());
1464 }
1465 
calculateAdaptiveDecimalStep(int steps) const1466 QVariant QDoubleSpinBoxPrivate::calculateAdaptiveDecimalStep(int steps) const
1467 {
1468     const double doubleValue = value.toDouble();
1469     const double minStep = std::pow(10, -decimals);
1470     double absValue = qAbs(doubleValue);
1471 
1472     if (absValue < minStep)
1473         return minStep;
1474 
1475     const bool valueNegative = doubleValue < 0;
1476     const bool stepsNegative = steps < 0;
1477     if (valueNegative != stepsNegative)
1478         absValue /= 1.01;
1479 
1480     const double shift = std::pow(10, 1 - std::floor(std::log10(absValue)));
1481     const double absRounded = round(absValue * shift) / shift;
1482     const double log = floorf(std::log10(absRounded)) - 1;
1483 
1484     return std::max(minStep, std::pow(10, log));
1485 }
1486 
1487 /*! \reimp */
event(QEvent * event)1488 bool QSpinBox::event(QEvent *event)
1489 {
1490     Q_D(QSpinBox);
1491     if (event->type() == QEvent::StyleChange
1492 #ifdef Q_OS_MAC
1493             || event->type() == QEvent::MacSizeChange
1494 #endif
1495             )
1496         d->setLayoutItemMargins(QStyle::SE_SpinBoxLayoutItem);
1497     return QAbstractSpinBox::event(event);
1498 }
1499 
1500 QT_END_NAMESPACE
1501 
1502 #include "moc_qspinbox.cpp"
1503