2015-10-10 14:07:28 +00:00
|
|
|
/****************************************************************************
|
|
|
|
**
|
2017-01-09 16:13:48 +00:00
|
|
|
** Copyright (C) 2017 The Qt Company Ltd.
|
2015-10-10 14:07:28 +00:00
|
|
|
** Contact: http://www.qt.io/licensing/
|
|
|
|
**
|
2016-04-14 05:57:25 +00:00
|
|
|
** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
|
2015-10-10 14:07:28 +00:00
|
|
|
**
|
|
|
|
** $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"
|
2017-12-13 15:10:51 +00:00
|
|
|
#include "qquickdeferredexecute_p_p.h"
|
2015-10-10 14:07:28 +00:00
|
|
|
|
|
|
|
#include <QtGui/qguiapplication.h>
|
|
|
|
#include <QtGui/qstylehints.h>
|
|
|
|
|
2015-10-26 15:36:32 +00:00
|
|
|
#include <QtQml/qqmlinfo.h>
|
|
|
|
#include <QtQml/private/qqmllocale_p.h>
|
|
|
|
#include <QtQml/private/qqmlengine_p.h>
|
2016-11-29 13:27:47 +00:00
|
|
|
#include <QtQuick/private/qquicktextinput_p.h>
|
2015-10-26 15:36:32 +00:00
|
|
|
|
2015-10-10 14:07:28 +00:00
|
|
|
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
|
2019-11-14 07:27:10 +00:00
|
|
|
//! \instantiates QQuickSpinBox
|
2016-04-21 14:56:59 +00:00
|
|
|
\inqmlmodule QtQuick.Controls
|
2016-05-25 06:41:21 +00:00
|
|
|
\since 5.7
|
2015-10-10 14:07:28 +00:00
|
|
|
\ingroup input
|
2018-03-06 14:13:09 +00:00
|
|
|
\ingroup qtquickcontrols2-focusscopes
|
2016-11-02 10:09:35 +00:00
|
|
|
\brief Allows the user to select from a set of preset values.
|
2015-10-10 14:07:28 +00:00
|
|
|
|
2016-04-13 18:30:26 +00:00
|
|
|
\image qtquickcontrols2-spinbox.png
|
2015-10-10 14:07:28 +00:00
|
|
|
|
|
|
|
SpinBox allows the user to choose an integer value by clicking the up
|
2016-02-22 13:13:39 +00:00
|
|
|
or down indicator buttons, or by pressing up or down on the keyboard.
|
|
|
|
Optionally, SpinBox can be also made \l editable, so the user can enter
|
|
|
|
a text value in the input field.
|
2015-10-10 14:07:28 +00:00
|
|
|
|
|
|
|
By default, SpinBox provides discrete values in the range of \c [0-99]
|
|
|
|
with a \l stepSize of \c 1.
|
|
|
|
|
2016-04-13 18:30:26 +00:00
|
|
|
\snippet qtquickcontrols2-spinbox.qml 1
|
2015-10-10 14:07:28 +00:00
|
|
|
|
2015-10-26 15:36:32 +00:00
|
|
|
\section2 Custom Values
|
|
|
|
|
2016-04-13 18:30:26 +00:00
|
|
|
\image qtquickcontrols2-spinbox-textual.png
|
2015-10-26 15:36:32 +00:00
|
|
|
|
|
|
|
Even though SpinBox works on integer values, it can be customized to
|
|
|
|
accept arbitrary input values. The following snippet demonstrates how
|
|
|
|
\l validator, \l textFromValue and \l valueFromText can be used to
|
|
|
|
customize the default behavior.
|
|
|
|
|
2016-04-13 18:30:26 +00:00
|
|
|
\snippet qtquickcontrols2-spinbox-textual.qml 1
|
2015-10-26 15:36:32 +00:00
|
|
|
|
2016-05-11 13:06:51 +00:00
|
|
|
In the same manner, SpinBox can be customized to accept floating point
|
|
|
|
numbers:
|
|
|
|
|
|
|
|
\image qtquickcontrols2-spinbox-double.png
|
|
|
|
|
|
|
|
\snippet qtquickcontrols2-spinbox-double.qml 1
|
|
|
|
|
2019-08-12 14:05:44 +00:00
|
|
|
\sa Tumbler, {Customizing SpinBox}, {Focus Management in Qt Quick Controls}
|
2015-10-10 14:07:28 +00:00
|
|
|
*/
|
|
|
|
|
2016-12-02 13:58:52 +00:00
|
|
|
/*!
|
2017-05-30 14:59:05 +00:00
|
|
|
\since QtQuick.Controls 2.2 (Qt 5.9)
|
2016-12-02 13:58:52 +00:00
|
|
|
\qmlsignal QtQuick.Controls::SpinBox::valueModified()
|
|
|
|
|
|
|
|
This signal is emitted when the spin box value has been interactively
|
|
|
|
modified by the user by either touch, mouse, wheel, or keys.
|
|
|
|
*/
|
|
|
|
|
2015-10-10 14:07:28 +00:00
|
|
|
class QQuickSpinBoxPrivate : public QQuickControlPrivate
|
|
|
|
{
|
|
|
|
Q_DECLARE_PUBLIC(QQuickSpinBox)
|
|
|
|
|
|
|
|
public:
|
2017-04-21 13:58:01 +00:00
|
|
|
int boundValue(int value, bool wrap) const;
|
2015-10-10 14:07:28 +00:00
|
|
|
void updateValue();
|
2017-06-22 18:59:07 +00:00
|
|
|
bool setValue(int value, bool wrap, bool modified);
|
|
|
|
bool stepBy(int steps, bool modified);
|
2017-06-14 17:08:52 +00:00
|
|
|
void increase(bool modified);
|
|
|
|
void decrease(bool modified);
|
2015-10-10 14:07:28 +00:00
|
|
|
|
|
|
|
int effectiveStepSize() const;
|
|
|
|
|
2017-10-24 19:04:43 +00:00
|
|
|
void updateDisplayText();
|
|
|
|
void setDisplayText(const QString &displayText);
|
|
|
|
|
2016-05-23 14:23:16 +00:00
|
|
|
bool upEnabled() const;
|
|
|
|
void updateUpEnabled();
|
|
|
|
bool downEnabled() const;
|
|
|
|
void updateDownEnabled();
|
2016-06-28 12:53:11 +00:00
|
|
|
void updateHover(const QPointF &pos);
|
2016-05-23 14:23:16 +00:00
|
|
|
|
2015-10-10 14:07:28 +00:00
|
|
|
void startRepeatDelay();
|
|
|
|
void startPressRepeat();
|
|
|
|
void stopPressRepeat();
|
|
|
|
|
2017-04-19 15:30:08 +00:00
|
|
|
void handlePress(const QPointF &point) override;
|
|
|
|
void handleMove(const QPointF &point) override;
|
|
|
|
void handleRelease(const QPointF &point) override;
|
|
|
|
void handleUngrab() override;
|
2015-10-10 14:07:28 +00:00
|
|
|
|
2018-04-18 13:35:32 +00:00
|
|
|
void itemImplicitWidthChanged(QQuickItem *item) override;
|
|
|
|
void itemImplicitHeightChanged(QQuickItem *item) override;
|
|
|
|
|
2018-05-03 09:23:56 +00:00
|
|
|
bool editable = false;
|
|
|
|
bool wrap = false;
|
|
|
|
int from = 0;
|
|
|
|
int to = 99;
|
|
|
|
int value = 0;
|
|
|
|
int stepSize = 1;
|
|
|
|
int delayTimer = 0;
|
|
|
|
int repeatTimer = 0;
|
2017-10-24 19:04:43 +00:00
|
|
|
QString displayText;
|
2018-05-03 09:23:56 +00:00
|
|
|
QQuickSpinButton *up = nullptr;
|
|
|
|
QQuickSpinButton *down = nullptr;
|
|
|
|
QValidator *validator = nullptr;
|
2016-01-29 08:46:25 +00:00
|
|
|
mutable QJSValue textFromValue;
|
|
|
|
mutable QJSValue valueFromText;
|
2018-05-03 09:23:56 +00:00
|
|
|
Qt::InputMethodHints inputMethodHints = Qt::ImhDigitsOnly;
|
2015-10-10 14:07:28 +00:00
|
|
|
};
|
|
|
|
|
2017-12-13 15:10:51 +00:00
|
|
|
class QQuickSpinButtonPrivate : public QObjectPrivate
|
|
|
|
{
|
|
|
|
Q_DECLARE_PUBLIC(QQuickSpinButton)
|
|
|
|
|
|
|
|
public:
|
|
|
|
static QQuickSpinButtonPrivate *get(QQuickSpinButton *button)
|
|
|
|
{
|
|
|
|
return button->d_func();
|
|
|
|
}
|
|
|
|
|
2017-12-19 12:38:40 +00:00
|
|
|
void cancelIndicator();
|
2017-12-13 15:10:51 +00:00
|
|
|
void executeIndicator(bool complete = false);
|
|
|
|
|
2018-05-03 09:23:56 +00:00
|
|
|
bool pressed = false;
|
|
|
|
bool hovered = false;
|
2017-12-13 15:10:51 +00:00
|
|
|
QQuickDeferredPointer<QQuickItem> indicator;
|
|
|
|
};
|
|
|
|
|
2017-04-21 13:58:01 +00:00
|
|
|
int QQuickSpinBoxPrivate::boundValue(int value, bool wrap) const
|
2015-10-10 14:07:28 +00:00
|
|
|
{
|
2017-04-21 13:58:01 +00:00
|
|
|
bool inverted = from > to;
|
|
|
|
if (!wrap)
|
|
|
|
return inverted ? qBound(to, value, from) : qBound(from, value, to);
|
|
|
|
|
|
|
|
int f = inverted ? to : from;
|
|
|
|
int t = inverted ? from : to;
|
|
|
|
if (value < f)
|
|
|
|
value = t;
|
|
|
|
else if (value > t)
|
|
|
|
value = f;
|
|
|
|
|
|
|
|
return value;
|
2015-10-10 14:07:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QQuickSpinBoxPrivate::updateValue()
|
|
|
|
{
|
|
|
|
Q_Q(QQuickSpinBox);
|
|
|
|
if (contentItem) {
|
|
|
|
QVariant text = contentItem->property("text");
|
2015-10-26 15:36:32 +00:00
|
|
|
if (text.isValid()) {
|
2017-10-24 19:04:43 +00:00
|
|
|
int val = 0;
|
2016-03-09 10:14:13 +00:00
|
|
|
QQmlEngine *engine = qmlEngine(q);
|
2017-10-24 19:04:43 +00:00
|
|
|
if (engine && valueFromText.isCallable()) {
|
2016-03-09 10:14:13 +00:00
|
|
|
QV4::ExecutionEngine *v4 = QQmlEnginePrivate::getV4Engine(engine);
|
|
|
|
QJSValue loc(v4, QQmlLocale::wrap(v4, locale));
|
2017-10-24 19:04:43 +00:00
|
|
|
val = valueFromText.call(QJSValueList() << text.toString() << loc).toInt();
|
|
|
|
} else {
|
|
|
|
val = locale.toInt(text.toString());
|
2016-03-09 10:14:13 +00:00
|
|
|
}
|
2017-11-06 19:32:26 +00:00
|
|
|
setValue(val, /* allowWrap = */ false, /* modified = */ true);
|
2015-10-26 15:36:32 +00:00
|
|
|
}
|
2015-10-10 14:07:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-22 18:59:07 +00:00
|
|
|
bool QQuickSpinBoxPrivate::setValue(int newValue, bool allowWrap, bool modified)
|
2017-01-17 10:48:45 +00:00
|
|
|
{
|
|
|
|
Q_Q(QQuickSpinBox);
|
|
|
|
if (q->isComponentComplete())
|
2017-04-21 13:58:01 +00:00
|
|
|
newValue = boundValue(newValue, allowWrap);
|
2017-01-17 10:48:45 +00:00
|
|
|
|
|
|
|
if (value == newValue)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
value = newValue;
|
|
|
|
|
2017-10-24 19:04:43 +00:00
|
|
|
updateDisplayText();
|
2017-01-17 10:48:45 +00:00
|
|
|
updateUpEnabled();
|
|
|
|
updateDownEnabled();
|
|
|
|
|
|
|
|
emit q->valueChanged();
|
2017-06-14 17:08:52 +00:00
|
|
|
if (modified)
|
|
|
|
emit q->valueModified();
|
2017-01-17 10:48:45 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-06-22 18:59:07 +00:00
|
|
|
bool QQuickSpinBoxPrivate::stepBy(int steps, bool modified)
|
|
|
|
{
|
|
|
|
return setValue(value + steps, wrap, modified);
|
|
|
|
}
|
|
|
|
|
2017-06-14 17:08:52 +00:00
|
|
|
void QQuickSpinBoxPrivate::increase(bool modified)
|
|
|
|
{
|
2017-06-22 18:59:07 +00:00
|
|
|
setValue(value + effectiveStepSize(), wrap, modified);
|
2017-06-14 17:08:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QQuickSpinBoxPrivate::decrease(bool modified)
|
2017-04-21 13:58:01 +00:00
|
|
|
{
|
2017-06-22 18:59:07 +00:00
|
|
|
setValue(value - effectiveStepSize(), wrap, modified);
|
2017-04-21 13:58:01 +00:00
|
|
|
}
|
|
|
|
|
2015-10-10 14:07:28 +00:00
|
|
|
int QQuickSpinBoxPrivate::effectiveStepSize() const
|
|
|
|
{
|
|
|
|
return from > to ? -1 * stepSize : stepSize;
|
|
|
|
}
|
|
|
|
|
2017-10-24 19:04:43 +00:00
|
|
|
void QQuickSpinBoxPrivate::updateDisplayText()
|
|
|
|
{
|
|
|
|
Q_Q(QQuickSpinBox);
|
|
|
|
QString text;
|
|
|
|
QQmlEngine *engine = qmlEngine(q);
|
|
|
|
if (engine && textFromValue.isCallable()) {
|
|
|
|
QV4::ExecutionEngine *v4 = QQmlEnginePrivate::getV4Engine(engine);
|
|
|
|
QJSValue loc(v4, QQmlLocale::wrap(v4, locale));
|
|
|
|
text = textFromValue.call(QJSValueList() << value << loc).toString();
|
|
|
|
} else {
|
|
|
|
text = locale.toString(value);
|
|
|
|
}
|
|
|
|
setDisplayText(text);
|
|
|
|
}
|
|
|
|
|
|
|
|
void QQuickSpinBoxPrivate::setDisplayText(const QString &text)
|
|
|
|
{
|
|
|
|
Q_Q(QQuickSpinBox);
|
|
|
|
if (displayText == text)
|
|
|
|
return;
|
|
|
|
|
|
|
|
displayText = text;
|
|
|
|
emit q->displayTextChanged();
|
|
|
|
}
|
|
|
|
|
2016-05-23 14:23:16 +00:00
|
|
|
bool QQuickSpinBoxPrivate::upEnabled() const
|
|
|
|
{
|
|
|
|
const QQuickItem *upIndicator = up->indicator();
|
|
|
|
return upIndicator && upIndicator->isEnabled();
|
|
|
|
}
|
|
|
|
|
|
|
|
void QQuickSpinBoxPrivate::updateUpEnabled()
|
|
|
|
{
|
|
|
|
QQuickItem *upIndicator = up->indicator();
|
|
|
|
if (!upIndicator)
|
|
|
|
return;
|
|
|
|
|
2017-04-21 13:58:01 +00:00
|
|
|
upIndicator->setEnabled(wrap || (from < to ? value < to : value > to));
|
2016-05-23 14:23:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool QQuickSpinBoxPrivate::downEnabled() const
|
|
|
|
{
|
|
|
|
const QQuickItem *downIndicator = down->indicator();
|
|
|
|
return downIndicator && downIndicator->isEnabled();
|
|
|
|
}
|
|
|
|
|
|
|
|
void QQuickSpinBoxPrivate::updateDownEnabled()
|
|
|
|
{
|
|
|
|
QQuickItem *downIndicator = down->indicator();
|
|
|
|
if (!downIndicator)
|
|
|
|
return;
|
|
|
|
|
2017-04-21 13:58:01 +00:00
|
|
|
downIndicator->setEnabled(wrap || (from < to ? value > from : value < from));
|
2016-05-23 14:23:16 +00:00
|
|
|
}
|
|
|
|
|
2016-06-28 12:53:11 +00:00
|
|
|
void QQuickSpinBoxPrivate::updateHover(const QPointF &pos)
|
|
|
|
{
|
|
|
|
Q_Q(QQuickSpinBox);
|
|
|
|
QQuickItem *ui = up->indicator();
|
|
|
|
QQuickItem *di = down->indicator();
|
|
|
|
up->setHovered(ui && ui->isEnabled() && ui->contains(q->mapToItem(ui, pos)));
|
|
|
|
down->setHovered(di && di->isEnabled() && di->contains(q->mapToItem(di, pos)));
|
|
|
|
}
|
|
|
|
|
2015-10-10 14:07:28 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-04-19 15:04:50 +00:00
|
|
|
void QQuickSpinBoxPrivate::handlePress(const QPointF &point)
|
2015-10-10 14:07:28 +00:00
|
|
|
{
|
|
|
|
Q_Q(QQuickSpinBox);
|
2017-04-19 15:30:08 +00:00
|
|
|
QQuickControlPrivate::handlePress(point);
|
2015-10-10 14:07:28 +00:00
|
|
|
QQuickItem *ui = up->indicator();
|
|
|
|
QQuickItem *di = down->indicator();
|
2017-01-24 10:26:08 +00:00
|
|
|
up->setPressed(ui && ui->isEnabled() && ui->contains(ui->mapFromItem(q, point)));
|
|
|
|
down->setPressed(di && di->isEnabled() && di->contains(di->mapFromItem(q, point)));
|
2015-10-10 14:07:28 +00:00
|
|
|
|
|
|
|
bool pressed = up->isPressed() || down->isPressed();
|
|
|
|
q->setAccessibleProperty("pressed", pressed);
|
|
|
|
if (pressed)
|
|
|
|
startRepeatDelay();
|
|
|
|
}
|
|
|
|
|
2017-04-19 15:04:50 +00:00
|
|
|
void QQuickSpinBoxPrivate::handleMove(const QPointF &point)
|
2015-10-10 14:07:28 +00:00
|
|
|
{
|
|
|
|
Q_Q(QQuickSpinBox);
|
2017-04-19 15:30:08 +00:00
|
|
|
QQuickControlPrivate::handleMove(point);
|
2015-10-10 14:07:28 +00:00
|
|
|
QQuickItem *ui = up->indicator();
|
|
|
|
QQuickItem *di = down->indicator();
|
2019-03-27 15:23:24 +00:00
|
|
|
up->setHovered(ui && ui->isEnabled() && ui->contains(ui->mapFromItem(q, point)));
|
|
|
|
up->setPressed(up->isHovered());
|
|
|
|
down->setHovered(di && di->isEnabled() && di->contains(di->mapFromItem(q, point)));
|
|
|
|
down->setPressed(down->isHovered());
|
2015-10-10 14:07:28 +00:00
|
|
|
|
|
|
|
bool pressed = up->isPressed() || down->isPressed();
|
|
|
|
q->setAccessibleProperty("pressed", pressed);
|
2016-11-15 13:35:56 +00:00
|
|
|
if (!pressed)
|
|
|
|
stopPressRepeat();
|
2015-10-10 14:07:28 +00:00
|
|
|
}
|
|
|
|
|
2017-04-19 15:04:50 +00:00
|
|
|
void QQuickSpinBoxPrivate::handleRelease(const QPointF &point)
|
2015-10-10 14:07:28 +00:00
|
|
|
{
|
|
|
|
Q_Q(QQuickSpinBox);
|
2017-04-19 15:30:08 +00:00
|
|
|
QQuickControlPrivate::handleRelease(point);
|
2015-10-10 14:07:28 +00:00
|
|
|
QQuickItem *ui = up->indicator();
|
|
|
|
QQuickItem *di = down->indicator();
|
2016-12-02 13:58:52 +00:00
|
|
|
|
|
|
|
int oldValue = value;
|
2015-12-18 14:22:07 +00:00
|
|
|
if (up->isPressed()) {
|
2015-10-10 14:07:28 +00:00
|
|
|
up->setPressed(false);
|
2017-01-24 10:26:08 +00:00
|
|
|
if (repeatTimer <= 0 && ui && ui->contains(ui->mapFromItem(q, point)))
|
2015-10-10 14:07:28 +00:00
|
|
|
q->increase();
|
2015-12-18 14:22:07 +00:00
|
|
|
} else if (down->isPressed()) {
|
2015-10-10 14:07:28 +00:00
|
|
|
down->setPressed(false);
|
2017-01-24 10:26:08 +00:00
|
|
|
if (repeatTimer <= 0 && di && di->contains(di->mapFromItem(q, point)))
|
2015-10-10 14:07:28 +00:00
|
|
|
q->decrease();
|
|
|
|
}
|
2016-12-02 13:58:52 +00:00
|
|
|
if (value != oldValue)
|
|
|
|
emit q->valueModified();
|
2015-10-10 14:07:28 +00:00
|
|
|
|
|
|
|
q->setAccessibleProperty("pressed", false);
|
|
|
|
stopPressRepeat();
|
|
|
|
}
|
|
|
|
|
2017-04-19 15:04:50 +00:00
|
|
|
void QQuickSpinBoxPrivate::handleUngrab()
|
2015-10-10 14:07:28 +00:00
|
|
|
{
|
|
|
|
Q_Q(QQuickSpinBox);
|
2017-04-19 15:30:08 +00:00
|
|
|
QQuickControlPrivate::handleUngrab();
|
2015-10-10 14:07:28 +00:00
|
|
|
up->setPressed(false);
|
|
|
|
down->setPressed(false);
|
|
|
|
|
|
|
|
q->setAccessibleProperty("pressed", false);
|
|
|
|
stopPressRepeat();
|
|
|
|
}
|
|
|
|
|
2018-04-18 13:35:32 +00:00
|
|
|
void QQuickSpinBoxPrivate::itemImplicitWidthChanged(QQuickItem *item)
|
|
|
|
{
|
|
|
|
QQuickControlPrivate::itemImplicitWidthChanged(item);
|
|
|
|
if (item == up->indicator())
|
|
|
|
emit up->implicitIndicatorWidthChanged();
|
|
|
|
else if (item == down->indicator())
|
|
|
|
emit down->implicitIndicatorWidthChanged();
|
|
|
|
}
|
|
|
|
|
|
|
|
void QQuickSpinBoxPrivate::itemImplicitHeightChanged(QQuickItem *item)
|
|
|
|
{
|
|
|
|
QQuickControlPrivate::itemImplicitHeightChanged(item);
|
|
|
|
if (item == up->indicator())
|
|
|
|
emit up->implicitIndicatorHeightChanged();
|
|
|
|
else if (item == down->indicator())
|
|
|
|
emit down->implicitIndicatorHeightChanged();
|
|
|
|
}
|
|
|
|
|
2017-01-19 10:20:11 +00:00
|
|
|
QQuickSpinBox::QQuickSpinBox(QQuickItem *parent)
|
|
|
|
: QQuickControl(*(new QQuickSpinBoxPrivate), parent)
|
2015-10-10 14:07:28 +00:00
|
|
|
{
|
|
|
|
Q_D(QQuickSpinBox);
|
2015-10-30 15:56:51 +00:00
|
|
|
d->up = new QQuickSpinButton(this);
|
|
|
|
d->down = new QQuickSpinButton(this);
|
2015-10-10 14:07:28 +00:00
|
|
|
|
|
|
|
setFlag(ItemIsFocusScope);
|
|
|
|
setFiltersChildMouseEvents(true);
|
2015-12-18 14:22:07 +00:00
|
|
|
setAcceptedMouseButtons(Qt::LeftButton);
|
2017-04-04 14:18:39 +00:00
|
|
|
#if QT_CONFIG(cursor)
|
|
|
|
setCursor(Qt::ArrowCursor);
|
|
|
|
#endif
|
2015-10-10 14:07:28 +00:00
|
|
|
}
|
|
|
|
|
2018-04-18 13:35:32 +00:00
|
|
|
QQuickSpinBox::~QQuickSpinBox()
|
|
|
|
{
|
|
|
|
Q_D(QQuickSpinBox);
|
|
|
|
d->removeImplicitSizeListener(d->up->indicator());
|
|
|
|
d->removeImplicitSizeListener(d->down->indicator());
|
|
|
|
}
|
|
|
|
|
2015-10-10 14:07:28 +00:00
|
|
|
/*!
|
2016-04-21 14:56:59 +00:00
|
|
|
\qmlproperty int QtQuick.Controls::SpinBox::from
|
2015-10-10 14:07:28 +00:00
|
|
|
|
|
|
|
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);
|
2016-02-11 17:24:18 +00:00
|
|
|
if (d->from == from)
|
|
|
|
return;
|
|
|
|
|
|
|
|
d->from = from;
|
|
|
|
emit fromChanged();
|
2017-01-17 10:48:45 +00:00
|
|
|
if (isComponentComplete()) {
|
2017-06-22 18:59:07 +00:00
|
|
|
if (!d->setValue(d->value, /* allowWrap = */ false, /* modified = */ false)) {
|
2017-01-17 10:48:45 +00:00
|
|
|
d->updateUpEnabled();
|
|
|
|
d->updateDownEnabled();
|
|
|
|
}
|
|
|
|
}
|
2015-10-10 14:07:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
2016-04-21 14:56:59 +00:00
|
|
|
\qmlproperty int QtQuick.Controls::SpinBox::to
|
2015-10-10 14:07:28 +00:00
|
|
|
|
|
|
|
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);
|
2016-02-11 17:24:18 +00:00
|
|
|
if (d->to == to)
|
|
|
|
return;
|
|
|
|
|
|
|
|
d->to = to;
|
|
|
|
emit toChanged();
|
2017-01-17 10:48:45 +00:00
|
|
|
if (isComponentComplete()) {
|
2017-06-22 18:59:07 +00:00
|
|
|
if (!d->setValue(d->value, /* allowWrap = */false, /* modified = */ false)) {
|
2017-01-17 10:48:45 +00:00
|
|
|
d->updateUpEnabled();
|
|
|
|
d->updateDownEnabled();
|
|
|
|
}
|
|
|
|
}
|
2015-10-10 14:07:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
2016-04-21 14:56:59 +00:00
|
|
|
\qmlproperty int QtQuick.Controls::SpinBox::value
|
2015-10-10 14:07:28 +00:00
|
|
|
|
|
|
|
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);
|
2017-06-22 18:59:07 +00:00
|
|
|
d->setValue(value, /* allowWrap = */ false, /* modified = */ false);
|
2015-10-10 14:07:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
2016-04-21 14:56:59 +00:00
|
|
|
\qmlproperty int QtQuick.Controls::SpinBox::stepSize
|
2015-10-10 14:07:28 +00:00
|
|
|
|
|
|
|
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);
|
2016-02-11 17:24:18 +00:00
|
|
|
if (d->stepSize == step)
|
|
|
|
return;
|
|
|
|
|
|
|
|
d->stepSize = step;
|
|
|
|
emit stepSizeChanged();
|
2015-10-10 14:07:28 +00:00
|
|
|
}
|
|
|
|
|
2016-02-22 13:13:39 +00:00
|
|
|
/*!
|
2016-04-21 14:56:59 +00:00
|
|
|
\qmlproperty bool QtQuick.Controls::SpinBox::editable
|
2016-02-22 13:13:39 +00:00
|
|
|
|
|
|
|
This property holds whether the spinbox is editable. The default value is \c false.
|
|
|
|
|
|
|
|
\sa validator
|
|
|
|
*/
|
|
|
|
bool QQuickSpinBox::isEditable() const
|
|
|
|
{
|
|
|
|
Q_D(const QQuickSpinBox);
|
|
|
|
return d->editable;
|
|
|
|
}
|
|
|
|
|
|
|
|
void QQuickSpinBox::setEditable(bool editable)
|
|
|
|
{
|
|
|
|
Q_D(QQuickSpinBox);
|
|
|
|
if (d->editable == editable)
|
|
|
|
return;
|
|
|
|
|
2017-04-04 14:18:39 +00:00
|
|
|
#if QT_CONFIG(cursor)
|
|
|
|
if (d->contentItem) {
|
|
|
|
if (editable)
|
|
|
|
d->contentItem->setCursor(Qt::IBeamCursor);
|
|
|
|
else
|
|
|
|
d->contentItem->unsetCursor();
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2016-02-22 13:13:39 +00:00
|
|
|
d->editable = editable;
|
2017-05-20 13:17:50 +00:00
|
|
|
setAccessibleProperty("editable", editable);
|
2016-02-22 13:13:39 +00:00
|
|
|
emit editableChanged();
|
|
|
|
}
|
|
|
|
|
2015-10-26 15:36:32 +00:00
|
|
|
/*!
|
2016-04-21 14:56:59 +00:00
|
|
|
\qmlproperty Validator QtQuick.Controls::SpinBox::validator
|
2015-10-26 15:36:32 +00:00
|
|
|
|
2016-02-22 13:13:39 +00:00
|
|
|
This property holds the input text validator for editable spinboxes. By
|
|
|
|
default, SpinBox uses \l IntValidator to accept input of integer numbers.
|
2015-10-26 15:36:32 +00:00
|
|
|
|
2016-11-01 14:07:51 +00:00
|
|
|
\code
|
|
|
|
SpinBox {
|
|
|
|
id: control
|
|
|
|
validator: IntValidator {
|
|
|
|
locale: control.locale.name
|
|
|
|
bottom: Math.min(control.from, control.to)
|
|
|
|
top: Math.max(control.from, control.to)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
\endcode
|
2015-10-26 15:36:32 +00:00
|
|
|
|
2016-02-22 13:13:39 +00:00
|
|
|
\sa editable, textFromValue, valueFromText, {Control::locale}{locale}
|
2015-10-26 15:36:32 +00:00
|
|
|
*/
|
|
|
|
QValidator *QQuickSpinBox::validator() const
|
|
|
|
{
|
|
|
|
Q_D(const QQuickSpinBox);
|
|
|
|
return d->validator;
|
|
|
|
}
|
|
|
|
|
|
|
|
void QQuickSpinBox::setValidator(QValidator *validator)
|
|
|
|
{
|
|
|
|
Q_D(QQuickSpinBox);
|
2016-02-11 17:24:18 +00:00
|
|
|
if (d->validator == validator)
|
|
|
|
return;
|
|
|
|
|
|
|
|
d->validator = validator;
|
|
|
|
emit validatorChanged();
|
2015-10-26 15:36:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
2016-04-21 14:56:59 +00:00
|
|
|
\qmlproperty function QtQuick.Controls::SpinBox::textFromValue
|
2015-10-26 15:36:32 +00:00
|
|
|
|
|
|
|
This property holds a callback function that is called whenever
|
|
|
|
an integer value needs to be converted to display text.
|
|
|
|
|
2016-10-17 13:06:58 +00:00
|
|
|
The default function can be overridden to display custom text for a given
|
|
|
|
value. This applies to both editable and non-editable spinboxes;
|
|
|
|
for example, when using the up and down buttons or a mouse wheel to
|
|
|
|
increment and decrement the value, the new value is converted to display
|
|
|
|
text using this function.
|
|
|
|
|
2015-10-26 15:36:32 +00:00
|
|
|
The callback function signature is \c {string function(value, locale)}.
|
|
|
|
The function can have one or two arguments, where the first argument
|
|
|
|
is the value to be converted, and the optional second argument is the
|
|
|
|
locale that should be used for the conversion, if applicable.
|
|
|
|
|
2019-02-18 09:20:36 +00:00
|
|
|
The default implementation does the conversion using
|
|
|
|
\l {QtQml::Number::toLocaleString()}{Number.toLocaleString}():
|
2015-10-26 15:36:32 +00:00
|
|
|
|
|
|
|
\code
|
|
|
|
textFromValue: function(value, locale) { return Number(value).toLocaleString(locale, 'f', 0); }
|
|
|
|
\endcode
|
|
|
|
|
2016-10-17 13:06:58 +00:00
|
|
|
\note When applying a custom \c textFromValue implementation for editable
|
|
|
|
spinboxes, a matching \l valueFromText implementation must be provided
|
|
|
|
to be able to convert the custom text back to an integer value.
|
|
|
|
|
2015-12-05 12:00:56 +00:00
|
|
|
\sa valueFromText, validator, {Control::locale}{locale}
|
2015-10-26 15:36:32 +00:00
|
|
|
*/
|
|
|
|
QJSValue QQuickSpinBox::textFromValue() const
|
|
|
|
{
|
|
|
|
Q_D(const QQuickSpinBox);
|
2016-01-29 08:46:25 +00:00
|
|
|
if (!d->textFromValue.isCallable()) {
|
|
|
|
QQmlEngine *engine = qmlEngine(this);
|
|
|
|
if (engine)
|
2018-06-21 07:30:54 +00:00
|
|
|
d->textFromValue = engine->evaluate(QStringLiteral("(function(value, locale) { return Number(value).toLocaleString(locale, 'f', 0); })"));
|
2016-01-29 08:46:25 +00:00
|
|
|
}
|
2015-10-26 15:36:32 +00:00
|
|
|
return d->textFromValue;
|
|
|
|
}
|
|
|
|
|
|
|
|
void QQuickSpinBox::setTextFromValue(const QJSValue &callback)
|
|
|
|
{
|
|
|
|
Q_D(QQuickSpinBox);
|
|
|
|
if (!callback.isCallable()) {
|
2017-01-05 20:07:35 +00:00
|
|
|
qmlWarning(this) << "textFromValue must be a callable function";
|
2015-10-26 15:36:32 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
d->textFromValue = callback;
|
|
|
|
emit textFromValueChanged();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
2016-04-21 14:56:59 +00:00
|
|
|
\qmlproperty function QtQuick.Controls::SpinBox::valueFromText
|
2015-10-26 15:36:32 +00:00
|
|
|
|
|
|
|
This property holds a callback function that is called whenever
|
|
|
|
input text needs to be converted to an integer value.
|
|
|
|
|
2016-10-17 13:06:58 +00:00
|
|
|
This function only needs to be overridden when \l textFromValue
|
|
|
|
is overridden for an editable spinbox.
|
|
|
|
|
2015-10-26 15:36:32 +00:00
|
|
|
The callback function signature is \c {int function(text, locale)}.
|
|
|
|
The function can have one or two arguments, where the first argument
|
|
|
|
is the text to be converted, and the optional second argument is the
|
|
|
|
locale that should be used for the conversion, if applicable.
|
|
|
|
|
|
|
|
The default implementation does the conversion using \l {QtQml::Locale}{Number.fromLocaleString()}:
|
|
|
|
|
|
|
|
\code
|
|
|
|
valueFromText: function(text, locale) { return Number.fromLocaleString(locale, text); }
|
|
|
|
\endcode
|
|
|
|
|
2016-10-17 13:06:58 +00:00
|
|
|
\note When applying a custom \l textFromValue implementation for editable
|
|
|
|
spinboxes, a matching \c valueFromText implementation must be provided
|
|
|
|
to be able to convert the custom text back to an integer value.
|
|
|
|
|
2015-12-05 12:00:56 +00:00
|
|
|
\sa textFromValue, validator, {Control::locale}{locale}
|
2015-10-26 15:36:32 +00:00
|
|
|
*/
|
|
|
|
QJSValue QQuickSpinBox::valueFromText() const
|
|
|
|
{
|
|
|
|
Q_D(const QQuickSpinBox);
|
2016-01-29 08:46:25 +00:00
|
|
|
if (!d->valueFromText.isCallable()) {
|
|
|
|
QQmlEngine *engine = qmlEngine(this);
|
|
|
|
if (engine)
|
|
|
|
d->valueFromText = engine->evaluate(QStringLiteral("function(text, locale) { return Number.fromLocaleString(locale, text); }"));
|
|
|
|
}
|
2015-10-26 15:36:32 +00:00
|
|
|
return d->valueFromText;
|
|
|
|
}
|
|
|
|
|
|
|
|
void QQuickSpinBox::setValueFromText(const QJSValue &callback)
|
|
|
|
{
|
|
|
|
Q_D(QQuickSpinBox);
|
|
|
|
if (!callback.isCallable()) {
|
2017-01-05 20:07:35 +00:00
|
|
|
qmlWarning(this) << "valueFromText must be a callable function";
|
2015-10-26 15:36:32 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
d->valueFromText = callback;
|
|
|
|
emit valueFromTextChanged();
|
|
|
|
}
|
|
|
|
|
2015-10-10 14:07:28 +00:00
|
|
|
/*!
|
2016-04-21 14:56:59 +00:00
|
|
|
\qmlpropertygroup QtQuick.Controls::SpinBox::up
|
|
|
|
\qmlproperty bool QtQuick.Controls::SpinBox::up.pressed
|
|
|
|
\qmlproperty Item QtQuick.Controls::SpinBox::up.indicator
|
2016-06-28 12:53:11 +00:00
|
|
|
\qmlproperty bool QtQuick.Controls::SpinBox::up.hovered
|
2018-04-18 13:35:32 +00:00
|
|
|
\qmlproperty real QtQuick.Controls::SpinBox::up.implicitIndicatorWidth
|
|
|
|
\qmlproperty real QtQuick.Controls::SpinBox::up.implicitIndicatorHeight
|
2015-10-10 14:07:28 +00:00
|
|
|
|
2016-06-28 12:53:11 +00:00
|
|
|
These properties hold the up indicator item and whether it is pressed or
|
2018-04-18 13:35:32 +00:00
|
|
|
hovered. The \c up.hovered property was introduced in QtQuick.Controls 2.1,
|
|
|
|
and the \c up.implicitIndicatorWidth and \c up.implicitIndicatorHeight
|
|
|
|
properties were introduced in QtQuick.Controls 2.5.
|
2015-10-10 14:07:28 +00:00
|
|
|
|
|
|
|
\sa increase()
|
|
|
|
*/
|
2015-10-30 15:56:51 +00:00
|
|
|
QQuickSpinButton *QQuickSpinBox::up() const
|
2015-10-10 14:07:28 +00:00
|
|
|
{
|
|
|
|
Q_D(const QQuickSpinBox);
|
|
|
|
return d->up;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
2016-04-21 14:56:59 +00:00
|
|
|
\qmlpropertygroup QtQuick.Controls::SpinBox::down
|
|
|
|
\qmlproperty bool QtQuick.Controls::SpinBox::down.pressed
|
|
|
|
\qmlproperty Item QtQuick.Controls::SpinBox::down.indicator
|
2016-06-28 12:53:11 +00:00
|
|
|
\qmlproperty bool QtQuick.Controls::SpinBox::down.hovered
|
2018-04-18 13:35:32 +00:00
|
|
|
\qmlproperty real QtQuick.Controls::SpinBox::down.implicitIndicatorWidth
|
|
|
|
\qmlproperty real QtQuick.Controls::SpinBox::down.implicitIndicatorHeight
|
2015-10-10 14:07:28 +00:00
|
|
|
|
2016-06-28 12:53:11 +00:00
|
|
|
These properties hold the down indicator item and whether it is pressed or
|
2018-04-18 13:35:32 +00:00
|
|
|
hovered. The \c down.hovered property was introduced in QtQuick.Controls 2.1,
|
|
|
|
and the \c down.implicitIndicatorWidth and \c down.implicitIndicatorHeight
|
|
|
|
properties were introduced in QtQuick.Controls 2.5.
|
2015-10-10 14:07:28 +00:00
|
|
|
|
|
|
|
\sa decrease()
|
|
|
|
*/
|
2015-10-30 15:56:51 +00:00
|
|
|
QQuickSpinButton *QQuickSpinBox::down() const
|
2015-10-10 14:07:28 +00:00
|
|
|
{
|
|
|
|
Q_D(const QQuickSpinBox);
|
|
|
|
return d->down;
|
|
|
|
}
|
|
|
|
|
2016-11-29 13:27:47 +00:00
|
|
|
/*!
|
2017-05-30 14:59:05 +00:00
|
|
|
\since QtQuick.Controls 2.2 (Qt 5.9)
|
2016-11-29 13:27:47 +00:00
|
|
|
\qmlproperty flags QtQuick.Controls::SpinBox::inputMethodHints
|
|
|
|
|
|
|
|
This property provides hints to the input method about the expected content
|
|
|
|
of the spin box and how it should operate.
|
|
|
|
|
|
|
|
The default value is \c Qt.ImhDigitsOnly.
|
|
|
|
|
|
|
|
\include inputmethodhints.qdocinc
|
|
|
|
*/
|
|
|
|
Qt::InputMethodHints QQuickSpinBox::inputMethodHints() const
|
|
|
|
{
|
|
|
|
Q_D(const QQuickSpinBox);
|
|
|
|
return d->inputMethodHints;
|
|
|
|
}
|
|
|
|
|
|
|
|
void QQuickSpinBox::setInputMethodHints(Qt::InputMethodHints hints)
|
|
|
|
{
|
|
|
|
Q_D(QQuickSpinBox);
|
|
|
|
if (d->inputMethodHints == hints)
|
|
|
|
return;
|
|
|
|
|
|
|
|
d->inputMethodHints = hints;
|
|
|
|
emit inputMethodHintsChanged();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
2017-05-30 14:59:05 +00:00
|
|
|
\since QtQuick.Controls 2.2 (Qt 5.9)
|
2016-11-29 13:27:47 +00:00
|
|
|
\qmlproperty bool QtQuick.Controls::SpinBox::inputMethodComposing
|
|
|
|
\readonly
|
|
|
|
|
|
|
|
This property holds whether an editable spin box has partial text input from an input method.
|
|
|
|
|
|
|
|
While it is composing, an input method may rely on mouse or key events from the spin box to
|
|
|
|
edit or commit the partial text. This property can be used to determine when to disable event
|
|
|
|
handlers that may interfere with the correct operation of an input method.
|
|
|
|
*/
|
|
|
|
bool QQuickSpinBox::isInputMethodComposing() const
|
|
|
|
{
|
|
|
|
Q_D(const QQuickSpinBox);
|
|
|
|
return d->contentItem && d->contentItem->property("inputMethodComposing").toBool();
|
|
|
|
}
|
|
|
|
|
2017-04-21 13:58:01 +00:00
|
|
|
/*!
|
2017-05-30 18:28:15 +00:00
|
|
|
\since QtQuick.Controls 2.3 (Qt 5.10)
|
2017-04-21 13:58:01 +00:00
|
|
|
\qmlproperty bool QtQuick.Controls::SpinBox::wrap
|
|
|
|
|
|
|
|
This property holds whether the spinbox wraps. The default value is \c false.
|
|
|
|
|
|
|
|
If wrap is \c true, stepping past \l to changes the value to \l from and vice versa.
|
|
|
|
*/
|
|
|
|
bool QQuickSpinBox::wrap() const
|
|
|
|
{
|
|
|
|
Q_D(const QQuickSpinBox);
|
|
|
|
return d->wrap;
|
|
|
|
}
|
|
|
|
|
|
|
|
void QQuickSpinBox::setWrap(bool wrap)
|
|
|
|
{
|
|
|
|
Q_D(QQuickSpinBox);
|
|
|
|
if (d->wrap == wrap)
|
|
|
|
return;
|
|
|
|
|
|
|
|
d->wrap = wrap;
|
|
|
|
if (d->value == d->from || d->value == d->to) {
|
|
|
|
d->updateUpEnabled();
|
|
|
|
d->updateDownEnabled();
|
|
|
|
}
|
|
|
|
emit wrapChanged();
|
|
|
|
}
|
|
|
|
|
2017-10-24 19:04:43 +00:00
|
|
|
/*!
|
|
|
|
\since QtQuick.Controls 2.4 (Qt 5.11)
|
|
|
|
\qmlproperty string QtQuick.Controls::SpinBox::displayText
|
|
|
|
\readonly
|
|
|
|
|
|
|
|
This property holds the textual value of the spinbox.
|
|
|
|
|
2018-02-12 18:33:01 +00:00
|
|
|
The value of the property is based on \l textFromValue and \l {Control::}
|
2017-10-24 19:04:43 +00:00
|
|
|
{locale}, and equal to:
|
|
|
|
\badcode
|
|
|
|
var text = spinBox.textFromValue(spinBox.value, spinBox.locale)
|
|
|
|
\endcode
|
|
|
|
|
|
|
|
\sa textFromValue
|
|
|
|
*/
|
|
|
|
QString QQuickSpinBox::displayText() const
|
|
|
|
{
|
|
|
|
Q_D(const QQuickSpinBox);
|
|
|
|
return d->displayText;
|
|
|
|
}
|
|
|
|
|
2015-10-10 14:07:28 +00:00
|
|
|
/*!
|
2016-04-21 14:56:59 +00:00
|
|
|
\qmlmethod void QtQuick.Controls::SpinBox::increase()
|
2015-10-10 14:07:28 +00:00
|
|
|
|
2016-10-17 13:06:58 +00:00
|
|
|
Increases the value by \l stepSize, or \c 1 if stepSize is not defined.
|
2015-10-10 14:07:28 +00:00
|
|
|
|
|
|
|
\sa stepSize
|
|
|
|
*/
|
|
|
|
void QQuickSpinBox::increase()
|
|
|
|
{
|
|
|
|
Q_D(QQuickSpinBox);
|
2017-06-14 17:08:52 +00:00
|
|
|
d->increase(false);
|
2015-10-10 14:07:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
2016-04-21 14:56:59 +00:00
|
|
|
\qmlmethod void QtQuick.Controls::SpinBox::decrease()
|
2015-10-10 14:07:28 +00:00
|
|
|
|
2016-10-17 13:06:58 +00:00
|
|
|
Decreases the value by \l stepSize, or \c 1 if stepSize is not defined.
|
2015-10-10 14:07:28 +00:00
|
|
|
|
|
|
|
\sa stepSize
|
|
|
|
*/
|
|
|
|
void QQuickSpinBox::decrease()
|
|
|
|
{
|
|
|
|
Q_D(QQuickSpinBox);
|
2017-06-14 17:08:52 +00:00
|
|
|
d->decrease(false);
|
2015-10-10 14:07:28 +00:00
|
|
|
}
|
|
|
|
|
2017-04-24 10:07:46 +00:00
|
|
|
void QQuickSpinBox::focusInEvent(QFocusEvent *event)
|
|
|
|
{
|
|
|
|
Q_D(QQuickSpinBox);
|
|
|
|
QQuickControl::focusInEvent(event);
|
|
|
|
|
|
|
|
// When an editable SpinBox gets focus, it must pass on the focus to its editor.
|
|
|
|
if (d->editable && d->contentItem && !d->contentItem->hasActiveFocus())
|
|
|
|
d->contentItem->forceActiveFocus(event->reason());
|
|
|
|
}
|
|
|
|
|
2016-06-28 12:53:11 +00:00
|
|
|
void QQuickSpinBox::hoverEnterEvent(QHoverEvent *event)
|
|
|
|
{
|
|
|
|
Q_D(QQuickSpinBox);
|
|
|
|
QQuickControl::hoverEnterEvent(event);
|
|
|
|
d->updateHover(event->posF());
|
|
|
|
}
|
|
|
|
|
|
|
|
void QQuickSpinBox::hoverMoveEvent(QHoverEvent *event)
|
|
|
|
{
|
|
|
|
Q_D(QQuickSpinBox);
|
|
|
|
QQuickControl::hoverMoveEvent(event);
|
|
|
|
d->updateHover(event->posF());
|
|
|
|
}
|
|
|
|
|
|
|
|
void QQuickSpinBox::hoverLeaveEvent(QHoverEvent *event)
|
|
|
|
{
|
|
|
|
Q_D(QQuickSpinBox);
|
|
|
|
QQuickControl::hoverLeaveEvent(event);
|
|
|
|
d->down->setHovered(false);
|
|
|
|
d->up->setHovered(false);
|
|
|
|
}
|
|
|
|
|
2015-10-10 14:07:28 +00:00
|
|
|
void QQuickSpinBox::keyPressEvent(QKeyEvent *event)
|
|
|
|
{
|
|
|
|
Q_D(QQuickSpinBox);
|
|
|
|
QQuickControl::keyPressEvent(event);
|
|
|
|
|
|
|
|
switch (event->key()) {
|
|
|
|
case Qt::Key_Up:
|
2016-05-23 14:23:16 +00:00
|
|
|
if (d->upEnabled()) {
|
2017-06-14 17:08:52 +00:00
|
|
|
d->increase(true);
|
2016-05-23 14:23:16 +00:00
|
|
|
d->up->setPressed(true);
|
|
|
|
event->accept();
|
|
|
|
}
|
2015-10-10 14:07:28 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case Qt::Key_Down:
|
2016-05-23 14:23:16 +00:00
|
|
|
if (d->downEnabled()) {
|
2017-06-14 17:08:52 +00:00
|
|
|
d->decrease(true);
|
2016-05-23 14:23:16 +00:00
|
|
|
d->down->setPressed(true);
|
|
|
|
event->accept();
|
|
|
|
}
|
2015-10-10 14:07:28 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
setAccessibleProperty("pressed", d->up->isPressed() || d->down->isPressed());
|
|
|
|
}
|
|
|
|
|
|
|
|
void QQuickSpinBox::keyReleaseEvent(QKeyEvent *event)
|
|
|
|
{
|
|
|
|
Q_D(QQuickSpinBox);
|
|
|
|
QQuickControl::keyReleaseEvent(event);
|
|
|
|
|
2016-09-27 12:47:06 +00:00
|
|
|
if (d->editable && (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return))
|
2015-10-10 14:07:28 +00:00
|
|
|
d->updateValue();
|
|
|
|
|
|
|
|
d->up->setPressed(false);
|
|
|
|
d->down->setPressed(false);
|
|
|
|
setAccessibleProperty("pressed", 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())
|
2017-06-14 17:08:52 +00:00
|
|
|
d->increase(true);
|
2015-10-10 14:07:28 +00:00
|
|
|
else if (d->down->isPressed())
|
2017-06-14 17:08:52 +00:00
|
|
|
d->decrease(true);
|
2015-10-10 14:07:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-31 11:55:29 +00:00
|
|
|
#if QT_CONFIG(wheelevent)
|
2016-02-23 14:35:28 +00:00
|
|
|
void QQuickSpinBox::wheelEvent(QWheelEvent *event)
|
|
|
|
{
|
|
|
|
Q_D(QQuickSpinBox);
|
|
|
|
QQuickControl::wheelEvent(event);
|
|
|
|
if (d->wheelEnabled) {
|
|
|
|
const QPointF angle = event->angleDelta();
|
|
|
|
const qreal delta = (qFuzzyIsNull(angle.y()) ? angle.x() : angle.y()) / QWheelEvent::DefaultDeltasPerStep;
|
2018-03-23 09:44:05 +00:00
|
|
|
d->stepBy(qRound(d->effectiveStepSize() * delta), true);
|
2016-02-23 14:35:28 +00:00
|
|
|
}
|
|
|
|
}
|
2017-01-31 11:55:29 +00:00
|
|
|
#endif
|
2016-02-23 14:35:28 +00:00
|
|
|
|
2017-12-13 15:10:51 +00:00
|
|
|
void QQuickSpinBox::classBegin()
|
|
|
|
{
|
|
|
|
Q_D(QQuickSpinBox);
|
|
|
|
QQuickControl::classBegin();
|
|
|
|
|
|
|
|
QQmlContext *context = qmlContext(this);
|
|
|
|
if (context) {
|
|
|
|
QQmlEngine::setContextForObject(d->up, context);
|
|
|
|
QQmlEngine::setContextForObject(d->down, context);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-23 14:23:16 +00:00
|
|
|
void QQuickSpinBox::componentComplete()
|
|
|
|
{
|
|
|
|
Q_D(QQuickSpinBox);
|
2017-12-13 15:10:51 +00:00
|
|
|
QQuickSpinButtonPrivate::get(d->up)->executeIndicator(true);
|
|
|
|
QQuickSpinButtonPrivate::get(d->down)->executeIndicator(true);
|
|
|
|
|
2016-05-23 14:23:16 +00:00
|
|
|
QQuickControl::componentComplete();
|
2017-10-27 09:56:10 +00:00
|
|
|
if (!d->setValue(d->value, /* allowWrap = */ false, /* modified = */ false)) {
|
2017-10-24 19:04:43 +00:00
|
|
|
d->updateDisplayText();
|
2017-08-29 11:58:18 +00:00
|
|
|
d->updateUpEnabled();
|
|
|
|
d->updateDownEnabled();
|
|
|
|
}
|
2016-05-23 14:23:16 +00:00
|
|
|
}
|
|
|
|
|
2015-10-10 14:07:28 +00:00
|
|
|
void QQuickSpinBox::itemChange(ItemChange change, const ItemChangeData &value)
|
|
|
|
{
|
|
|
|
Q_D(QQuickSpinBox);
|
|
|
|
QQuickControl::itemChange(change, value);
|
2016-09-27 12:47:06 +00:00
|
|
|
if (d->editable && change == ItemActiveFocusHasChanged && !value.boolValue)
|
2015-10-10 14:07:28 +00:00
|
|
|
d->updateValue();
|
|
|
|
}
|
|
|
|
|
|
|
|
void QQuickSpinBox::contentItemChange(QQuickItem *newItem, QQuickItem *oldItem)
|
|
|
|
{
|
2017-04-04 14:18:39 +00:00
|
|
|
Q_D(QQuickSpinBox);
|
2016-11-29 13:27:47 +00:00
|
|
|
if (QQuickTextInput *oldInput = qobject_cast<QQuickTextInput *>(oldItem))
|
|
|
|
disconnect(oldInput, &QQuickTextInput::inputMethodComposingChanged, this, &QQuickSpinBox::inputMethodComposingChanged);
|
|
|
|
|
|
|
|
if (newItem) {
|
2015-10-10 14:07:28 +00:00
|
|
|
newItem->setActiveFocusOnTab(true);
|
2017-12-13 15:10:51 +00:00
|
|
|
if (d->activeFocus)
|
|
|
|
newItem->forceActiveFocus(d->focusReason);
|
2017-04-04 14:18:39 +00:00
|
|
|
#if QT_CONFIG(cursor)
|
|
|
|
if (d->editable)
|
|
|
|
newItem->setCursor(Qt::IBeamCursor);
|
|
|
|
#endif
|
2016-11-29 13:27:47 +00:00
|
|
|
|
|
|
|
if (QQuickTextInput *newInput = qobject_cast<QQuickTextInput *>(newItem))
|
|
|
|
connect(newInput, &QQuickTextInput::inputMethodComposingChanged, this, &QQuickSpinBox::inputMethodComposingChanged);
|
|
|
|
}
|
2015-10-10 14:07:28 +00:00
|
|
|
}
|
|
|
|
|
2017-10-24 19:04:43 +00:00
|
|
|
void QQuickSpinBox::localeChange(const QLocale &newLocale, const QLocale &oldLocale)
|
|
|
|
{
|
|
|
|
Q_D(QQuickSpinBox);
|
|
|
|
QQuickControl::localeChange(newLocale, oldLocale);
|
|
|
|
d->updateDisplayText();
|
|
|
|
}
|
|
|
|
|
2016-03-19 19:02:24 +00:00
|
|
|
QFont QQuickSpinBox::defaultFont() const
|
|
|
|
{
|
2018-05-16 11:57:00 +00:00
|
|
|
return QQuickTheme::font(QQuickTheme::SpinBox);
|
2016-03-19 19:02:24 +00:00
|
|
|
}
|
|
|
|
|
2017-05-10 10:47:51 +00:00
|
|
|
QPalette QQuickSpinBox::defaultPalette() const
|
|
|
|
{
|
2018-05-16 11:57:00 +00:00
|
|
|
return QQuickTheme::palette(QQuickTheme::SpinBox);
|
2017-05-10 10:47:51 +00:00
|
|
|
}
|
|
|
|
|
2017-02-23 14:18:57 +00:00
|
|
|
#if QT_CONFIG(accessibility)
|
2015-10-28 14:20:41 +00:00
|
|
|
QAccessible::Role QQuickSpinBox::accessibleRole() const
|
|
|
|
{
|
|
|
|
return QAccessible::SpinBox;
|
|
|
|
}
|
2017-05-20 13:17:50 +00:00
|
|
|
|
|
|
|
void QQuickSpinBox::accessibilityActiveChanged(bool active)
|
|
|
|
{
|
|
|
|
Q_D(QQuickSpinBox);
|
|
|
|
QQuickControl::accessibilityActiveChanged(active);
|
|
|
|
|
|
|
|
if (active)
|
|
|
|
setAccessibleProperty("editable", d->editable);
|
|
|
|
}
|
2015-10-28 14:20:41 +00:00
|
|
|
#endif
|
|
|
|
|
2017-12-13 15:10:51 +00:00
|
|
|
static inline QString indicatorName() { return QStringLiteral("indicator"); }
|
|
|
|
|
2017-12-19 12:38:40 +00:00
|
|
|
void QQuickSpinButtonPrivate::cancelIndicator()
|
|
|
|
{
|
|
|
|
Q_Q(QQuickSpinButton);
|
|
|
|
quickCancelDeferred(q, indicatorName());
|
|
|
|
}
|
|
|
|
|
2017-12-13 15:10:51 +00:00
|
|
|
void QQuickSpinButtonPrivate::executeIndicator(bool complete)
|
2015-10-10 14:07:28 +00:00
|
|
|
{
|
2017-12-13 15:10:51 +00:00
|
|
|
Q_Q(QQuickSpinButton);
|
|
|
|
if (indicator.wasExecuted())
|
|
|
|
return;
|
2017-01-19 09:28:27 +00:00
|
|
|
|
2017-12-19 12:38:40 +00:00
|
|
|
if (!indicator || complete)
|
2017-12-13 15:10:51 +00:00
|
|
|
quickBeginDeferred(q, indicatorName(), indicator);
|
|
|
|
if (complete)
|
|
|
|
quickCompleteDeferred(q, indicatorName(), indicator);
|
|
|
|
}
|
2015-10-10 14:07:28 +00:00
|
|
|
|
2017-01-19 10:20:11 +00:00
|
|
|
QQuickSpinButton::QQuickSpinButton(QQuickSpinBox *parent)
|
|
|
|
: QObject(*(new QQuickSpinButtonPrivate), parent)
|
2015-10-10 14:07:28 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2015-10-30 15:56:51 +00:00
|
|
|
bool QQuickSpinButton::isPressed() const
|
2015-10-10 14:07:28 +00:00
|
|
|
{
|
2015-10-30 15:56:51 +00:00
|
|
|
Q_D(const QQuickSpinButton);
|
2015-10-10 14:07:28 +00:00
|
|
|
return d->pressed;
|
|
|
|
}
|
|
|
|
|
2015-10-30 15:56:51 +00:00
|
|
|
void QQuickSpinButton::setPressed(bool pressed)
|
2015-10-10 14:07:28 +00:00
|
|
|
{
|
2015-10-30 15:56:51 +00:00
|
|
|
Q_D(QQuickSpinButton);
|
2016-02-11 17:24:18 +00:00
|
|
|
if (d->pressed == pressed)
|
|
|
|
return;
|
|
|
|
|
|
|
|
d->pressed = pressed;
|
|
|
|
emit pressedChanged();
|
2015-10-10 14:07:28 +00:00
|
|
|
}
|
|
|
|
|
2015-10-30 15:56:51 +00:00
|
|
|
QQuickItem *QQuickSpinButton::indicator() const
|
2015-10-10 14:07:28 +00:00
|
|
|
{
|
2017-12-13 15:10:51 +00:00
|
|
|
QQuickSpinButtonPrivate *d = const_cast<QQuickSpinButtonPrivate *>(d_func());
|
|
|
|
if (!d->indicator)
|
|
|
|
d->executeIndicator();
|
2015-10-10 14:07:28 +00:00
|
|
|
return d->indicator;
|
|
|
|
}
|
|
|
|
|
2015-10-30 15:56:51 +00:00
|
|
|
void QQuickSpinButton::setIndicator(QQuickItem *indicator)
|
2015-10-10 14:07:28 +00:00
|
|
|
{
|
2015-10-30 15:56:51 +00:00
|
|
|
Q_D(QQuickSpinButton);
|
2016-02-11 17:24:18 +00:00
|
|
|
if (d->indicator == indicator)
|
|
|
|
return;
|
|
|
|
|
2017-12-19 12:38:40 +00:00
|
|
|
if (!d->indicator.isExecuting())
|
|
|
|
d->cancelIndicator();
|
|
|
|
|
2018-04-18 13:35:32 +00:00
|
|
|
const qreal oldImplicitIndicatorWidth = implicitIndicatorWidth();
|
|
|
|
const qreal oldImplicitIndicatorHeight = implicitIndicatorHeight();
|
|
|
|
|
|
|
|
QQuickSpinBox *spinBox = static_cast<QQuickSpinBox *>(parent());
|
|
|
|
QQuickSpinBoxPrivate::get(spinBox)->removeImplicitSizeListener(d->indicator);
|
Don't delete items we didn't create
Up until this patch, we've always deleted "old" items when a new one is
assigned. For example, the style's implementation of contentItem will
be destroyed here as it is not accessible by the user and is no longer
used:
Button {
contentItem: Item { /* ... */ }
}
This was especially important before the introduction of deferred
execution, as the "default" items would always be created, regardless
of whether the user had overridden it with one of their own items.
By deleting the old items, we free unused resources that would
otherwise persist until application shutdown (calling gc() does not
result in the items being garbage-collected, from my testing).
Although this has largely worked without issues, deleting objects
that weren't created by us in C++ is not supported. User-assigned items
can be created in QML (with JavaScriptOwnership) or C++ (with
CppOwnership), and it is up to the user and/or the QML engine to
manage the lifetime of these items.
After the introduction of deferred execution, it became possible to
skip creation of the default items altogether, meaning that there was
nothing to delete when assigning a new, user-specified item. This
requires that no ids are used in these items, as doing so prevents
deferred execution. Assuming that users avoid using ids in their items,
there should be no unused items that live unnecessarily until
application shutdown. The remaining cases where items do not get
destroyed when they should result from the following:
- Imperative assignments (e.g. assigning an item to a Button's
contentItem in Component.onCompleted). We already encourage
declarative bindings rather than imperative assignments.
- Using ids in items.
Given that these are use cases that we will advise against in the
documentation, it's an acceptable compromise.
[ChangeLog][Important Behavior Changes] Old delegate items (background,
contentItem, etc.) are no longer destroyed, as they are technically
owned by user code. Instead, they are hidden, unparented from the
control (QQuickItem parent, not QObject), and Accessible.ignored is
set to true. This prevents them from being unintentionally visible and
interfering with the accessibility tree when a new delegate item is
set.
Change-Id: I56c39a73dfee989dbe8f8b8bb33aaa187750fdb7
Task-number: QTBUG-72085
Fixes: QTBUG-70144
Fixes: QTBUG-75605
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
2019-11-08 14:53:18 +00:00
|
|
|
QQuickControlPrivate::hideOldItem(d->indicator);
|
2016-02-11 17:24:18 +00:00
|
|
|
d->indicator = indicator;
|
2016-09-07 13:49:37 +00:00
|
|
|
|
2016-02-11 17:24:18 +00:00
|
|
|
if (indicator) {
|
|
|
|
if (!indicator->parentItem())
|
2018-04-18 13:35:32 +00:00
|
|
|
indicator->setParentItem(spinBox);
|
|
|
|
QQuickSpinBoxPrivate::get(spinBox)->addImplicitSizeListener(indicator);
|
2015-10-10 14:07:28 +00:00
|
|
|
}
|
2018-04-18 13:35:32 +00:00
|
|
|
|
|
|
|
if (!qFuzzyCompare(oldImplicitIndicatorWidth, implicitIndicatorWidth()))
|
|
|
|
emit implicitIndicatorWidthChanged();
|
|
|
|
if (!qFuzzyCompare(oldImplicitIndicatorHeight, implicitIndicatorHeight()))
|
|
|
|
emit implicitIndicatorHeightChanged();
|
2017-12-13 15:10:51 +00:00
|
|
|
if (!d->indicator.isExecuting())
|
|
|
|
emit indicatorChanged();
|
2015-10-10 14:07:28 +00:00
|
|
|
}
|
|
|
|
|
2017-11-04 09:49:42 +00:00
|
|
|
bool QQuickSpinButton::isHovered() const
|
|
|
|
{
|
|
|
|
Q_D(const QQuickSpinButton);
|
|
|
|
return d->hovered;
|
|
|
|
}
|
|
|
|
|
|
|
|
void QQuickSpinButton::setHovered(bool hovered)
|
|
|
|
{
|
|
|
|
Q_D(QQuickSpinButton);
|
|
|
|
if (d->hovered == hovered)
|
|
|
|
return;
|
|
|
|
|
|
|
|
d->hovered = hovered;
|
|
|
|
emit hoveredChanged();
|
|
|
|
}
|
|
|
|
|
2018-04-18 13:35:32 +00:00
|
|
|
qreal QQuickSpinButton::implicitIndicatorWidth() const
|
|
|
|
{
|
|
|
|
Q_D(const QQuickSpinButton);
|
|
|
|
if (!d->indicator)
|
|
|
|
return 0;
|
|
|
|
return d->indicator->implicitWidth();
|
|
|
|
}
|
|
|
|
|
|
|
|
qreal QQuickSpinButton::implicitIndicatorHeight() const
|
|
|
|
{
|
|
|
|
Q_D(const QQuickSpinButton);
|
|
|
|
if (!d->indicator)
|
|
|
|
return 0;
|
|
|
|
return d->indicator->implicitHeight();
|
|
|
|
}
|
|
|
|
|
2015-10-10 14:07:28 +00:00
|
|
|
QT_END_NAMESPACE
|