8#include <QtCore/qmath.h>
9#include <QtQuick/private/qquickflickable_p.h>
10#include <QtQuickTemplates2/private/qquickcontrol_p_p.h>
11#include <QtQuickTemplates2/private/qtquicktemplates2math_p.h>
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
56
57
58
59
60
61
64
65
66
67
68
69
70
71
72
73
74
75
80constexpr qreal toUserAngleDeg(qreal logicAngleRad) {
82 return -logicAngleRad /
M_PI * 180. + 90;
90 Q_DECLARE_PUBLIC(QQuickDial)
104 bool handleMove(
const QPointF &point, ulong timestamp)
override;
136 qreal value = from + (to - from) * position;
139
140
141
142 if (allValuesAreInteger)
143 value = qRound(value);
150 const qreal range = to - from;
151 if (qFuzzyIsNull(range))
154 const qreal effectiveStep = stepSize / range;
155 if (qFuzzyIsNull(effectiveStep))
158 return qRound(position / effectiveStep) * effectiveStep;
163 return inputMode == QQuickDial::Circular ? circularPositionAt(point) : linearPositionAt(point);
168 qreal yy = height / 2.0 - point.y();
169 qreal xx = point.x() - width / 2.0;
170 qreal alpha = (xx || yy) ? toUserAngleDeg(std::atan2(yy, xx)) : 0;
173 if (alpha < startAngle && alpha + 360. < endAngle)
175 else if (alpha >= endAngle && alpha - 360. >= startAngle)
180 if ((alpha < startAngle || alpha > endAngle) && wrap) {
181 if (abs(alpha - startAngle) > abs(endAngle - alpha - 360.))
183 else if (abs(alpha - startAngle - 360.) < abs(endAngle - alpha))
191 if (abs(angle - alpha) > abs(angle - (alpha + 360.)))
193 if (abs(angle - alpha) > abs(angle - (alpha - 360.)))
197 return (alpha - startAngle) / (endAngle - startAngle);
213 qreal dragDistance = 0;
215 if (inputMode == QQuickDial::Horizontal) {
216 dragArea = width * 2;
217 dragDistance = pressPoint.x() - point.x();
219 dragArea = height * 2;
220 dragDistance = point.y() - pressPoint.y();
222 const qreal normalisedDifference = dragDistance / dragArea;
223 return qBound(qreal(0), positionBeforePress - normalisedDifference, qreal(1));
229 pos = qBound<qreal>(qreal(0), pos, qreal(1));
230 const qreal alpha = startAngle + pos * qAbs(endAngle - startAngle);
231 if (qFuzzyCompare(position, pos) && qFuzzyCompare(angle, alpha))
238 emit q->positionChanged();
239 emit q->angleChanged();
245 if (!qFuzzyCompare(from, to))
246 pos = (value - from) / (to - from);
252 if (endAngle - startAngle < 180.0)
254 return qAbs(proposedPosition - position) > qreal(0.5);
259 return inputMode == QQuickDial::Horizontal || inputMode == QQuickDial::Vertical;
265 QQuickControlPrivate::handlePress(point, timestamp);
267 positionBeforePress = position;
275 QQuickControlPrivate::handleMove(point, timestamp);
276 const qreal oldPos = position;
277 qreal pos = qBound(0.0, positionAt(point), 1.0);
278 if (snapMode == QQuickDial::SnapAlways)
279 pos = snapPosition(pos);
281 maybeEmitWrapAround(pos);
283 if (wrap || isHorizontalOrVertical() || !isLargeChange(pos)) {
285 q->setValue(valueAt(pos));
288 if (!qFuzzyCompare(pos, oldPos))
297 QQuickControlPrivate::handleRelease(point, timestamp);
298 if (q->keepMouseGrab() || q->keepTouchGrab()) {
299 const qreal oldPos = position;
300 qreal pos = positionAt(point);
301 if (snapMode != QQuickDial::NoSnap)
302 pos = snapPosition(pos);
304 maybeEmitWrapAround(pos);
306 if (wrap || isHorizontalOrVertical() || !isLargeChange(pos))
307 q->setValue(valueAt(pos));
308 if (!qFuzzyCompare(pos, oldPos))
311 q->setKeepMouseGrab(
false);
312 q->setKeepTouchGrab(
false);
315 q->setPressed(
false);
316 pressPoint = QPointF();
317 positionBeforePress = 0;
324 QQuickControlPrivate::handleUngrab();
325 pressPoint = QPointF();
326 positionBeforePress = 0;
327 q->setPressed(
false);
333 quickCancelDeferred(q, handleName());
339 if (handle.wasExecuted())
342 if (!handle || complete)
343 quickBeginDeferred(q, handleName(), handle);
345 quickCompleteDeferred(q, handleName(), handle);
350 allValuesAreInteger = areRepresentableAsInteger(to, from, stepSize) && stepSize != 0.0;
357 if (wrap && isLargeChange(pos))
358 emit q->wrapped((pos < q->position()) ? QQuickDial::Clockwise : QQuickDial::CounterClockwise);
361QQuickDial::QQuickDial(QQuickItem *parent)
362 : QQuickControl(*(
new QQuickDialPrivate), parent)
364 setActiveFocusOnTab(
true);
365 setAcceptedMouseButtons(Qt::LeftButton);
366#if QT_CONFIG(quicktemplates2_multitouch)
367 setAcceptTouchEvents(
true);
370 setCursor(Qt::ArrowCursor);
373 d->setSizePolicy(QLayoutPolicy::Preferred, QLayoutPolicy::Preferred);
377
378
379
380
381
382
383qreal QQuickDial::from()
const
385 Q_D(
const QQuickDial);
389void QQuickDial::setFrom(qreal from)
392 if (qFuzzyCompare(d->from, from))
397 d->updateAllValuesAreInteger();
398 if (isComponentComplete()) {
405
406
407
408
409
410
411
412qreal QQuickDial::to()
const
414 Q_D(
const QQuickDial);
418void QQuickDial::setTo(qreal to)
421 if (qFuzzyCompare(d->to, to))
425 d->updateAllValuesAreInteger();
427 if (isComponentComplete()) {
434
435
436
437
438
439
440
441qreal QQuickDial::value()
const
443 Q_D(
const QQuickDial);
447void QQuickDial::setValue(qreal value)
450 if (isComponentComplete())
451 value = d->from > d->to ? qBound(d->to, value, d->from) : qBound(d->from, value, d->to);
453 if (qFuzzyCompare(d->value, value))
462
463
464
465
466
467
468
469
470
471
472qreal QQuickDial::position()
const
474 Q_D(
const QQuickDial);
479
480
481
482
483
484
485
486
487
488
489qreal QQuickDial::angle()
const
491 Q_D(
const QQuickDial);
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513qreal QQuickDial::stepSize()
const
515 Q_D(
const QQuickDial);
519void QQuickDial::setStepSize(qreal step)
522 if (qFuzzyCompare(d->stepSize, step))
526 d->updateAllValuesAreInteger();
527 emit stepSizeChanged();
532
533
534
535
536
537
538
539
540
541
542
543qreal QQuickDial::startAngle()
const
545 Q_D(
const QQuickDial);
546 return d->startAngle;
549void QQuickDial::setStartAngle(qreal startAngle)
552 if (!d->componentComplete) {
556 d->startAngle = startAngle;
560 if (qFuzzyCompare(d->startAngle, startAngle))
564 if (startAngle >= d->endAngle) {
565 qmlWarning(
this) <<
"startAngle (" << startAngle
566 <<
") cannot be greater than or equal to endAngle (" << d->endAngle <<
")";
571 if (startAngle <= -360.) {
572 qmlWarning(
this) <<
"startAngle (" << startAngle <<
") cannot be less than or equal to -360";
577 if (startAngle < d->endAngle - 360.) {
578 qmlWarning(
this) <<
"Difference between startAngle (" << startAngle
579 <<
") and endAngle (" << d->endAngle <<
") cannot be greater than 360."
580 <<
" Changing endAngle to avoid overlaps.";
581 d->endAngle = startAngle + 360.;
582 emit endAngleChanged();
585 d->startAngle = startAngle;
589 emit startAngleChanged();
593
594
595
596
597
598
599
600
601
602
603
604qreal QQuickDial::endAngle()
const
606 Q_D(
const QQuickDial);
611void QQuickDial::setEndAngle(qreal endAngle)
614 if (!d->componentComplete) {
618 d->endAngle = endAngle;
622 if (qFuzzyCompare(d->endAngle, endAngle))
625 if (endAngle <= d->startAngle) {
626 qmlWarning(
this) <<
"endAngle (" << endAngle
627 <<
") cannot be less than or equal to startAngle (" << d->startAngle <<
")";
632 if (endAngle >= 720.) {
633 qmlWarning(
this) <<
"endAngle (" << endAngle <<
") cannot be greater than or equal to 720";
638 if (endAngle > d->startAngle + 360.) {
639 qmlWarning(
this) <<
"Difference between startAngle (" << d->startAngle
640 <<
") and endAngle (" << endAngle <<
") cannot be greater than 360."
641 <<
" Changing startAngle to avoid overlaps.";
642 d->startAngle = endAngle - 360.;
643 emit startAngleChanged();
646 d->endAngle = endAngle;
650 emit endAngleChanged();
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668QQuickDial::SnapMode QQuickDial::snapMode()
const
670 Q_D(
const QQuickDial);
674void QQuickDial::setSnapMode(SnapMode mode)
677 if (d->snapMode == mode)
681 emit snapModeChanged();
685
686
687
688
689
690
691
692
693
694QQuickDial::InputMode QQuickDial::inputMode()
const
696 Q_D(
const QQuickDial);
700void QQuickDial::setInputMode(QQuickDial::InputMode mode)
703 if (d->inputMode == mode)
707 emit inputModeChanged();
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730bool QQuickDial::wrap()
const
732 Q_D(
const QQuickDial);
736void QQuickDial::setWrap(
bool wrap)
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764bool QQuickDial::isPressed()
const
766 Q_D(
const QQuickDial);
770void QQuickDial::setPressed(
bool pressed)
773 if (d->pressed == pressed)
776 d->pressed = pressed;
777 setAccessibleProperty(
"pressed", pressed);
778 emit pressedChanged();
782
783
784
785
786
787
788
789
790QQuickItem *QQuickDial::handle()
const
792 QQuickDialPrivate *d =
const_cast<QQuickDialPrivate *>(d_func());
798void QQuickDial::setHandle(QQuickItem *handle)
801 if (handle == d->handle)
804 QQuickControlPrivate::warnIfCustomizationNotSupported(
this, handle, QStringLiteral(
"handle"));
806 if (!d->handle.isExecuting())
809 QQuickControlPrivate::hideOldItem(d->handle);
811 if (d->handle && !d->handle->parentItem())
812 d->handle->setParentItem(
this);
813 if (!d->handle.isExecuting())
814 emit handleChanged();
818
819
820
821
822
823
824
825
826
827
828bool QQuickDial::live()
const
830 Q_D(
const QQuickDial);
834void QQuickDial::setLive(
bool live)
845
846
847
848
849
850
851void QQuickDial::increase()
854 qreal step = qFuzzyIsNull(d->stepSize) ? 0.1 : d->stepSize;
855 setValue(d->value + step);
859
860
861
862
863
864
865void QQuickDial::decrease()
868 qreal step = qFuzzyIsNull(d->stepSize) ? 0.1 : d->stepSize;
869 setValue(d->value - step);
872void QQuickDial::keyPressEvent(QKeyEvent *event)
875 const qreal oldValue = d->value;
876 switch (event->key()) {
897 setValue(isMirrored() ? d->to : d->from);
902 setValue(isMirrored() ? d->from : d->to);
907 QQuickControl::keyPressEvent(event);
910 if (!qFuzzyCompare(d->value, oldValue))
914void QQuickDial::keyReleaseEvent(QKeyEvent *event)
916 QQuickControl::keyReleaseEvent(event);
920void QQuickDial::mousePressEvent(QMouseEvent *event)
923 QQuickControl::mousePressEvent(event);
924 d->handleMove(event->position(), event->timestamp());
925 setKeepMouseGrab(
true);
928#if QT_CONFIG(quicktemplates2_multitouch)
929void QQuickDial::touchEvent(QTouchEvent *event)
932 switch (event->type()) {
933 case QEvent::TouchUpdate:
934 for (
const QTouchEvent::TouchPoint &point : event->points()) {
935 if (!d->acceptTouch(point))
938 switch (point.state()) {
939 case QEventPoint::Updated:
940 if (!keepTouchGrab()) {
941 bool overXDragThreshold = QQuickDeliveryAgentPrivate::dragOverThreshold(point.position().x() - d->pressPoint.x(),
943 setKeepTouchGrab(overXDragThreshold);
945 if (!overXDragThreshold) {
946 bool overYDragThreshold = QQuickDeliveryAgentPrivate::dragOverThreshold(point.position().y() - d->pressPoint.y(),
948 setKeepTouchGrab(overYDragThreshold);
952 d->handleMove(point.position(), event->timestamp());
956 QQuickControl::touchEvent(event);
963 QQuickControl::touchEvent(event);
969#if QT_CONFIG(wheelevent)
970void QQuickDial::wheelEvent(QWheelEvent *event)
973 QQuickControl::wheelEvent(event);
974 if (d->wheelEnabled) {
975 const qreal oldValue = d->value;
976 const QPointF angle = event->angleDelta();
977 const qreal delta = (qFuzzyIsNull(angle.y()) ? angle.x() : (event->inverted() ? -angle.y() : angle.y())) /
int(QWheelEvent::DefaultDeltasPerStep);
978 const qreal step = qFuzzyIsNull(d->stepSize) ? 0.1 : d->stepSize;
979 setValue(oldValue + step * delta);
980 event->setAccepted(!qFuzzyCompare(d->value, oldValue));
985void QQuickDial::mirrorChange()
987 QQuickControl::mirrorChange();
991void QQuickDial::componentComplete()
994 d->executeHandle(
true);
995 QQuickControl::componentComplete();
998 if (!qFuzzyCompare(d->startAngle, defaultStartAngle)) {
999 const qreal startAngle = d->startAngle;
1001 d->startAngle = defaultStartAngle;
1002 setStartAngle(startAngle);
1005 if (!qFuzzyCompare(d->endAngle, defaultEndAngle)) {
1006 const qreal endAngle = d->endAngle;
1007 d->endAngle = defaultEndAngle;
1008 setEndAngle(endAngle);
1012 d->updatePosition();
1015#if QT_CONFIG(accessibility)
1016void QQuickDial::accessibilityActiveChanged(
bool active)
1018 QQuickControl::accessibilityActiveChanged(active);
1022 setAccessibleProperty(
"pressed", d->pressed);
1025QAccessible::Role QQuickDial::accessibleRole()
const
1027 return QAccessible::Dial;
1033#include "moc_qquickdial_p.cpp"
void executeHandle(bool complete=false)
bool handlePress(const QPointF &point, ulong timestamp) override
bool handleRelease(const QPointF &point, ulong timestamp) override
void maybeEmitWrapAround(qreal pos)
qreal linearPositionAt(const QPointF &point) const
void handleUngrab() override
qreal snapPosition(qreal position) const
bool isHorizontalOrVertical() const
qreal positionAt(const QPointF &point) const
bool isLargeChange(qreal proposedPosition) const
qreal positionBeforePress
QQuickDeferredPointer< QQuickItem > handle
void setPosition(qreal position)
qreal circularPositionAt(const QPointF &point) const
void updateAllValuesAreInteger()
bool handleMove(const QPointF &point, ulong timestamp) override
static const qreal defaultEndAngle
static const qreal defaultStartAngle