diff options
-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.) + } + } } |