diff options
-rw-r--r-- | src/quicktemplates2/qquickdial.cpp | 48 | ||||
-rw-r--r-- | src/quicktemplates2/qquickdial_p.h | 5 | ||||
-rw-r--r-- | tests/auto/controls/data/tst_dial.qml | 38 |
3 files changed, 88 insertions, 3 deletions
diff --git a/src/quicktemplates2/qquickdial.cpp b/src/quicktemplates2/qquickdial.cpp index 7f73d399..e1084978 100644 --- a/src/quicktemplates2/qquickdial.cpp +++ b/src/quicktemplates2/qquickdial.cpp @@ -94,6 +94,7 @@ public: stepSize(0), pressed(false), snapMode(QQuickDial::NoSnap), + wrap(true), handle(nullptr) { } @@ -103,6 +104,7 @@ public: qreal positionAt(const QPoint &point) const; void setPosition(qreal position); void updatePosition(); + bool isLargeChange(const QPoint &eventPos, qreal proposedPosition) const; qreal from; qreal to; @@ -113,6 +115,7 @@ public: bool pressed; QPoint pressPoint; QQuickDial::SnapMode snapMode; + bool wrap; QQuickItem *handle; }; @@ -164,6 +167,11 @@ void QQuickDialPrivate::updatePosition() setPosition(pos); } +bool QQuickDialPrivate::isLargeChange(const QPoint &eventPos, qreal proposedPosition) const +{ + return qAbs(proposedPosition - position) >= 0.5 && eventPos.y() >= height / 2; +} + QQuickDial::QQuickDial(QQuickItem *parent) : QQuickControl(*(new QQuickDialPrivate), parent) { @@ -349,6 +357,33 @@ void QQuickDial::setSnapMode(SnapMode mode) } /*! + \qmlproperty bool Qt.labs.controls::Dial::wrap + + This property holds whether the dial wraps when dragged. + + For example, when this property is set to \c true, dragging the dial past + the \e "zero" position will result in the handle being positioned at the + opposite side, and vice versa. + + The default value is \c true. +*/ +bool QQuickDial::wrap() const +{ + Q_D(const QQuickDial); + return d->wrap; +} + +void QQuickDial::setWrap(bool wrap) +{ + Q_D(QQuickDial); + if (d->wrap == wrap) + return; + + d->wrap = wrap; + emit wrapChanged(); +} + +/*! \qmlproperty bool Qt.labs.controls::Dial::pressed This property holds whether the dial is pressed. @@ -508,7 +543,9 @@ void QQuickDial::mouseMoveEvent(QMouseEvent *event) qreal pos = d->positionAt(event->pos()); if (d->snapMode == SnapAlways) pos = d->snapPosition(pos); - d->setPosition(pos); + + if (d->wrap || (!d->wrap && !d->isLargeChange(event->pos(), pos))) + d->setPosition(pos); } } @@ -516,15 +553,20 @@ void QQuickDial::mouseReleaseEvent(QMouseEvent *event) { Q_D(QQuickDial); QQuickControl::mouseReleaseEvent(event); - d->pressPoint = QPoint(); + if (keepMouseGrab()) { qreal pos = d->positionAt(event->pos()); if (d->snapMode != NoSnap) pos = d->snapPosition(pos); - setValue(d->valueAt(pos)); + + if (d->wrap || (!d->wrap && !d->isLargeChange(event->pos(), pos))) + setValue(d->valueAt(pos)); + setKeepMouseGrab(false); } + setPressed(false); + d->pressPoint = QPoint(); } void QQuickDial::mouseUngrabEvent() diff --git a/src/quicktemplates2/qquickdial_p.h b/src/quicktemplates2/qquickdial_p.h index 6c83baef..f736e607 100644 --- a/src/quicktemplates2/qquickdial_p.h +++ b/src/quicktemplates2/qquickdial_p.h @@ -67,6 +67,7 @@ class Q_QUICKTEMPLATES2_EXPORT QQuickDial : public QQuickControl Q_PROPERTY(qreal angle READ angle NOTIFY angleChanged FINAL) 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) Q_PROPERTY(bool pressed READ isPressed NOTIFY pressedChanged FINAL) Q_PROPERTY(QQuickItem *handle READ handle WRITE setHandle NOTIFY handleChanged FINAL) @@ -99,6 +100,9 @@ public: SnapMode snapMode() const; void setSnapMode(SnapMode mode); + bool wrap() const; + void setWrap(bool wrap); + bool isPressed() const; void setPressed(bool pressed); @@ -117,6 +121,7 @@ Q_SIGNALS: void angleChanged(); void stepSizeChanged(); void snapModeChanged(); + void wrapChanged(); void pressedChanged(); void handleChanged(); diff --git a/tests/auto/controls/data/tst_dial.qml b/tests/auto/controls/data/tst_dial.qml index e0eba27e..0f7a4f85 100644 --- a/tests/auto/controls/data/tst_dial.qml +++ b/tests/auto/controls/data/tst_dial.qml @@ -179,6 +179,7 @@ TestCase { } function test_dragging(data) { + verify(dial.wrap); dial.from = data.from; dial.to = data.to; @@ -210,6 +211,43 @@ TestCase { valueSpy.clear(); } + function test_nonWrapping() { + dial.wrap = false; + dial.value = 0; + + // Ensure that dragging from bottom left to bottom right doesn't work. + var yPos = dial.height * 0.75; + mousePress(dial, dial.width * 0.25, yPos, Qt.LeftButton); + var positionAtPress = dial.position; + mouseMove(dial, dial.width * 0.5, yPos, Qt.LeftButton); + compare(dial.position, positionAtPress); + mouseMove(dial, dial.width * 0.75, yPos, Qt.LeftButton); + compare(dial.position, positionAtPress); + mouseRelease(dial, dial.width * 0.75, yPos, Qt.LeftButton); + compare(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, Qt.LeftButton); + compare(dial.position, positionAtPress); + mouseMove(dial, dial.width * 0.75, yPos, Qt.LeftButton); + compare(dial.position, positionAtPress); + mouseRelease(dial, dial.width * 0.75, yPos, Qt.LeftButton); + compare(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, Qt.LeftButton); + compare(dial.position, positionAtPress); + mouseMove(dial, dial.width * 0.75, dial.height * 0.4, Qt.LeftButton); + verify(dial.position > positionAtPress); + mouseRelease(dial, dial.width * 0.75, dial.height * 0.3, Qt.LeftButton); + verify(dial.position > positionAtPress); + } + property Component focusTest: Component { FocusScope { signal receivedKeyPress |