1// Copyright (C) 2017 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qquickslider_p.h"
5#include "qquickcontrol_p_p.h"
6#include "qquickdeferredexecute_p_p.h"
7
8#include <QtQuick/private/qquickwindow_p.h>
9
10#include <algorithm>
11
12QT_BEGIN_NAMESPACE
13
14/*!
15 \qmltype Slider
16 \inherits Control
17//! \nativetype QQuickSlider
18 \inqmlmodule QtQuick.Controls
19 \since 5.7
20 \ingroup qtquickcontrols-input
21 \brief Used to select a value by sliding a handle along a track.
22
23 \image qtquickcontrols-slider.gif
24
25 Slider is used to select a value by sliding a handle along a track.
26
27 In the example below, custom \l from, \l value, and \l to values are set:
28
29 \code
30 Slider {
31 from: 1
32 value: 25
33 to: 100
34 }
35 \endcode
36
37 The \l position property is expressed as a fraction of the control's size,
38 in the range \c {0.0 - 1.0}. The \l visualPosition property is
39 the same, except that it is reversed in a
40 \l {Right-to-left User Interfaces}{right-to-left} application. The
41 visualPosition is useful for positioning the handle when styling Slider.
42 In the example above, \l visualPosition will be \c 0.24 in a left-to-right
43 application, and \c 0.76 in a right-to-left application.
44
45 For a slider that allows the user to select a range by providing two
46 handles, see \l RangeSlider.
47
48 \sa {Customizing Slider}, {Input Controls}
49*/
50
51/*!
52 \since QtQuick.Controls 2.2 (Qt 5.9)
53 \qmlsignal QtQuick.Controls::Slider::moved()
54
55 This signal is emitted when the slider has been interactively moved
56 by the user by either touch, mouse, wheel, or keys.
57*/
58
59class QQuickSliderPrivate : public QQuickControlPrivate
60{
61 Q_DECLARE_PUBLIC(QQuickSlider)
62
63public:
64 qreal snapPosition(qreal position) const;
65 qreal positionAt(const QPointF &point) const;
66 void setPosition(qreal position);
67 void updatePosition();
68
69 bool handlePress(const QPointF &point, ulong timestamp) override;
70 bool handleMove(const QPointF &point, ulong timestamp) override;
71 bool handleRelease(const QPointF &point, ulong timestamp) override;
72 void handleUngrab() override;
73
74 void cancelHandle();
75 void executeHandle(bool complete = false);
76
77 void itemImplicitWidthChanged(QQuickItem *item) override;
78 void itemImplicitHeightChanged(QQuickItem *item) override;
79 void itemDestroyed(QQuickItem *item) override;
80
81 qreal from = 0;
82 qreal to = 1;
83 qreal value = 0;
84 qreal position = 0;
85 qreal stepSize = 0;
86 qreal touchDragThreshold = -1; // in QQuickWindowPrivate::dragOverThreshold, '-1' implies using styleHints::startDragDistance()
87 bool live = true;
88 bool pressed = false;
89 QPointF pressPoint;
90 Qt::Orientation orientation = Qt::Horizontal;
91 QQuickSlider::SnapMode snapMode = QQuickSlider::NoSnap;
92 QQuickDeferredPointer<QQuickItem> handle;
93};
94
95qreal QQuickSliderPrivate::snapPosition(qreal position) const
96{
97 const qreal range = to - from;
98 if (qFuzzyIsNull(d: range))
99 return position;
100
101 const qreal effectiveStep = stepSize / range;
102 if (qFuzzyIsNull(d: effectiveStep))
103 return position;
104
105 return qRound(d: position / effectiveStep) * effectiveStep;
106}
107
108qreal QQuickSliderPrivate::positionAt(const QPointF &point) const
109{
110 Q_Q(const QQuickSlider);
111 qreal pos = 0.0;
112 if (orientation == Qt::Horizontal) {
113 const qreal hw = handle ? handle->width() : 0;
114 const qreal offset = hw / 2;
115 const qreal extent = q->availableWidth() - hw;
116 if (!qFuzzyIsNull(d: extent)) {
117 if (q->isMirrored())
118 pos = (q->width() - point.x() - q->rightPadding() - offset) / extent;
119 else
120 pos = (point.x() - q->leftPadding() - offset) / extent;
121 }
122 } else {
123 const qreal hh = handle ? handle->height() : 0;
124 const qreal offset = hh / 2;
125 const qreal extent = q->availableHeight() - hh;
126 if (!qFuzzyIsNull(d: extent))
127 pos = (q->height() - point.y() - q->bottomPadding() - offset) / extent;
128 }
129 return std::clamp(val: pos, lo: qreal(0.0), hi: qreal(1.0));
130}
131
132void QQuickSliderPrivate::setPosition(qreal pos)
133{
134 Q_Q(QQuickSlider);
135 pos = std::clamp(val: pos, lo: qreal(0.0), hi: qreal(1.0));
136 if (qFuzzyCompare(p1: position, p2: pos))
137 return;
138
139 position = pos;
140 emit q->positionChanged();
141 emit q->visualPositionChanged();
142}
143
144void QQuickSliderPrivate::updatePosition()
145{
146 qreal pos = 0;
147 if (!qFuzzyCompare(p1: from, p2: to))
148 pos = (value - from) / (to - from);
149 setPosition(pos);
150}
151
152bool QQuickSliderPrivate::handlePress(const QPointF &point, ulong timestamp)
153{
154 Q_Q(QQuickSlider);
155 QQuickControlPrivate::handlePress(point, timestamp);
156 pressPoint = point;
157 q->setPressed(true);
158 return true;
159}
160
161bool QQuickSliderPrivate::handleMove(const QPointF &point, ulong timestamp)
162{
163 Q_Q(QQuickSlider);
164 QQuickControlPrivate::handleMove(point, timestamp);
165 const qreal oldPos = position;
166 qreal pos = positionAt(point);
167 if (snapMode == QQuickSlider::SnapAlways)
168 pos = snapPosition(position: pos);
169 if (live)
170 q->setValue(q->valueAt(position: pos));
171 if (!live || snapMode == QQuickSlider::NoSnap || snapMode == QQuickSlider::SnapOnRelease)
172 setPosition(pos);
173 if (!qFuzzyCompare(p1: pos, p2: oldPos))
174 emit q->moved();
175 return true;
176}
177
178bool QQuickSliderPrivate::handleRelease(const QPointF &point, ulong timestamp)
179{
180 Q_Q(QQuickSlider);
181 QQuickControlPrivate::handleRelease(point, timestamp);
182 pressPoint = QPointF();
183 const qreal oldPos = position;
184 qreal pos = positionAt(point);
185 if (snapMode != QQuickSlider::NoSnap)
186 pos = snapPosition(position: pos);
187 qreal val = q->valueAt(position: pos);
188 if (!qFuzzyCompare(p1: val, p2: value))
189 q->setValue(val);
190 else if (snapMode != QQuickSlider::NoSnap)
191 setPosition(pos);
192 if (!qFuzzyCompare(p1: pos, p2: oldPos))
193 emit q->moved();
194 q->setKeepMouseGrab(false);
195 q->setKeepTouchGrab(false);
196 q->setPressed(false);
197 return true;
198}
199
200void QQuickSliderPrivate::handleUngrab()
201{
202 Q_Q(QQuickSlider);
203 QQuickControlPrivate::handleUngrab();
204 pressPoint = QPointF();
205 q->setPressed(false);
206}
207
208void QQuickSliderPrivate::cancelHandle()
209{
210 Q_Q(QQuickSlider);
211 quickCancelDeferred(object: q, property: handleName());
212}
213
214void QQuickSliderPrivate::executeHandle(bool complete)
215{
216 Q_Q(QQuickSlider);
217 if (handle.wasExecuted())
218 return;
219
220 if (!handle || complete)
221 quickBeginDeferred(object: q, property: handleName(), delegate&: handle);
222 if (complete)
223 quickCompleteDeferred(object: q, property: handleName(), delegate&: handle);
224}
225
226void QQuickSliderPrivate::itemImplicitWidthChanged(QQuickItem *item)
227{
228 Q_Q(QQuickSlider);
229 QQuickControlPrivate::itemImplicitWidthChanged(item);
230 if (item == handle)
231 emit q->implicitHandleWidthChanged();
232}
233
234void QQuickSliderPrivate::itemImplicitHeightChanged(QQuickItem *item)
235{
236 Q_Q(QQuickSlider);
237 QQuickControlPrivate::itemImplicitHeightChanged(item);
238 if (item == handle)
239 emit q->implicitHandleHeightChanged();
240}
241
242void QQuickSliderPrivate::itemDestroyed(QQuickItem *item)
243{
244 Q_Q(QQuickSlider);
245 QQuickControlPrivate::itemDestroyed(item);
246 if (item == handle) {
247 handle = nullptr;
248 emit q->handleChanged();
249 }
250}
251
252QQuickSlider::QQuickSlider(QQuickItem *parent)
253 : QQuickControl(*(new QQuickSliderPrivate), parent)
254{
255 Q_D(QQuickSlider);
256 d->setSizePolicy(horizontalPolicy: QLayoutPolicy::Expanding, verticalPolicy: QLayoutPolicy::Fixed);
257 setActiveFocusOnTab(true);
258#ifdef Q_OS_MACOS
259 setFocusPolicy(Qt::TabFocus);
260#else
261 setFocusPolicy(Qt::StrongFocus);
262#endif
263 setAcceptedMouseButtons(Qt::LeftButton);
264#if QT_CONFIG(quicktemplates2_multitouch)
265 setAcceptTouchEvents(true);
266#endif
267#if QT_CONFIG(cursor)
268 setCursor(Qt::ArrowCursor);
269#endif
270}
271
272QQuickSlider::~QQuickSlider()
273{
274 Q_D(QQuickSlider);
275 d->removeImplicitSizeListener(item: d->handle);
276}
277
278/*!
279 \qmlproperty real QtQuick.Controls::Slider::from
280
281 This property holds the starting value for the range. The default value is \c 0.0.
282
283 \sa to, value
284*/
285qreal QQuickSlider::from() const
286{
287 Q_D(const QQuickSlider);
288 return d->from;
289}
290
291void QQuickSlider::setFrom(qreal from)
292{
293 Q_D(QQuickSlider);
294 if (qFuzzyCompare(p1: d->from, p2: from))
295 return;
296
297 d->from = from;
298 emit fromChanged();
299 if (isComponentComplete()) {
300 setValue(d->value);
301 d->updatePosition();
302 }
303}
304
305/*!
306 \qmlproperty real QtQuick.Controls::Slider::to
307
308 This property holds the end value for the range. The default value is \c 1.0.
309
310 \sa from, value
311*/
312qreal QQuickSlider::to() const
313{
314 Q_D(const QQuickSlider);
315 return d->to;
316}
317
318void QQuickSlider::setTo(qreal to)
319{
320 Q_D(QQuickSlider);
321 if (qFuzzyCompare(p1: d->to, p2: to))
322 return;
323
324 d->to = to;
325 emit toChanged();
326 if (isComponentComplete()) {
327 setValue(d->value);
328 d->updatePosition();
329 }
330}
331
332/*!
333 \qmlproperty real QtQuick.Controls::Slider::value
334
335 This property holds the value in the range \c from - \c to. The default value is \c 0.0.
336
337 \sa position
338*/
339qreal QQuickSlider::value() const
340{
341 Q_D(const QQuickSlider);
342 return d->value;
343}
344
345void QQuickSlider::setValue(qreal value)
346{
347 Q_D(QQuickSlider);
348 if (isComponentComplete())
349 value = d->from > d->to ? qBound(min: d->to, val: value, max: d->from) : qBound(min: d->from, val: value, max: d->to);
350
351 if (qFuzzyIsNull(d: value))
352 value = 0.0;
353
354 if (qFuzzyCompare(p1: d->value, p2: value))
355 return;
356
357 d->value = value;
358 d->updatePosition();
359 emit valueChanged();
360}
361
362/*!
363 \qmlproperty real QtQuick.Controls::Slider::position
364 \readonly
365
366 This property holds the logical position of the handle.
367
368 The position is expressed as a fraction of the control's size, in the range
369 \c {0.0 - 1.0}. For visualizing a slider, the right-to-left aware
370 \l visualPosition should be used instead.
371
372 \sa value, visualPosition, valueAt()
373*/
374qreal QQuickSlider::position() const
375{
376 Q_D(const QQuickSlider);
377 return d->position;
378}
379
380/*!
381 \qmlproperty real QtQuick.Controls::Slider::visualPosition
382 \readonly
383
384 This property holds the visual position of the handle.
385
386 The position is expressed as a fraction of the control's size, in the range
387 \c {0.0 - 1.0}. When the control is \l {Control::mirrored}{mirrored}, the
388 value is equal to \c {1.0 - position}. This makes the value suitable for
389 visualizing the slider, taking right-to-left support into account.
390
391 \sa position
392*/
393qreal QQuickSlider::visualPosition() const
394{
395 Q_D(const QQuickSlider);
396 if (d->orientation == Qt::Vertical || isMirrored())
397 return 1.0 - d->position;
398 return d->position;
399}
400
401/*!
402 \qmlproperty real QtQuick.Controls::Slider::stepSize
403
404 This property holds the step size. The default value is \c 0.0.
405
406 \sa snapMode, increase(), decrease()
407*/
408qreal QQuickSlider::stepSize() const
409{
410 Q_D(const QQuickSlider);
411 return d->stepSize;
412}
413
414void QQuickSlider::setStepSize(qreal step)
415{
416 Q_D(QQuickSlider);
417 if (qFuzzyCompare(p1: d->stepSize, p2: step))
418 return;
419
420 d->stepSize = step;
421 emit stepSizeChanged();
422}
423
424/*!
425 \qmlproperty enumeration QtQuick.Controls::Slider::snapMode
426
427 This property holds the snap mode.
428
429 The snap mode determines how the slider handle behaves with
430 regards to the \l stepSize.
431
432 Possible values:
433 \value Slider.NoSnap The slider does not snap (default).
434 \value Slider.SnapAlways The slider snaps while the handle is dragged.
435 \value Slider.SnapOnRelease The slider does not snap while being dragged, but only after the handle is released.
436
437 In the following table, the various modes are illustrated with animations.
438 The movement of the mouse cursor and the \l stepSize (\c 0.2) are identical
439 in each animation.
440
441 \table
442 \header
443 \row \li \b Value \li \b Example
444 \row \li \c Slider.NoSnap \li \image qtquickcontrols-slider-nosnap.gif
445 \row \li \c Slider.SnapAlways \li \image qtquickcontrols-slider-snapalways.gif
446 \row \li \c Slider.SnapOnRelease \li \image qtquickcontrols-slider-snaponrelease.gif
447 \endtable
448
449 \sa stepSize
450*/
451QQuickSlider::SnapMode QQuickSlider::snapMode() const
452{
453 Q_D(const QQuickSlider);
454 return d->snapMode;
455}
456
457void QQuickSlider::setSnapMode(SnapMode mode)
458{
459 Q_D(QQuickSlider);
460 if (d->snapMode == mode)
461 return;
462
463 d->snapMode = mode;
464 emit snapModeChanged();
465}
466
467/*!
468 \qmlproperty bool QtQuick.Controls::Slider::pressed
469
470 This property holds whether the slider is pressed by either touch, mouse,
471 or keys.
472*/
473bool QQuickSlider::isPressed() const
474{
475 Q_D(const QQuickSlider);
476 return d->pressed;
477}
478
479void QQuickSlider::setPressed(bool pressed)
480{
481 Q_D(QQuickSlider);
482 if (d->pressed == pressed)
483 return;
484
485 d->pressed = pressed;
486 setAccessibleProperty(propertyName: "pressed", value: pressed);
487 emit pressedChanged();
488}
489
490/*!
491 \since QtQuick.Controls 2.3 (Qt 5.10)
492 \qmlproperty bool QtQuick.Controls::Slider::horizontal
493 \readonly
494
495 This property holds whether the slider is horizontal.
496
497 \sa orientation
498*/
499bool QQuickSlider::isHorizontal() const
500{
501 Q_D(const QQuickSlider);
502 return d->orientation == Qt::Horizontal;
503}
504
505/*!
506 \since QtQuick.Controls 2.3 (Qt 5.10)
507 \qmlproperty bool QtQuick.Controls::Slider::vertical
508 \readonly
509
510 This property holds whether the slider is vertical.
511
512 \sa orientation
513*/
514bool QQuickSlider::isVertical() const
515{
516 Q_D(const QQuickSlider);
517 return d->orientation == Qt::Vertical;
518}
519
520/*!
521 \qmlproperty enumeration QtQuick.Controls::Slider::orientation
522
523 This property holds the orientation.
524
525 Possible values:
526 \value Qt.Horizontal Horizontal (default)
527 \value Qt.Vertical Vertical
528
529 \sa horizontal, vertical
530*/
531Qt::Orientation QQuickSlider::orientation() const
532{
533 Q_D(const QQuickSlider);
534 return d->orientation;
535}
536
537void QQuickSlider::setOrientation(Qt::Orientation orientation)
538{
539 Q_D(QQuickSlider);
540 if (d->orientation == orientation)
541 return;
542
543 if (orientation == Qt::Horizontal)
544 d->setSizePolicy(horizontalPolicy: QLayoutPolicy::Expanding, verticalPolicy: QLayoutPolicy::Fixed);
545 else
546 d->setSizePolicy(horizontalPolicy: QLayoutPolicy::Fixed, verticalPolicy: QLayoutPolicy::Expanding);
547
548 d->orientation = orientation;
549 emit orientationChanged();
550}
551
552/*!
553 \qmlproperty Item QtQuick.Controls::Slider::handle
554
555 This property holds the handle item.
556
557 \sa {Customizing Slider}
558*/
559QQuickItem *QQuickSlider::handle() const
560{
561 QQuickSliderPrivate *d = const_cast<QQuickSliderPrivate *>(d_func());
562 if (!d->handle)
563 d->executeHandle();
564 return d->handle;
565}
566
567void QQuickSlider::setHandle(QQuickItem *handle)
568{
569 Q_D(QQuickSlider);
570 if (d->handle == handle)
571 return;
572
573 QQuickControlPrivate::warnIfCustomizationNotSupported(control: this, item: handle, QStringLiteral("handle"));
574
575 if (!d->handle.isExecuting())
576 d->cancelHandle();
577
578 const qreal oldImplicitHandleWidth = implicitHandleWidth();
579 const qreal oldImplicitHandleHeight = implicitHandleHeight();
580
581 d->removeImplicitSizeListener(item: d->handle);
582 QQuickControlPrivate::hideOldItem(item: d->handle);
583 d->handle = handle;
584
585 if (handle) {
586 if (!handle->parentItem())
587 handle->setParentItem(this);
588 d->addImplicitSizeListener(item: handle);
589 }
590
591 if (!qFuzzyCompare(p1: oldImplicitHandleWidth, p2: implicitHandleWidth()))
592 emit implicitHandleWidthChanged();
593 if (!qFuzzyCompare(p1: oldImplicitHandleHeight, p2: implicitHandleHeight()))
594 emit implicitHandleHeightChanged();
595 if (!d->handle.isExecuting())
596 emit handleChanged();
597}
598
599/*!
600 \since QtQuick.Controls 2.1 (Qt 5.8)
601 \qmlmethod real QtQuick.Controls::Slider::valueAt(real position)
602
603 Returns the value for the given \a position.
604
605 \sa value, position
606*/
607qreal QQuickSlider::valueAt(qreal position) const
608{
609 Q_D(const QQuickSlider);
610 const qreal value = (d->to - d->from) * position;
611 if (qFuzzyIsNull(d: d->stepSize))
612 return d->from + value;
613 return d->from + qRound(d: value / d->stepSize) * d->stepSize;
614}
615
616/*!
617 \since QtQuick.Controls 2.2 (Qt 5.9)
618 \qmlproperty bool QtQuick.Controls::Slider::live
619
620 This property holds whether the slider provides live updates for the \l value
621 property while the handle is dragged.
622
623 The default value is \c true.
624
625 \sa value, valueAt()
626*/
627bool QQuickSlider::live() const
628{
629 Q_D(const QQuickSlider);
630 return d->live;
631}
632
633void QQuickSlider::setLive(bool live)
634{
635 Q_D(QQuickSlider);
636 if (d->live == live)
637 return;
638
639 d->live = live;
640 emit liveChanged();
641}
642
643/*!
644 \qmlmethod void QtQuick.Controls::Slider::increase()
645
646 Increases the value by \l stepSize or \c 0.1 if stepSize is not defined.
647
648 \sa stepSize
649*/
650void QQuickSlider::increase()
651{
652 Q_D(QQuickSlider);
653 qreal step = qFuzzyIsNull(d: d->stepSize) ? 0.1 : d->stepSize;
654 setValue(d->value + step);
655}
656
657/*!
658 \qmlmethod void QtQuick.Controls::Slider::decrease()
659
660 Decreases the value by \l stepSize or \c 0.1 if stepSize is not defined.
661
662 \sa stepSize
663*/
664void QQuickSlider::decrease()
665{
666 Q_D(QQuickSlider);
667 qreal step = qFuzzyIsNull(d: d->stepSize) ? 0.1 : d->stepSize;
668 setValue(d->value - step);
669}
670
671/*!
672 \since QtQuick.Controls 2.5 (Qt 5.12)
673 \qmlproperty real QtQuick.Controls::Slider::touchDragThreshold
674
675 This property holds the threshold (in logical pixels) at which a touch drag event will be initiated.
676 The mouse drag threshold won't be affected.
677 The default value is \c Application.styleHints.startDragDistance.
678
679 \sa QStyleHints
680*/
681qreal QQuickSlider::touchDragThreshold() const
682{
683 Q_D(const QQuickSlider);
684 return d->touchDragThreshold;
685}
686
687void QQuickSlider::setTouchDragThreshold(qreal touchDragThreshold)
688{
689 Q_D(QQuickSlider);
690 if (d->touchDragThreshold == touchDragThreshold)
691 return;
692
693 d->touchDragThreshold = touchDragThreshold;
694 emit touchDragThresholdChanged();
695}
696
697void QQuickSlider::resetTouchDragThreshold()
698{
699 setTouchDragThreshold(-1);
700}
701
702/*!
703 \since QtQuick.Controls 2.5 (Qt 5.12)
704 \qmlproperty real QtQuick.Controls::Slider::implicitHandleWidth
705 \readonly
706
707 This property holds the implicit handle width.
708
709 The value is equal to \c {handle ? handle.implicitWidth : 0}.
710
711 This is typically used, together with \l {Control::}{implicitContentWidth} and
712 \l {Control::}{implicitBackgroundWidth}, to calculate the \l {Item::}{implicitWidth}.
713
714 \sa implicitHandleHeight
715*/
716qreal QQuickSlider::implicitHandleWidth() const
717{
718 Q_D(const QQuickSlider);
719 if (!d->handle)
720 return 0;
721 return d->handle->implicitWidth();
722}
723
724/*!
725 \since QtQuick.Controls 2.5 (Qt 5.12)
726 \qmlproperty real QtQuick.Controls::Slider::implicitHandleHeight
727 \readonly
728
729 This property holds the implicit handle height.
730
731 The value is equal to \c {handle ? handle.implicitHeight : 0}.
732
733 This is typically used, together with \l {Control::}{implicitContentHeight} and
734 \l {Control::}{implicitBackgroundHeight}, to calculate the \l {Item::}{implicitHeight}.
735
736 \sa implicitHandleWidth
737*/
738qreal QQuickSlider::implicitHandleHeight() const
739{
740 Q_D(const QQuickSlider);
741 if (!d->handle)
742 return 0;
743 return d->handle->implicitHeight();
744}
745
746void QQuickSlider::keyPressEvent(QKeyEvent *event)
747{
748 Q_D(QQuickSlider);
749 QQuickControl::keyPressEvent(event);
750
751 const qreal oldValue = d->value;
752 if (d->orientation == Qt::Horizontal) {
753 if (event->key() == Qt::Key_Left) {
754 setPressed(true);
755 if (isMirrored())
756 increase();
757 else
758 decrease();
759 event->accept();
760 } else if (event->key() == Qt::Key_Right) {
761 setPressed(true);
762 if (isMirrored())
763 decrease();
764 else
765 increase();
766 event->accept();
767 }
768 } else {
769 if (event->key() == Qt::Key_Up) {
770 setPressed(true);
771 increase();
772 event->accept();
773 } else if (event->key() == Qt::Key_Down) {
774 setPressed(true);
775 decrease();
776 event->accept();
777 }
778 }
779 if (!qFuzzyCompare(p1: d->value, p2: oldValue))
780 emit moved();
781}
782
783void QQuickSlider::keyReleaseEvent(QKeyEvent *event)
784{
785 QQuickControl::keyReleaseEvent(event);
786 setPressed(false);
787}
788
789void QQuickSlider::mousePressEvent(QMouseEvent *event)
790{
791 Q_D(QQuickSlider);
792 QQuickControl::mousePressEvent(event);
793 d->handleMove(point: event->position(), timestamp: event->timestamp());
794 setKeepMouseGrab(true);
795}
796
797#if QT_CONFIG(quicktemplates2_multitouch)
798void QQuickSlider::touchEvent(QTouchEvent *event)
799{
800 Q_D(QQuickSlider);
801 switch (event->type()) {
802 case QEvent::TouchUpdate:
803 for (const QTouchEvent::TouchPoint &point : event->points()) {
804 if (!d->acceptTouch(point))
805 continue;
806
807 switch (point.state()) {
808 case QEventPoint::Pressed:
809 d->handlePress(point: point.position(), timestamp: event->timestamp());
810 break;
811 case QEventPoint::Updated:
812 if (!keepTouchGrab()) {
813 if (d->orientation == Qt::Horizontal) {
814 setKeepTouchGrab(QQuickDeliveryAgentPrivate::dragOverThreshold(d: point.position().x() - d->pressPoint.x(),
815 axis: Qt::XAxis, tp: point, startDragThreshold: qRound(d: d->touchDragThreshold)));
816 } else {
817 setKeepTouchGrab(QQuickDeliveryAgentPrivate::dragOverThreshold(d: point.position().y() - d->pressPoint.y(),
818 axis: Qt::YAxis, tp: point, startDragThreshold: qRound(d: d->touchDragThreshold)));
819 }
820 }
821 if (keepTouchGrab())
822 d->handleMove(point: point.position(), timestamp: event->timestamp());
823 break;
824 case QEventPoint::Released:
825 d->handleRelease(point: point.position(), timestamp: event->timestamp());
826 break;
827 default:
828 break;
829 }
830 }
831 break;
832
833 default:
834 QQuickControl::touchEvent(event);
835 break;
836 }
837}
838#endif
839
840#if QT_CONFIG(wheelevent)
841void QQuickSlider::wheelEvent(QWheelEvent *event)
842{
843 Q_D(QQuickSlider);
844 QQuickControl::wheelEvent(event);
845 if (d->wheelEnabled) {
846 const qreal oldValue = d->value;
847 const QPointF angle = event->angleDelta();
848 const qreal delta = (qAbs(t: angle.y()) < qAbs(t: angle.x()) ? angle.x() : (event->inverted() ? -angle.y() : angle.y())) / int(QWheelEvent::DefaultDeltasPerStep);
849 const qreal step = qFuzzyIsNull(d: d->stepSize) ? 0.1 : d->stepSize;
850 setValue(oldValue + step * delta);
851 const bool wasMoved = !qFuzzyCompare(p1: d->value, p2: oldValue);
852 if (wasMoved)
853 emit moved();
854 }
855}
856#endif
857
858void QQuickSlider::mirrorChange()
859{
860 QQuickControl::mirrorChange();
861 emit visualPositionChanged();
862}
863
864void QQuickSlider::componentComplete()
865{
866 Q_D(QQuickSlider);
867 d->executeHandle(complete: true);
868 QQuickControl::componentComplete();
869 setValue(d->value);
870 d->updatePosition();
871}
872
873#if QT_CONFIG(accessibility)
874void QQuickSlider::accessibilityActiveChanged(bool active)
875{
876 QQuickControl::accessibilityActiveChanged(active);
877
878 Q_D(QQuickSlider);
879 if (active)
880 setAccessibleProperty(propertyName: "pressed", value: d->pressed);
881}
882
883QAccessible::Role QQuickSlider::accessibleRole() const
884{
885 return QAccessible::Slider;
886}
887#endif
888
889QT_END_NAMESPACE
890
891#include "moc_qquickslider_p.cpp"
892

source code of qtdeclarative/src/quicktemplates/qquickslider.cpp