1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
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 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file.  Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #include <qapplication.h>
43 #include "qabstractslider.h"
44 #include "qevent.h"
45 #include "qabstractslider_p.h"
46 #include "qdebug.h"
47 #ifndef QT_NO_ACCESSIBILITY
48 #include "qaccessible.h"
49 #endif
50 #include <limits.h>
51 
52 QT_BEGIN_NAMESPACE
53 
54 /*!
55     \class QAbstractSlider
56     \brief The QAbstractSlider class provides an integer value within a range.
57 
58     \ingroup abstractwidgets
59 
60     The class is designed as a common super class for widgets like
61     QScrollBar, QSlider and QDial.
62 
63     Here are the main properties of the class:
64 
65     \list 1
66 
67     \i \l value: The bounded integer that QAbstractSlider maintains.
68 
69     \i \l minimum: The lowest possible value.
70 
71     \i \l maximum: The highest possible value.
72 
73     \i \l singleStep: The smaller of two natural steps that an
74     abstract sliders provides and typically corresponds to the user
75     pressing an arrow key.
76 
77     \i \l pageStep: The larger of two natural steps that an abstract
78     slider provides and typically corresponds to the user pressing
79     PageUp or PageDown.
80 
81     \i \l tracking: Whether slider tracking is enabled.
82 
83     \i \l sliderPosition: The current position of the slider. If \l
84     tracking is enabled (the default), this is identical to \l value.
85 
86     \endlist
87 
88     Unity (1) may be viewed as a third step size. setValue() lets you
89     set the current value to any integer in the allowed range, not
90     just minimum() + \e n * singleStep() for integer values of \e n.
91     Some widgets may allow the user to set any value at all; others
92     may just provide multiples of singleStep() or pageStep().
93 
94     QAbstractSlider emits a comprehensive set of signals:
95 
96     \table
97     \header \i Signal \i Emitted when
98     \row \i \l valueChanged()
99          \i the value has changed. The \l tracking
100             determines whether this signal is emitted during user
101             interaction.
102     \row \i \l sliderPressed()
103          \i the user starts to drag the slider.
104     \row \i \l sliderMoved()
105          \i the user drags the slider.
106     \row \i \l sliderReleased()
107          \i the user releases the slider.
108     \row \i \l actionTriggered()
109          \i a slider action was triggerd.
110     \row \i \l rangeChanged()
111          \i a the range has changed.
112     \endtable
113 
114     QAbstractSlider provides a virtual sliderChange() function that is
115     well suited for updating the on-screen representation of
116     sliders. By calling triggerAction(), subclasses trigger slider
117     actions. Two helper functions QStyle::sliderPositionFromValue() and
118     QStyle::sliderValueFromPosition() help subclasses and styles to map
119     screen coordinates to logical range values.
120 
121     \sa QAbstractSpinBox, QSlider, QDial, QScrollBar, {Sliders Example}
122 */
123 
124 /*!
125     \enum QAbstractSlider::SliderAction
126 
127     \value SliderNoAction
128     \value SliderSingleStepAdd
129     \value SliderSingleStepSub
130     \value SliderPageStepAdd
131     \value SliderPageStepSub
132     \value SliderToMinimum
133     \value SliderToMaximum
134     \value SliderMove
135 
136 */
137 
138 /*!
139     \fn void QAbstractSlider::valueChanged(int value)
140 
141     This signal is emitted when the slider value has changed, with the
142     new slider \a value as argument.
143 */
144 
145 /*!
146     \fn void QAbstractSlider::sliderPressed()
147 
148     This signal is emitted when the user presses the slider with the
149     mouse, or programmatically when setSliderDown(true) is called.
150 
151     \sa sliderReleased(), sliderMoved(), isSliderDown()
152 */
153 
154 /*!
155     \fn void QAbstractSlider::sliderMoved(int value)
156 
157     This signal is emitted when sliderDown is true and the slider moves. This
158     usually happens when the user is dragging the slider. The \a value
159     is the new slider position.
160 
161     This signal is emitted even when tracking is turned off.
162 
163     \sa setTracking(), valueChanged(), isSliderDown(),
164     sliderPressed(), sliderReleased()
165 */
166 
167 /*!
168     \fn void QAbstractSlider::sliderReleased()
169 
170     This signal is emitted when the user releases the slider with the
171     mouse, or programmatically when setSliderDown(false) is called.
172 
173     \sa sliderPressed() sliderMoved() sliderDown
174 */
175 
176 /*!
177     \fn void QAbstractSlider::rangeChanged(int min, int max)
178 
179     This signal is emitted when the slider range has changed, with \a
180     min being the new minimum, and \a max being the new maximum.
181 
182     \sa minimum, maximum
183 */
184 
185 /*!
186     \fn void QAbstractSlider::actionTriggered(int action)
187 
188     This signal is emitted when the slider action \a action is
189     triggered. Actions are \l SliderSingleStepAdd, \l
190     SliderSingleStepSub, \l SliderPageStepAdd, \l SliderPageStepSub,
191     \l SliderToMinimum, \l SliderToMaximum, and \l SliderMove.
192 
193     When the signal is emitted, the \l sliderPosition has been
194     adjusted according to the action, but the \l value has not yet
195     been propagated (meaning the valueChanged() signal was not yet
196     emitted), and the visual display has not been updated. In slots
197     connected to this signal you can thus safely adjust any action by
198     calling setSliderPosition() yourself, based on both the action and
199     the slider's value.
200 
201     \sa triggerAction()
202 */
203 
204 /*!
205     \enum QAbstractSlider::SliderChange
206 
207     \value SliderRangeChange
208     \value SliderOrientationChange
209     \value SliderStepsChange
210     \value SliderValueChange
211 */
212 
QAbstractSliderPrivate()213 QAbstractSliderPrivate::QAbstractSliderPrivate()
214     : minimum(0), maximum(99), pageStep(10), value(0), position(0), pressValue(-1),
215       singleStep(1), offset_accumulated(0), tracking(true),
216       blocktracking(false), pressed(false),
217       invertedAppearance(false), invertedControls(false),
218       orientation(Qt::Horizontal), repeatAction(QAbstractSlider::SliderNoAction)
219 #ifdef QT_KEYPAD_NAVIGATION
220       , isAutoRepeating(false)
221       , repeatMultiplier(1)
222 {
223     firstRepeat.invalidate();
224 #else
225 {
226 #endif
227 
228 }
229 
230 QAbstractSliderPrivate::~QAbstractSliderPrivate()
231 {
232 }
233 
234 /*!
235     Sets the slider's minimum to \a min and its maximum to \a max.
236 
237     If \a max is smaller than \a min, \a min becomes the only legal
238     value.
239 
240     \sa minimum maximum
241 */
242 void QAbstractSlider::setRange(int min, int max)
243 {
244     Q_D(QAbstractSlider);
245     int oldMin = d->minimum;
246     int oldMax = d->maximum;
247     d->minimum = min;
248     d->maximum = qMax(min, max);
249     if (oldMin != d->minimum || oldMax != d->maximum) {
250         sliderChange(SliderRangeChange);
251         emit rangeChanged(d->minimum, d->maximum);
252         setValue(d->value); // re-bound
253     }
254 }
255 
256 
257 void QAbstractSliderPrivate::setSteps(int single, int page)
258 {
259     Q_Q(QAbstractSlider);
260     singleStep = qAbs(single);
261     pageStep = qAbs(page);
262     q->sliderChange(QAbstractSlider::SliderStepsChange);
263 }
264 
265 /*!
266     Constructs an abstract slider.
267 
268     The \a parent argument is sent to the QWidget constructor.
269 
270     The \l minimum defaults to 0, the \l maximum to 99, with a \l
271     singleStep size of 1 and a \l pageStep size of 10, and an initial
272     \l value of 0.
273 */
274 QAbstractSlider::QAbstractSlider(QWidget *parent)
275     :QWidget(*new QAbstractSliderPrivate, parent, 0)
276 {
277 }
278 
279 /*! \internal */
280 QAbstractSlider::QAbstractSlider(QAbstractSliderPrivate &dd, QWidget *parent)
281     :QWidget(dd, parent, 0)
282 {
283 }
284 
285 /*!
286     Destroys the slider.
287 */
288 QAbstractSlider::~QAbstractSlider()
289 {
290 }
291 
292 /*!
293     \property QAbstractSlider::orientation
294     \brief the orientation of the slider
295 
296     The orientation must be \l Qt::Vertical (the default) or \l
297     Qt::Horizontal.
298 */
299 void QAbstractSlider::setOrientation(Qt::Orientation orientation)
300 {
301     Q_D(QAbstractSlider);
302     if (d->orientation == orientation)
303         return;
304 
305     d->orientation = orientation;
306     if (!testAttribute(Qt::WA_WState_OwnSizePolicy)) {
307         QSizePolicy sp = sizePolicy();
308         sp.transpose();
309         setSizePolicy(sp);
310         setAttribute(Qt::WA_WState_OwnSizePolicy, false);
311     }
312     update();
313     updateGeometry();
314 }
315 
316 Qt::Orientation QAbstractSlider::orientation() const
317 {
318     Q_D(const QAbstractSlider);
319     return d->orientation;
320 }
321 
322 
323 /*!
324     \property QAbstractSlider::minimum
325     \brief the sliders's minimum value
326 
327     When setting this property, the \l maximum is adjusted if
328     necessary to ensure that the range remains valid. Also the
329     slider's current value is adjusted to be within the new range.
330 
331 */
332 
333 void QAbstractSlider::setMinimum(int min)
334 {
335     Q_D(QAbstractSlider);
336     setRange(min, qMax(d->maximum, min));
337 }
338 
339 int QAbstractSlider::minimum() const
340 {
341     Q_D(const QAbstractSlider);
342     return d->minimum;
343 }
344 
345 
346 /*!
347     \property QAbstractSlider::maximum
348     \brief the slider's maximum value
349 
350     When setting this property, the \l minimum is adjusted if
351     necessary to ensure that the range remains valid.  Also the
352     slider's current value is adjusted to be within the new range.
353 
354 
355 */
356 
357 void QAbstractSlider::setMaximum(int max)
358 {
359     Q_D(QAbstractSlider);
360     setRange(qMin(d->minimum, max), max);
361 }
362 
363 int QAbstractSlider::maximum() const
364 {
365     Q_D(const QAbstractSlider);
366     return d->maximum;
367 }
368 
369 
370 
371 /*!
372     \property QAbstractSlider::singleStep
373     \brief the single step.
374 
375     The smaller of two natural steps that an
376     abstract sliders provides and typically corresponds to the user
377     pressing an arrow key.
378 
379     If the property is modified during an auto repeating key event, behavior
380     is undefined.
381 
382     \sa pageStep
383 */
384 
385 void QAbstractSlider::setSingleStep(int step)
386 {
387     Q_D(QAbstractSlider);
388     if (step != d->singleStep)
389         d->setSteps(step, d->pageStep);
390 }
391 
392 int QAbstractSlider::singleStep() const
393 {
394     Q_D(const QAbstractSlider);
395     return d->singleStep;
396 }
397 
398 
399 /*!
400     \property QAbstractSlider::pageStep
401     \brief the page step.
402 
403     The larger of two natural steps that an abstract slider provides
404     and typically corresponds to the user pressing PageUp or PageDown.
405 
406     \sa singleStep
407 */
408 
409 void QAbstractSlider::setPageStep(int step)
410 {
411     Q_D(QAbstractSlider);
412     if (step != d->pageStep)
413         d->setSteps(d->singleStep, step);
414 }
415 
416 int QAbstractSlider::pageStep() const
417 {
418     Q_D(const QAbstractSlider);
419     return d->pageStep;
420 }
421 
422 /*!
423     \property QAbstractSlider::tracking
424     \brief whether slider tracking is enabled
425 
426     If tracking is enabled (the default), the slider emits the
427     valueChanged() signal while the slider is being dragged. If
428     tracking is disabled, the slider emits the valueChanged() signal
429     only when the user releases the slider.
430 
431     \sa sliderDown
432 */
433 void QAbstractSlider::setTracking(bool enable)
434 {
435     Q_D(QAbstractSlider);
436     d->tracking = enable;
437 }
438 
439 bool QAbstractSlider::hasTracking() const
440 {
441     Q_D(const QAbstractSlider);
442     return d->tracking;
443 }
444 
445 
446 /*!
447     \property QAbstractSlider::sliderDown
448     \brief whether the slider is pressed down.
449 
450     The property is set by subclasses in order to let the abstract
451     slider know whether or not \l tracking has any effect.
452 
453     Changing the slider down property emits the sliderPressed() and
454     sliderReleased() signals.
455 
456 */
457 void QAbstractSlider::setSliderDown(bool down)
458 {
459     Q_D(QAbstractSlider);
460     bool doEmit = d->pressed != down;
461 
462     d->pressed = down;
463 
464     if (doEmit) {
465         if (down)
466             emit sliderPressed();
467         else
468             emit sliderReleased();
469     }
470 
471     if (!down && d->position != d->value)
472         triggerAction(SliderMove);
473 }
474 
475 bool QAbstractSlider::isSliderDown() const
476 {
477     Q_D(const QAbstractSlider);
478     return d->pressed;
479 }
480 
481 
482 /*!
483     \property QAbstractSlider::sliderPosition
484     \brief the current slider position
485 
486     If \l tracking is enabled (the default), this is identical to \l value.
487 */
488 void QAbstractSlider::setSliderPosition(int position)
489 {
490     Q_D(QAbstractSlider);
491     position = d->bound(position);
492     if (position == d->position)
493         return;
494     d->position = position;
495     if (!d->tracking)
496         update();
497     if (d->pressed)
498         emit sliderMoved(position);
499     if (d->tracking && !d->blocktracking)
500         triggerAction(SliderMove);
501 }
502 
503 int QAbstractSlider::sliderPosition() const
504 {
505     Q_D(const QAbstractSlider);
506     return d->position;
507 }
508 
509 
510 /*!
511     \property QAbstractSlider::value
512     \brief the slider's current value
513 
514     The slider forces the value to be within the legal range: \l
515     minimum <= \c value <= \l maximum.
516 
517     Changing the value also changes the \l sliderPosition.
518 */
519 
520 
521 int QAbstractSlider::value() const
522 {
523     Q_D(const QAbstractSlider);
524     return d->value;
525 }
526 
527 void QAbstractSlider::setValue(int value)
528 {
529     Q_D(QAbstractSlider);
530     value = d->bound(value);
531     if (d->value == value && d->position == value)
532         return;
533     d->value = value;
534     if (d->position != value) {
535         d->position = value;
536         if (d->pressed)
537             emit sliderMoved((d->position = value));
538     }
539 #ifndef QT_NO_ACCESSIBILITY
540     QAccessible::updateAccessibility(this, 0, QAccessible::ValueChanged);
541 #endif
542     sliderChange(SliderValueChange);
543     emit valueChanged(value);
544 }
545 
546 /*!
547     \property QAbstractSlider::invertedAppearance
548     \brief whether or not a slider shows its values inverted.
549 
550     If this property is false (the default), the minimum and maximum will
551     be shown in its classic position for the inherited widget. If the
552     value is true, the minimum and maximum appear at their opposite location.
553 
554     Note: This property makes most sense for sliders and dials. For
555     scroll bars, the visual effect of the scroll bar subcontrols depends on
556     whether or not the styles understand inverted appearance; most styles
557     ignore this property for scroll bars.
558 */
559 
560 bool QAbstractSlider::invertedAppearance() const
561 {
562     Q_D(const QAbstractSlider);
563     return d->invertedAppearance;
564 }
565 
566 void QAbstractSlider::setInvertedAppearance(bool invert)
567 {
568     Q_D(QAbstractSlider);
569     d->invertedAppearance = invert;
570     update();
571 }
572 
573 
574 /*!
575     \property QAbstractSlider::invertedControls
576     \brief whether or not the slider inverts its wheel and key events.
577 
578     If this property is false, scrolling the mouse wheel "up" and using keys
579     like page up will increase the slider's value towards its maximum. Otherwise
580     pressing page up will move value towards the slider's minimum.
581 */
582 
583 
584 bool QAbstractSlider::invertedControls() const
585 {
586     Q_D(const QAbstractSlider);
587     return d->invertedControls;
588 }
589 
590 void QAbstractSlider::setInvertedControls(bool invert)
591 {
592     Q_D(QAbstractSlider);
593     d->invertedControls = invert;
594 }
595 
596 /*!  Triggers a slider \a action.  Possible actions are \l
597   SliderSingleStepAdd, \l SliderSingleStepSub, \l SliderPageStepAdd,
598   \l SliderPageStepSub, \l SliderToMinimum, \l SliderToMaximum, and \l
599   SliderMove.
600 
601   \sa actionTriggered()
602  */
603 void QAbstractSlider::triggerAction(SliderAction action)
604 {
605     Q_D(QAbstractSlider);
606     d->blocktracking = true;
607     switch (action) {
608     case SliderSingleStepAdd:
609         setSliderPosition(d->overflowSafeAdd(d->effectiveSingleStep()));
610         break;
611     case SliderSingleStepSub:
612         setSliderPosition(d->overflowSafeAdd(-d->effectiveSingleStep()));
613         break;
614     case SliderPageStepAdd:
615         setSliderPosition(d->overflowSafeAdd(d->pageStep));
616         break;
617     case SliderPageStepSub:
618         setSliderPosition(d->overflowSafeAdd(-d->pageStep));
619         break;
620     case SliderToMinimum:
621         setSliderPosition(d->minimum);
622         break;
623     case SliderToMaximum:
624         setSliderPosition(d->maximum);
625         break;
626     case SliderMove:
627     case SliderNoAction:
628         break;
629     };
630     emit actionTriggered(action);
631     d->blocktracking = false;
632     setValue(d->position);
633 }
634 
635 /*!  Sets action \a action to be triggered repetitively in intervals
636 of \a repeatTime, after an initial delay of \a thresholdTime.
637 
638 \sa triggerAction() repeatAction()
639  */
640 void QAbstractSlider::setRepeatAction(SliderAction action, int thresholdTime, int repeatTime)
641 {
642     Q_D(QAbstractSlider);
643     if ((d->repeatAction = action) == SliderNoAction) {
644         d->repeatActionTimer.stop();
645     } else {
646         d->repeatActionTime = repeatTime;
647         d->repeatActionTimer.start(thresholdTime, this);
648     }
649 }
650 
651 /*!
652   Returns the current repeat action.
653   \sa setRepeatAction()
654  */
655 QAbstractSlider::SliderAction QAbstractSlider::repeatAction() const
656 {
657     Q_D(const QAbstractSlider);
658     return d->repeatAction;
659 }
660 
661 /*!\reimp
662  */
663 void QAbstractSlider::timerEvent(QTimerEvent *e)
664 {
665     Q_D(QAbstractSlider);
666     if (e->timerId() == d->repeatActionTimer.timerId()) {
667         if (d->repeatActionTime) { // was threshold time, use repeat time next time
668             d->repeatActionTimer.start(d->repeatActionTime, this);
669             d->repeatActionTime = 0;
670         }
671         if (d->repeatAction == SliderPageStepAdd)
672             d->setAdjustedSliderPosition(d->overflowSafeAdd(d->pageStep));
673         else if (d->repeatAction == SliderPageStepSub)
674             d->setAdjustedSliderPosition(d->overflowSafeAdd(-d->pageStep));
675         else
676             triggerAction(d->repeatAction);
677     }
678 }
679 
680 /*!
681     Reimplement this virtual function to track slider changes such as
682     \l SliderRangeChange, \l SliderOrientationChange, \l
683     SliderStepsChange, or \l SliderValueChange. The default
684     implementation only updates the display and ignores the \a change
685     parameter.
686  */
687 void QAbstractSlider::sliderChange(SliderChange)
688 {
689     update();
690 }
691 
692 /*!
693     \internal
694 
695     Truncate qreal to int without flipping on overflow.
696 */
697 static inline int clampScrollStep(qreal x)
698 {
699     return int(qBound(qreal(INT_MIN), x, qreal(INT_MAX)));
700 }
701 
702 bool QAbstractSliderPrivate::scrollByDelta(Qt::Orientation orientation, Qt::KeyboardModifiers modifiers, int delta)
703 {
704     Q_Q(QAbstractSlider);
705     int stepsToScroll = 0;
706     // in Qt scrolling to the right gives negative values.
707     if (orientation == Qt::Horizontal)
708         delta = -delta;
709     qreal offset = qreal(delta) / 120;
710 
711     if ((modifiers & Qt::ControlModifier) || (modifiers & Qt::ShiftModifier)) {
712         // Scroll one page regardless of delta:
713         stepsToScroll = qBound(-pageStep, clampScrollStep(offset * pageStep), pageStep);
714         offset_accumulated = 0;
715     } else {
716         // Calculate how many lines to scroll. Depending on what delta is (and
717         // offset), we might end up with a fraction (e.g. scroll 1.3 lines). We can
718         // only scroll whole lines, so we keep the reminder until next event.
719         qreal stepsToScrollF =
720 #ifndef QT_NO_WHEELEVENT
721                 QApplication::wheelScrollLines() *
722 #endif
723                 offset * effectiveSingleStep();
724         // Check if wheel changed direction since last event:
725         if (offset_accumulated != 0 && (offset / offset_accumulated) < 0)
726             offset_accumulated = 0;
727 
728         offset_accumulated += stepsToScrollF;
729 #ifndef Q_WS_MAC
730         // Don't scroll more than one page in any case:
731         stepsToScroll = qBound(-pageStep, clampScrollStep(offset_accumulated), pageStep);
732 #else
733         // Native UI-elements on Mac can scroll hundreds of lines at a time as
734         // a result of acceleration. So keep the same behaviour in Qt, and
735         // don't restrict stepsToScroll to certain maximum (pageStep):
736         stepsToScroll = clampScrollStep(offset_accumulated);
737 #endif
738         offset_accumulated -= clampScrollStep(offset_accumulated);
739         if (stepsToScroll == 0)
740             return false;
741     }
742 
743     if (invertedControls)
744         stepsToScroll = -stepsToScroll;
745 
746     int prevValue = value;
747     position = overflowSafeAdd(stepsToScroll); // value will be updated by triggerAction()
748     q->triggerAction(QAbstractSlider::SliderMove);
749 
750     if (prevValue == value) {
751         offset_accumulated = 0;
752         return false;
753     }
754     return true;
755 }
756 
757 /*!
758     \reimp
759 */
760 #ifndef QT_NO_WHEELEVENT
761 void QAbstractSlider::wheelEvent(QWheelEvent * e)
762 {
763     Q_D(QAbstractSlider);
764     e->ignore();
765     int delta = e->delta();
766     if (d->scrollByDelta(e->orientation(), e->modifiers(), delta))
767         e->accept();
768 }
769 
770 #endif
771 
772 /*!
773     \reimp
774 */
775 void QAbstractSlider::keyPressEvent(QKeyEvent *ev)
776 {
777     Q_D(QAbstractSlider);
778     SliderAction action = SliderNoAction;
779 #ifdef QT_KEYPAD_NAVIGATION
780     if (ev->isAutoRepeat()) {
781         if (!d->firstRepeat.isValid())
782             d->firstRepeat.start();
783         else if (1 == d->repeatMultiplier) {
784             // This is the interval in milli seconds which one key repetition
785             // takes.
786             const int repeatMSecs = d->firstRepeat.elapsed();
787 
788             /**
789              * The time it takes to currently navigate the whole slider.
790              */
791             const qreal currentTimeElapse = (qreal(maximum()) / singleStep()) * repeatMSecs;
792 
793             /**
794              * This is an arbitrarily determined constant in msecs that
795              * specifies how long time it should take to navigate from the
796              * start to the end(excluding starting key auto repeat).
797              */
798             const int SliderRepeatElapse = 2500;
799 
800             d->repeatMultiplier = currentTimeElapse / SliderRepeatElapse;
801         }
802 
803     }
804     else if (d->firstRepeat.isValid()) {
805         d->firstRepeat.invalidate();
806         d->repeatMultiplier = 1;
807     }
808 
809 #endif
810 
811     switch (ev->key()) {
812 #ifdef QT_KEYPAD_NAVIGATION
813         case Qt::Key_Select:
814             if (QApplication::keypadNavigationEnabled())
815                 setEditFocus(!hasEditFocus());
816             else
817                 ev->ignore();
818             break;
819         case Qt::Key_Back:
820             if (QApplication::keypadNavigationEnabled() && hasEditFocus()) {
821                 setValue(d->origValue);
822                 setEditFocus(false);
823             } else
824                 ev->ignore();
825             break;
826 #endif
827 
828         // It seems we need to use invertedAppearance for Left and right, otherwise, things look weird.
829         case Qt::Key_Left:
830 #ifdef QT_KEYPAD_NAVIGATION
831             // In QApplication::KeypadNavigationDirectional, we want to change the slider
832             // value if there is no left/right navigation possible and if this slider is not
833             // inside a tab widget.
834             if (QApplication::keypadNavigationEnabled()
835                     && (!hasEditFocus() && QApplication::navigationMode() == Qt::NavigationModeKeypadTabOrder
836                     || d->orientation == Qt::Vertical
837                     || !hasEditFocus()
838                     && (QWidgetPrivate::canKeypadNavigate(Qt::Horizontal) || QWidgetPrivate::inTabWidget(this)))) {
839                 ev->ignore();
840                 return;
841             }
842             if (QApplication::keypadNavigationEnabled() && d->orientation == Qt::Vertical)
843                 action = d->invertedControls ? SliderSingleStepSub : SliderSingleStepAdd;
844             else
845 #endif
846             if (isRightToLeft())
847                 action = d->invertedAppearance ? SliderSingleStepSub : SliderSingleStepAdd;
848             else
849                 action = !d->invertedAppearance ? SliderSingleStepSub : SliderSingleStepAdd;
850             break;
851         case Qt::Key_Right:
852 #ifdef QT_KEYPAD_NAVIGATION
853             // Same logic as in Qt::Key_Left
854             if (QApplication::keypadNavigationEnabled()
855                     && (!hasEditFocus() && QApplication::navigationMode() == Qt::NavigationModeKeypadTabOrder
856                     || d->orientation == Qt::Vertical
857                     || !hasEditFocus()
858                     && (QWidgetPrivate::canKeypadNavigate(Qt::Horizontal) || QWidgetPrivate::inTabWidget(this)))) {
859                 ev->ignore();
860                 return;
861             }
862             if (QApplication::keypadNavigationEnabled() && d->orientation == Qt::Vertical)
863                 action = d->invertedControls ? SliderSingleStepAdd : SliderSingleStepSub;
864             else
865 #endif
866             if (isRightToLeft())
867                 action = d->invertedAppearance ? SliderSingleStepAdd : SliderSingleStepSub;
868             else
869                 action = !d->invertedAppearance ? SliderSingleStepAdd : SliderSingleStepSub;
870             break;
871         case Qt::Key_Up:
872 #ifdef QT_KEYPAD_NAVIGATION
873             // In QApplication::KeypadNavigationDirectional, we want to change the slider
874             // value if there is no up/down navigation possible.
875             if (QApplication::keypadNavigationEnabled()
876                     && (QApplication::navigationMode() == Qt::NavigationModeKeypadTabOrder
877                     || d->orientation == Qt::Horizontal
878                     || !hasEditFocus() && QWidgetPrivate::canKeypadNavigate(Qt::Vertical))) {
879                 ev->ignore();
880                 break;
881             }
882 #endif
883             action = d->invertedControls ? SliderSingleStepSub : SliderSingleStepAdd;
884             break;
885         case Qt::Key_Down:
886 #ifdef QT_KEYPAD_NAVIGATION
887             // Same logic as in Qt::Key_Up
888             if (QApplication::keypadNavigationEnabled()
889                     && (QApplication::navigationMode() == Qt::NavigationModeKeypadTabOrder
890                     || d->orientation == Qt::Horizontal
891                     || !hasEditFocus() && QWidgetPrivate::canKeypadNavigate(Qt::Vertical))) {
892                 ev->ignore();
893                 break;
894             }
895 #endif
896             action = d->invertedControls ? SliderSingleStepAdd : SliderSingleStepSub;
897             break;
898         case Qt::Key_PageUp:
899             action = d->invertedControls ? SliderPageStepSub : SliderPageStepAdd;
900             break;
901         case Qt::Key_PageDown:
902             action = d->invertedControls ? SliderPageStepAdd : SliderPageStepSub;
903             break;
904         case Qt::Key_Home:
905             action = SliderToMinimum;
906             break;
907         case Qt::Key_End:
908             action = SliderToMaximum;
909             break;
910         default:
911             ev->ignore();
912             break;
913     }
914     if (action)
915         triggerAction(action);
916 }
917 
918 /*!
919     \reimp
920 */
921 void QAbstractSlider::changeEvent(QEvent *ev)
922 {
923     Q_D(QAbstractSlider);
924     switch (ev->type()) {
925     case QEvent::EnabledChange:
926         if (!isEnabled()) {
927             d->repeatActionTimer.stop();
928             setSliderDown(false);
929         }
930         // fall through...
931     default:
932         QWidget::changeEvent(ev);
933     }
934 }
935 
936 /*!
937     \reimp
938 */
939 bool QAbstractSlider::event(QEvent *e)
940 {
941 #ifdef QT_KEYPAD_NAVIGATION
942     Q_D(QAbstractSlider);
943     switch (e->type()) {
944     case QEvent::FocusIn:
945         d->origValue = d->value;
946         break;
947     default:
948         break;
949     }
950 #endif
951 
952     return QWidget::event(e);
953 }
954 
955 /*! \fn int QAbstractSlider::minValue() const
956 
957     Use minimum() instead.
958 */
959 
960 /*! \fn int QAbstractSlider::maxValue() const
961 
962     Use maximum() instead.
963 */
964 
965 /*! \fn int QAbstractSlider::lineStep() const
966 
967     Use singleStep() instead.
968 */
969 
970 /*! \fn void QAbstractSlider::setMinValue(int v)
971 
972     Use setMinimum() instead.
973 */
974 
975 /*! \fn void QAbstractSlider::setMaxValue(int v)
976 
977     Use setMaximum() instead.
978 */
979 
980 /*! \fn void QAbstractSlider::setLineStep(int v)
981 
982     Use setSingleStep() instead.
983 */
984 
985 /*! \fn void QAbstractSlider::addPage()
986 
987     Use triggerAction(QAbstractSlider::SliderPageStepAdd) instead.
988 */
989 
990 /*! \fn void QAbstractSlider::subtractPage()
991 
992     Use triggerAction(QAbstractSlider::SliderPageStepSub) instead.
993 */
994 
995 /*! \fn void QAbstractSlider::addLine()
996 
997     Use triggerAction(QAbstractSlider::SliderSingleStepAdd) instead.
998 */
999 
1000 /*! \fn void QAbstractSlider::subtractLine()
1001 
1002     Use triggerAction(QAbstractSlider::SliderSingleStepSub) instead.
1003 */
1004 
1005 /*! \fn void QAbstractSlider::setSteps(int single, int page)
1006 
1007     Use setSingleStep(\a single) followed by setPageStep(\a page)
1008     instead.
1009 */
1010 
1011 QT_END_NAMESPACE
1012