diff options
author | Matthias Rauter <[email protected]> | 2023-03-17 14:33:40 +0100 |
---|---|---|
committer | Matthias Rauter <[email protected]> | 2023-04-28 09:54:16 +0200 |
commit | d93ca833f65893653071d7ba33fd129fe3db53dc (patch) | |
tree | 7434a2aed7db461c0392d3757cead8e8dd6e709e | |
parent | 0a333bc7e5ae9db1d289a65aa7eef46ae7916936 (diff) |
Add startAngle and endAngle properties to Dial
The start and end angle of the Dial element were hard coded before. Now
they can be set by the application developer using the new properties
startAngle and endAngle. The angle property is set to an angle between
those values, even if it is >360 or <0. The setter functions make sure
that the relation between angle and value is unique. Further, values for
start and endAngle are limited to [-360, 720]. Wrap works as before.
Tests have been updated.
All styles have been updated to the new functionality except the Imagine
style (see task QTBUG-112387).
[ChangeLog][Controls] The start and end angle of the dial element are
made customizabe.
Fixes: QTBUG-57822
Change-Id: I941837008d4f9b4dde1979e91db5adb624bcbe41
Reviewed-by: Mitch Curtis <[email protected]>
-rw-r--r-- | src/quickcontrols/basic/Dial.qml | 2 | ||||
-rw-r--r-- | src/quickcontrols/basic/impl/qquickbasicdial.cpp | 32 | ||||
-rw-r--r-- | src/quickcontrols/basic/impl/qquickbasicdial_p.h | 10 | ||||
-rw-r--r-- | src/quickcontrols/doc/src/qtquickcontrols-imagine.qdoc | 6 | ||||
-rw-r--r-- | src/quickcontrols/ios/Dial.qml | 4 | ||||
-rw-r--r-- | src/quicknativestyle/items/qquickstyleitemdial.cpp | 4 | ||||
-rw-r--r-- | src/quicknativestyle/qstyle/qquickcommonstyle.cpp | 9 | ||||
-rw-r--r-- | src/quicknativestyle/qstyle/qquickstylehelper.cpp | 9 | ||||
-rw-r--r-- | src/quicknativestyle/qstyle/qquickstyleoption.h | 2 | ||||
-rw-r--r-- | src/quicktemplates/qquickdial.cpp | 211 | ||||
-rw-r--r-- | src/quicktemplates/qquickdial_p.h | 10 | ||||
-rw-r--r-- | tests/auto/quickcontrols/controls/data/tst_dial.qml | 153 |
12 files changed, 407 insertions, 45 deletions
diff --git a/src/quickcontrols/basic/Dial.qml b/src/quickcontrols/basic/Dial.qml index 3692ae22de..8648c99442 100644 --- a/src/quickcontrols/basic/Dial.qml +++ b/src/quickcontrols/basic/Dial.qml @@ -20,6 +20,8 @@ T.Dial { color: control.visualFocus ? control.palette.highlight : control.palette.dark progress: control.position opacity: control.enabled ? 1 : 0.3 + startAngle: control.startAngle + endAngle: control.endAngle } handle: ColorImage { diff --git a/src/quickcontrols/basic/impl/qquickbasicdial.cpp b/src/quickcontrols/basic/impl/qquickbasicdial.cpp index 7726bfb159..d2550b7c27 100644 --- a/src/quickcontrols/basic/impl/qquickbasicdial.cpp +++ b/src/quickcontrols/basic/impl/qquickbasicdial.cpp @@ -29,6 +29,34 @@ void QQuickBasicDial::setProgress(qreal progress) update(); } +qreal QQuickBasicDial::startAngle() const +{ + return m_startAngle; +} + +void QQuickBasicDial::setStartAngle(qreal startAngle) +{ + if (startAngle == m_startAngle) + return; + + m_startAngle = startAngle; + update(); +} + +qreal QQuickBasicDial::endAngle() const +{ + return m_endAngle; +} + +void QQuickBasicDial::setEndAngle(qreal endAngle) +{ + if (endAngle == m_endAngle) + return; + + m_endAngle = endAngle; + update(); +} + QColor QQuickBasicDial::color() const { return m_color; @@ -70,8 +98,8 @@ void QQuickBasicDial::paint(QPainter *painter) painter->setRenderHint(QPainter::Antialiasing); - const qreal startAngle = (140 + 90); - const qreal spanAngle = (m_progress * 280) * -1; + const qreal startAngle = 90. - m_startAngle; + const qreal spanAngle = m_progress * (m_startAngle - m_endAngle); QPainterPath path; path.arcMoveTo(rect, startAngle); path.arcTo(rect, startAngle, spanAngle); diff --git a/src/quickcontrols/basic/impl/qquickbasicdial_p.h b/src/quickcontrols/basic/impl/qquickbasicdial_p.h index 1406bf6906..31e533fdc8 100644 --- a/src/quickcontrols/basic/impl/qquickbasicdial_p.h +++ b/src/quickcontrols/basic/impl/qquickbasicdial_p.h @@ -25,6 +25,8 @@ class QQuickBasicDial : public QQuickPaintedItem { Q_OBJECT Q_PROPERTY(qreal progress READ progress WRITE setProgress FINAL) + Q_PROPERTY(qreal startAngle READ startAngle WRITE setStartAngle FINAL) + Q_PROPERTY(qreal endAngle READ endAngle WRITE setEndAngle FINAL) Q_PROPERTY(QColor color READ color WRITE setColor FINAL) QML_NAMED_ELEMENT(DialImpl) QML_ADDED_IN_VERSION(2, 0) @@ -35,6 +37,12 @@ public: qreal progress() const; void setProgress(qreal progress); + qreal startAngle() const; + void setStartAngle(qreal startAngle); + + qreal endAngle() const; + void setEndAngle(qreal endAngle); + QColor color() const; void setColor(const QColor &color); @@ -42,6 +50,8 @@ public: private: qreal m_progress = 0; + qreal m_startAngle = -140.; + qreal m_endAngle = 140.; QColor m_color = Qt::black; }; diff --git a/src/quickcontrols/doc/src/qtquickcontrols-imagine.qdoc b/src/quickcontrols/doc/src/qtquickcontrols-imagine.qdoc index 2e476c3b24..3b78bec57a 100644 --- a/src/quickcontrols/doc/src/qtquickcontrols-imagine.qdoc +++ b/src/quickcontrols/doc/src/qtquickcontrols-imagine.qdoc @@ -129,7 +129,7 @@ \li .9.png (or .png) \row \li \l Dial - \li background + \li background\sup{1} \li disabled, pressed, focused, mirrored, hovered \li .9.png (or .png) \row @@ -469,6 +469,10 @@ \li .9.png (or .png) \endtable + \note \sup{1}) The Imagine style Dial does not yet support the + \l {Dial::}{startAngle} and \l {Dial::}{endAngle} properties that were + introduced in Qt 6.6, and instead uses a fixed background image. + \section2 Asset Examples The following table lists examples of assets (taken from the diff --git a/src/quickcontrols/ios/Dial.qml b/src/quickcontrols/ios/Dial.qml index fe21fdccc4..3fc77035b8 100644 --- a/src/quickcontrols/ios/Dial.qml +++ b/src/quickcontrols/ios/Dial.qml @@ -64,8 +64,8 @@ T.Dial { centerY: control.background.children[0].height / 2 radiusX: control.background.children[0].width / 2 - 2 radiusY: radiusX - startAngle: -230 - sweepAngle: 140 + control.angle + startAngle: control.startAngle - 90 + sweepAngle: control.angle - control.startAngle } } } diff --git a/src/quicknativestyle/items/qquickstyleitemdial.cpp b/src/quicknativestyle/items/qquickstyleitemdial.cpp index e2407e9e81..fe36f866e4 100644 --- a/src/quicknativestyle/items/qquickstyleitemdial.cpp +++ b/src/quicknativestyle/items/qquickstyleitemdial.cpp @@ -19,6 +19,8 @@ void QQuickStyleItemDial::connectToControl() const connect(dial, &QQuickDial::positionChanged, this, &QQuickStyleItem::markImageDirty); connect(dial, &QQuickDial::valueChanged, this, &QQuickStyleItem::markImageDirty); connect(dial, &QQuickDial::stepSizeChanged, this, &QQuickStyleItem::markImageDirty); + connect(dial, &QQuickDial::startAngleChanged, this, &QQuickStyleItem::markImageDirty); + connect(dial, &QQuickDial::endAngleChanged, this, &QQuickStyleItem::markImageDirty); connect(dial, &QQuickDial::pressedChanged, this, &QQuickStyleItem::markImageDirty); } @@ -54,6 +56,8 @@ void QQuickStyleItemDial::initStyleOption(QStyleOptionSlider &styleOption) const styleOption.tickInterval = dial->stepSize(); styleOption.dialWrapping = dial->wrap(); styleOption.upsideDown = true; + styleOption.startAngle = dial->startAngle(); + styleOption.endAngle = dial->endAngle(); if (dial->isPressed()) styleOption.state |= QStyle::State_Sunken; diff --git a/src/quicknativestyle/qstyle/qquickcommonstyle.cpp b/src/quicknativestyle/qstyle/qquickcommonstyle.cpp index 664ca4c528..a962a5792e 100644 --- a/src/quicknativestyle/qstyle/qquickcommonstyle.cpp +++ b/src/quicknativestyle/qstyle/qquickcommonstyle.cpp @@ -2900,14 +2900,13 @@ static StaticPolygonF<3> calcArrow(const QStyleOptionSlider *dial, qreal &a) int r = qMin(width, height) / 2; int currentSliderPosition = dial->upsideDown ? dial->sliderPosition : (dial->maximum - dial->sliderPosition); + qreal startAngle = (90. - dial->startAngle) * Q_PI / 180.; + qreal spanAngle = (dial->endAngle - dial->startAngle) * Q_PI / 180.; if (dial->maximum == dial->minimum) a = Q_PI / 2; - else if (dial->dialWrapping) - a = Q_PI * 3 / 2 - (currentSliderPosition - dial->minimum) * 2 * Q_PI - / (dial->maximum - dial->minimum); else - a = (Q_PI * 8 - (currentSliderPosition - dial->minimum) * 10 * Q_PI - / (dial->maximum - dial->minimum)) / 6; + a = (startAngle - (currentSliderPosition - dial->minimum) * spanAngle + / (dial->maximum - dial->minimum)); int xc = width / 2; int yc = height / 2; diff --git a/src/quicknativestyle/qstyle/qquickstylehelper.cpp b/src/quicknativestyle/qstyle/qquickstylehelper.cpp index dab6b041d8..6b73a5fcf3 100644 --- a/src/quicknativestyle/qstyle/qquickstylehelper.cpp +++ b/src/quicknativestyle/qstyle/qquickstylehelper.cpp @@ -121,14 +121,13 @@ static QPointF calcRadialPos(const QStyleOptionSlider *dial, qreal offset) const int r = qMin(width, height) / 2; const int currentSliderPosition = dial->upsideDown ? dial->sliderPosition : (dial->maximum - dial->sliderPosition); qreal a = 0; + qreal startAngle = (90. - dial->startAngle) * Q_PI / 180.; + qreal spanAngle = (dial->endAngle - dial->startAngle) * Q_PI / 180.; if (dial->maximum == dial->minimum) a = Q_PI / 2; - else if (dial->dialWrapping) - a = Q_PI * 3 / 2 - (currentSliderPosition - dial->minimum) * 2 * Q_PI - / (dial->maximum - dial->minimum); else - a = (Q_PI * 8 - (currentSliderPosition - dial->minimum) * 10 * Q_PI - / (dial->maximum - dial->minimum)) / 6; + a = (startAngle - (currentSliderPosition - dial->minimum) * spanAngle + / (dial->maximum - dial->minimum)); qreal xc = width / 2.0; qreal yc = height / 2.0; qreal len = r - QStyleHelper::calcBigLineSize(r) - 3; diff --git a/src/quicknativestyle/qstyle/qquickstyleoption.h b/src/quicknativestyle/qstyle/qquickstyleoption.h index e7770cc277..02b17dc121 100644 --- a/src/quicknativestyle/qstyle/qquickstyleoption.h +++ b/src/quicknativestyle/qstyle/qquickstyleoption.h @@ -514,6 +514,8 @@ public: int pageStep; qreal notchTarget; bool dialWrapping; + qreal startAngle; + qreal endAngle; QStyleOptionSlider(); QStyleOptionSlider(const QStyleOptionSlider &other) : QStyleOptionComplex(Version, Type) { *this = other; } diff --git a/src/quicktemplates/qquickdial.cpp b/src/quicktemplates/qquickdial.cpp index c5e35c39d2..c955e519ca 100644 --- a/src/quicktemplates/qquickdial.cpp +++ b/src/quicktemplates/qquickdial.cpp @@ -57,10 +57,16 @@ QT_BEGIN_NAMESPACE by the user by either touch, mouse, or keys. */ -static const qreal startAngleRadians = (M_PI * 2.0) * (4.0 / 6.0); -static const qreal startAngle = -140; -static const qreal endAngleRadians = (M_PI * 2.0) * (5.0 / 6.0); -static const qreal endAngle = 140; +// The user angle is the clockwise angle between the position and the vertical +// y-axis (12 o clock position). +// Using radians for logic (atan2(...)) and degree for user interface +constexpr qreal toUserAngleDeg(qreal logicAngleRad) { + // minus to turn clockwise, add 90 deg clockwise + return -logicAngleRad / M_PI * 180. + 90; +} + +static const qreal defaultStartAngle = -140; +static const qreal defaultEndAngle = 140; class QQuickDialPrivate : public QQuickControlPrivate { @@ -74,7 +80,7 @@ public: qreal linearPositionAt(const QPointF &point) const; void setPosition(qreal position); void updatePosition(); - bool isLargeChange(const QPointF &eventPos, qreal proposedPosition) const; + bool isLargeChange(qreal proposedPosition) const; bool isHorizontalOrVertical() const; bool handlePress(const QPointF &point, ulong timestamp) override; @@ -91,6 +97,8 @@ public: qreal to = 1; qreal value = 0; qreal position = 0; + qreal startAngle = defaultStartAngle; + qreal endAngle = defaultEndAngle; qreal angle = startAngle; qreal stepSize = 0; QPointF pressPoint; @@ -140,13 +148,34 @@ qreal QQuickDialPrivate::circularPositionAt(const QPointF &point) const { qreal yy = height / 2.0 - point.y(); qreal xx = point.x() - width / 2.0; - qreal angle = (xx || yy) ? std::atan2(yy, xx) : 0; + qreal alpha = (xx || yy) ? toUserAngleDeg(std::atan2(yy, xx)) : 0; + + // Move around the circle to reach the interval. + if (alpha < startAngle && alpha + 360. < endAngle) + alpha += 360.; + else if (alpha >= endAngle && alpha - 360. >= startAngle) + alpha -= 360.; + + // If wrap is on and we are out of the interval [startAngle, endAngle], + // we want to jump to the closest border to make it feel nice and responsive + if ((alpha < startAngle || alpha > endAngle) && wrap) { + if (abs(alpha - startAngle) > abs(endAngle - alpha - 360.)) + alpha += 360.; + else if (abs(alpha - startAngle - 360.) < abs(endAngle - alpha)) + alpha -= 360.; + } - if (angle < M_PI / -2) - angle = angle + M_PI * 2; + // If wrap is off, + // we want to stay as close as possible to the current angle. + // This is important to allow easy setting of boundary values (0,1) + if (!wrap) { + if (abs(angle - alpha) > abs(angle - (alpha + 360.))) + alpha += 360.; + if (abs(angle - alpha) > abs(angle - (alpha - 360.))) + alpha -= 360.; + } - qreal normalizedAngle = (startAngleRadians - angle) / endAngleRadians; - return normalizedAngle; + return (alpha - startAngle) / (endAngle - startAngle); } qreal QQuickDialPrivate::linearPositionAt(const QPointF &point) const @@ -179,12 +208,13 @@ void QQuickDialPrivate::setPosition(qreal pos) { Q_Q(QQuickDial); pos = qBound<qreal>(qreal(0), pos, qreal(1)); - if (qFuzzyCompare(position, pos)) + const qreal alpha = startAngle + pos * qAbs(endAngle - startAngle); + if (qFuzzyCompare(position, pos) && qFuzzyCompare(angle, alpha)) return; + angle = alpha; position = pos; - angle = startAngle + position * qAbs(endAngle - startAngle); emit q->positionChanged(); emit q->angleChanged(); @@ -198,9 +228,11 @@ void QQuickDialPrivate::updatePosition() setPosition(pos); } -bool QQuickDialPrivate::isLargeChange(const QPointF &eventPos, qreal proposedPosition) const +bool QQuickDialPrivate::isLargeChange(qreal proposedPosition) const { - return qAbs(proposedPosition - position) >= qreal(0.5) && eventPos.y() >= height / 2; + if (endAngle - startAngle < 180) + return false; + return qAbs(proposedPosition - position) > qreal(0.5); } bool QQuickDialPrivate::isHorizontalOrVertical() const @@ -223,11 +255,11 @@ bool QQuickDialPrivate::handleMove(const QPointF &point, ulong timestamp) Q_Q(QQuickDial); QQuickControlPrivate::handleMove(point, timestamp); const qreal oldPos = position; - qreal pos = positionAt(point); + qreal pos = qBound(0.0, positionAt(point), 1.0); if (snapMode == QQuickDial::SnapAlways) pos = snapPosition(pos); - if (wrap || isHorizontalOrVertical() || !isLargeChange(point, pos)) { + if (wrap || isHorizontalOrVertical() || !isLargeChange(pos)) { if (live) q->setValue(valueAt(pos)); else @@ -248,7 +280,7 @@ bool QQuickDialPrivate::handleRelease(const QPointF &point, ulong timestamp) if (snapMode != QQuickDial::NoSnap) pos = snapPosition(pos); - if (wrap || isHorizontalOrVertical() || !isLargeChange(point, pos)) + if (wrap || isHorizontalOrVertical() || !isLargeChange(pos)) q->setValue(valueAt(pos)); if (!qFuzzyCompare(pos, oldPos)) emit q->moved(); @@ -420,11 +452,12 @@ qreal QQuickDial::position() const \qmlproperty real QtQuick.Controls::Dial::angle \readonly - This property holds the angle of the handle. + This property holds the clockwise angle of the handle in degrees. - The range is from \c -140 degrees to \c 140 degrees. + The angle is zero at the 12 o'clock position and the range is from + \l startAngle to \c endAngle. - \sa position + \sa position, startAngle, endAngle */ qreal QQuickDial::angle() const { @@ -467,6 +500,129 @@ void QQuickDial::setStepSize(qreal step) emit stepSizeChanged(); } + +/*! + \qmlproperty real QtQuick.Controls::Dial::startAngle + \since 6.6 + + This property holds the starting angle of the dial in degrees. + + This is the \l angle the dial will have for its minimum value, i.e. \l from. + The \l startAngle has to be smaller than the \l endAngle, larger than -360 + and larger or equal to the \l endAngle - 360 degrees. + + \sa endAngle, angle +*/ +qreal QQuickDial::startAngle() const +{ + Q_D(const QQuickDial); + return d->startAngle; +} + +void QQuickDial::setStartAngle(qreal startAngle) +{ + Q_D(QQuickDial); + if (!d->componentComplete) { + // Binding evaluation order can cause warnings with certain combinations + // of start and end angles, so delay the actual setting until after component completion. + // Store the requested value in the existing member to avoid the need for an extra one. + d->startAngle = startAngle; + return; + } + + if (qFuzzyCompare(d->startAngle, startAngle)) + return; + + // do not allow to change direction + if (startAngle >= d->endAngle) { + qmlWarning(this) << "startAngle (" << startAngle + << ") cannot be greater than or equal to endAngle (" << d->endAngle << ")"; + return; + } + + // Keep the interval around 0 + if (startAngle <= -360.) { + qmlWarning(this) << "startAngle (" << startAngle << ") cannot be less than or equal to -360"; + return; + } + + // keep the interval [startAngle, endAngle] unique + if (startAngle < d->endAngle - 360.) { + qmlWarning(this) << "Difference between startAngle (" << startAngle + << ") and endAngle (" << d->endAngle << ") cannot be greater than 360." + << " Changing endAngle to avoid overlaps."; + d->endAngle = startAngle + 360.; + emit endAngleChanged(); + } + + d->startAngle = startAngle; + // changing the startAngle will change the angle + // if the value is kept constant + d->updatePosition(); + emit startAngleChanged(); +} + +/*! + \qmlproperty real QtQuick.Controls::Dial::endAngle + \since 6.6 + + This property holds the end angle of the dial in degrees. + + This is the \l angle the dial will have for its maximum value, i.e. \l to. + The \l endAngle has to be bigger than the \l startAngle, smaller than 720 + and smaller or equal than the \l startAngle + 360 degrees. + + \sa endAngle, angle +*/ +qreal QQuickDial::endAngle() const +{ + Q_D(const QQuickDial); + return d->endAngle; + +} + +void QQuickDial::setEndAngle(qreal endAngle) +{ + Q_D(QQuickDial); + if (!d->componentComplete) { + // Binding evaluation order can cause warnings with certain combinations + // of start and end angles, so delay the actual setting until after component completion. + // Store the requested value in the existing member to avoid the need for an extra one. + d->endAngle = endAngle; + return; + } + + if (qFuzzyCompare(d->endAngle, endAngle)) + return; + + if (endAngle <= d->startAngle) { + qmlWarning(this) << "endAngle (" << endAngle + << ") cannot be less than or equal to startAngle (" << d->startAngle << ")"; + return; + } + + // Keep the interval around 0 + if (endAngle >= 720.) { + qmlWarning(this) << "endAngle (" << endAngle << ") cannot be greater than or equal to 720"; + return; + } + + // keep the interval [startAngle, endAngle] unique + if (endAngle > d->startAngle + 360.) { + qmlWarning(this) << "Difference between startAngle (" << d->startAngle + << ") and endAngle (" << endAngle << ") cannot be greater than 360." + << " Changing startAngle to avoid overlaps."; + d->startAngle = endAngle - 360.; + emit startAngleChanged(); + } + + d->endAngle = endAngle; + // changing the startAngle will change the angle + // if the value is kept constant + d->updatePosition(); + emit endAngleChanged(); +} + /*! \qmlproperty enumeration QtQuick.Controls::Dial::snapMode @@ -806,6 +962,21 @@ void QQuickDial::componentComplete() Q_D(QQuickDial); d->executeHandle(true); QQuickControl::componentComplete(); + + // Set the (delayed) start and end angles, if necessary (see the setters for more info). + if (!qFuzzyCompare(d->startAngle, defaultStartAngle)) { + const qreal startAngle = d->startAngle; + // Temporarily set it to something else so that it sees that it has changed. + d->startAngle = defaultStartAngle; + setStartAngle(startAngle); + } + + if (!qFuzzyCompare(d->endAngle, defaultEndAngle)) { + const qreal endAngle = d->endAngle; + d->endAngle = defaultEndAngle; + setEndAngle(endAngle); + } + setValue(d->value); d->updatePosition(); } diff --git a/src/quicktemplates/qquickdial_p.h b/src/quicktemplates/qquickdial_p.h index c716b9671b..b291fc673e 100644 --- a/src/quicktemplates/qquickdial_p.h +++ b/src/quicktemplates/qquickdial_p.h @@ -32,6 +32,8 @@ class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickDial : public QQuickControl Q_PROPERTY(qreal value READ value WRITE setValue NOTIFY valueChanged FINAL) Q_PROPERTY(qreal position READ position NOTIFY positionChanged FINAL) Q_PROPERTY(qreal angle READ angle NOTIFY angleChanged FINAL) + Q_PROPERTY(qreal startAngle READ startAngle WRITE setStartAngle NOTIFY startAngleChanged FINAL REVISION(6, 6)) + Q_PROPERTY(qreal endAngle READ endAngle WRITE setEndAngle NOTIFY endAngleChanged FINAL REVISION(6, 6)) Q_PROPERTY(qreal stepSize READ stepSize WRITE setStepSize NOTIFY stepSizeChanged FINAL) Q_PROPERTY(SnapMode snapMode READ snapMode WRITE setSnapMode NOTIFY snapModeChanged FINAL) Q_PROPERTY(bool wrap READ wrap WRITE setWrap NOTIFY wrapChanged FINAL) @@ -64,6 +66,12 @@ public: qreal stepSize() const; void setStepSize(qreal step); + qreal startAngle() const; + void setStartAngle(qreal startAngle); + + qreal endAngle() const; + void setEndAngle(qreal endAngle); + enum SnapMode { NoSnap, SnapAlways, @@ -118,6 +126,8 @@ Q_SIGNALS: Q_REVISION(2, 2) void liveChanged(); // 2.5 (Qt 5.12) Q_REVISION(2, 5) void inputModeChanged(); + Q_REVISION(6, 6) void startAngleChanged(); + Q_REVISION(6, 6) void endAngleChanged(); protected: void keyPressEvent(QKeyEvent *event) override; diff --git a/tests/auto/quickcontrols/controls/data/tst_dial.qml b/tests/auto/quickcontrols/controls/data/tst_dial.qml index 3fcf8c7e88..1f8c1b3827 100644 --- a/tests/auto/quickcontrols/controls/data/tst_dial.qml +++ b/tests/auto/quickcontrols/controls/data/tst_dial.qml @@ -228,29 +228,30 @@ TestCase { mousePress(dial, dial.width * 0.25, yPos, Qt.LeftButton); var positionAtPress = dial.position; mouseMove(dial, dial.width * 0.5, yPos); - compare(dial.position, positionAtPress); + verify(dial.position < positionAtPress); mouseMove(dial, dial.width * 0.75, yPos); - compare(dial.position, positionAtPress); + verify(dial.position < positionAtPress); mouseRelease(dial, dial.width * 0.75, yPos, Qt.LeftButton); - compare(dial.position, positionAtPress); + verify(dial.position < positionAtPress); // Try the same thing, but a bit higher. yPos = dial.height * 0.6; mousePress(dial, dial.width * 0.25, yPos, Qt.LeftButton); positionAtPress = dial.position; mouseMove(dial, dial.width * 0.5, yPos); - compare(dial.position, positionAtPress); + verify(dial.position < positionAtPress); mouseMove(dial, dial.width * 0.75, yPos); - compare(dial.position, positionAtPress); + verify(dial.position < positionAtPress); mouseRelease(dial, dial.width * 0.75, yPos, Qt.LeftButton); - compare(dial.position, positionAtPress); + verify(dial.position < positionAtPress); // Going from below the center of the dial to above it should work (once it gets above the center). mousePress(dial, dial.width * 0.25, dial.height * 0.75, Qt.LeftButton); positionAtPress = dial.position; mouseMove(dial, dial.width * 0.5, dial.height * 0.6); - compare(dial.position, positionAtPress); - mouseMove(dial, dial.width * 0.75, dial.height * 0.4); + verify(dial.position < positionAtPress); + mouseMove(dial, dial.width * 0.5, dial.height * 0.4); //move over the top + mouseMove(dial, dial.width * 0.75, dial.height * 0.6); //and back down again verify(dial.position > positionAtPress); mouseRelease(dial, dial.width * 0.75, dial.height * 0.3, Qt.LeftButton); verify(dial.position > positionAtPress); @@ -289,7 +290,8 @@ TestCase { positionAtPress = dial.position; touch.move(0, dial, dial.width * 0.5, dial.height * 0.6).commit(); compare(dial.position, positionAtPress); - touch.move(0, dial, dial.width * 0.75, dial.height * 0.4).commit(); + touch.move(0, dial, dial.width * 0.5, dial.height * 0.4).commit(); //move over the top + touch.move(0, dial, dial.width * 0.75, dial.height * 0.6).commit(); //and back down again verify(dial.position > positionAtPress); touch.release(0, dial, dial.width * 0.75, dial.height * 0.3).commit(); verify(dial.position > positionAtPress); @@ -434,7 +436,7 @@ TestCase { { tag: "NoSnap", snapMode: Dial.NoSnap, from: 0, to: 2, values: [0, 0, 1], positions: [0, 0.5, 0.5] }, { tag: "SnapAlways (0..2)", snapMode: Dial.SnapAlways, from: 0, to: 2, values: [0.0, 0.0, 1.0], positions: [0.0, 0.5, 0.5] }, { tag: "SnapAlways (1..3)", snapMode: Dial.SnapAlways, from: 1, to: 3, values: [1.0, 1.0, 2.0], positions: [0.0, 0.5, 0.5] }, - { tag: "SnapAlways (-1..1)", snapMode: Dial.SnapAlways, from: -1, to: 1, values: [0.0, 0.0, 0.0], positions: [0.5, 0.5, 0.5] }, + { tag: "SnapAlways (-1..1)", snapMode: Dial.SnapAlways, from: -1, to: 1, values: [0.0, 0.0, 0.0], positions: [immediate ? 0.0 : 0.5, 0.5, 0.5] }, { tag: "SnapAlways (1..-1)", snapMode: Dial.SnapAlways, from: 1, to: -1, values: [1.0, 1.0, 0.0], positions: [0.0, 0.5, 0.5] }, { tag: "SnapOnRelease (0..2)", snapMode: Dial.SnapOnRelease, from: 0, to: 2, values: [0.0, 0.0, 1.0], positions: [0.0, 0.5, 0.5] }, { tag: "SnapOnRelease (1..3)", snapMode: Dial.SnapOnRelease, from: 1, to: 3, values: [1.0, 1.0, 2.0], positions: [0.0, 0.5, 0.5] }, @@ -661,4 +663,135 @@ TestCase { keyClick(Qt.Key_Right) } } + + function test_startEndAngle_data() { + return [ + { + tag: "Default wrap", startAngle: -140, endAngle: 140, from: 0, to: 1, wrap: true, + x: [0.49, 0.25, 0.5, 0.75, 0.51, 0.49], + y: [0.99, 0.5, 0.01, 0.5, 0.99, 0.99], + values: [0.0, 0.5-0.32, 0.5, 0.5+0.32, 1.0, 0.0], //140/90*0.5 = 0.32 + angles: [-140.0, -90.0, 0.0, 90.0, 140.0, -140.0] + }, + { + tag: "-30..30 wrap", startAngle: -30, endAngle: 30, from: 0, to: 1, wrap: true, + x: [0.49, 0.25, 0.5, 0.75, 0.51, 0.49], + y: [0.99, 0.5, 0.01, 0.5, 0.99, 0.99], + values: [0.0, 0.0, 0.5, 1.0, 1.0, 0.0], + angles: [-30.0, -30.0, 0.0, 30.0, 30.0, -30.0] + }, + { + tag: "-180..180 wrap", startAngle: -180, endAngle: 180, from: 0, to: 1, wrap: true, + x: [0.49, 0.25, 0.5, 0.75, 0.51, 0.49], + y: [0.99, 0.5, 0.01, 0.5, 0.99, 0.99], + values: [0.0, 0.25, 0.5, 0.75, 1.0, 0.0], + angles: [-180.0, -90.0, 0.0, 90.0, 180.0, -180.0] + }, + { + tag: "90..360 wrap", startAngle: 90, endAngle: 360, from: 0, to: 1, wrap: true, + x: [0.49, 0.25, 0.5, 0.75, 0.51, 0.49], + y: [0.99, 0.5, 0.01, 0.5, 0.99, 0.99], + values: [0.33, 0.66, 1.0, 0.0, 0.33, 0.33], + angles: [180.0, 270.0, 360.0, 90.0, 180.0, 180.0] + }, + { + tag: "90..450 wrap", startAngle: 90, endAngle: 450, from: 0, to: 1, wrap: true, + x: [0.49, 0.25, 0.5, 0.75, 0.75, 0.51, 0.49], + y: [0.99, 0.5, 0.01, 0.49, 0.501, 0.99, 0.99], + values: [0.25, 0.5, 0.75, 1.0, 0.0, 0.5, 0.5], + angles: [180.0, 270.0, 360.0, 450.0, 90.0, 180.0, 180.0] + }, + { + tag: "Default nowrap", startAngle: -140, endAngle: 140, from: 0, to: 1, wrap: false, + x: [0.49, 0.25, 0.5, 0.75, 0.51, 0.49], + y: [0.99, 0.5, 0.01, 0.5, 0.99, 0.99], + values: [0.0, 0.5-0.32, 0.5, 0.5+0.32, 1.0, 1.0], //140/90*0.5 = 0.32 + angles: [-140.0, -90.0, 0.0, 90.0, 140.0, 140.0] + }, + { + tag: "-30..30 nowrap", startAngle: -30, endAngle: 30, from: 0, to: 1, wrap: false, + x: [0.49, 0.25, 0.5, 0.75, 0.51, 0.49], + y: [0.99, 0.5, 0.01, 0.5, 0.99, 0.99], + values: [0.0, 0.0, 0.5, 1.0, 1.0, 1.0], + angles: [-30.0, -30.0, 0.0, 30.0, 30.0, 30.0] + }, + { + tag: "-180..180 nowrap", startAngle: -180, endAngle: 180, from: 0, to: 1, wrap: false, + x: [0.49, 0.25, 0.5, 0.75, 0.51, 0.49], + y: [0.99, 0.5, 0.01, 0.5, 0.99, 0.99], + values: [0.0, 0.25, 0.5, 0.75, 1.0, 1.0], + angles: [-180.0, -90.0, 0.0, 90.0, 180.0, 180.0] + }, + { + tag: "90..360 nowrap", startAngle: 90, endAngle: 360, from: 0, to: 1, wrap: false, + x: [0.49, 0.25, 0.5, 0.75, 0.51, 0.49], + y: [0.99, 0.5, 0.01, 0.5, 0.99, 0.99], + values: [0.33, 0.66, 1.0, 1.0, 1.0, 1.0], + angles: [180.0, 270.0, 360.0, 360.0, 360.0, 360.0] + } + ] + } + + function test_startEndAngle(data) { + let dial = createTemporaryObject(dialComponent, testCase) + verify(dial) + + dial.startAngle = data.startAngle + dial.endAngle = data.endAngle + dial.from = data.from + dial.to = data.to + //Give a defined start in case wrap = true + dial.value = data.values[0] + dial.wrap = data.wrap + + compare(dial.startAngle, data.startAngle) + compare(dial.endAngle, data.endAngle) + + + for (let i = 0; i < data.x.length; i++) { + mousePress(dial, dial.width * data.x[i], dial.height * 0.5 + dial.width * ( data.y[i] - 0.5)) + fuzzyCompare(dial.angle, data.angles[i], 3.0) + fuzzyCompare(dial.value, data.values[i], 0.3) + } + } + + function test_startEndAngleWarnings(data) { + // Fail on any warning that we don't expect. + failOnWarning(/.?/) + + let dial = createTemporaryObject(dialComponent, testCase) + verify(dial) + + dial.startAngle = -180. + dial.endAngle = 180. + + //provoke warning + ignoreWarning(new RegExp("Changing endAngle to avoid overlaps")) + dial.startAngle = -270. + dial.endAngle = 90. + + compare(dial.startAngle, -270.) + compare(dial.endAngle, 90.) + + + dial.startAngle = -180. + dial.endAngle = 180. + + //provoke warning + ignoreWarning(new RegExp("Changing startAngle to avoid overlaps")) + dial.endAngle = 270. + dial.startAngle = -90. + + compare(dial.startAngle, -90.) + compare(dial.endAngle, 270.) + + { + // Should not warn since we delay the setting of start and end angles to avoid + // binding order evaluation conflicts. + let dial = createTemporaryObject(dialComponent, testCase, { startAngle: -10, endAngle: 300 }) + verify(dial) + compare(dial.startAngle, -10.) + compare(dial.endAngle, 300.) + } + } } |