Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qquickspinbox.cpp
Go to the documentation of this file.
1// Copyright (C) 2017 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
6
7#include <private/qquickcontrol_p_p.h>
8#include <private/qquickindicatorbutton_p.h>
9#include <private/qquicktextinput_p.h>
10
11#include <private/qqmlengine_p.h>
12
13#include <QtQml/qqmlinfo.h>
14
16
17// copied from qabstractbutton.cpp
18static const int AUTO_REPEAT_DELAY = 300;
19static const int AUTO_REPEAT_INTERVAL = 100;
20
21/*!
22 \qmltype SpinBox
23 \inherits Control
24//! \nativetype QQuickSpinBox
25 \inqmlmodule QtQuick.Controls
26 \since 5.7
27 \ingroup qtquickcontrols-input
28 \ingroup qtquickcontrols-focusscopes
29 \brief Allows the user to select from a set of preset values.
30
31 \image qtquickcontrols-spinbox.png
32
33 SpinBox allows the user to choose an integer value by clicking the up
34 or down indicator buttons, or by pressing up or down on the keyboard.
35 Optionally, SpinBox can be also made \l editable, so the user can enter
36 a text value in the input field.
37
38 By default, SpinBox provides discrete values in the range of \c [0-99]
39 with a \l stepSize of \c 1.
40
41 \snippet qtquickcontrols-spinbox.qml 1
42
43 \section2 Custom Values
44
45 \image qtquickcontrols-spinbox-textual.png
46
47 Even though SpinBox works on integer values, it can be customized to
48 accept arbitrary input values. The following snippet demonstrates how
49 \l validator, \l textFromValue and \l valueFromText can be used to
50 customize the default behavior.
51
52 \snippet qtquickcontrols-spinbox-textual.qml 1
53
54 In the same manner, SpinBox can be customized to accept floating point
55 numbers:
56
57 \image qtquickcontrols-spinbox-double.png
58
59 \snippet qtquickcontrols-spinbox-double.qml 1
60
61 A prefix and suffix can be added using regular expressions:
62
63 \snippet qtquickcontrols-spinbox-prefix.qml 1
64
65 \sa Tumbler, {Customizing SpinBox}, {Focus Management in Qt Quick Controls}
66*/
67
68/*!
69 \since QtQuick.Controls 2.2 (Qt 5.9)
70 \qmlsignal QtQuick.Controls::SpinBox::valueModified()
71
72 This signal is emitted when the spin box value has been interactively
73 modified by the user by either touch, mouse, wheel, or keys.
74 In the case of interaction via keyboard, the signal is only emitted
75 when the text has been accepted; meaning when the enter or return keys
76 are pressed, or the input field loses focus.
77*/
78
80{
81 Q_DECLARE_PUBLIC(QQuickSpinBox)
82
83public:
84 int boundValue(int value, bool wrap) const;
86 bool setValue(int value, bool wrap, bool modified);
87 bool stepBy(int steps, bool modified);
88 void increase(bool modified);
89 void decrease(bool modified);
90
91 int effectiveStepSize() const;
92
94 void setDisplayText(const QString &displayText);
96
97 bool upEnabled() const;
99 bool downEnabled() const;
101 void updateHover(const QPointF &pos);
102
106
107 bool handlePress(const QPointF &point, ulong timestamp) override;
108 bool handleMove(const QPointF &point, ulong timestamp) override;
109 bool handleRelease(const QPointF &point, ulong timestamp) override;
111
112 void itemImplicitWidthChanged(QQuickItem *item) override;
113 void itemImplicitHeightChanged(QQuickItem *item) override;
114 void itemDestroyed(QQuickItem *item) override;
115
117 int evaluateValueFromText(const QString &text) const;
118
119 QPalette defaultPalette() const override { return QQuickTheme::palette(QQuickTheme::SpinBox); }
120
121 bool editable = false;
122 bool live = false;
123 bool wrap = false;
124 int from = 0;
125 int to = 99;
126 int value = 0;
127 int stepSize = 1;
128 int delayTimer = 0;
129 int repeatTimer = 0;
131 QQuickIndicatorButton *up = nullptr;
132 QQuickIndicatorButton *down = nullptr;
133#if QT_CONFIG(validator)
134 QValidator *validator = nullptr;
135#endif
139};
140
141int QQuickSpinBoxPrivate::boundValue(int value, bool wrap) const
142{
143 bool inverted = from > to;
144 if (!wrap)
145 return inverted ? qBound(to, value, from) : qBound(from, value, to);
146
147 int f = inverted ? to : from;
148 int t = inverted ? from : to;
149 if (value < f)
150 value = t;
151 else if (value > t)
152 value = f;
153
154 return value;
155}
156
158{
159 if (contentItem) {
160 QVariant text = contentItem->property("text");
161 if (text.isValid()) {
162 setValue(evaluateValueFromText(text.toString()), /* allowWrap = */ false, /* modified = */ true);
163 }
164 }
165}
166
167// modified indicates if the value was modified by the user and not programatically
168// this is then passed on to updateDisplayText to indicate that the user has modified
169// the value so it may need to trigger an update of the contentItem's text too
170
171bool QQuickSpinBoxPrivate::setValue(int newValue, bool allowWrap, bool modified)
172{
173 Q_Q(QQuickSpinBox);
174 int correctedValue = newValue;
175 if (q->isComponentComplete())
176 correctedValue = boundValue(newValue, allowWrap);
177
178 if (!modified && newValue == correctedValue && newValue == value)
179 return false;
180
181 const bool emitSignals = (value != correctedValue);
182 value = correctedValue;
183
187
188 // Only emit the signals if the corrected value is not the same as the
189 // original value to avoid unnecessary updates
190 if (emitSignals) {
191 emit q->valueChanged();
192 if (modified)
193 emit q->valueModified();
194 }
195 return true;
196}
197
198bool QQuickSpinBoxPrivate::stepBy(int steps, bool modified)
199{
200 return setValue(value + steps, wrap, modified);
201}
202
203void QQuickSpinBoxPrivate::increase(bool modified)
204{
206}
207
208void QQuickSpinBoxPrivate::decrease(bool modified)
209{
211}
212
214{
215 return from > to ? -1 * stepSize : stepSize;
216}
217
219{
220 setDisplayText(evaluateTextFromValue(value));
221}
222
223void QQuickSpinBoxPrivate::setDisplayText(const QString &text)
224{
225 Q_Q(QQuickSpinBox);
226
227 if (displayText == text)
228 return;
229
230 displayText = text;
231 emit q->displayTextChanged();
232}
233
235{
236 Q_Q(QQuickSpinBox);
237
238 QQuickTextInput *inputTextItem = qobject_cast<QQuickTextInput *>(q->contentItem());
239 if (!inputTextItem)
240 return;
241 QString text = inputTextItem->text();
242#if QT_CONFIG(validator)
243 if (validator && live)
244 validator->fixup(text);
245#endif
246
247 if (live) {
248 const int enteredVal = evaluateValueFromText(text);
249 const int correctedValue = boundValue(enteredVal, false);
250 if (correctedValue == enteredVal && correctedValue != value) {
251 // If live is true and the text is valid change the value
252 // setValue will set the displayText for us.
253 q->setValue(correctedValue);
254 return;
255 }
256 }
257 // If live is false or the value is not valid, just set the displayText
258 setDisplayText(text);
259}
260
262{
263 const QQuickItem *upIndicator = up->indicator();
264 return upIndicator && upIndicator->isEnabled();
265}
266
268{
269 QQuickItem *upIndicator = up->indicator();
270 if (!upIndicator)
271 return;
272
273 upIndicator->setEnabled(wrap || (from < to ? value < to : value > to));
274}
275
277{
278 const QQuickItem *downIndicator = down->indicator();
279 return downIndicator && downIndicator->isEnabled();
280}
281
283{
284 QQuickItem *downIndicator = down->indicator();
285 if (!downIndicator)
286 return;
287
288 downIndicator->setEnabled(wrap || (from < to ? value > from : value < from));
289}
290
291void QQuickSpinBoxPrivate::updateHover(const QPointF &pos)
292{
293 Q_Q(QQuickSpinBox);
294 QQuickItem *ui = up->indicator();
295 QQuickItem *di = down->indicator();
296 up->setHovered(ui && ui->isEnabled() && ui->contains(q->mapToItem(ui, pos)));
297 down->setHovered(di && di->isEnabled() && di->contains(q->mapToItem(di, pos)));
298}
299
301{
302 Q_Q(QQuickSpinBox);
304 delayTimer = q->startTimer(AUTO_REPEAT_DELAY);
305}
306
308{
309 Q_Q(QQuickSpinBox);
311 repeatTimer = q->startTimer(AUTO_REPEAT_INTERVAL);
312}
313
315{
316 Q_Q(QQuickSpinBox);
317 if (delayTimer > 0) {
318 q->killTimer(delayTimer);
319 delayTimer = 0;
320 }
321 if (repeatTimer > 0) {
322 q->killTimer(repeatTimer);
323 repeatTimer = 0;
324 }
325}
326
327bool QQuickSpinBoxPrivate::handlePress(const QPointF &point, ulong timestamp)
328{
329 Q_Q(QQuickSpinBox);
330 QQuickControlPrivate::handlePress(point, timestamp);
331 QQuickItem *ui = up->indicator();
332 QQuickItem *di = down->indicator();
333 up->setPressed(ui && ui->isEnabled() && ui->contains(ui->mapFromItem(q, point)));
334 down->setPressed(di && di->isEnabled() && di->contains(di->mapFromItem(q, point)));
335
336 bool pressed = up->isPressed() || down->isPressed();
337 q->setAccessibleProperty("pressed", pressed);
338 if (pressed)
340 return true;
341}
342
343bool QQuickSpinBoxPrivate::handleMove(const QPointF &point, ulong timestamp)
344{
345 Q_Q(QQuickSpinBox);
346 QQuickControlPrivate::handleMove(point, timestamp);
347 QQuickItem *upIndicator = up->indicator();
348 const bool upIndicatorContainsPoint = upIndicator && upIndicator->isEnabled()
349 && upIndicator->contains(upIndicator->mapFromItem(q, point));
350 up->setHovered(touchId == -1 && upIndicatorContainsPoint);
351 up->setPressed(upIndicatorContainsPoint);
352
353 QQuickItem *downIndicator = down->indicator();
354 const bool downIndicatorContainsPoint = downIndicator && downIndicator->isEnabled()
355 && downIndicator->contains(downIndicator->mapFromItem(q, point));
356 down->setHovered(touchId == -1 && downIndicatorContainsPoint);
357 down->setPressed(downIndicatorContainsPoint);
358
359 bool pressed = up->isPressed() || down->isPressed();
360 q->setAccessibleProperty("pressed", pressed);
361 if (!pressed)
363 return true;
364}
365
366bool QQuickSpinBoxPrivate::handleRelease(const QPointF &point, ulong timestamp)
367{
368 Q_Q(QQuickSpinBox);
369 QQuickControlPrivate::handleRelease(point, timestamp);
370 QQuickItem *ui = up->indicator();
371 QQuickItem *di = down->indicator();
372
373 int oldValue = value;
374 if (up->isPressed()) {
375 if (repeatTimer <= 0 && ui && ui->contains(ui->mapFromItem(q, point)))
376 q->increase();
377 // Retain pressed state until after increasing is done in case user code binds stepSize
378 // to up/down.pressed.
379 up->setPressed(false);
380 } else if (down->isPressed()) {
381 if (repeatTimer <= 0 && di && di->contains(di->mapFromItem(q, point)))
382 q->decrease();
383 down->setPressed(false);
384 }
385 if (value != oldValue)
386 emit q->valueModified();
387
388 q->setAccessibleProperty("pressed", false);
390 return true;
391}
392
394{
395 Q_Q(QQuickSpinBox);
396 QQuickControlPrivate::handleUngrab();
397 up->setPressed(false);
398 down->setPressed(false);
399
400 q->setAccessibleProperty("pressed", false);
402}
403
405{
406 QQuickControlPrivate::itemImplicitWidthChanged(item);
407 if (item == up->indicator())
408 emit up->implicitIndicatorWidthChanged();
409 else if (item == down->indicator())
410 emit down->implicitIndicatorWidthChanged();
411}
412
414{
415 QQuickControlPrivate::itemImplicitHeightChanged(item);
416 if (item == up->indicator())
417 emit up->implicitIndicatorHeightChanged();
418 else if (item == down->indicator())
419 emit down->implicitIndicatorHeightChanged();
420}
421
422void QQuickSpinBoxPrivate::itemDestroyed(QQuickItem *item)
423{
424 QQuickControlPrivate::itemDestroyed(item);
425 if (item == up->indicator())
426 up->setIndicator(nullptr);
427 else if (item == down->indicator())
428 down->setIndicator(nullptr);
429}
430
431
433{
434 Q_Q(const QQuickSpinBox);
435
436 QString text;
437 QQmlEngine *engine = qmlEngine(q);
438 if (engine && textFromValue.isCallable()) {
439 QJSValue loc;
440#if QT_CONFIG(qml_locale)
441 loc = QJSValuePrivate::fromReturnedValue(
442 engine->handle()->fromData(QMetaType::fromType<QLocale>(), &locale));
443#endif
444 text = textFromValue.call(QJSValueList() << val << loc).toString();
445 } else {
446 text = locale.toString(val);
447 }
448 return text;
449}
450
451int QQuickSpinBoxPrivate::evaluateValueFromText(const QString &text) const
452{
453 Q_Q(const QQuickSpinBox);
454 int value;
455 QQmlEngine *engine = qmlEngine(q);
456 if (engine && valueFromText.isCallable()) {
457 QJSValue loc;
458#if QT_CONFIG(qml_locale)
459 loc = QJSValuePrivate::fromReturnedValue(
460 engine->handle()->fromData(QMetaType::fromType<QLocale>(), &locale));
461#endif
462 value = valueFromText.call(QJSValueList() << text << loc).toInt();
463 } else {
464 value = locale.toInt(text);
465 }
466 return value;
467}
468
469QQuickSpinBox::QQuickSpinBox(QQuickItem *parent)
470 : QQuickControl(*(new QQuickSpinBoxPrivate), parent)
471{
472 Q_D(QQuickSpinBox);
473 d->up = new QQuickIndicatorButton(this);
474 d->down = new QQuickIndicatorButton(this);
475 d->setSizePolicy(QLayoutPolicy::Preferred, QLayoutPolicy::Fixed);
476
477 setFlag(ItemIsFocusScope);
478 setFiltersChildMouseEvents(true);
479 setAcceptedMouseButtons(Qt::LeftButton);
480#if QT_CONFIG(cursor)
481 setCursor(Qt::ArrowCursor);
482#endif
483#if QT_CONFIG(quicktemplates2_multitouch)
484 setAcceptTouchEvents(true);
485#endif
486}
487
488QQuickSpinBox::~QQuickSpinBox()
489{
490 Q_D(QQuickSpinBox);
491 d->removeImplicitSizeListener(d->up->indicator());
492 d->removeImplicitSizeListener(d->down->indicator());
493}
494
495/*!
496 \qmlproperty int QtQuick.Controls::SpinBox::from
497
498 This property holds the starting value for the range. The default value is \c 0.
499
500 \sa to, value
501*/
502int QQuickSpinBox::from() const
503{
504 Q_D(const QQuickSpinBox);
505 return d->from;
506}
507
508void QQuickSpinBox::setFrom(int from)
509{
510 Q_D(QQuickSpinBox);
511 if (d->from == from)
512 return;
513
514 d->from = from;
515 emit fromChanged();
516 if (isComponentComplete()) {
517 if (!d->setValue(d->value, /* allowWrap = */ false, /* modified = */ false)) {
518 d->updateUpEnabled();
519 d->updateDownEnabled();
520 }
521 }
522}
523
524/*!
525 \qmlproperty int QtQuick.Controls::SpinBox::to
526
527 This property holds the end value for the range. The default value is \c 99.
528
529 \sa from, value
530*/
531int QQuickSpinBox::to() const
532{
533 Q_D(const QQuickSpinBox);
534 return d->to;
535}
536
537void QQuickSpinBox::setTo(int to)
538{
539 Q_D(QQuickSpinBox);
540 if (d->to == to)
541 return;
542
543 d->to = to;
544 emit toChanged();
545 if (isComponentComplete()) {
546 if (!d->setValue(d->value, /* allowWrap = */false, /* modified = */ false)) {
547 d->updateUpEnabled();
548 d->updateDownEnabled();
549 }
550 }
551}
552
553/*!
554 \qmlproperty int QtQuick.Controls::SpinBox::value
555
556 This property holds the value in the range \c from - \c to. The default value is \c 0.
557*/
558int QQuickSpinBox::value() const
559{
560 Q_D(const QQuickSpinBox);
561 return d->value;
562}
563
564void QQuickSpinBox::setValue(int value)
565{
566 Q_D(QQuickSpinBox);
567 d->setValue(value, /* allowWrap = */ false, /* modified = */ false);
568}
569
570/*!
571 \qmlproperty int QtQuick.Controls::SpinBox::stepSize
572
573 This property holds the step size. The default value is \c 1.
574
575 \sa increase(), decrease()
576*/
577int QQuickSpinBox::stepSize() const
578{
579 Q_D(const QQuickSpinBox);
580 return d->stepSize;
581}
582
583void QQuickSpinBox::setStepSize(int step)
584{
585 Q_D(QQuickSpinBox);
586 if (d->stepSize == step)
587 return;
588
589 d->stepSize = step;
590 emit stepSizeChanged();
591}
592
593/*!
594 \qmlproperty bool QtQuick.Controls::SpinBox::editable
595
596 This property holds whether the spinbox is editable. The default value is \c false.
597
598 \sa validator
599*/
600bool QQuickSpinBox::isEditable() const
601{
602 Q_D(const QQuickSpinBox);
603 return d->editable;
604}
605
606void QQuickSpinBox::setEditable(bool editable)
607{
608 Q_D(QQuickSpinBox);
609 if (d->editable == editable)
610 return;
611
612#if QT_CONFIG(cursor)
613 if (d->contentItem) {
614 if (editable)
615 d->contentItem->setCursor(Qt::IBeamCursor);
616 else
617 d->contentItem->unsetCursor();
618 }
619#endif
620
621 d->editable = editable;
622 setAccessibleProperty("editable", editable);
623 emit editableChanged();
624}
625
626/*!
627 \qmlproperty bool QtQuick.Controls::SpinBox::live
628 \since 6.6
629
630 This property holds whether the \l value is updated when the user edits the
631 \l displayText. The default value is \c false. If this property is \c true and
632 the value entered by the user is valid and within the bounds of the spinbox
633 [\l from, \l to], the value of the SpinBox will be set. If this property is
634 \c false or the value entered by the user is outside the boundaries, the
635 value will not be updated until the enter or return keys are pressed, or the
636 input field loses focus.
637
638 \sa editable, displayText
639*/
640bool QQuickSpinBox::isLive() const
641{
642 Q_D(const QQuickSpinBox);
643 return d->live;
644}
645
646void QQuickSpinBox::setLive(bool live)
647{
648 Q_D(QQuickSpinBox);
649 if (d->live == live)
650 return;
651
652 d->live = live;
653
654 //make sure to update the value when changing to live
655 if (live)
656 d->contentItemTextChanged();
657
658 emit liveChanged();
659}
660
661#if QT_CONFIG(validator)
662/*!
663 \qmlproperty Validator QtQuick.Controls::SpinBox::validator
664
665 This property holds the input text validator for editable spinboxes. By
666 default, SpinBox uses \l IntValidator to accept input of integer numbers.
667
668 \code
669 SpinBox {
670 id: control
671 validator: IntValidator {
672 locale: control.locale.name
673 bottom: Math.min(control.from, control.to)
674 top: Math.max(control.from, control.to)
675 }
676 }
677 \endcode
678
679 \sa editable, textFromValue, valueFromText, {Control::locale}{locale},
680 {Validating Input Text}
681*/
682QValidator *QQuickSpinBox::validator() const
683{
684 Q_D(const QQuickSpinBox);
685 return d->validator;
686}
687
688void QQuickSpinBox::setValidator(QValidator *validator)
689{
690 Q_D(QQuickSpinBox);
691 if (d->validator == validator)
692 return;
693
694 d->validator = validator;
695 emit validatorChanged();
696}
697#endif
698
699/*!
700 \qmlproperty function QtQuick.Controls::SpinBox::textFromValue
701
702 This property holds a callback function that is called whenever
703 an integer value needs to be converted to display text.
704
705 The default function can be overridden to display custom text for a given
706 value. This applies to both editable and non-editable spinboxes;
707 for example, when using the up and down buttons or a mouse wheel to
708 increment and decrement the value, the new value is converted to display
709 text using this function.
710
711 The callback function signature is \c {string function(value, locale)}.
712 The function can have one or two arguments, where the first argument
713 is the value to be converted, and the optional second argument is the
714 locale that should be used for the conversion, if applicable.
715
716 The default implementation does the conversion using
717 \l {QtQml::Number::toLocaleString()}{Number.toLocaleString}():
718
719 \code
720 textFromValue: function(value, locale) { return Number(value).toLocaleString(locale, 'f', 0); }
721 \endcode
722
723 \note When applying a custom \c textFromValue implementation for editable
724 spinboxes, a matching \l valueFromText implementation must be provided
725 to be able to convert the custom text back to an integer value.
726
727 \sa valueFromText, validator, {Control::locale}{locale}
728*/
729QJSValue QQuickSpinBox::textFromValue() const
730{
731 Q_D(const QQuickSpinBox);
732 if (!d->textFromValue.isCallable()) {
733 QQmlEngine *engine = qmlEngine(this);
734 if (engine)
735 d->textFromValue = engine->evaluate(QStringLiteral("(function(value, locale) { return Number(value).toLocaleString(locale, 'f', 0); })"));
736 }
737 return d->textFromValue;
738}
739
740void QQuickSpinBox::setTextFromValue(const QJSValue &callback)
741{
742 Q_D(QQuickSpinBox);
743 if (!callback.isCallable()) {
744 qmlWarning(this) << "textFromValue must be a callable function";
745 return;
746 }
747 d->textFromValue = callback;
748 emit textFromValueChanged();
749}
750
751/*!
752 \qmlproperty function QtQuick.Controls::SpinBox::valueFromText
753
754 This property holds a callback function that is called whenever
755 input text needs to be converted to an integer value.
756
757 This function only needs to be overridden when \l textFromValue
758 is overridden for an editable spinbox.
759
760 The callback function signature is \c {int function(text, locale)}.
761 The function can have one or two arguments, where the first argument
762 is the text to be converted, and the optional second argument is the
763 locale that should be used for the conversion, if applicable.
764
765 The default implementation does the conversion using \l {QtQml::Locale}{Number.fromLocaleString()}:
766
767 \code
768 valueFromText: function(text, locale) { return Number.fromLocaleString(locale, text); }
769 \endcode
770
771 \note When applying a custom \l textFromValue implementation for editable
772 spinboxes, a matching \c valueFromText implementation must be provided
773 to be able to convert the custom text back to an integer value.
774
775 \sa textFromValue, validator, {Control::locale}{locale}
776*/
777QJSValue QQuickSpinBox::valueFromText() const
778{
779 Q_D(const QQuickSpinBox);
780 if (!d->valueFromText.isCallable()) {
781 QQmlEngine *engine = qmlEngine(this);
782 if (engine)
783 d->valueFromText = engine->evaluate(QStringLiteral("(function(text, locale) { return Number.fromLocaleString(locale, text); })"));
784 }
785 return d->valueFromText;
786}
787
788void QQuickSpinBox::setValueFromText(const QJSValue &callback)
789{
790 Q_D(QQuickSpinBox);
791 if (!callback.isCallable()) {
792 qmlWarning(this) << "valueFromText must be a callable function";
793 return;
794 }
795 d->valueFromText = callback;
796 emit valueFromTextChanged();
797}
798
799/*!
800 \qmlproperty bool QtQuick.Controls::SpinBox::up.pressed
801 \qmlproperty Item QtQuick.Controls::SpinBox::up.indicator
802 \qmlproperty bool QtQuick.Controls::SpinBox::up.hovered
803 \qmlproperty real QtQuick.Controls::SpinBox::up.implicitIndicatorWidth
804 \qmlproperty real QtQuick.Controls::SpinBox::up.implicitIndicatorHeight
805
806 These properties hold the up indicator item and whether it is pressed or
807 hovered. The \c up.hovered property was introduced in QtQuick.Controls 2.1,
808 and the \c up.implicitIndicatorWidth and \c up.implicitIndicatorHeight
809 properties were introduced in QtQuick.Controls 2.5.
810
811 \sa increase()
812*/
813QQuickIndicatorButton *QQuickSpinBox::up() const
814{
815 Q_D(const QQuickSpinBox);
816 return d->up;
817}
818
819/*!
820 \qmlproperty bool QtQuick.Controls::SpinBox::down.pressed
821 \qmlproperty Item QtQuick.Controls::SpinBox::down.indicator
822 \qmlproperty bool QtQuick.Controls::SpinBox::down.hovered
823 \qmlproperty real QtQuick.Controls::SpinBox::down.implicitIndicatorWidth
824 \qmlproperty real QtQuick.Controls::SpinBox::down.implicitIndicatorHeight
825
826 These properties hold the down indicator item and whether it is pressed or
827 hovered. The \c down.hovered property was introduced in QtQuick.Controls 2.1,
828 and the \c down.implicitIndicatorWidth and \c down.implicitIndicatorHeight
829 properties were introduced in QtQuick.Controls 2.5.
830
831 \sa decrease()
832*/
833QQuickIndicatorButton *QQuickSpinBox::down() const
834{
835 Q_D(const QQuickSpinBox);
836 return d->down;
837}
838
839/*!
840 \since QtQuick.Controls 2.2 (Qt 5.9)
841 \qmlproperty flags QtQuick.Controls::SpinBox::inputMethodHints
842
843 This property provides hints to the input method about the expected content
844 of the spin box and how it should operate.
845
846 The default value is \c Qt.ImhDigitsOnly.
847
848 \include inputmethodhints.qdocinc
849*/
850Qt::InputMethodHints QQuickSpinBox::inputMethodHints() const
851{
852 Q_D(const QQuickSpinBox);
853 return d->inputMethodHints;
854}
855
856void QQuickSpinBox::setInputMethodHints(Qt::InputMethodHints hints)
857{
858 Q_D(QQuickSpinBox);
859 if (d->inputMethodHints == hints)
860 return;
861
862 d->inputMethodHints = hints;
863 emit inputMethodHintsChanged();
864}
865
866/*!
867 \since QtQuick.Controls 2.2 (Qt 5.9)
868 \qmlproperty bool QtQuick.Controls::SpinBox::inputMethodComposing
869 \readonly
870
871 This property holds whether an editable spin box has partial text input from an input method.
872
873 While it is composing, an input method may rely on mouse or key events from the spin box to
874 edit or commit the partial text. This property can be used to determine when to disable event
875 handlers that may interfere with the correct operation of an input method.
876*/
877bool QQuickSpinBox::isInputMethodComposing() const
878{
879 Q_D(const QQuickSpinBox);
880 return d->contentItem && d->contentItem->property("inputMethodComposing").toBool();
881}
882
883/*!
884 \since QtQuick.Controls 2.3 (Qt 5.10)
885 \qmlproperty bool QtQuick.Controls::SpinBox::wrap
886
887 This property holds whether the spinbox wraps. The default value is \c false.
888
889 If wrap is \c true, stepping past \l to changes the value to \l from and vice versa.
890*/
891bool QQuickSpinBox::wrap() const
892{
893 Q_D(const QQuickSpinBox);
894 return d->wrap;
895}
896
897void QQuickSpinBox::setWrap(bool wrap)
898{
899 Q_D(QQuickSpinBox);
900 if (d->wrap == wrap)
901 return;
902
903 d->wrap = wrap;
904 if (d->value == d->from || d->value == d->to) {
905 d->updateUpEnabled();
906 d->updateDownEnabled();
907 }
908 emit wrapChanged();
909}
910
911/*!
912 \since QtQuick.Controls 2.4 (Qt 5.11)
913 \qmlproperty string QtQuick.Controls::SpinBox::displayText
914 \readonly
915
916 This property holds the textual value of the spinbox.
917
918 The value of the property is based on \l textFromValue and \l {Control::}
919 {locale}, and equal to:
920 \badcode
921 var text = spinBox.textFromValue(spinBox.value, spinBox.locale)
922 \endcode
923
924 \sa textFromValue
925*/
926QString QQuickSpinBox::displayText() const
927{
928 Q_D(const QQuickSpinBox);
929 return d->displayText;
930}
931
932/*!
933 \qmlmethod void QtQuick.Controls::SpinBox::increase()
934
935 Increases the value by \l stepSize, or \c 1 if stepSize is not defined.
936
937 \sa stepSize
938*/
939void QQuickSpinBox::increase()
940{
941 Q_D(QQuickSpinBox);
942 d->increase(false);
943}
944
945/*!
946 \qmlmethod void QtQuick.Controls::SpinBox::decrease()
947
948 Decreases the value by \l stepSize, or \c 1 if stepSize is not defined.
949
950 \sa stepSize
951*/
952void QQuickSpinBox::decrease()
953{
954 Q_D(QQuickSpinBox);
955 d->decrease(false);
956}
957
958void QQuickSpinBox::focusInEvent(QFocusEvent *event)
959{
960 Q_D(QQuickSpinBox);
961 QQuickControl::focusInEvent(event);
962
963 // When an editable SpinBox gets focus, it must pass on the focus to its editor.
964 if (d->editable && d->contentItem && !d->contentItem->hasActiveFocus())
965 d->contentItem->forceActiveFocus(event->reason());
966}
967
968void QQuickSpinBox::hoverEnterEvent(QHoverEvent *event)
969{
970 Q_D(QQuickSpinBox);
971 QQuickControl::hoverEnterEvent(event);
972 d->updateHover(event->position());
973 event->ignore();
974}
975
976void QQuickSpinBox::hoverMoveEvent(QHoverEvent *event)
977{
978 Q_D(QQuickSpinBox);
979 QQuickControl::hoverMoveEvent(event);
980 d->updateHover(event->position());
981 event->ignore();
982}
983
984void QQuickSpinBox::hoverLeaveEvent(QHoverEvent *event)
985{
986 Q_D(QQuickSpinBox);
987 QQuickControl::hoverLeaveEvent(event);
988 d->down->setHovered(false);
989 d->up->setHovered(false);
990 event->ignore();
991}
992
993void QQuickSpinBox::keyPressEvent(QKeyEvent *event)
994{
995 Q_D(QQuickSpinBox);
996 QQuickControl::keyPressEvent(event);
997
998 switch (event->key()) {
999 case Qt::Key_Up:
1000 if (d->upEnabled()) {
1001 // Update the pressed state before increasing/decreasing in case user code binds
1002 // stepSize to up/down.pressed.
1003 d->up->setPressed(true);
1004 d->increase(true);
1005 event->accept();
1006 }
1007 break;
1008
1009 case Qt::Key_Down:
1010 if (d->downEnabled()) {
1011 d->down->setPressed(true);
1012 d->decrease(true);
1013 event->accept();
1014 }
1015 break;
1016
1017 default:
1018 break;
1019 }
1020
1021 setAccessibleProperty("pressed", d->up->isPressed() || d->down->isPressed());
1022}
1023
1024void QQuickSpinBox::keyReleaseEvent(QKeyEvent *event)
1025{
1026 Q_D(QQuickSpinBox);
1027 QQuickControl::keyReleaseEvent(event);
1028
1029 if (d->editable && (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return))
1030 d->updateValue();
1031
1032 d->up->setPressed(false);
1033 d->down->setPressed(false);
1034 setAccessibleProperty("pressed", false);
1035}
1036
1037void QQuickSpinBox::timerEvent(QTimerEvent *event)
1038{
1039 Q_D(QQuickSpinBox);
1040 QQuickControl::timerEvent(event);
1041 if (event->timerId() == d->delayTimer) {
1042 d->startPressRepeat();
1043 } else if (event->timerId() == d->repeatTimer) {
1044 if (d->up->isPressed())
1045 d->increase(true);
1046 else if (d->down->isPressed())
1047 d->decrease(true);
1048 }
1049}
1050
1051#if QT_CONFIG(wheelevent)
1052void QQuickSpinBox::wheelEvent(QWheelEvent *event)
1053{
1054 Q_D(QQuickSpinBox);
1055 QQuickControl::wheelEvent(event);
1056 if (d->wheelEnabled) {
1057 const QPointF angle = event->angleDelta();
1058 const qreal delta = (qFuzzyIsNull(angle.y()) ? angle.x() : angle.y()) / int(QWheelEvent::DefaultDeltasPerStep);
1059 d->stepBy(qRound(d->effectiveStepSize() * delta), true);
1060 }
1061}
1062#endif
1063
1064void QQuickSpinBox::classBegin()
1065{
1066 Q_D(QQuickSpinBox);
1067 QQuickControl::classBegin();
1068
1069 QQmlContext *context = qmlContext(this);
1070 if (context) {
1071 QQmlEngine::setContextForObject(d->up, context);
1072 QQmlEngine::setContextForObject(d->down, context);
1073 }
1074}
1075
1076void QQuickSpinBox::componentComplete()
1077{
1078 Q_D(QQuickSpinBox);
1079 QQuickIndicatorButtonPrivate::get(d->up)->executeIndicator(true);
1080 QQuickIndicatorButtonPrivate::get(d->down)->executeIndicator(true);
1081
1082 QQuickControl::componentComplete();
1083 if (!d->setValue(d->value, /* allowWrap = */ false, /* modified = */ false)) {
1084 d->updateDisplayText();
1085 d->updateUpEnabled();
1086 d->updateDownEnabled();
1087 }
1088}
1089
1090void QQuickSpinBox::itemChange(ItemChange change, const ItemChangeData &value)
1091{
1092 Q_D(QQuickSpinBox);
1093 QQuickControl::itemChange(change, value);
1094 if (d->editable && change == ItemActiveFocusHasChanged && !value.boolValue)
1095 d->updateValue();
1096}
1097
1098void QQuickSpinBox::contentItemChange(QQuickItem *newItem, QQuickItem *oldItem)
1099{
1100 Q_D(QQuickSpinBox);
1101 if (QQuickTextInput *oldInput = qobject_cast<QQuickTextInput *>(oldItem)) {
1102 disconnect(oldInput, &QQuickTextInput::inputMethodComposingChanged, this, &QQuickSpinBox::inputMethodComposingChanged);
1103 QObjectPrivate::disconnect(oldInput, &QQuickTextInput::textChanged, d, &QQuickSpinBoxPrivate::contentItemTextChanged);
1104 }
1105
1106 if (newItem) {
1107 newItem->setActiveFocusOnTab(true);
1108 if (d->activeFocus)
1109 newItem->forceActiveFocus(static_cast<Qt::FocusReason>(d->focusReason));
1110#if QT_CONFIG(cursor)
1111 if (d->editable)
1112 newItem->setCursor(Qt::IBeamCursor);
1113#endif
1114
1115 if (QQuickTextInput *newInput = qobject_cast<QQuickTextInput *>(newItem)) {
1116 connect(newInput, &QQuickTextInput::inputMethodComposingChanged, this, &QQuickSpinBox::inputMethodComposingChanged);
1117 QObjectPrivate::connect(newInput, &QQuickTextInput::textChanged, d, &QQuickSpinBoxPrivate::contentItemTextChanged);
1118 }
1119 }
1120}
1121
1122void QQuickSpinBox::localeChange(const QLocale &newLocale, const QLocale &oldLocale)
1123{
1124 Q_D(QQuickSpinBox);
1125 QQuickControl::localeChange(newLocale, oldLocale);
1126 d->updateDisplayText();
1127}
1128
1129QFont QQuickSpinBox::defaultFont() const
1130{
1131 return QQuickTheme::font(QQuickTheme::SpinBox);
1132}
1133
1134#if QT_CONFIG(accessibility)
1135QAccessible::Role QQuickSpinBox::accessibleRole() const
1136{
1137 return QAccessible::SpinBox;
1138}
1139
1140void QQuickSpinBox::accessibilityActiveChanged(bool active)
1141{
1142 Q_D(QQuickSpinBox);
1143 QQuickControl::accessibilityActiveChanged(active);
1144
1145 if (active)
1146 setAccessibleProperty("editable", d->editable);
1147}
1148#endif
1149
1150QT_END_NAMESPACE
1151
1152#include "moc_qquickspinbox_p.cpp"
Allows the user to select from a set of preset values.
void handleUngrab() override
int evaluateValueFromText(const QString &text) const
void itemDestroyed(QQuickItem *item) override
QQuickIndicatorButton * down
bool handleMove(const QPointF &point, ulong timestamp) override
bool handleRelease(const QPointF &point, ulong timestamp) override
Qt::InputMethodHints inputMethodHints
void decrease(bool modified)
void itemImplicitWidthChanged(QQuickItem *item) override
bool handlePress(const QPointF &point, ulong timestamp) override
bool stepBy(int steps, bool modified)
int effectiveStepSize() const
bool setValue(int value, bool wrap, bool modified)
void itemImplicitHeightChanged(QQuickItem *item) override
QString evaluateTextFromValue(int val) const
QQuickIndicatorButton * up
void updateHover(const QPointF &pos)
void increase(bool modified)
QPalette defaultPalette() const override
void setDisplayText(const QString &displayText)
static QT_BEGIN_NAMESPACE const int AUTO_REPEAT_DELAY
static const int AUTO_REPEAT_INTERVAL