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

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