aboutsummaryrefslogtreecommitdiffstats
path: root/src/quicktemplates2/qquickdial.cpp
diff options
context:
space:
mode:
authorMitch Curtis <mitch.curtis@qt.io>2017-08-09 17:36:44 +0200
committerMitch Curtis <mitch.curtis@qt.io>2018-05-15 09:11:57 +0000
commit9e1a353a864cf777034b969a59fb1d616b7bfc73 (patch)
treeed8faae6a5ca840e21936e7f7ae729be209b1eba /src/quicktemplates2/qquickdial.cpp
parent4458589b4082ca060384f5b3af8dfcbdb677da4d (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/qquickdial.cpp')
-rw-r--r--src/quicktemplates2/qquickdial.cpp76
1 files changed, 74 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.