aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/imports/controls/SpinBox.qml142
-rw-r--r--src/imports/controls/controls.pri1
-rw-r--r--src/imports/controls/doc/images/qtlabscontrols-spinbox-background.pngbin0 -> 1053 bytes
-rw-r--r--src/imports/controls/doc/images/qtlabscontrols-spinbox-contentItem.pngbin0 -> 1144 bytes
-rw-r--r--src/imports/controls/doc/images/qtlabscontrols-spinbox-down.pngbin0 -> 1078 bytes
-rw-r--r--src/imports/controls/doc/images/qtlabscontrols-spinbox-up.pngbin0 -> 1130 bytes
-rw-r--r--src/imports/controls/doc/images/qtlabscontrols-spinbox.pngbin0 -> 1146 bytes
-rw-r--r--src/imports/controls/doc/src/qtlabscontrols-customize.qdoc31
-rw-r--r--src/imports/controls/doc/src/qtlabscontrols-index.qdoc2
-rw-r--r--src/imports/controls/qtlabscontrolsplugin.cpp1
-rw-r--r--src/imports/templates/qtlabstemplatesplugin.cpp3
-rw-r--r--src/templates/qquickspinbox.cpp527
-rw-r--r--src/templates/qquickspinbox_p.h145
-rw-r--r--src/templates/templates.pri2
-rw-r--r--tests/auto/accessibility/data/spinbox.qml16
-rw-r--r--tests/auto/accessibility/tst_accessibility.cpp1
-rw-r--r--tests/auto/activeFocusOnTab/data/activeFocusOnTab.qml5
-rw-r--r--tests/auto/activeFocusOnTab/tst_activeFocusOnTab.cpp33
-rw-r--r--tests/auto/controls/data/tst_spinbox.qml301
-rw-r--r--tests/auto/snippets/data/qtlabscontrols-spinbox-background.qml11
-rw-r--r--tests/auto/snippets/data/qtlabscontrols-spinbox-contentItem.qml11
-rw-r--r--tests/auto/snippets/data/qtlabscontrols-spinbox-down.qml11
-rw-r--r--tests/auto/snippets/data/qtlabscontrols-spinbox-up.qml11
-rw-r--r--tests/auto/snippets/data/qtlabscontrols-spinbox.qml8
-rw-r--r--tests/benchmarks/objectcount/tst_objectcount.cpp4
25 files changed, 1262 insertions, 4 deletions
diff --git a/src/imports/controls/SpinBox.qml b/src/imports/controls/SpinBox.qml
new file mode 100644
index 00000000..3607a701
--- /dev/null
+++ b/src/imports/controls/SpinBox.qml
@@ -0,0 +1,142 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Labs Controls module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.6
+import Qt.labs.controls 1.0
+import Qt.labs.templates 1.0 as T
+
+T.SpinBox {
+ id: control
+
+ implicitWidth: Math.max(background ? background.implicitWidth : 0,
+ contentItem.implicitWidth + 2 * padding +
+ (up.indicator ? up.indicator.implicitWidth : 0) +
+ (down.indicator ? down.indicator.implicitWidth : 0))
+ implicitHeight: Math.max(contentItem.implicitHeight + topPadding + bottomPadding,
+ background ? background.implicitHeight : 0,
+ up.indicator ? up.indicator.implicitHeight : 0,
+ down.indicator ? down.indicator.implicitHeight : 0)
+
+ padding: 6
+ leftPadding: 6 + (control.mirrored ? (up.indicator ? up.indicator.width : 0) : (down.indicator ? down.indicator.width : 0))
+ rightPadding: 6 + (control.mirrored ? (down.indicator ? down.indicator.width : 0) : (up.indicator ? up.indicator.width : 0))
+
+ //! [contentItem]
+ contentItem: TextInput {
+ text: Number(control.value).toLocaleString(control.locale, 'f', 0)
+
+ font: control.font
+ color: control.Theme.textColor
+ selectionColor: control.Theme.selectionColor
+ selectedTextColor: control.Theme.selectedTextColor
+ horizontalAlignment: Qt.AlignHCenter
+ verticalAlignment: Qt.AlignVCenter
+
+ validator: IntValidator {
+ bottom: Math.min(control.from, control.to)
+ top: Math.max(control.from, control.to)
+ }
+ inputMethodHints: Qt.ImhFormattedNumbersOnly
+ }
+ //! [contentItem]
+
+ //! [up.indicator]
+ up.indicator: Item {
+ implicitWidth: 26
+ height: parent.height
+ x: control.mirrored ? 0 : parent.width - width
+
+ clip: true
+ Rectangle {
+ x: -radius
+ width: parent.width + radius
+ height: parent.height
+ radius: 3
+ color: Qt.tint(Qt.tint(control.Theme.accentColor,
+ control.activeFocus ? control.Theme.focusColor : "transparent"),
+ control.up.pressed ? control.Theme.pressColor : "transparent")
+ }
+ Rectangle {
+ x: (parent.width - width) / 2
+ y: (parent.height - height) / 2
+ width: parent.width / 3
+ height: 2
+ color: control.Theme.selectedTextColor
+ }
+ Rectangle {
+ x: (parent.width - width) / 2
+ y: (parent.height - height) / 2
+ width: 2
+ height: parent.height / 3
+ color: control.Theme.selectedTextColor
+ }
+ }
+ //! [up.indicator]
+
+ //! [down.indicator]
+ down.indicator: Item {
+ implicitWidth: 26
+ height: parent.height
+ x: control.mirrored ? parent.width - width : 0
+
+ clip: true
+ Rectangle {
+ width: parent.width + radius
+ height: parent.height
+ radius: 3
+ color: Qt.tint(Qt.tint(control.Theme.accentColor,
+ control.activeFocus ? control.Theme.focusColor : "transparent"),
+ control.down.pressed ? control.Theme.pressColor : "transparent")
+ }
+ Rectangle {
+ x: (parent.width - width) / 2
+ y: (parent.height - height) / 2
+ width: parent.width / 3
+ height: 2
+ color: control.Theme.selectedTextColor
+ }
+ }
+ //! [down.indicator]
+
+ //! [background]
+ background: Rectangle {
+ implicitWidth: 80
+ radius: 3
+ border.width: control.activeFocus ? 2 : 1
+ border.color: control.activeFocus ? control.Theme.focusColor : control.Theme.frameColor
+ }
+ //! [background]
+}
diff --git a/src/imports/controls/controls.pri b/src/imports/controls/controls.pri
index 41651a24..53615c08 100644
--- a/src/imports/controls/controls.pri
+++ b/src/imports/controls/controls.pri
@@ -15,6 +15,7 @@ QML_FILES = \
ScrollBar.qml \
ScrollIndicator.qml \
Slider.qml \
+ SpinBox.qml \
StackView.qml \
Switch.qml \
SwipeView.qml \
diff --git a/src/imports/controls/doc/images/qtlabscontrols-spinbox-background.png b/src/imports/controls/doc/images/qtlabscontrols-spinbox-background.png
new file mode 100644
index 00000000..0224e6f1
--- /dev/null
+++ b/src/imports/controls/doc/images/qtlabscontrols-spinbox-background.png
Binary files differ
diff --git a/src/imports/controls/doc/images/qtlabscontrols-spinbox-contentItem.png b/src/imports/controls/doc/images/qtlabscontrols-spinbox-contentItem.png
new file mode 100644
index 00000000..0e39d92f
--- /dev/null
+++ b/src/imports/controls/doc/images/qtlabscontrols-spinbox-contentItem.png
Binary files differ
diff --git a/src/imports/controls/doc/images/qtlabscontrols-spinbox-down.png b/src/imports/controls/doc/images/qtlabscontrols-spinbox-down.png
new file mode 100644
index 00000000..a6bbecdf
--- /dev/null
+++ b/src/imports/controls/doc/images/qtlabscontrols-spinbox-down.png
Binary files differ
diff --git a/src/imports/controls/doc/images/qtlabscontrols-spinbox-up.png b/src/imports/controls/doc/images/qtlabscontrols-spinbox-up.png
new file mode 100644
index 00000000..3c6c870b
--- /dev/null
+++ b/src/imports/controls/doc/images/qtlabscontrols-spinbox-up.png
Binary files differ
diff --git a/src/imports/controls/doc/images/qtlabscontrols-spinbox.png b/src/imports/controls/doc/images/qtlabscontrols-spinbox.png
new file mode 100644
index 00000000..39fa813a
--- /dev/null
+++ b/src/imports/controls/doc/images/qtlabscontrols-spinbox.png
Binary files differ
diff --git a/src/imports/controls/doc/src/qtlabscontrols-customize.qdoc b/src/imports/controls/doc/src/qtlabscontrols-customize.qdoc
index 474caba9..c4124191 100644
--- a/src/imports/controls/doc/src/qtlabscontrols-customize.qdoc
+++ b/src/imports/controls/doc/src/qtlabscontrols-customize.qdoc
@@ -305,6 +305,37 @@
\snippet Slider.qml handle
+ \section1 Customizing SpinBox
+
+ SpinBox consists of four visual items: \l {Control::background}{background},
+ \l {Control::contentItem}{contentItem}, \l {SpinBox::up.indicator}{up indicator},
+ and \l {SpinBox::down.indicator}{down indicator}.
+
+ \section3 Background
+
+ \image qtlabscontrols-spinbox-background.png
+
+ \snippet SpinBox.qml background
+
+ \section3 Content item
+
+ \image qtlabscontrols-spinbox-contentItem.png
+
+ \snippet SpinBox.qml contentItem
+
+ \section3 Down indicator
+
+ \image qtlabscontrols-spinbox-down.png
+
+ \snippet Spinbox.qml down.indicator
+
+ \section3 Up indicator
+
+ \image qtlabscontrols-spinbox-up.png
+
+ \snippet Spinbox.qml up.indicator
+
+
\section1 Customizing StackView
StackView can have a visual \l {Control::background}{background}
diff --git a/src/imports/controls/doc/src/qtlabscontrols-index.qdoc b/src/imports/controls/doc/src/qtlabscontrols-index.qdoc
index 557bc73a..c105ede9 100644
--- a/src/imports/controls/doc/src/qtlabscontrols-index.qdoc
+++ b/src/imports/controls/doc/src/qtlabscontrols-index.qdoc
@@ -250,7 +250,7 @@
\li \l [QtLabsControls] {Slider}
\row
\li \l [QtQuickControls] {SpinBox}
- \li No equivalent; see \l [QtLabsControls] {Tumbler} instead.
+ \li \l [QtLabsControls] {SpinBox}
\row
\li \l [QtQuickControls] {Stack},
\l [QtQuickControls] {StackView},
diff --git a/src/imports/controls/qtlabscontrolsplugin.cpp b/src/imports/controls/qtlabscontrolsplugin.cpp
index 8d042381..249375d2 100644
--- a/src/imports/controls/qtlabscontrolsplugin.cpp
+++ b/src/imports/controls/qtlabscontrolsplugin.cpp
@@ -85,6 +85,7 @@ void QtLabsControlsPlugin::registerTypes(const char *uri)
qmlRegisterType(selector.select(QUrl(base + QStringLiteral("/ScrollBar.qml"))), uri, 1, 0, "ScrollBar");
qmlRegisterType(selector.select(QUrl(base + QStringLiteral("/ScrollIndicator.qml"))), uri, 1, 0, "ScrollIndicator");
qmlRegisterType(selector.select(QUrl(base + QStringLiteral("/Slider.qml"))), uri, 1, 0, "Slider");
+ qmlRegisterType(selector.select(QUrl(base + QStringLiteral("/SpinBox.qml"))), uri, 1, 0, "SpinBox");
qmlRegisterType(selector.select(QUrl(base + QStringLiteral("/StackView.qml"))), uri, 1, 0, "StackView");
qmlRegisterType(selector.select(QUrl(base + QStringLiteral("/SwipeView.qml"))), uri, 1, 0, "SwipeView");
qmlRegisterType(selector.select(QUrl(base + QStringLiteral("/Switch.qml"))), uri, 1, 0, "Switch");
diff --git a/src/imports/templates/qtlabstemplatesplugin.cpp b/src/imports/templates/qtlabstemplatesplugin.cpp
index 51c15dd9..cf97f743 100644
--- a/src/imports/templates/qtlabstemplatesplugin.cpp
+++ b/src/imports/templates/qtlabstemplatesplugin.cpp
@@ -54,6 +54,7 @@
#include <QtLabsTemplates/private/qquickscrollbar_p.h>
#include <QtLabsTemplates/private/qquickscrollindicator_p.h>
#include <QtLabsTemplates/private/qquickslider_p.h>
+#include <QtLabsTemplates/private/qquickspinbox_p.h>
#include <QtLabsTemplates/private/qquickstackview_p.h>
#include <QtLabsTemplates/private/qquickswipeview_p.h>
#include <QtLabsTemplates/private/qquickswitch_p.h>
@@ -97,6 +98,8 @@ void QtLabsTemplatesPlugin::registerTypes(const char *uri)
qmlRegisterType<QQuickScrollBar>(uri, 1, 0, "ScrollBar");
qmlRegisterType<QQuickScrollIndicator>(uri, 1, 0, "ScrollIndicator");
qmlRegisterType<QQuickSlider>(uri, 1, 0, "Slider");
+ qmlRegisterType<QQuickSpinBox>(uri, 1, 0, "SpinBox");
+ qmlRegisterType<QQuickSpinner>();
qmlRegisterType<QQuickStackView>(uri, 1, 0, "StackView");
qmlRegisterType<QQuickSwipeViewAttached>();
qmlRegisterType<QQuickSwipeView>(uri, 1, 0, "SwipeView");
diff --git a/src/templates/qquickspinbox.cpp b/src/templates/qquickspinbox.cpp
new file mode 100644
index 00000000..cac210ec
--- /dev/null
+++ b/src/templates/qquickspinbox.cpp
@@ -0,0 +1,527 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Labs Templates module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickspinbox_p.h"
+#include "qquickcontrol_p_p.h"
+
+#include <QtGui/qguiapplication.h>
+#include <QtGui/qstylehints.h>
+
+QT_BEGIN_NAMESPACE
+
+// copied from qabstractbutton.cpp
+static const int AUTO_REPEAT_DELAY = 300;
+static const int AUTO_REPEAT_INTERVAL = 100;
+
+/*!
+ \qmltype SpinBox
+ \inherits Control
+ \instantiates QQuickSpinBox
+ \inqmlmodule Qt.labs.controls
+ \ingroup input
+ \brief A spinbox control.
+
+ \image qtlabscontrols-spinbox.png
+
+ SpinBox allows the user to choose an integer value by clicking the up
+ or down indicator buttons, by pressing up or down on the keyboard, or
+ by entering a text value in the input field.
+
+ By default, SpinBox provides discrete values in the range of \c [0-99]
+ with a \l stepSize of \c 1.
+
+ \snippet qtlabscontrols-spinbox.qml 1
+
+ \sa Tumbler, {Customizing SpinBox}
+*/
+
+class QQuickSpinBoxPrivate : public QQuickControlPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickSpinBox)
+
+public:
+ QQuickSpinBoxPrivate() : from(0), to(99), value(0), stepSize(1),
+ delayTimer(0), repeatTimer(0), up(Q_NULLPTR), down(Q_NULLPTR) { }
+
+ int boundValue(int value) const;
+ void updateValue();
+
+ int effectiveStepSize() const;
+
+ void startRepeatDelay();
+ void startPressRepeat();
+ void stopPressRepeat();
+
+ bool handleMousePressEvent(QQuickItem *child, QMouseEvent *event);
+ bool handleMouseMoveEvent(QQuickItem *child, QMouseEvent *event);
+ bool handleMouseReleaseEvent(QQuickItem *child, QMouseEvent *event);
+ bool handleMouseUngrabEvent(QQuickItem *child);
+
+ int from;
+ int to;
+ int value;
+ int stepSize;
+ int delayTimer;
+ int repeatTimer;
+ QQuickSpinner *up;
+ QQuickSpinner *down;
+ QLocale locale;
+};
+
+int QQuickSpinBoxPrivate::boundValue(int value) const
+{
+ return from > to ? qBound(to, value, from) : qBound(from, value, to);
+}
+
+void QQuickSpinBoxPrivate::updateValue()
+{
+ Q_Q(QQuickSpinBox);
+ if (contentItem) {
+ QVariant text = contentItem->property("text");
+ if (text.isValid())
+ q->setValue(locale.toInt(text.toString()));
+ }
+}
+
+int QQuickSpinBoxPrivate::effectiveStepSize() const
+{
+ return from > to ? -1 * stepSize : stepSize;
+}
+
+void QQuickSpinBoxPrivate::startRepeatDelay()
+{
+ Q_Q(QQuickSpinBox);
+ stopPressRepeat();
+ delayTimer = q->startTimer(AUTO_REPEAT_DELAY);
+}
+
+void QQuickSpinBoxPrivate::startPressRepeat()
+{
+ Q_Q(QQuickSpinBox);
+ stopPressRepeat();
+ repeatTimer = q->startTimer(AUTO_REPEAT_INTERVAL);
+}
+
+void QQuickSpinBoxPrivate::stopPressRepeat()
+{
+ Q_Q(QQuickSpinBox);
+ if (delayTimer > 0) {
+ q->killTimer(delayTimer);
+ delayTimer = 0;
+ }
+ if (repeatTimer > 0) {
+ q->killTimer(repeatTimer);
+ repeatTimer = 0;
+ }
+}
+
+bool QQuickSpinBoxPrivate::handleMousePressEvent(QQuickItem *child, QMouseEvent *)
+{
+ Q_Q(QQuickSpinBox);
+ QQuickItem *ui = up->indicator();
+ QQuickItem *di = down->indicator();
+ up->setPressed(child == ui);
+ down->setPressed(child == di);
+
+ bool pressed = up->isPressed() || down->isPressed();
+ q->setAccessibleProperty("pressed", pressed);
+ if (pressed)
+ startRepeatDelay();
+ return child == ui || child == di;
+}
+
+bool QQuickSpinBoxPrivate::handleMouseMoveEvent(QQuickItem *child, QMouseEvent *event)
+{
+ Q_Q(QQuickSpinBox);
+ QQuickItem *ui = up->indicator();
+ QQuickItem *di = down->indicator();
+ up->setPressed(child == ui && ui->contains(event->pos()));
+ down->setPressed(child == di && di->contains(event->pos()));
+
+ bool pressed = up->isPressed() || down->isPressed();
+ q->setAccessibleProperty("pressed", pressed);
+ stopPressRepeat();
+ return child == ui || child == di;
+}
+
+bool QQuickSpinBoxPrivate::handleMouseReleaseEvent(QQuickItem *child, QMouseEvent *event)
+{
+ Q_Q(QQuickSpinBox);
+ QQuickItem *ui = up->indicator();
+ QQuickItem *di = down->indicator();
+ if (child == ui) {
+ up->setPressed(false);
+ if (repeatTimer <= 0 && ui->contains(event->pos()))
+ q->increase();
+ } else if (child == di) {
+ down->setPressed(false);
+ if (repeatTimer <= 0 && di->contains(event->pos()))
+ q->decrease();
+ }
+
+ q->setAccessibleProperty("pressed", false);
+ stopPressRepeat();
+ return child == ui || child == di;
+}
+
+bool QQuickSpinBoxPrivate::handleMouseUngrabEvent(QQuickItem *child)
+{
+ Q_Q(QQuickSpinBox);
+ QQuickItem *ui = up->indicator();
+ QQuickItem *di = down->indicator();
+ up->setPressed(false);
+ down->setPressed(false);
+
+ q->setAccessibleProperty("pressed", false);
+ stopPressRepeat();
+ return child == ui || child == di;
+}
+
+QQuickSpinBox::QQuickSpinBox(QQuickItem *parent) :
+ QQuickControl(*(new QQuickSpinBoxPrivate), parent)
+{
+ Q_D(QQuickSpinBox);
+ d->up = new QQuickSpinner(this);
+ d->down = new QQuickSpinner(this);
+
+ setFlag(ItemIsFocusScope);
+ setFiltersChildMouseEvents(true);
+ setAccessibleRole(0x00000034); //QAccessible::SpinBox
+}
+
+/*!
+ \qmlproperty int Qt.labs.controls::SpinBox::from
+
+ This property holds the starting value for the range. The default value is \c 0.
+
+ \sa to, value
+*/
+int QQuickSpinBox::from() const
+{
+ Q_D(const QQuickSpinBox);
+ return d->from;
+}
+
+void QQuickSpinBox::setFrom(int from)
+{
+ Q_D(QQuickSpinBox);
+ if (d->from != from) {
+ d->from = from;
+ emit fromChanged();
+ if (isComponentComplete())
+ setValue(d->value);
+ }
+}
+
+/*!
+ \qmlproperty int Qt.labs.controls::SpinBox::to
+
+ This property holds the end value for the range. The default value is \c 99.
+
+ \sa from, value
+*/
+int QQuickSpinBox::to() const
+{
+ Q_D(const QQuickSpinBox);
+ return d->to;
+}
+
+void QQuickSpinBox::setTo(int to)
+{
+ Q_D(QQuickSpinBox);
+ if (d->to != to) {
+ d->to = to;
+ emit toChanged();
+ if (isComponentComplete())
+ setValue(d->value);
+ }
+}
+
+/*!
+ \qmlproperty int Qt.labs.controls::SpinBox::value
+
+ This property holds the value in the range \c from - \c to. The default value is \c 0.
+*/
+int QQuickSpinBox::value() const
+{
+ Q_D(const QQuickSpinBox);
+ return d->value;
+}
+
+void QQuickSpinBox::setValue(int value)
+{
+ Q_D(QQuickSpinBox);
+ if (isComponentComplete())
+ value = d->boundValue(value);
+
+ if (d->value != value) {
+ d->value = value;
+ emit valueChanged();
+ }
+}
+
+/*!
+ \qmlproperty int Qt.labs.controls::SpinBox::stepSize
+
+ This property holds the step size. The default value is \c 1.
+
+ \sa increase(), decrease()
+*/
+int QQuickSpinBox::stepSize() const
+{
+ Q_D(const QQuickSpinBox);
+ return d->stepSize;
+}
+
+void QQuickSpinBox::setStepSize(int step)
+{
+ Q_D(QQuickSpinBox);
+ if (d->stepSize != step) {
+ d->stepSize = step;
+ emit stepSizeChanged();
+ }
+}
+
+/*!
+ \qmlproperty Locale Qt.labs.controls::SpinBox::locale
+
+ This property holds the locale that is used to format the value.
+*/
+QLocale QQuickSpinBox::locale() const
+{
+ Q_D(const QQuickSpinBox);
+ return d->locale;
+}
+
+void QQuickSpinBox::setLocale(const QLocale &locale)
+{
+ Q_D(QQuickSpinBox);
+ if (d->locale != locale) {
+ d->locale = locale;
+ emit localeChanged();
+ }
+}
+
+/*!
+ \qmlpropertygroup Qt.labs.controls::SpinBox::up
+ \qmlproperty bool Qt.labs.controls::SpinBox::up.pressed
+ \qmlproperty Item Qt.labs.controls::SpinBox::up.indicator
+
+ These properties hold the up indicator item and whether it is pressed.
+
+ \sa increase()
+*/
+QQuickSpinner *QQuickSpinBox::up() const
+{
+ Q_D(const QQuickSpinBox);
+ return d->up;
+}
+
+/*!
+ \qmlpropertygroup Qt.labs.controls::SpinBox::down
+ \qmlproperty bool Qt.labs.controls::SpinBox::down.pressed
+ \qmlproperty Item Qt.labs.controls::SpinBox::down.indicator
+
+ These properties hold the down indicator item and whether it is pressed.
+
+ \sa decrease()
+*/
+QQuickSpinner *QQuickSpinBox::down() const
+{
+ Q_D(const QQuickSpinBox);
+ return d->down;
+}
+
+/*!
+ \qmlmethod void Qt.labs.controls::SpinBox::increase()
+
+ Increases the value by \l stepSize.
+
+ \sa stepSize
+*/
+void QQuickSpinBox::increase()
+{
+ Q_D(QQuickSpinBox);
+ setValue(d->value + d->effectiveStepSize());
+}
+
+/*!
+ \qmlmethod void Qt.labs.controls::SpinBox::decrease()
+
+ Decreases the value by \l stepSize.
+
+ \sa stepSize
+*/
+void QQuickSpinBox::decrease()
+{
+ Q_D(QQuickSpinBox);
+ setValue(d->value - d->effectiveStepSize());
+}
+
+void QQuickSpinBox::keyPressEvent(QKeyEvent *event)
+{
+ Q_D(QQuickSpinBox);
+ QQuickControl::keyPressEvent(event);
+
+ switch (event->key()) {
+ case Qt::Key_Up:
+ increase();
+ d->up->setPressed(true);
+ event->accept();
+ break;
+
+ case Qt::Key_Down:
+ decrease();
+ d->down->setPressed(true);
+ event->accept();
+ break;
+
+ default:
+ break;
+ }
+
+ setAccessibleProperty("pressed", d->up->isPressed() || d->down->isPressed());
+}
+
+void QQuickSpinBox::keyReleaseEvent(QKeyEvent *event)
+{
+ Q_D(QQuickSpinBox);
+ QQuickControl::keyReleaseEvent(event);
+
+ if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return)
+ d->updateValue();
+
+ d->up->setPressed(false);
+ d->down->setPressed(false);
+ setAccessibleProperty("pressed", false);
+}
+
+bool QQuickSpinBox::childMouseEventFilter(QQuickItem *child, QEvent *event)
+{
+ Q_D(QQuickSpinBox);
+ switch (event->type()) {
+ case QEvent::MouseButtonPress:
+ return d->handleMousePressEvent(child, static_cast<QMouseEvent *>(event));
+ case QEvent::MouseMove:
+ return d->handleMouseMoveEvent(child, static_cast<QMouseEvent *>(event));
+ case QEvent::MouseButtonRelease:
+ return d->handleMouseReleaseEvent(child, static_cast<QMouseEvent *>(event));
+ case QEvent::UngrabMouse:
+ return d->handleMouseUngrabEvent(child);
+ default:
+ return false;
+ }
+}
+
+void QQuickSpinBox::timerEvent(QTimerEvent *event)
+{
+ Q_D(QQuickSpinBox);
+ QQuickControl::timerEvent(event);
+ if (event->timerId() == d->delayTimer) {
+ d->startPressRepeat();
+ } else if (event->timerId() == d->repeatTimer) {
+ if (d->up->isPressed())
+ increase();
+ else if (d->down->isPressed())
+ decrease();
+ }
+}
+
+void QQuickSpinBox::itemChange(ItemChange change, const ItemChangeData &value)
+{
+ Q_D(QQuickSpinBox);
+ QQuickControl::itemChange(change, value);
+ if (change == ItemActiveFocusHasChanged && !value.boolValue)
+ d->updateValue();
+}
+
+void QQuickSpinBox::contentItemChange(QQuickItem *newItem, QQuickItem *oldItem)
+{
+ Q_UNUSED(oldItem);
+ if (newItem)
+ newItem->setActiveFocusOnTab(true);
+}
+
+class QQuickSpinnerPrivate : public QObjectPrivate
+{
+public:
+ QQuickSpinnerPrivate() : pressed(false), indicator(Q_NULLPTR) { }
+ bool pressed;
+ QQuickItem *indicator;
+};
+
+QQuickSpinner::QQuickSpinner(QQuickSpinBox *parent) :
+ QObject(*(new QQuickSpinnerPrivate), parent)
+{
+}
+
+bool QQuickSpinner::isPressed() const
+{
+ Q_D(const QQuickSpinner);
+ return d->pressed;
+}
+
+void QQuickSpinner::setPressed(bool pressed)
+{
+ Q_D(QQuickSpinner);
+ if (d->pressed != pressed) {
+ d->pressed = pressed;
+ emit pressedChanged();
+ }
+}
+
+QQuickItem *QQuickSpinner::indicator() const
+{
+ Q_D(const QQuickSpinner);
+ return d->indicator;
+}
+
+void QQuickSpinner::setIndicator(QQuickItem *indicator)
+{
+ Q_D(QQuickSpinner);
+ if (d->indicator != indicator) {
+ delete d->indicator;
+ d->indicator = indicator;
+ if (indicator) {
+ if (!indicator->parentItem())
+ indicator->setParentItem(static_cast<QQuickItem *>(parent()));
+ indicator->setAcceptedMouseButtons(Qt::LeftButton);
+ }
+ emit indicatorChanged();
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/templates/qquickspinbox_p.h b/src/templates/qquickspinbox_p.h
new file mode 100644
index 00000000..9188d397
--- /dev/null
+++ b/src/templates/qquickspinbox_p.h
@@ -0,0 +1,145 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Labs Templates module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKSPINBOX_P_H
+#define QQUICKSPINBOX_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtLabsTemplates/private/qquickcontrol_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickSpinner;
+class QQuickSpinnerPrivate;
+class QQuickSpinBoxPrivate;
+
+class Q_LABSTEMPLATES_EXPORT QQuickSpinBox : public QQuickControl
+{
+ Q_OBJECT
+ Q_PROPERTY(int from READ from WRITE setFrom NOTIFY fromChanged FINAL)
+ Q_PROPERTY(int to READ to WRITE setTo NOTIFY toChanged FINAL)
+ Q_PROPERTY(int value READ value WRITE setValue NOTIFY valueChanged FINAL)
+ Q_PROPERTY(int stepSize READ stepSize WRITE setStepSize NOTIFY stepSizeChanged FINAL)
+ Q_PROPERTY(QLocale locale READ locale WRITE setLocale NOTIFY localeChanged FINAL)
+ Q_PROPERTY(QQuickSpinner *up READ up CONSTANT FINAL)
+ Q_PROPERTY(QQuickSpinner *down READ down CONSTANT FINAL)
+
+public:
+ explicit QQuickSpinBox(QQuickItem *parent = Q_NULLPTR);
+
+ int from() const;
+ void setFrom(int from);
+
+ int to() const;
+ void setTo(int to);
+
+ int value() const;
+ void setValue(int value);
+
+ int stepSize() const;
+ void setStepSize(int step);
+
+ QLocale locale() const;
+ void setLocale(const QLocale &locale);
+
+ QQuickSpinner *up() const;
+ QQuickSpinner *down() const;
+
+public Q_SLOTS:
+ void increase();
+ void decrease();
+
+Q_SIGNALS:
+ void fromChanged();
+ void toChanged();
+ void valueChanged();
+ void stepSizeChanged();
+ void localeChanged();
+
+protected:
+ bool childMouseEventFilter(QQuickItem *child, QEvent *event) Q_DECL_OVERRIDE;
+ void keyPressEvent(QKeyEvent *event) Q_DECL_OVERRIDE;
+ void keyReleaseEvent(QKeyEvent *event) Q_DECL_OVERRIDE;
+ void timerEvent(QTimerEvent *event) Q_DECL_OVERRIDE;
+
+ void itemChange(ItemChange change, const ItemChangeData &value) Q_DECL_OVERRIDE;
+ void contentItemChange(QQuickItem *newItem, QQuickItem *oldItem) Q_DECL_OVERRIDE;
+
+private:
+ Q_DISABLE_COPY(QQuickSpinBox)
+ Q_DECLARE_PRIVATE(QQuickSpinBox)
+};
+
+class Q_LABSTEMPLATES_EXPORT QQuickSpinner : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(bool pressed READ isPressed WRITE setPressed NOTIFY pressedChanged FINAL)
+ Q_PROPERTY(QQuickItem *indicator READ indicator WRITE setIndicator NOTIFY indicatorChanged FINAL)
+
+public:
+ explicit QQuickSpinner(QQuickSpinBox *parent);
+
+ bool isPressed() const;
+ void setPressed(bool pressed);
+
+ QQuickItem *indicator() const;
+ void setIndicator(QQuickItem *indicator);
+
+Q_SIGNALS:
+ void pressedChanged();
+ void indicatorChanged();
+
+private:
+ Q_DISABLE_COPY(QQuickSpinner)
+ Q_DECLARE_PRIVATE(QQuickSpinner)
+};
+
+Q_DECLARE_TYPEINFO(QQuickSpinBox, Q_COMPLEX_TYPE);
+Q_DECLARE_TYPEINFO(QQuickSpinner, Q_COMPLEX_TYPE);
+
+QT_END_NAMESPACE
+
+#endif // QQUICKSPINBOX_P_H
diff --git a/src/templates/templates.pri b/src/templates/templates.pri
index 48405c42..8dc9764d 100644
--- a/src/templates/templates.pri
+++ b/src/templates/templates.pri
@@ -27,6 +27,7 @@ HEADERS += \
$$PWD/qquickscrollbar_p.h \
$$PWD/qquickscrollindicator_p.h \
$$PWD/qquickslider_p.h \
+ $$PWD/qquickspinbox_p.h \
$$PWD/qquickstackview_p.h \
$$PWD/qquickstackview_p_p.h \
$$PWD/qquickswipeview_p.h \
@@ -63,6 +64,7 @@ SOURCES += \
$$PWD/qquickscrollbar.cpp \
$$PWD/qquickscrollindicator.cpp \
$$PWD/qquickslider.cpp \
+ $$PWD/qquickspinbox.cpp \
$$PWD/qquickstackview.cpp \
$$PWD/qquickstackview_p.cpp \
$$PWD/qquickswipeview.cpp \
diff --git a/tests/auto/accessibility/data/spinbox.qml b/tests/auto/accessibility/data/spinbox.qml
new file mode 100644
index 00000000..abaee9ca
--- /dev/null
+++ b/tests/auto/accessibility/data/spinbox.qml
@@ -0,0 +1,16 @@
+import QtQuick 2.5
+import QtQuick.Window 2.2
+import Qt.labs.controls 1.0
+
+Window {
+ visible: true
+
+ SpinBox {
+ id: spinbox
+ objectName: "spinbox"
+ from: 0
+ to: 100
+ value: 50
+ stepSize: 1
+ }
+}
diff --git a/tests/auto/accessibility/tst_accessibility.cpp b/tests/auto/accessibility/tst_accessibility.cpp
index 873a86c1..a9e04d59 100644
--- a/tests/auto/accessibility/tst_accessibility.cpp
+++ b/tests/auto/accessibility/tst_accessibility.cpp
@@ -82,6 +82,7 @@ void tst_accessibility::a11y_data()
QTest::newRow("ScrollBar") << "scrollbar" << 0x00000003 << ""; //QAccessible::ScrollBar
QTest::newRow("ScrollIndicator") << "scrollindicator" << 0x00000027 << ""; //QAccessible::Indicator
QTest::newRow("Slider") << "slider" << 0x00000033 << ""; //QAccessible::Slider
+ QTest::newRow("SpinBox") << "spinbox" << 0x00000034 << ""; //QAccessible::SpinBox
// StackView
QTest::newRow("Switch") << "switch" << 0x0000002B << "Switch"; //QAccessible::Button
QTest::newRow("TabBar") << "tabbar" << 0x0000003C << ""; //QAccessible::PageTabList
diff --git a/tests/auto/activeFocusOnTab/data/activeFocusOnTab.qml b/tests/auto/activeFocusOnTab/data/activeFocusOnTab.qml
index 5ab0191e..cf107373 100644
--- a/tests/auto/activeFocusOnTab/data/activeFocusOnTab.qml
+++ b/tests/auto/activeFocusOnTab/data/activeFocusOnTab.qml
@@ -141,6 +141,11 @@ Item {
objectName: "slider"
value: 0.5
}
+ SpinBox {
+ id: spinbox
+ objectName: "spinbox"
+ value: 50
+ }
// StackView
Switch {
id: swtich // switch
diff --git a/tests/auto/activeFocusOnTab/tst_activeFocusOnTab.cpp b/tests/auto/activeFocusOnTab/tst_activeFocusOnTab.cpp
index 88607514..c618a2d5 100644
--- a/tests/auto/activeFocusOnTab/tst_activeFocusOnTab.cpp
+++ b/tests/auto/activeFocusOnTab/tst_activeFocusOnTab.cpp
@@ -191,7 +191,16 @@ void tst_activeFocusOnTab::allControls()
QVERIFY(item);
QVERIFY(item->hasActiveFocus());
- // Tab: slider->switch
+ // Tab: slider->spinbox
+ key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "", false, 1);
+ QGuiApplication::sendEvent(window, &key);
+ QVERIFY(key.isAccepted());
+
+ item = findItem<QQuickItem>(window->rootObject(), "spinbox");
+ QVERIFY(item);
+ QVERIFY(item->hasActiveFocus());
+
+ // Tab: spinbox->switch
key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::NoModifier, "", false, 1);
QGuiApplication::sendEvent(window, &key);
QVERIFY(key.isAccepted());
@@ -290,7 +299,16 @@ void tst_activeFocusOnTab::allControls()
QVERIFY(item);
QVERIFY(item->hasActiveFocus());
- // BackTab: switch->switch
+ // BackTab: switch->spinbox
+ key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "", false, 1);
+ QGuiApplication::sendEvent(window, &key);
+ QVERIFY(key.isAccepted());
+
+ item = findItem<QQuickItem>(window->rootObject(), "spinbox");
+ QVERIFY(item);
+ QVERIFY(item->hasActiveFocus());
+
+ // BackTab: spinbox->slider
key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "", false, 1);
QGuiApplication::sendEvent(window, &key);
QVERIFY(key.isAccepted());
@@ -450,7 +468,16 @@ void tst_activeFocusOnTab::textControls()
QVERIFY(item);
QVERIFY(item->hasActiveFocus());
- // BackTab: textfield->textarea
+ // BackTab: textfield->spinbox
+ key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "", false, 1);
+ QGuiApplication::sendEvent(window, &key);
+ QVERIFY(key.isAccepted());
+
+ item = findItem<QQuickItem>(window->rootObject(), "spinbox");
+ QVERIFY(item);
+ QVERIFY(item->hasActiveFocus());
+
+ // BackTab: spinbox->textarea
key = QKeyEvent(QEvent::KeyPress, Qt::Key_Tab, Qt::ShiftModifier, "", false, 1);
QGuiApplication::sendEvent(window, &key);
QVERIFY(key.isAccepted());
diff --git a/tests/auto/controls/data/tst_spinbox.qml b/tests/auto/controls/data/tst_spinbox.qml
new file mode 100644
index 00000000..b5d85dbd
--- /dev/null
+++ b/tests/auto/controls/data/tst_spinbox.qml
@@ -0,0 +1,301 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.2
+import QtTest 1.0
+import Qt.labs.controls 1.0
+
+TestCase {
+ id: testCase
+ width: 400
+ height: 400
+ visible: true
+ when: windowShown
+ name: "SpinBox"
+
+ SignalSpy{
+ id: upPressedSpy
+ signalName: "pressedChanged"
+ }
+
+ SignalSpy{
+ id: downPressedSpy
+ signalName: "pressedChanged"
+ }
+
+ Component {
+ id: spinBox
+ SpinBox { }
+ }
+
+ function init() {
+ verify(!upPressedSpy.target)
+ compare(upPressedSpy.count, 0)
+ verify(!downPressedSpy.target)
+ compare(downPressedSpy.count, 0)
+ }
+
+ function cleanup() {
+ upPressedSpy.target = null
+ upPressedSpy.clear()
+ downPressedSpy.target = null
+ downPressedSpy.clear()
+ }
+
+ function test_defaults() {
+ var control = spinBox.createObject(testCase)
+ verify(control)
+
+ compare(control.from, 0)
+ compare(control.to, 99)
+ compare(control.value, 0)
+ compare(control.stepSize, 1)
+ compare(control.up.pressed, false)
+ compare(control.down.pressed, false)
+
+ control.destroy()
+ }
+
+ function test_value() {
+ var control = spinBox.createObject(testCase)
+ verify(control)
+
+ compare(control.value, 0)
+ control.value = 50
+ compare(control.value, 50)
+ control.value = 99
+ compare(control.value, 99)
+ control.value = -99
+ compare(control.value, 0)
+ control.value = 100
+ compare(control.value, 99)
+
+ control.destroy()
+ }
+
+ function test_range() {
+ var control = spinBox.createObject(testCase, {from: 0, to: 100, value: 50})
+ verify(control)
+
+ compare(control.from, 0)
+ compare(control.to, 100)
+ compare(control.value, 50)
+
+ control.value = 1000
+ compare(control.value, 100)
+
+ control.value = -1
+ compare(control.value, 0)
+
+ control.from = 25
+ compare(control.from, 25)
+ compare(control.value, 25)
+
+ control.to = 75
+ compare(control.to, 75)
+ compare(control.value, 25)
+
+ control.value = 50
+ compare(control.value, 50)
+
+ control.destroy()
+ }
+
+ function test_inverted() {
+ var control = spinBox.createObject(testCase, {from: 100, to: -100})
+ verify(control)
+
+ compare(control.from, 100)
+ compare(control.to, -100)
+ compare(control.value, 0)
+
+ control.value = 200
+ compare(control.value, 100)
+
+ control.value = -200
+ compare(control.value, -100)
+
+ control.value = 0
+ compare(control.value, 0)
+
+ control.destroy()
+ }
+
+ function test_mouse() {
+ var control = spinBox.createObject(testCase, {stepSize: 50})
+ verify(control)
+
+ upPressedSpy.target = control.up
+ verify(upPressedSpy.valid)
+
+ mousePress(control.up.indicator)
+ compare(upPressedSpy.count, 1)
+ compare(control.up.pressed, true)
+ compare(downPressedSpy.count, 0)
+ compare(control.down.pressed, false)
+ compare(control.value, 0)
+
+ mouseRelease(control.up.indicator)
+ compare(upPressedSpy.count, 2)
+ compare(control.up.pressed, false)
+ compare(downPressedSpy.count, 0)
+ compare(control.down.pressed, false)
+ compare(control.value, 50)
+
+ downPressedSpy.target = control.down
+ verify(downPressedSpy.valid)
+
+ mousePress(control.down.indicator)
+ compare(downPressedSpy.count, 1)
+ compare(control.down.pressed, true)
+ compare(upPressedSpy.count, 2)
+ compare(control.up.pressed, false)
+ compare(control.value, 50)
+
+ mouseRelease(control.down.indicator)
+ compare(downPressedSpy.count, 2)
+ compare(control.down.pressed, false)
+ compare(upPressedSpy.count, 2)
+ compare(control.up.pressed, false)
+ compare(control.value, 0)
+
+ control.destroy()
+ }
+
+ function test_keys() {
+ var control = spinBox.createObject(testCase)
+ verify(control)
+
+ var upPressedCount = 0
+ var downPressedCount = 0
+
+ upPressedSpy.target = control.up
+ verify(upPressedSpy.valid)
+
+ downPressedSpy.target = control.down
+ verify(downPressedSpy.valid)
+
+ control.forceActiveFocus()
+ verify(control.activeFocus)
+
+ control.value = 50
+ compare(control.value, 50)
+
+ for (var d1 = 1; d1 <= 10; ++d1) {
+ keyPress(Qt.Key_Down)
+ compare(control.down.pressed, true)
+ compare(control.up.pressed, false)
+ compare(downPressedSpy.count, ++downPressedCount)
+
+ compare(control.value, 50 - d1)
+
+ keyRelease(Qt.Key_Down)
+ compare(control.down.pressed, false)
+ compare(control.up.pressed, false)
+ compare(downPressedSpy.count, ++downPressedCount)
+ }
+ compare(control.value, 40)
+
+ for (var i1 = 1; i1 <= 10; ++i1) {
+ keyPress(Qt.Key_Up)
+ compare(control.up.pressed, true)
+ compare(control.down.pressed, false)
+ compare(upPressedSpy.count, ++upPressedCount)
+
+ compare(control.value, 40 + i1)
+
+ keyRelease(Qt.Key_Up)
+ compare(control.down.pressed, false)
+ compare(control.up.pressed, false)
+ compare(upPressedSpy.count, ++upPressedCount)
+ }
+ compare(control.value, 50)
+
+ control.stepSize = 25
+ compare(control.stepSize, 25)
+
+ for (var d2 = 1; d2 <= 10; ++d2) {
+ keyPress(Qt.Key_Down)
+ compare(control.down.pressed, true)
+ compare(control.up.pressed, false)
+ compare(downPressedSpy.count, ++downPressedCount)
+
+ compare(control.value, Math.max(0, 50 - d2 * 25))
+
+ keyRelease(Qt.Key_Down)
+ compare(control.down.pressed, false)
+ compare(control.up.pressed, false)
+ compare(downPressedSpy.count, ++downPressedCount)
+ }
+ compare(control.value, 0)
+
+ for (var i2 = 1; i2 <= 10; ++i2) {
+ keyPress(Qt.Key_Up)
+ compare(control.up.pressed, true)
+ compare(control.down.pressed, false)
+ compare(upPressedSpy.count, ++upPressedCount)
+
+ compare(control.value, Math.min(99, i2 * 25))
+
+ keyRelease(Qt.Key_Up)
+ compare(control.down.pressed, false)
+ compare(control.up.pressed, false)
+ compare(upPressedSpy.count, ++upPressedCount)
+ }
+ compare(control.value, 99)
+
+ control.destroy()
+ }
+
+ function test_locale() {
+ var control = spinBox.createObject(testCase)
+ verify(control)
+
+ control.locale = Qt.locale("ar_EG") // Arabic, Egypt
+
+ var numbers = ["٠", "١", "٢", "٣", "٤", "٥", "٦", "٧", "٨", "٩"]
+ for (var i = 0; i < 10; ++i) {
+ control.value = i
+ compare(control.contentItem.text, numbers[i])
+ }
+
+ control.destroy()
+ }
+}
diff --git a/tests/auto/snippets/data/qtlabscontrols-spinbox-background.qml b/tests/auto/snippets/data/qtlabscontrols-spinbox-background.qml
new file mode 100644
index 00000000..65545970
--- /dev/null
+++ b/tests/auto/snippets/data/qtlabscontrols-spinbox-background.qml
@@ -0,0 +1,11 @@
+import QtQuick 2.0
+import Qt.labs.controls 1.0
+
+SpinBox {
+ value: 50
+ Rectangle {
+ anchors.fill: parent
+ color: "transparent"
+ border.color: "red"
+ }
+}
diff --git a/tests/auto/snippets/data/qtlabscontrols-spinbox-contentItem.qml b/tests/auto/snippets/data/qtlabscontrols-spinbox-contentItem.qml
new file mode 100644
index 00000000..e0fb39f4
--- /dev/null
+++ b/tests/auto/snippets/data/qtlabscontrols-spinbox-contentItem.qml
@@ -0,0 +1,11 @@
+import QtQuick 2.0
+import Qt.labs.controls 1.0
+
+SpinBox {
+ value: 50
+ Rectangle {
+ anchors.fill: contentItem
+ color: "transparent"
+ border.color: "red"
+ }
+}
diff --git a/tests/auto/snippets/data/qtlabscontrols-spinbox-down.qml b/tests/auto/snippets/data/qtlabscontrols-spinbox-down.qml
new file mode 100644
index 00000000..b6e78c83
--- /dev/null
+++ b/tests/auto/snippets/data/qtlabscontrols-spinbox-down.qml
@@ -0,0 +1,11 @@
+import QtQuick 2.0
+import Qt.labs.controls 1.0
+
+SpinBox {
+ value: 50
+ Rectangle {
+ anchors.fill: down.indicator
+ color: "transparent"
+ border.color: "red"
+ }
+}
diff --git a/tests/auto/snippets/data/qtlabscontrols-spinbox-up.qml b/tests/auto/snippets/data/qtlabscontrols-spinbox-up.qml
new file mode 100644
index 00000000..6f150b56
--- /dev/null
+++ b/tests/auto/snippets/data/qtlabscontrols-spinbox-up.qml
@@ -0,0 +1,11 @@
+import QtQuick 2.0
+import Qt.labs.controls 1.0
+
+SpinBox {
+ value: 50
+ Rectangle {
+ anchors.fill: up.indicator
+ color: "transparent"
+ border.color: "red"
+ }
+}
diff --git a/tests/auto/snippets/data/qtlabscontrols-spinbox.qml b/tests/auto/snippets/data/qtlabscontrols-spinbox.qml
new file mode 100644
index 00000000..588dce65
--- /dev/null
+++ b/tests/auto/snippets/data/qtlabscontrols-spinbox.qml
@@ -0,0 +1,8 @@
+import QtQuick 2.0
+import Qt.labs.controls 1.0
+
+//! [1]
+SpinBox {
+ value: 50
+}
+//! [1]
diff --git a/tests/benchmarks/objectcount/tst_objectcount.cpp b/tests/benchmarks/objectcount/tst_objectcount.cpp
index 3b5db87d..b2170cd5 100644
--- a/tests/benchmarks/objectcount/tst_objectcount.cpp
+++ b/tests/benchmarks/objectcount/tst_objectcount.cpp
@@ -209,6 +209,10 @@ void tst_ObjectCount::testCount_data()
<< QByteArray("import QtQuick.Controls 1.3; Slider { }")
<< QByteArray("import Qt.labs.controls 1.0; Slider { }");
+ QTest::newRow("SpinBox")
+ << QByteArray("import QtQuick.Controls 1.3; SpinBox { }")
+ << QByteArray("import Qt.labs.controls 1.0; SpinBox { }");
+
QTest::newRow("StackView")
<< QByteArray("import QtQuick.Controls 1.3; StackView { }")
<< QByteArray("import Qt.labs.controls 1.0; StackView { }");