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
55
56
57
58
59
60
63
64
65
66
67
68
69
70
71
72
73
74
79constexpr qreal toUserAngleDeg(qreal logicAngleRad) {
81 return -logicAngleRad /
M_PI * 180. + 90;
89 Q_DECLARE_PUBLIC(QQuickDial)
103 bool handleMove(
const QPointF &point, ulong timestamp)
override;
135 qreal value = from + (to - from) * position;
138
139
140
141 if (allValuesAreInteger)
142 value = qRound(value);
149 const qreal range = to - from;
150 if (qFuzzyIsNull(range))
153 const qreal effectiveStep = stepSize / range;
154 if (qFuzzyIsNull(effectiveStep))
157 return qRound(position / effectiveStep) * effectiveStep;
162 return inputMode == QQuickDial::Circular ? circularPositionAt(point) : linearPositionAt(point);
167 qreal yy = height / 2.0 - point.y();
168 qreal xx = point.x() - width / 2.0;
169 qreal alpha = (xx || yy) ? toUserAngleDeg(std::atan2(yy, xx)) : 0;
172 if (alpha < startAngle && alpha + 360. < endAngle)
174 else if (alpha >= endAngle && alpha - 360. >= startAngle)
179 if ((alpha < startAngle || alpha > endAngle) && wrap) {
180 if (abs(alpha - startAngle) > abs(endAngle - alpha - 360.))
182 else if (abs(alpha - startAngle - 360.) < abs(endAngle - alpha))
190 if (abs(angle - alpha) > abs(angle - (alpha + 360.)))
192 if (abs(angle - alpha) > abs(angle - (alpha - 360.)))
196 return (alpha - startAngle) / (endAngle - startAngle);
212 qreal dragDistance = 0;
214 if (inputMode == QQuickDial::Horizontal) {
215 dragArea = width * 2;
216 dragDistance = pressPoint.x() - point.x();
218 dragArea = height * 2;
219 dragDistance = point.y() - pressPoint.y();
221 const qreal normalisedDifference = dragDistance / dragArea;
222 return qBound(qreal(0), positionBeforePress - normalisedDifference, qreal(1));
228 pos = qBound<qreal>(qreal(0), pos, qreal(1));
229 const qreal alpha = startAngle + pos * qAbs(endAngle - startAngle);
230 if (qFuzzyCompare(position, pos) && qFuzzyCompare(angle, alpha))
237 emit q->positionChanged();
238 emit q->angleChanged();
244 if (!qFuzzyCompare(from, to))
245 pos = (value - from) / (to - from);
251 if (endAngle - startAngle < 180.0)
253 return qAbs(proposedPosition - position) > qreal(0.5);
258 return inputMode == QQuickDial::Horizontal || inputMode == QQuickDial::Vertical;
264 QQuickControlPrivate::handlePress(point, timestamp);
266 positionBeforePress = position;
274 QQuickControlPrivate::handleMove(point, timestamp);
275 const qreal oldPos = position;
276 qreal pos = qBound(0.0, positionAt(point), 1.0);
277 if (snapMode == QQuickDial::SnapAlways)
278 pos = snapPosition(pos);
280 maybeEmitWrapAround(pos);
282 if (wrap || isHorizontalOrVertical() || !isLargeChange(pos)) {
284 q->setValue(valueAt(pos));
287 if (!qFuzzyCompare(pos, oldPos))
296 QQuickControlPrivate::handleRelease(point, timestamp);
297 if (q->keepMouseGrab() || q->keepTouchGrab()) {
298 const qreal oldPos = position;
299 qreal pos = positionAt(point);
300 if (snapMode != QQuickDial::NoSnap)
301 pos = snapPosition(pos);
303 maybeEmitWrapAround(pos);
305 if (wrap || isHorizontalOrVertical() || !isLargeChange(pos))
306 q->setValue(valueAt(pos));
307 if (!qFuzzyCompare(pos, oldPos))
310 q->setKeepMouseGrab(
false);
311 q->setKeepTouchGrab(
false);
314 q->setPressed(
false);
315 pressPoint = QPointF();
316 positionBeforePress = 0;
323 QQuickControlPrivate::handleUngrab();
324 pressPoint = QPointF();
325 positionBeforePress = 0;
326 q->setPressed(
false);
332 quickCancelDeferred(q, handleName());
338 if (handle.wasExecuted())
341 if (!handle || complete)
342 quickBeginDeferred(q, handleName(), handle);
344 quickCompleteDeferred(q, handleName(), handle);
349 allValuesAreInteger = areRepresentableAsInteger(to, from, stepSize) && stepSize != 0.0;
356 if (wrap && isLargeChange(pos))
357 emit q->wrapped((pos < q->position()) ? QQuickDial::Clockwise : QQuickDial::CounterClockwise);
360QQuickDial::QQuickDial(QQuickItem *parent)
361 : QQuickControl(*(
new QQuickDialPrivate), parent)
363 setActiveFocusOnTab(
true);
364 setAcceptedMouseButtons(Qt::LeftButton);
365#if QT_CONFIG(quicktemplates2_multitouch)
366 setAcceptTouchEvents(
true);
369 setCursor(Qt::ArrowCursor);
372 d->setSizePolicy(QLayoutPolicy::Preferred, QLayoutPolicy::Preferred);
376
377
378
379
380
381
382qreal QQuickDial::from()
const
384 Q_D(
const QQuickDial);
388void QQuickDial::setFrom(qreal from)
391 if (qFuzzyCompare(d->from, from))
396 d->updateAllValuesAreInteger();
397 if (isComponentComplete()) {
404
405
406
407
408
409
410
411qreal QQuickDial::to()
const
413 Q_D(
const QQuickDial);
417void QQuickDial::setTo(qreal to)
420 if (qFuzzyCompare(d->to, to))
424 d->updateAllValuesAreInteger();
426 if (isComponentComplete()) {
433
434
435
436
437
438
439
440qreal QQuickDial::value()
const
442 Q_D(
const QQuickDial);
446void QQuickDial::setValue(qreal value)
449 if (isComponentComplete())
450 value = d->from > d->to ? qBound(d->to, value, d->from) : qBound(d->from, value, d->to);
452 if (qFuzzyCompare(d->value, value))
461
462
463
464
465
466
467
468
469
470
471qreal QQuickDial::position()
const
473 Q_D(
const QQuickDial);
478
479
480
481
482
483
484
485
486
487
488qreal QQuickDial::angle()
const
490 Q_D(
const QQuickDial);
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512qreal QQuickDial::stepSize()
const
514 Q_D(
const QQuickDial);
518void QQuickDial::setStepSize(qreal step)
521 if (qFuzzyCompare(d->stepSize, step))
525 d->updateAllValuesAreInteger();
526 emit stepSizeChanged();
531
532
533
534
535
536
537
538
539
540
541
542qreal QQuickDial::startAngle()
const
544 Q_D(
const QQuickDial);
545 return d->startAngle;
548void QQuickDial::setStartAngle(qreal startAngle)
551 if (!d->componentComplete) {
555 d->startAngle = startAngle;
559 if (qFuzzyCompare(d->startAngle, startAngle))
563 if (startAngle >= d->endAngle) {
564 qmlWarning(
this) <<
"startAngle (" << startAngle
565 <<
") cannot be greater than or equal to endAngle (" << d->endAngle <<
")";
570 if (startAngle <= -360.) {
571 qmlWarning(
this) <<
"startAngle (" << startAngle <<
") cannot be less than or equal to -360";
576 if (startAngle < d->endAngle - 360.) {
577 qmlWarning(
this) <<
"Difference between startAngle (" << startAngle
578 <<
") and endAngle (" << d->endAngle <<
") cannot be greater than 360."
579 <<
" Changing endAngle to avoid overlaps.";
580 d->endAngle = startAngle + 360.;
581 emit endAngleChanged();
584 d->startAngle = startAngle;
588 emit startAngleChanged();
592
593
594
595
596
597
598
599
600
601
602
603qreal QQuickDial::endAngle()
const
605 Q_D(
const QQuickDial);
610void QQuickDial::setEndAngle(qreal endAngle)
613 if (!d->componentComplete) {
617 d->endAngle = endAngle;
621 if (qFuzzyCompare(d->endAngle, endAngle))
624 if (endAngle <= d->startAngle) {
625 qmlWarning(
this) <<
"endAngle (" << endAngle
626 <<
") cannot be less than or equal to startAngle (" << d->startAngle <<
")";
631 if (endAngle >= 720.) {
632 qmlWarning(
this) <<
"endAngle (" << endAngle <<
") cannot be greater than or equal to 720";
637 if (endAngle > d->startAngle + 360.) {
638 qmlWarning(
this) <<
"Difference between startAngle (" << d->startAngle
639 <<
") and endAngle (" << endAngle <<
") cannot be greater than 360."
640 <<
" Changing startAngle to avoid overlaps.";
641 d->startAngle = endAngle - 360.;
642 emit startAngleChanged();
645 d->endAngle = endAngle;
649 emit endAngleChanged();
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667QQuickDial::SnapMode QQuickDial::snapMode()
const
669 Q_D(
const QQuickDial);
673void QQuickDial::setSnapMode(SnapMode mode)
676 if (d->snapMode == mode)
680 emit snapModeChanged();
684
685
686
687
688
689
690
691
692
693QQuickDial::InputMode QQuickDial::inputMode()
const
695 Q_D(
const QQuickDial);
699void QQuickDial::setInputMode(QQuickDial::InputMode mode)
702 if (d->inputMode == mode)
706 emit inputModeChanged();
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727bool QQuickDial::wrap()
const
729 Q_D(
const QQuickDial);
733void QQuickDial::setWrap(
bool wrap)
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761bool QQuickDial::isPressed()
const
763 Q_D(
const QQuickDial);
767void QQuickDial::setPressed(
bool pressed)
770 if (d->pressed == pressed)
773 d->pressed = pressed;
774 setAccessibleProperty(
"pressed", pressed);
775 emit pressedChanged();
779
780
781
782
783
784
785
786
787QQuickItem *QQuickDial::handle()
const
789 QQuickDialPrivate *d =
const_cast<QQuickDialPrivate *>(d_func());
795void QQuickDial::setHandle(QQuickItem *handle)
798 if (handle == d->handle)
801 QQuickControlPrivate::warnIfCustomizationNotSupported(
this, handle, QStringLiteral(
"handle"));
803 if (!d->handle.isExecuting())
806 QQuickControlPrivate::hideOldItem(d->handle);
808 if (d->handle && !d->handle->parentItem())
809 d->handle->setParentItem(
this);
810 if (!d->handle.isExecuting())
811 emit handleChanged();
815
816
817
818
819
820
821
822
823
824
825bool QQuickDial::live()
const
827 Q_D(
const QQuickDial);
831void QQuickDial::setLive(
bool live)
842
843
844
845
846
847
848void QQuickDial::increase()
851 qreal step = qFuzzyIsNull(d->stepSize) ? 0.1 : d->stepSize;
852 setValue(d->value + step);
856
857
858
859
860
861
862void QQuickDial::decrease()
865 qreal step = qFuzzyIsNull(d->stepSize) ? 0.1 : d->stepSize;
866 setValue(d->value - step);
869void QQuickDial::keyPressEvent(QKeyEvent *event)
872 const qreal oldValue = d->value;
873 switch (event->key()) {
894 setValue(isMirrored() ? d->to : d->from);
899 setValue(isMirrored() ? d->from : d->to);
904 QQuickControl::keyPressEvent(event);
907 if (!qFuzzyCompare(d->value, oldValue))
911void QQuickDial::keyReleaseEvent(QKeyEvent *event)
913 QQuickControl::keyReleaseEvent(event);
917void QQuickDial::mousePressEvent(QMouseEvent *event)
920 QQuickControl::mousePressEvent(event);
921 d->handleMove(event->position(), event->timestamp());
922 setKeepMouseGrab(
true);
925#if QT_CONFIG(quicktemplates2_multitouch)
926void QQuickDial::touchEvent(QTouchEvent *event)
929 switch (event->type()) {
930 case QEvent::TouchUpdate:
931 for (
const QTouchEvent::TouchPoint &point : event->points()) {
932 if (!d->acceptTouch(point))
935 switch (point.state()) {
936 case QEventPoint::Updated:
937 if (!keepTouchGrab()) {
938 bool overXDragThreshold = QQuickDeliveryAgentPrivate::dragOverThreshold(point.position().x() - d->pressPoint.x(),
940 setKeepTouchGrab(overXDragThreshold);
942 if (!overXDragThreshold) {
943 bool overYDragThreshold = QQuickDeliveryAgentPrivate::dragOverThreshold(point.position().y() - d->pressPoint.y(),
945 setKeepTouchGrab(overYDragThreshold);
949 d->handleMove(point.position(), event->timestamp());
953 QQuickControl::touchEvent(event);
960 QQuickControl::touchEvent(event);
966#if QT_CONFIG(wheelevent)
967void QQuickDial::wheelEvent(QWheelEvent *event)
970 QQuickControl::wheelEvent(event);
971 if (d->wheelEnabled) {
972 const qreal oldValue = d->value;
973 const QPointF angle = event->angleDelta();
974 const qreal delta = (qFuzzyIsNull(angle.y()) ? angle.x() : (event->inverted() ? -angle.y() : angle.y())) /
int(QWheelEvent::DefaultDeltasPerStep);
975 const qreal step = qFuzzyIsNull(d->stepSize) ? 0.1 : d->stepSize;
976 setValue(oldValue + step * delta);
977 event->setAccepted(!qFuzzyCompare(d->value, oldValue));
982void QQuickDial::mirrorChange()
984 QQuickControl::mirrorChange();
988void QQuickDial::componentComplete()
991 d->executeHandle(
true);
992 QQuickControl::componentComplete();
995 if (!qFuzzyCompare(d->startAngle, defaultStartAngle)) {
996 const qreal startAngle = d->startAngle;
998 d->startAngle = defaultStartAngle;
999 setStartAngle(startAngle);
1002 if (!qFuzzyCompare(d->endAngle, defaultEndAngle)) {
1003 const qreal endAngle = d->endAngle;
1004 d->endAngle = defaultEndAngle;
1005 setEndAngle(endAngle);
1009 d->updatePosition();
1012#if QT_CONFIG(accessibility)
1013void QQuickDial::accessibilityActiveChanged(
bool active)
1015 QQuickControl::accessibilityActiveChanged(active);
1019 setAccessibleProperty(
"pressed", d->pressed);
1022QAccessible::Role QQuickDial::accessibleRole()
const
1024 return QAccessible::Dial;
1030#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