diff options
author | Mitch Curtis <mitch.curtis@qt.io> | 2017-08-09 17:36:44 +0200 |
---|---|---|
committer | Mitch Curtis <mitch.curtis@qt.io> | 2018-05-15 09:11:57 +0000 |
commit | 9e1a353a864cf777034b969a59fb1d616b7bfc73 (patch) | |
tree | ed8faae6a5ca840e21936e7f7ae729be209b1eba /src/quicktemplates2 | |
parent | 4458589b4082ca060384f5b3af8dfcbdb677da4d (diff) |
Dial: add inputMode property
This property adds two new ways of interacting with the dial:
horizontally and vertically. These new input modes use a relative
input system, which means that, unlike the old absolute input system,
changes to the dial's position are "added" to its value. This results
in a dial that is less "jumpy", making it safe for operations that
could be harmful if done incorrectly, like adjusting audio levels.
[ChangeLog][Controls][Dial] Added the inputMode property. This property
controls how the dial is interacted with. The circular input mode
(default, old behavior) operates on an absolute input system, whereas
the horizontal and vertical input modes use a relative input system.
Task-number: QTBUG-56323
Change-Id: Iab4e7f048b4797ab626741326ce709914e67bd31
Reviewed-by: J-P Nurmi <jpnurmi@qt.io>
Diffstat (limited to 'src/quicktemplates2')
-rw-r--r-- | src/quicktemplates2/qquickdial.cpp | 76 | ||||
-rw-r--r-- | src/quicktemplates2/qquickdial_p.h | 15 |
2 files changed, 89 insertions, 2 deletions
diff --git a/src/quicktemplates2/qquickdial.cpp b/src/quicktemplates2/qquickdial.cpp index a4124678..123f9b1b 100644 --- a/src/quicktemplates2/qquickdial.cpp +++ b/src/quicktemplates2/qquickdial.cpp @@ -75,6 +75,8 @@ QT_BEGIN_NAMESPACE \row \li Set \l value to \l to \li \c Qt.Key_End \endtable + \include qquickdial.qdocinc inputMode + \sa {Customizing Dial}, {Input Controls} */ @@ -99,9 +101,12 @@ public: qreal valueAt(qreal position) const; qreal snapPosition(qreal position) const; qreal positionAt(const QPointF &point) const; + qreal circularPositionAt(const QPointF &point) const; + qreal linearPositionAt(const QPointF &point) const; void setPosition(qreal position); void updatePosition(); bool isLargeChange(const QPointF &eventPos, qreal proposedPosition) const; + bool isHorizontalOrVertical() const; void handlePress(const QPointF &point) override; void handleMove(const QPointF &point) override; @@ -119,7 +124,9 @@ public: qreal stepSize = 0; bool pressed = false; QPointF pressPoint; + qreal positionBeforePress = 0; QQuickDial::SnapMode snapMode = QQuickDial::NoSnap; + QQuickDial::InputMode inputMode = QQuickDial::Circular; bool wrap = false; bool live = true; QQuickDeferredPointer<QQuickItem> handle; @@ -145,6 +152,11 @@ qreal QQuickDialPrivate::snapPosition(qreal position) const qreal QQuickDialPrivate::positionAt(const QPointF &point) const { + return inputMode == QQuickDial::Circular ? circularPositionAt(point) : linearPositionAt(point); +} + +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; @@ -156,6 +168,32 @@ qreal QQuickDialPrivate::positionAt(const QPointF &point) const return normalizedAngle; } +qreal QQuickDialPrivate::linearPositionAt(const QPointF &point) const +{ + // This value determines the range (either horizontal or vertical) + // within which the dial can be dragged. + // The larger this value is, the further the drag distance + // must be to go from a position of e.g. 0.0 to 1.0. + qreal dragArea = 0; + + // The linear input mode uses a "relative" input system, + // where the distance from the press point is used to calculate + // the change in position. Moving the mouse above the press + // point increases the position (when inputMode is Vertical), + // and vice versa. This prevents the dial from jumping when clicked. + qreal dragDistance = 0; + + if (inputMode == QQuickDial::Horizontal) { + dragArea = width * 2; + dragDistance = pressPoint.x() - point.x(); + } else { + dragArea = height * 2; + dragDistance = point.y() - pressPoint.y(); + } + const qreal normalisedDifference = dragDistance / dragArea; + return qBound(0.0, positionBeforePress - normalisedDifference, 1.0); +} + void QQuickDialPrivate::setPosition(qreal pos) { Q_Q(QQuickDial); @@ -184,11 +222,17 @@ bool QQuickDialPrivate::isLargeChange(const QPointF &eventPos, qreal proposedPos return qAbs(proposedPosition - position) >= 0.5 && eventPos.y() >= height / 2; } +bool QQuickDialPrivate::isHorizontalOrVertical() const +{ + return inputMode == QQuickDial::Horizontal || inputMode == QQuickDial::Vertical; +} + void QQuickDialPrivate::handlePress(const QPointF &point) { Q_Q(QQuickDial); QQuickControlPrivate::handlePress(point); pressPoint = point; + positionBeforePress = position; q->setPressed(true); } @@ -201,7 +245,7 @@ void QQuickDialPrivate::handleMove(const QPointF &point) if (snapMode == QQuickDial::SnapAlways) pos = snapPosition(pos); - if (wrap || (!wrap && !isLargeChange(point, pos))) { + if (wrap || (!wrap && (isHorizontalOrVertical() || !isLargeChange(point, pos)))) { if (live) q->setValue(valueAt(pos)); else @@ -221,7 +265,7 @@ void QQuickDialPrivate::handleRelease(const QPointF &point) if (snapMode != QQuickDial::NoSnap) pos = snapPosition(pos); - if (wrap || (!wrap && !isLargeChange(point, pos))) + if (wrap || (!wrap && (isHorizontalOrVertical() || !isLargeChange(point, pos)))) q->setValue(valueAt(pos)); if (!qFuzzyCompare(pos, oldPos)) emit q->moved(); @@ -232,6 +276,7 @@ void QQuickDialPrivate::handleRelease(const QPointF &point) q->setPressed(false); pressPoint = QPointF(); + positionBeforePress = 0; } void QQuickDialPrivate::handleUngrab() @@ -239,6 +284,7 @@ void QQuickDialPrivate::handleUngrab() Q_Q(QQuickDial); QQuickControlPrivate::handleUngrab(); pressPoint = QPointF(); + positionBeforePress = 0; q->setPressed(false); } @@ -454,6 +500,32 @@ void QQuickDial::setSnapMode(SnapMode mode) } /*! + \since QtQuick.Controls 2.5 (Qt 5.12) + \qmlproperty enumeration QtQuick.Controls::Dial::inputMode + + This property holds the input mode. + + \include qquickdial.qdocinc inputMode + + The default value is \c Dial.Circular. +*/ +QQuickDial::InputMode QQuickDial::inputMode() const +{ + Q_D(const QQuickDial); + return d->inputMode; +} + +void QQuickDial::setInputMode(QQuickDial::InputMode mode) +{ + Q_D(QQuickDial); + if (d->inputMode == mode) + return; + + d->inputMode = mode; + emit inputModeChanged(); +} + +/*! \qmlproperty bool QtQuick.Controls::Dial::wrap This property holds whether the dial wraps when dragged. diff --git a/src/quicktemplates2/qquickdial_p.h b/src/quicktemplates2/qquickdial_p.h index d2caccfc..cc641c78 100644 --- a/src/quicktemplates2/qquickdial_p.h +++ b/src/quicktemplates2/qquickdial_p.h @@ -72,6 +72,8 @@ class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickDial : public QQuickControl Q_PROPERTY(QQuickItem *handle READ handle WRITE setHandle NOTIFY handleChanged FINAL) // 2.2 (Qt 5.9) Q_PROPERTY(bool live READ live WRITE setLive NOTIFY liveChanged FINAL REVISION 2) + // 2.5 (Qt 5.12) + Q_PROPERTY(InputMode inputMode READ inputMode WRITE setInputMode NOTIFY inputModeChanged FINAL REVISION 5) Q_CLASSINFO("DeferredPropertyNames", "background,handle") public: @@ -103,6 +105,13 @@ public: SnapMode snapMode() const; void setSnapMode(SnapMode mode); + enum InputMode { + Circular, + Horizontal, + Vertical, + }; + Q_ENUM(InputMode) + bool wrap() const; void setWrap(bool wrap); @@ -116,6 +125,10 @@ public: bool live() const; void setLive(bool live); + // 2.5 (Qt 5.12) + InputMode inputMode() const; + void setInputMode(InputMode mode); + public Q_SLOTS: void increase(); void decrease(); @@ -134,6 +147,8 @@ Q_SIGNALS: // 2.2 (Qt 5.9) Q_REVISION(2) void moved(); Q_REVISION(2) void liveChanged(); + // 2.5 (Qt 5.12) + Q_REVISION(5) void inputModeChanged(); protected: void keyPressEvent(QKeyEvent *event) override; |