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