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