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