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

source code of qtbase/src/widgets/widgets/qabstractslider.cpp