1/****************************************************************************
2**
3** Copyright (C) 2017 The Qt Company Ltd.
4** Contact: http://www.qt.io/licensing/
5**
6** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL3$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see http://www.qt.io/terms-conditions. For further
15** information use the contact form at http://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPLv3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or later as published by the Free
28** Software Foundation and appearing in the file LICENSE.GPL included in
29** the packaging of this file. Please review the following information to
30** ensure the GNU General Public License version 2.0 requirements will be
31** met: http://www.gnu.org/licenses/gpl-2.0.html.
32**
33** $QT_END_LICENSE$
34**
35****************************************************************************/
36
37#include "qquickdial_p.h"
38#include "qquickdeferredexecute_p_p.h"
39
40#include <QtCore/qmath.h>
41#include <QtQuick/private/qquickflickable_p.h>
42#include <QtQuickTemplates2/private/qquickcontrol_p_p.h>
43
44#include <cmath>
45
46QT_BEGIN_NAMESPACE
47
48/*!
49 \qmltype Dial
50 \inherits Control
51//! \instantiates QQuickDial
52 \inqmlmodule QtQuick.Controls
53 \since 5.7
54 \ingroup qtquickcontrols2-input
55 \brief Circular dial that is rotated to set a value.
56
57 The Dial is similar to a traditional dial knob that is found on devices
58 such as stereos or industrial equipment. It allows the user to specify a
59 value within a range.
60
61 \image qtquickcontrols2-dial-no-wrap.gif
62
63 The value of the dial is set with the \l value property. The range is
64 set with the \l from and \l to properties. To enable or disable wrapping,
65 use the \l wrap property.
66
67 The dial can be manipulated with a keyboard. It supports the following
68 actions:
69
70 \table
71 \header \li \b {Action} \li \b {Key}
72 \row \li Decrease \l value by \l stepSize \li \c Qt.Key_Left
73 \row \li Decrease \l value by \l stepSize \li \c Qt.Key_Down
74 \row \li Set \l value to \l from \li \c Qt.Key_Home
75 \row \li Increase \l value by \l stepSize \li \c Qt.Key_Right
76 \row \li Increase \l value by \l stepSize \li \c Qt.Key_Up
77 \row \li Set \l value to \l to \li \c Qt.Key_End
78 \endtable
79
80 \include qquickdial.qdocinc inputMode
81
82 \sa {Customizing Dial}, {Input Controls}
83*/
84
85/*!
86 \since QtQuick.Controls 2.2 (Qt 5.9)
87 \qmlsignal QtQuick.Controls::Dial::moved()
88
89 This signal is emitted when the dial has been interactively moved
90 by the user by either touch, mouse, or keys.
91*/
92
93static const qreal startAngleRadians = (M_PI * 2.0) * (4.0 / 6.0);
94static const qreal startAngle = -140;
95static const qreal endAngleRadians = (M_PI * 2.0) * (5.0 / 6.0);
96static const qreal endAngle = 140;
97
98class QQuickDialPrivate : public QQuickControlPrivate
99{
100 Q_DECLARE_PUBLIC(QQuickDial)
101
102public:
103 qreal valueAt(qreal position) const;
104 qreal snapPosition(qreal position) const;
105 qreal positionAt(const QPointF &point) const;
106 qreal circularPositionAt(const QPointF &point) const;
107 qreal linearPositionAt(const QPointF &point) const;
108 void setPosition(qreal position);
109 void updatePosition();
110 bool isLargeChange(const QPointF &eventPos, qreal proposedPosition) const;
111 bool isHorizontalOrVertical() const;
112
113 void handlePress(const QPointF &point) override;
114 void handleMove(const QPointF &point) override;
115 void handleRelease(const QPointF &point) override;
116 void handleUngrab() override;
117
118 void cancelHandle();
119 void executeHandle(bool complete = false);
120
121 void updateAllValuesAreInteger();
122
123 qreal from = 0;
124 qreal to = 1;
125 qreal value = 0;
126 qreal position = 0;
127 qreal angle = startAngle;
128 qreal stepSize = 0;
129 QPointF pressPoint;
130 qreal positionBeforePress = 0;
131 QQuickDial::SnapMode snapMode = QQuickDial::NoSnap;
132 QQuickDial::InputMode inputMode = QQuickDial::Circular;
133 QQuickDeferredPointer<QQuickItem> handle;
134 bool wrap = false;
135 bool live = true;
136 bool pressed = false;
137 bool allValuesAreInteger = false;
138};
139
140qreal QQuickDialPrivate::valueAt(qreal position) const
141{
142 qreal value = from + (to - from) * position;
143
144 /* play nice with users expecting that integer from, to and stepSize leads to
145 integer values - given that we are using floating point internally (and in
146 the API of value), this does not hold, but it is easy enough to handle
147 */
148 if (allValuesAreInteger)
149 value = qRound(d: value);
150
151 return value;
152}
153
154qreal QQuickDialPrivate::snapPosition(qreal position) const
155{
156 const qreal range = to - from;
157 if (qFuzzyIsNull(d: range))
158 return position;
159
160 const qreal effectiveStep = stepSize / range;
161 if (qFuzzyIsNull(d: effectiveStep))
162 return position;
163
164 return qRound(d: position / effectiveStep) * effectiveStep;
165}
166
167qreal QQuickDialPrivate::positionAt(const QPointF &point) const
168{
169 return inputMode == QQuickDial::Circular ? circularPositionAt(point) : linearPositionAt(point);
170}
171
172qreal QQuickDialPrivate::circularPositionAt(const QPointF &point) const
173{
174 qreal yy = height / 2.0 - point.y();
175 qreal xx = point.x() - width / 2.0;
176 qreal angle = (xx || yy) ? std::atan2(y: yy, x: xx) : 0;
177
178 if (angle < M_PI / -2)
179 angle = angle + M_PI * 2;
180
181 qreal normalizedAngle = (startAngleRadians - angle) / endAngleRadians;
182 return normalizedAngle;
183}
184
185qreal QQuickDialPrivate::linearPositionAt(const QPointF &point) const
186{
187 // This value determines the range (either horizontal or vertical)
188 // within which the dial can be dragged.
189 // The larger this value is, the further the drag distance
190 // must be to go from a position of e.g. 0.0 to 1.0.
191 qreal dragArea = 0;
192
193 // The linear input mode uses a "relative" input system,
194 // where the distance from the press point is used to calculate
195 // the change in position. Moving the mouse above the press
196 // point increases the position (when inputMode is Vertical),
197 // and vice versa. This prevents the dial from jumping when clicked.
198 qreal dragDistance = 0;
199
200 if (inputMode == QQuickDial::Horizontal) {
201 dragArea = width * 2;
202 dragDistance = pressPoint.x() - point.x();
203 } else {
204 dragArea = height * 2;
205 dragDistance = point.y() - pressPoint.y();
206 }
207 const qreal normalisedDifference = dragDistance / dragArea;
208 return qBound(min: qreal(0), val: positionBeforePress - normalisedDifference, max: qreal(1));
209}
210
211void QQuickDialPrivate::setPosition(qreal pos)
212{
213 Q_Q(QQuickDial);
214 pos = qBound<qreal>(min: qreal(0), val: pos, max: qreal(1));
215 if (qFuzzyCompare(p1: position, p2: pos))
216 return;
217
218 position = pos;
219
220 angle = startAngle + position * qAbs(t: endAngle - startAngle);
221
222 emit q->positionChanged();
223 emit q->angleChanged();
224}
225
226void QQuickDialPrivate::updatePosition()
227{
228 qreal pos = 0;
229 if (!qFuzzyCompare(p1: from, p2: to))
230 pos = (value - from) / (to - from);
231 setPosition(pos);
232}
233
234bool QQuickDialPrivate::isLargeChange(const QPointF &eventPos, qreal proposedPosition) const
235{
236 return qAbs(t: proposedPosition - position) >= qreal(0.5) && eventPos.y() >= height / 2;
237}
238
239bool QQuickDialPrivate::isHorizontalOrVertical() const
240{
241 return inputMode == QQuickDial::Horizontal || inputMode == QQuickDial::Vertical;
242}
243
244void QQuickDialPrivate::handlePress(const QPointF &point)
245{
246 Q_Q(QQuickDial);
247 QQuickControlPrivate::handlePress(point);
248 pressPoint = point;
249 positionBeforePress = position;
250 q->setPressed(true);
251}
252
253void QQuickDialPrivate::handleMove(const QPointF &point)
254{
255 Q_Q(QQuickDial);
256 QQuickControlPrivate::handleMove(point);
257 const qreal oldPos = position;
258 qreal pos = positionAt(point);
259 if (snapMode == QQuickDial::SnapAlways)
260 pos = snapPosition(position: pos);
261
262 if (wrap || (!wrap && (isHorizontalOrVertical() || !isLargeChange(eventPos: point, proposedPosition: pos)))) {
263 if (live)
264 q->setValue(valueAt(position: pos));
265 else
266 setPosition(pos);
267 if (!qFuzzyCompare(p1: pos, p2: oldPos))
268 emit q->moved();
269 }
270}
271
272void QQuickDialPrivate::handleRelease(const QPointF &point)
273{
274 Q_Q(QQuickDial);
275 QQuickControlPrivate::handleRelease(point);
276 if (q->keepMouseGrab() || q->keepTouchGrab()) {
277 const qreal oldPos = position;
278 qreal pos = positionAt(point);
279 if (snapMode != QQuickDial::NoSnap)
280 pos = snapPosition(position: pos);
281
282 if (wrap || (!wrap && (isHorizontalOrVertical() || !isLargeChange(eventPos: point, proposedPosition: pos))))
283 q->setValue(valueAt(position: pos));
284 if (!qFuzzyCompare(p1: pos, p2: oldPos))
285 emit q->moved();
286
287 q->setKeepMouseGrab(false);
288 q->setKeepTouchGrab(false);
289 }
290
291 q->setPressed(false);
292 pressPoint = QPointF();
293 positionBeforePress = 0;
294}
295
296void QQuickDialPrivate::handleUngrab()
297{
298 Q_Q(QQuickDial);
299 QQuickControlPrivate::handleUngrab();
300 pressPoint = QPointF();
301 positionBeforePress = 0;
302 q->setPressed(false);
303}
304
305static inline QString handleName() { return QStringLiteral("handle"); }
306
307void QQuickDialPrivate::cancelHandle()
308{
309 Q_Q(QQuickDial);
310 quickCancelDeferred(object: q, property: handleName());
311}
312
313void QQuickDialPrivate::executeHandle(bool complete)
314{
315 Q_Q(QQuickDial);
316 if (handle.wasExecuted())
317 return;
318
319 if (!handle || complete)
320 quickBeginDeferred(object: q, property: handleName(), delegate&: handle);
321 if (complete)
322 quickCompleteDeferred(object: q, property: handleName(), delegate&: handle);
323}
324
325static bool areRepresentableAsInteger(qreal num1, qreal num2, qreal num3) {
326 auto check = [](qreal number) -> bool { return std::nearbyint(x: number) == number; };
327 return check(num1) && check(num2) && check(num3);
328}
329
330void QQuickDialPrivate::updateAllValuesAreInteger()
331{
332 allValuesAreInteger = areRepresentableAsInteger(num1: to, num2: from, num3: stepSize) && stepSize != 0.0;
333}
334
335QQuickDial::QQuickDial(QQuickItem *parent)
336 : QQuickControl(*(new QQuickDialPrivate), parent)
337{
338 setActiveFocusOnTab(true);
339 setAcceptedMouseButtons(Qt::LeftButton);
340#if QT_CONFIG(quicktemplates2_multitouch)
341 setAcceptTouchEvents(true);
342#endif
343#if QT_CONFIG(cursor)
344 setCursor(Qt::ArrowCursor);
345#endif
346}
347
348/*!
349 \qmlproperty real QtQuick.Controls::Dial::from
350
351 This property holds the starting value for the range. The default value is \c 0.0.
352
353 \sa to, value
354*/
355qreal QQuickDial::from() const
356{
357 Q_D(const QQuickDial);
358 return d->from;
359}
360
361void QQuickDial::setFrom(qreal from)
362{
363 Q_D(QQuickDial);
364 if (qFuzzyCompare(p1: d->from, p2: from))
365 return;
366
367 d->from = from;
368 emit fromChanged();
369 d->updateAllValuesAreInteger();
370 if (isComponentComplete()) {
371 setValue(d->value);
372 d->updatePosition();
373 }
374}
375
376/*!
377 \qmlproperty real QtQuick.Controls::Dial::to
378
379 This property holds the end value for the range. The default value is
380 \c 1.0.
381
382 \sa from, value
383*/
384qreal QQuickDial::to() const
385{
386 Q_D(const QQuickDial);
387 return d->to;
388}
389
390void QQuickDial::setTo(qreal to)
391{
392 Q_D(QQuickDial);
393 if (qFuzzyCompare(p1: d->to, p2: to))
394 return;
395
396 d->to = to;
397 d->updateAllValuesAreInteger();
398 emit toChanged();
399 if (isComponentComplete()) {
400 setValue(d->value);
401 d->updatePosition();
402 }
403}
404
405/*!
406 \qmlproperty real QtQuick.Controls::Dial::value
407
408 This property holds the value in the range \c from - \c to. The default
409 value is \c 0.0.
410
411 \sa position, live
412*/
413qreal QQuickDial::value() const
414{
415 Q_D(const QQuickDial);
416 return d->value;
417}
418
419void QQuickDial::setValue(qreal value)
420{
421 Q_D(QQuickDial);
422 if (isComponentComplete())
423 value = d->from > d->to ? qBound(min: d->to, val: value, max: d->from) : qBound(min: d->from, val: value, max: d->to);
424
425 if (qFuzzyCompare(p1: d->value, p2: value))
426 return;
427
428 d->value = value;
429 d->updatePosition();
430 emit valueChanged();
431}
432
433/*!
434 \qmlproperty real QtQuick.Controls::Dial::position
435 \readonly
436
437 This property holds the logical position of the handle.
438
439 The position is expressed as a fraction of the control's angle range (the
440 range within which the handle can be moved) in the range \c {0.0 - 1.0}.
441
442 \sa value, angle
443*/
444qreal QQuickDial::position() const
445{
446 Q_D(const QQuickDial);
447 return d->position;
448}
449
450/*!
451 \qmlproperty real QtQuick.Controls::Dial::angle
452 \readonly
453
454 This property holds the angle of the handle.
455
456 The range is from \c -140 degrees to \c 140 degrees.
457
458 \sa position
459*/
460qreal QQuickDial::angle() const
461{
462 Q_D(const QQuickDial);
463 return d->angle;
464}
465
466/*!
467 \qmlproperty real QtQuick.Controls::Dial::stepSize
468
469 This property holds the step size.
470
471 The step size determines the amount by which the dial's value
472 is increased and decreased when interacted with via the keyboard.
473 For example, a step size of \c 0.2, will result in the dial's
474 value increasing and decreasing in increments of \c 0.2.
475
476 The step size is only respected for touch and mouse interaction
477 when \l snapMode is set to a value other than \c Dial.NoSnap.
478
479 The default value is \c 0.0, which results in an effective step
480 size of \c 0.1 for keyboard interaction.
481
482 \sa snapMode, increase(), decrease()
483*/
484qreal QQuickDial::stepSize() const
485{
486 Q_D(const QQuickDial);
487 return d->stepSize;
488}
489
490void QQuickDial::setStepSize(qreal step)
491{
492 Q_D(QQuickDial);
493 if (qFuzzyCompare(p1: d->stepSize, p2: step))
494 return;
495
496 d->stepSize = step;
497 d->updateAllValuesAreInteger();
498 emit stepSizeChanged();
499}
500
501/*!
502 \qmlproperty enumeration QtQuick.Controls::Dial::snapMode
503
504 This property holds the snap mode.
505
506 The snap mode works with the \l stepSize to allow the handle to snap to
507 certain points along the dial.
508
509 Possible values:
510 \value Dial.NoSnap The dial does not snap (default).
511 \value Dial.SnapAlways The dial snaps while the handle is dragged.
512 \value Dial.SnapOnRelease The dial does not snap while being dragged, but only after the handle is released.
513
514 \sa stepSize
515*/
516QQuickDial::SnapMode QQuickDial::snapMode() const
517{
518 Q_D(const QQuickDial);
519 return d->snapMode;
520}
521
522void QQuickDial::setSnapMode(SnapMode mode)
523{
524 Q_D(QQuickDial);
525 if (d->snapMode == mode)
526 return;
527
528 d->snapMode = mode;
529 emit snapModeChanged();
530}
531
532/*!
533 \since QtQuick.Controls 2.5 (Qt 5.12)
534 \qmlproperty enumeration QtQuick.Controls::Dial::inputMode
535
536 This property holds the input mode.
537
538 \include qquickdial.qdocinc inputMode
539
540 The default value is \c Dial.Circular.
541*/
542QQuickDial::InputMode QQuickDial::inputMode() const
543{
544 Q_D(const QQuickDial);
545 return d->inputMode;
546}
547
548void QQuickDial::setInputMode(QQuickDial::InputMode mode)
549{
550 Q_D(QQuickDial);
551 if (d->inputMode == mode)
552 return;
553
554 d->inputMode = mode;
555 emit inputModeChanged();
556}
557
558/*!
559 \qmlproperty bool QtQuick.Controls::Dial::wrap
560
561 This property holds whether the dial wraps when dragged.
562
563 For example, when this property is set to \c true, dragging the dial past
564 the \l to position will result in the handle being positioned at the
565 \l from position, and vice versa:
566
567 \image qtquickcontrols2-dial-wrap.gif
568
569 When this property is \c false, it's not possible to drag the dial across
570 the from and to values.
571
572 \image qtquickcontrols2-dial-no-wrap.gif
573
574 The default value is \c false.
575*/
576bool QQuickDial::wrap() const
577{
578 Q_D(const QQuickDial);
579 return d->wrap;
580}
581
582void QQuickDial::setWrap(bool wrap)
583{
584 Q_D(QQuickDial);
585 if (d->wrap == wrap)
586 return;
587
588 d->wrap = wrap;
589 emit wrapChanged();
590}
591
592/*!
593 \qmlproperty bool QtQuick.Controls::Dial::pressed
594
595 This property holds whether the dial is pressed.
596
597 The dial will be pressed when either the mouse is pressed over it, or a key
598 such as \c Qt.Key_Left is held down. If you'd prefer not to have the dial
599 be pressed upon key presses (due to styling reasons, for example), you can
600 use the \l {Keys}{Keys attached property}:
601
602 \code
603 Dial {
604 Keys.onLeftPressed: {}
605 }
606 \endcode
607
608 This will result in pressed only being \c true upon mouse presses.
609*/
610bool QQuickDial::isPressed() const
611{
612 Q_D(const QQuickDial);
613 return d->pressed;
614}
615
616void QQuickDial::setPressed(bool pressed)
617{
618 Q_D(QQuickDial);
619 if (d->pressed == pressed)
620 return;
621
622 d->pressed = pressed;
623 setAccessibleProperty(propertyName: "pressed", value: pressed);
624 emit pressedChanged();
625}
626
627/*!
628 \qmlproperty Item QtQuick.Controls::Dial::handle
629
630 This property holds the handle of the dial.
631
632 The handle acts as a visual indicator of the position of the dial.
633
634 \sa {Customizing Dial}
635*/
636QQuickItem *QQuickDial::handle() const
637{
638 QQuickDialPrivate *d = const_cast<QQuickDialPrivate *>(d_func());
639 if (!d->handle)
640 d->executeHandle();
641 return d->handle;
642}
643
644void QQuickDial::setHandle(QQuickItem *handle)
645{
646 Q_D(QQuickDial);
647 if (handle == d->handle)
648 return;
649
650 if (!d->handle.isExecuting())
651 d->cancelHandle();
652
653 QQuickControlPrivate::hideOldItem(item: d->handle);
654 d->handle = handle;
655 if (d->handle && !d->handle->parentItem())
656 d->handle->setParentItem(this);
657 if (!d->handle.isExecuting())
658 emit handleChanged();
659}
660
661/*!
662 \since QtQuick.Controls 2.2 (Qt 5.9)
663 \qmlproperty bool QtQuick.Controls::Dial::live
664
665 This property holds whether the dial provides live updates for the \l value
666 property while the handle is dragged.
667
668 The default value is \c true.
669
670 \sa value
671*/
672bool QQuickDial::live() const
673{
674 Q_D(const QQuickDial);
675 return d->live;
676}
677
678void QQuickDial::setLive(bool live)
679{
680 Q_D(QQuickDial);
681 if (d->live == live)
682 return;
683
684 d->live = live;
685 emit liveChanged();
686}
687
688/*!
689 \qmlmethod void QtQuick.Controls::Dial::increase()
690
691 Increases the value by \l stepSize, or \c 0.1 if stepSize is not defined.
692
693 \sa stepSize
694*/
695void QQuickDial::increase()
696{
697 Q_D(QQuickDial);
698 qreal step = qFuzzyIsNull(d: d->stepSize) ? 0.1 : d->stepSize;
699 setValue(d->value + step);
700}
701
702/*!
703 \qmlmethod void QtQuick.Controls::Dial::decrease()
704
705 Decreases the value by \l stepSize, or \c 0.1 if stepSize is not defined.
706
707 \sa stepSize
708*/
709void QQuickDial::decrease()
710{
711 Q_D(QQuickDial);
712 qreal step = qFuzzyIsNull(d: d->stepSize) ? 0.1 : d->stepSize;
713 setValue(d->value - step);
714}
715
716void QQuickDial::keyPressEvent(QKeyEvent *event)
717{
718 Q_D(QQuickDial);
719 const qreal oldValue = d->value;
720 switch (event->key()) {
721 case Qt::Key_Left:
722 case Qt::Key_Down:
723 setPressed(true);
724 if (isMirrored())
725 increase();
726 else
727 decrease();
728 break;
729
730 case Qt::Key_Right:
731 case Qt::Key_Up:
732 setPressed(true);
733 if (isMirrored())
734 decrease();
735 else
736 increase();
737 break;
738
739 case Qt::Key_Home:
740 setPressed(true);
741 setValue(isMirrored() ? d->to : d->from);
742 break;
743
744 case Qt::Key_End:
745 setPressed(true);
746 setValue(isMirrored() ? d->from : d->to);
747 break;
748
749 default:
750 event->ignore();
751 QQuickControl::keyPressEvent(event);
752 break;
753 }
754 if (!qFuzzyCompare(p1: d->value, p2: oldValue))
755 emit moved();
756}
757
758void QQuickDial::keyReleaseEvent(QKeyEvent *event)
759{
760 QQuickControl::keyReleaseEvent(event);
761 setPressed(false);
762}
763
764void QQuickDial::mousePressEvent(QMouseEvent *event)
765{
766 Q_D(QQuickDial);
767 QQuickControl::mousePressEvent(event);
768 d->handleMove(point: event->localPos());
769 setKeepMouseGrab(true);
770}
771
772#if QT_CONFIG(quicktemplates2_multitouch)
773void QQuickDial::touchEvent(QTouchEvent *event)
774{
775 Q_D(QQuickDial);
776 switch (event->type()) {
777 case QEvent::TouchUpdate:
778 for (const QTouchEvent::TouchPoint &point : event->touchPoints()) {
779 if (!d->acceptTouch(point))
780 continue;
781
782 switch (point.state()) {
783 case Qt::TouchPointMoved:
784 if (!keepTouchGrab()) {
785 bool overXDragThreshold = QQuickWindowPrivate::dragOverThreshold(d: point.pos().x() - d->pressPoint.x(), axis: Qt::XAxis, tp: &point);
786 setKeepTouchGrab(overXDragThreshold);
787
788 if (!overXDragThreshold) {
789 bool overYDragThreshold = QQuickWindowPrivate::dragOverThreshold(d: point.pos().y() - d->pressPoint.y(), axis: Qt::YAxis, tp: &point);
790 setKeepTouchGrab(overYDragThreshold);
791 }
792 }
793 if (keepTouchGrab())
794 d->handleMove(point: point.pos());
795 break;
796
797 default:
798 QQuickControl::touchEvent(event);
799 break;
800 }
801 }
802 break;
803
804 default:
805 QQuickControl::touchEvent(event);
806 break;
807 }
808}
809#endif
810
811#if QT_CONFIG(wheelevent)
812void QQuickDial::wheelEvent(QWheelEvent *event)
813{
814 Q_D(QQuickDial);
815 QQuickControl::wheelEvent(event);
816 if (d->wheelEnabled) {
817 const qreal oldValue = d->value;
818 const QPointF angle = event->angleDelta();
819 const qreal delta = (qFuzzyIsNull(d: angle.y()) ? angle.x() : (event->inverted() ? -angle.y() : angle.y())) / QWheelEvent::DefaultDeltasPerStep;
820 const qreal step = qFuzzyIsNull(d: d->stepSize) ? 0.1 : d->stepSize;
821 setValue(oldValue + step * delta);
822 event->setAccepted(!qFuzzyCompare(p1: d->value, p2: oldValue));
823 }
824}
825#endif
826
827void QQuickDial::mirrorChange()
828{
829 QQuickControl::mirrorChange();
830 emit angleChanged();
831}
832
833void QQuickDial::componentComplete()
834{
835 Q_D(QQuickDial);
836 d->executeHandle(complete: true);
837 QQuickControl::componentComplete();
838 setValue(d->value);
839 d->updatePosition();
840}
841
842#if QT_CONFIG(accessibility)
843void QQuickDial::accessibilityActiveChanged(bool active)
844{
845 QQuickControl::accessibilityActiveChanged(active);
846
847 Q_D(QQuickDial);
848 if (active)
849 setAccessibleProperty(propertyName: "pressed", value: d->pressed);
850}
851
852QAccessible::Role QQuickDial::accessibleRole() const
853{
854 return QAccessible::Dial;
855}
856#endif
857
858QT_END_NAMESPACE
859

source code of qtquickcontrols2/src/quicktemplates2/qquickdial.cpp