Qt 4.8
qabstractslider.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #include <qapplication.h>
43 #include "qabstractslider.h"
44 #include "qevent.h"
45 #include "qabstractslider_p.h"
46 #include "qdebug.h"
47 #ifndef QT_NO_ACCESSIBILITY
48 #include "qaccessible.h"
49 #endif
50 #include <limits.h>
51 
53 
233  : minimum(0), maximum(99), pageStep(10), value(0), position(0), pressValue(-1),
234  singleStep(1), offset_accumulated(0), tracking(true),
235  blocktracking(false), pressed(false),
236  invertedAppearance(false), invertedControls(false),
237  orientation(Qt::Horizontal), repeatAction(QAbstractSlider::SliderNoAction)
238 #ifdef QT_KEYPAD_NAVIGATION
239  , isAutoRepeating(false)
240  , repeatMultiplier(1)
241 {
242  firstRepeat.invalidate();
243 #else
244 {
245 #endif
246 
247 }
248 
250 {
251 }
252 
261 void QAbstractSlider::setRange(int min, int max)
262 {
264  int oldMin = d->minimum;
265  int oldMax = d->maximum;
266  d->minimum = min;
267  d->maximum = qMax(min, max);
268  if (oldMin != d->minimum || oldMax != d->maximum) {
269  sliderChange(SliderRangeChange);
270  emit rangeChanged(d->minimum, d->maximum);
271  setValue(d->value); // re-bound
272  }
273 }
274 
275 
276 void QAbstractSliderPrivate::setSteps(int single, int page)
277 {
279  singleStep = qAbs(single);
280  pageStep = qAbs(page);
281  q->sliderChange(QAbstractSlider::SliderStepsChange);
282 }
283 
293  :QWidget(*new QAbstractSliderPrivate, parent, 0)
294 {
295 }
296 
299  :QWidget(dd, parent, 0)
300 {
301 }
302 
307 {
308 }
309 
320 {
322  if (d->orientation == orientation)
323  return;
324 
325  d->orientation = orientation;
327  QSizePolicy sp = sizePolicy();
328  sp.transpose();
329  setSizePolicy(sp);
331  }
332  update();
333  updateGeometry();
334 }
335 
337 {
338  Q_D(const QAbstractSlider);
339  return d->orientation;
340 }
341 
342 
357 {
359  setRange(min, qMax(d->maximum, min));
360 }
361 
362 int QAbstractSlider::minimum() const
363 {
364  Q_D(const QAbstractSlider);
365  return d->minimum;
366 }
367 
368 
384 {
386  setRange(qMin(d->minimum, max), max);
387 }
388 
389 int QAbstractSlider::maximum() const
390 {
391  Q_D(const QAbstractSlider);
392  return d->maximum;
393 }
394 
395 
396 
415 {
417  if (step != d->singleStep)
418  d->setSteps(step, d->pageStep);
419 }
420 
421 int QAbstractSlider::singleStep() const
422 {
423  Q_D(const QAbstractSlider);
424  return d->singleStep;
425 }
426 
427 
442 {
444  if (step != d->pageStep)
445  d->setSteps(d->singleStep, step);
446 }
447 
448 int QAbstractSlider::pageStep() const
449 {
450  Q_D(const QAbstractSlider);
451  return d->pageStep;
452 }
453 
469 {
471  d->tracking = enable;
472 }
473 
475 {
476  Q_D(const QAbstractSlider);
477  return d->tracking;
478 }
479 
480 
496 {
498  bool doEmit = d->pressed != down;
499 
500  d->pressed = down;
501 
502  if (doEmit) {
503  if (down)
505  else
507  }
508 
509  if (!down && d->position != d->value)
511 }
512 
514 {
515  Q_D(const QAbstractSlider);
516  return d->pressed;
517 }
518 
519 
530 {
532  position = d->bound(position);
533  if (position == d->position)
534  return;
535  d->position = position;
536  if (!d->tracking)
537  update();
538  if (d->pressed)
539  emit sliderMoved(position);
540  if (d->tracking && !d->blocktracking)
542 }
543 
545 {
546  Q_D(const QAbstractSlider);
547  return d->position;
548 }
549 
550 
564 int QAbstractSlider::value() const
565 {
566  Q_D(const QAbstractSlider);
567  return d->value;
568 }
569 
571 {
573  value = d->bound(value);
574  if (d->value == value && d->position == value)
575  return;
576  d->value = value;
577  if (d->position != value) {
578  d->position = value;
579  if (d->pressed)
580  emit sliderMoved((d->position = value));
581  }
582 #ifndef QT_NO_ACCESSIBILITY
584 #endif
586  emit valueChanged(value);
587 }
588 
607 {
608  Q_D(const QAbstractSlider);
609  return d->invertedAppearance;
610 }
611 
613 {
615  d->invertedAppearance = invert;
616  update();
617 }
618 
619 
634 {
635  Q_D(const QAbstractSlider);
636  return d->invertedControls;
637 }
638 
640 {
642  d->invertedControls = invert;
643 }
644 
651 {
653  d->blocktracking = true;
654  switch (action) {
655  case SliderSingleStepAdd:
656  setSliderPosition(d->overflowSafeAdd(d->effectiveSingleStep()));
657  break;
658  case SliderSingleStepSub:
659  setSliderPosition(d->overflowSafeAdd(-d->effectiveSingleStep()));
660  break;
661  case SliderPageStepAdd:
662  setSliderPosition(d->overflowSafeAdd(d->pageStep));
663  break;
664  case SliderPageStepSub:
665  setSliderPosition(d->overflowSafeAdd(-d->pageStep));
666  break;
667  case SliderToMinimum:
668  setSliderPosition(d->minimum);
669  break;
670  case SliderToMaximum:
671  setSliderPosition(d->maximum);
672  break;
673  case SliderMove:
674  case SliderNoAction:
675  break;
676  };
677  emit actionTriggered(action);
678  d->blocktracking = false;
679  setValue(d->position);
680 }
681 
687 void QAbstractSlider::setRepeatAction(SliderAction action, int thresholdTime, int repeatTime)
688 {
690  if ((d->repeatAction = action) == SliderNoAction) {
691  d->repeatActionTimer.stop();
692  } else {
693  d->repeatActionTime = repeatTime;
694  d->repeatActionTimer.start(thresholdTime, this);
695  }
696 }
697 
703 {
704  Q_D(const QAbstractSlider);
705  return d->repeatAction;
706 }
707 
711 {
713  if (e->timerId() == d->repeatActionTimer.timerId()) {
714  if (d->repeatActionTime) { // was threshold time, use repeat time next time
715  d->repeatActionTimer.start(d->repeatActionTime, this);
716  d->repeatActionTime = 0;
717  }
718  if (d->repeatAction == SliderPageStepAdd)
719  d->setAdjustedSliderPosition(d->overflowSafeAdd(d->pageStep));
720  else if (d->repeatAction == SliderPageStepSub)
721  d->setAdjustedSliderPosition(d->overflowSafeAdd(-d->pageStep));
722  else
723  triggerAction(d->repeatAction);
724  }
725 }
726 
734 {
735  update();
736 }
737 
746 static inline int clampScrollStep(qreal x)
747 {
748  return int(qBound(qreal(INT_MIN), x, qreal(INT_MAX)));
749 }
750 
751 bool QAbstractSliderPrivate::scrollByDelta(Qt::Orientation orientation, Qt::KeyboardModifiers modifiers, int delta)
752 {
754  int stepsToScroll = 0;
755  // in Qt scrolling to the right gives negative values.
756  if (orientation == Qt::Horizontal)
757  delta = -delta;
758  qreal offset = qreal(delta) / 120;
759 
760  if ((modifiers & Qt::ControlModifier) || (modifiers & Qt::ShiftModifier)) {
761  // Scroll one page regardless of delta:
762  stepsToScroll = qBound(-pageStep, clampScrollStep(offset * pageStep), pageStep);
763  offset_accumulated = 0;
764  } else {
765  // Calculate how many lines to scroll. Depending on what delta is (and
766  // offset), we might end up with a fraction (e.g. scroll 1.3 lines). We can
767  // only scroll whole lines, so we keep the reminder until next event.
768  qreal stepsToScrollF =
769 #ifndef QT_NO_WHEELEVENT
771 #endif
772  offset * effectiveSingleStep();
773  // Check if wheel changed direction since last event:
774  if (offset_accumulated != 0 && (offset / offset_accumulated) < 0)
775  offset_accumulated = 0;
776 
777  offset_accumulated += stepsToScrollF;
778 #ifndef Q_WS_MAC
779  // Don't scroll more than one page in any case:
780  stepsToScroll = qBound(-pageStep, clampScrollStep(offset_accumulated), pageStep);
781 #else
782  // Native UI-elements on Mac can scroll hundreds of lines at a time as
783  // a result of acceleration. So keep the same behaviour in Qt, and
784  // don't restrict stepsToScroll to certain maximum (pageStep):
785  stepsToScroll = clampScrollStep(offset_accumulated);
786 #endif
787  offset_accumulated -= clampScrollStep(offset_accumulated);
788  if (stepsToScroll == 0)
789  return false;
790  }
791 
792  if (invertedControls)
793  stepsToScroll = -stepsToScroll;
794 
795  int prevValue = value;
796  position = overflowSafeAdd(stepsToScroll); // value will be updated by triggerAction()
797  q->triggerAction(QAbstractSlider::SliderMove);
798 
799  if (prevValue == value) {
800  offset_accumulated = 0;
801  return false;
802  }
803  return true;
804 }
805 
809 #ifndef QT_NO_WHEELEVENT
811 {
813  e->ignore();
814  int delta = e->delta();
815  if (d->scrollByDelta(e->orientation(), e->modifiers(), delta))
816  e->accept();
817 }
818 
819 #endif
820 
825 {
827  SliderAction action = SliderNoAction;
828 #ifdef QT_KEYPAD_NAVIGATION
829  if (ev->isAutoRepeat()) {
830  if (!d->firstRepeat.isValid())
831  d->firstRepeat.start();
832  else if (1 == d->repeatMultiplier) {
833  // This is the interval in milli seconds which one key repetition
834  // takes.
835  const int repeatMSecs = d->firstRepeat.elapsed();
836 
840  const qreal currentTimeElapse = (qreal(maximum()) / singleStep()) * repeatMSecs;
841 
847  const int SliderRepeatElapse = 2500;
848 
849  d->repeatMultiplier = currentTimeElapse / SliderRepeatElapse;
850  }
851 
852  }
853  else if (d->firstRepeat.isValid()) {
854  d->firstRepeat.invalidate();
855  d->repeatMultiplier = 1;
856  }
857 
858 #endif
859 
860  switch (ev->key()) {
861 #ifdef QT_KEYPAD_NAVIGATION
862  case Qt::Key_Select:
863  if (QApplication::keypadNavigationEnabled())
864  setEditFocus(!hasEditFocus());
865  else
866  ev->ignore();
867  break;
868  case Qt::Key_Back:
869  if (QApplication::keypadNavigationEnabled() && hasEditFocus()) {
870  setValue(d->origValue);
871  setEditFocus(false);
872  } else
873  ev->ignore();
874  break;
875 #endif
876 
877  // It seems we need to use invertedAppearance for Left and right, otherwise, things look weird.
878  case Qt::Key_Left:
879 #ifdef QT_KEYPAD_NAVIGATION
880  // In QApplication::KeypadNavigationDirectional, we want to change the slider
881  // value if there is no left/right navigation possible and if this slider is not
882  // inside a tab widget.
883  if (QApplication::keypadNavigationEnabled()
884  && (!hasEditFocus() && QApplication::navigationMode() == Qt::NavigationModeKeypadTabOrder
885  || d->orientation == Qt::Vertical
886  || !hasEditFocus()
887  && (QWidgetPrivate::canKeypadNavigate(Qt::Horizontal) || QWidgetPrivate::inTabWidget(this)))) {
888  ev->ignore();
889  return;
890  }
891  if (QApplication::keypadNavigationEnabled() && d->orientation == Qt::Vertical)
892  action = d->invertedControls ? SliderSingleStepSub : SliderSingleStepAdd;
893  else
894 #endif
895  if (isRightToLeft())
896  action = d->invertedAppearance ? SliderSingleStepSub : SliderSingleStepAdd;
897  else
898  action = !d->invertedAppearance ? SliderSingleStepSub : SliderSingleStepAdd;
899  break;
900  case Qt::Key_Right:
901 #ifdef QT_KEYPAD_NAVIGATION
902  // Same logic as in Qt::Key_Left
903  if (QApplication::keypadNavigationEnabled()
904  && (!hasEditFocus() && QApplication::navigationMode() == Qt::NavigationModeKeypadTabOrder
905  || d->orientation == Qt::Vertical
906  || !hasEditFocus()
907  && (QWidgetPrivate::canKeypadNavigate(Qt::Horizontal) || QWidgetPrivate::inTabWidget(this)))) {
908  ev->ignore();
909  return;
910  }
911  if (QApplication::keypadNavigationEnabled() && d->orientation == Qt::Vertical)
912  action = d->invertedControls ? SliderSingleStepAdd : SliderSingleStepSub;
913  else
914 #endif
915  if (isRightToLeft())
916  action = d->invertedAppearance ? SliderSingleStepAdd : SliderSingleStepSub;
917  else
918  action = !d->invertedAppearance ? SliderSingleStepAdd : SliderSingleStepSub;
919  break;
920  case Qt::Key_Up:
921 #ifdef QT_KEYPAD_NAVIGATION
922  // In QApplication::KeypadNavigationDirectional, we want to change the slider
923  // value if there is no up/down navigation possible.
924  if (QApplication::keypadNavigationEnabled()
925  && (QApplication::navigationMode() == Qt::NavigationModeKeypadTabOrder
926  || d->orientation == Qt::Horizontal
927  || !hasEditFocus() && QWidgetPrivate::canKeypadNavigate(Qt::Vertical))) {
928  ev->ignore();
929  break;
930  }
931 #endif
932  action = d->invertedControls ? SliderSingleStepSub : SliderSingleStepAdd;
933  break;
934  case Qt::Key_Down:
935 #ifdef QT_KEYPAD_NAVIGATION
936  // Same logic as in Qt::Key_Up
937  if (QApplication::keypadNavigationEnabled()
938  && (QApplication::navigationMode() == Qt::NavigationModeKeypadTabOrder
939  || d->orientation == Qt::Horizontal
940  || !hasEditFocus() && QWidgetPrivate::canKeypadNavigate(Qt::Vertical))) {
941  ev->ignore();
942  break;
943  }
944 #endif
945  action = d->invertedControls ? SliderSingleStepAdd : SliderSingleStepSub;
946  break;
947  case Qt::Key_PageUp:
948  action = d->invertedControls ? SliderPageStepSub : SliderPageStepAdd;
949  break;
950  case Qt::Key_PageDown:
951  action = d->invertedControls ? SliderPageStepAdd : SliderPageStepSub;
952  break;
953  case Qt::Key_Home:
954  action = SliderToMinimum;
955  break;
956  case Qt::Key_End:
957  action = SliderToMaximum;
958  break;
959  default:
960  ev->ignore();
961  break;
962  }
963  if (action)
964  triggerAction(action);
965 }
966 
971 {
973  switch (ev->type()) {
975  if (!isEnabled()) {
976  d->repeatActionTimer.stop();
977  setSliderDown(false);
978  }
979  // fall through...
980  default:
982  }
983 }
984 
989 {
990 #ifdef QT_KEYPAD_NAVIGATION
992  switch (e->type()) {
993  case QEvent::FocusIn:
994  d->origValue = d->value;
995  break;
996  default:
997  break;
998  }
999 #endif
1000 
1001  return QWidget::event(e);
1002 }
1003 
double d
Definition: qnumeric_p.h:62
bool hasTracking() const
static void updateAccessibility(QObject *, int who, Event reason)
Notifies accessibility clients about a change in object&#39;s accessibility information.
The QKeyEvent class describes a key event.
Definition: qevent.h:224
double qreal
Definition: qglobal.h:1193
void sliderPressed()
This signal is emitted when the user presses the slider with the mouse, or programmatically when setS...
Q_DECL_CONSTEXPR const T & qMin(const T &a, const T &b)
Definition: qglobal.h:1215
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
bool scrollByDelta(Qt::Orientation orientation, Qt::KeyboardModifiers modifiers, int delta)
virtual void sliderChange(SliderChange change)
Reimplement this virtual function to track slider changes such as SliderRangeChange ...
bool event(QEvent *e)
Reimplemented Function
void sliderMoved(int position)
This signal is emitted when sliderDown is true and the slider moves.
int minimum() const
int sliderPosition() const
The QWheelEvent class contains parameters that describe a wheel event.
Definition: qevent.h:139
static qreal position(QGraphicsObject *item, QDeclarativeAnchorLine::AnchorLine anchorLine)
The QWidget class is the base class of all user interface objects.
Definition: qwidget.h:150
void triggerAction(SliderAction action)
Triggers a slider action.
void actionTriggered(int action)
This signal is emitted when the slider action action is triggered.
QAbstractSlider(QWidget *parent=0)
Constructs an abstract slider.
void changeEvent(QEvent *e)
Reimplemented Function
void setInvertedAppearance(bool)
Q_DECL_CONSTEXPR T qAbs(const T &t)
Definition: qglobal.h:1201
#define Q_D(Class)
Definition: qglobal.h:2482
static int wheelScrollLines()
Q_DECL_CONSTEXPR const T & qMax(const T &a, const T &b)
Definition: qglobal.h:1217
void setRange(int min, int max)
Sets the slider&#39;s minimum to min and its maximum to max.
void keyPressEvent(QKeyEvent *ev)
Reimplemented Function
#define Q_Q(Class)
Definition: qglobal.h:2483
void update()
Updates the widget unless updates are disabled or the widget is hidden.
Definition: qwidget.cpp:10883
QSizePolicy sizePolicy() const
int key() const
Returns the code of the key that was pressed or released.
Definition: qevent.h:231
bool isSliderDown() const
void setInvertedControls(bool)
int value() const
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
bool testAttribute(Qt::WidgetAttribute) const
Returns true if attribute attribute is set on this widget; otherwise returns false.
Definition: qwidget.h:1041
#define emit
Definition: qobjectdefs.h:76
virtual void changeEvent(QEvent *)
This event handler can be reimplemented to handle state changes.
Definition: qwidget.cpp:9170
int delta() const
Returns the distance that the wheel is rotated, in eighths of a degree.
Definition: qevent.h:150
int timerId() const
Returns the unique timer identifier, which is the same identifier as returned from QObject::startTime...
Definition: qcoreevent.h:346
Qt::Orientation orientation() const
static int clampScrollStep(qreal x)
Truncate qreal to int without flipping on overflow.
bool invertedControls() const
bool invertedAppearance() const
void valueChanged(int value)
This signal is emitted when the slider value has changed, with the new slider value as argument...
Qt::Orientation orientation() const
Returns the wheel&#39;s orientation.
Definition: qevent.h:159
void setSliderDown(bool)
bool isEnabled() const
Definition: qwidget.h:948
int x() const
~QAbstractSlider()
Destroys the slider.
The QTimerEvent class contains parameters that describe a timer event.
Definition: qcoreevent.h:341
void sliderReleased()
This signal is emitted when the user releases the slider with the mouse, or programmatically when set...
QObject * parent() const
Returns a pointer to the parent object.
Definition: qobject.h:273
Q_DECL_CONSTEXPR const T & qBound(const T &min, const T &val, const T &max)
Definition: qglobal.h:1219
void setSliderPosition(int)
Definition: qnamespace.h:54
The QAbstractSlider class provides an integer value within a range.
bool isAutoRepeat() const
Returns true if this event comes from an auto-repeating key; returns false if it comes from an initia...
Definition: qevent.h:237
void transpose()
Definition: qsizepolicy.h:229
void setAttribute(Qt::WidgetAttribute, bool on=true)
Sets the attribute attribute on this widget if on is true; otherwise clears the attribute.
Definition: qwidget.cpp:11087
QObject * parent
Definition: qobject.h:92
void wheelEvent(QWheelEvent *e)
Reimplemented Function
int singleStep() const
void setOrientation(Qt::Orientation)
void ignore()
Clears the accept flag parameter of the event object, the equivalent of calling setAccepted(false).
Definition: qcoreevent.h:310
void accept()
Sets the accept flag of the event object, the equivalent of calling setAccepted(true).
Definition: qcoreevent.h:309
bool isRightToLeft() const
Definition: qwidget.h:428
void setTracking(bool enable)
void updateGeometry()
Notifies the layout system that this widget has changed and may need to change geometry.
Definition: qwidget.cpp:10372
bool event(QEvent *)
This is the main event handler; it handles event event.
Definition: qwidget.cpp:8636
Qt::KeyboardModifiers modifiers() const
Returns the keyboard modifier flags that existed immediately before the event occurred.
Definition: qevent.h:79
int maximum() const
void setSizePolicy(QSizePolicy)
Definition: qwidget.cpp:10198
Orientation
Definition: qnamespace.h:174
The QEvent class is the base class of all event classes.
Definition: qcoreevent.h:56
Type type() const
Returns the event type.
Definition: qcoreevent.h:303
int pageStep() const
void setSteps(int single, int page)
void timerEvent(QTimerEvent *)
This event handler can be reimplemented in a subclass to receive timer events for the object...
#define INT_MAX
void setRepeatAction(SliderAction action, int thresholdTime=500, int repeatTime=50)
Sets action action to be triggered repetitively in intervals of repeatTime, after an initial delay of...
SliderAction repeatAction() const
Returns the current repeat action.