source: trunk/src/gui/widgets/qabstractslider.cpp@ 603

Last change on this file since 603 was 561, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.1 sources.

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