src/gui/widgets/qabstractslider.cpp
changeset 7 f7bc934e204c
parent 3 41300fa6a67c
equal deleted inserted replaced
3:41300fa6a67c 7:f7bc934e204c
     1 /****************************************************************************
     1 /****************************************************************************
     2 **
     2 **
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
     3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     4 ** All rights reserved.
     4 ** All rights reserved.
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
     6 **
     6 **
     7 ** This file is part of the QtGui module of the Qt Toolkit.
     7 ** This file is part of the QtGui module of the Qt Toolkit.
     8 **
     8 **
    45 #include "qabstractslider_p.h"
    45 #include "qabstractslider_p.h"
    46 #include "qdebug.h"
    46 #include "qdebug.h"
    47 #ifndef QT_NO_ACCESSIBILITY
    47 #ifndef QT_NO_ACCESSIBILITY
    48 #include "qaccessible.h"
    48 #include "qaccessible.h"
    49 #endif
    49 #endif
    50 #ifdef QT_KEYPAD_NAVIGATION
       
    51 #include "qtabwidget.h" // Needed in inTabWidget()
       
    52 #endif // QT_KEYPAD_NAVIGATION
       
    53 #include <limits.h>
    50 #include <limits.h>
    54 
    51 
    55 QT_BEGIN_NAMESPACE
    52 QT_BEGIN_NAMESPACE
    56 
    53 
    57 /*!
    54 /*!
   212     \value SliderStepsChange
   209     \value SliderStepsChange
   213     \value SliderValueChange
   210     \value SliderValueChange
   214 */
   211 */
   215 
   212 
   216 QAbstractSliderPrivate::QAbstractSliderPrivate()
   213 QAbstractSliderPrivate::QAbstractSliderPrivate()
   217     : minimum(0), maximum(99), singleStep(1), pageStep(10),
   214     : minimum(0), maximum(99), pageStep(10), value(0), position(0), pressValue(-1),
   218       value(0), position(0), pressValue(-1), offset_accumulated(0), tracking(true),
   215       singleStep(1), offset_accumulated(0), tracking(true),
   219       blocktracking(false), pressed(false),
   216       blocktracking(false), pressed(false),
   220       invertedAppearance(false), invertedControls(false),
   217       invertedAppearance(false), invertedControls(false),
   221       orientation(Qt::Horizontal), repeatAction(QAbstractSlider::SliderNoAction)
   218       orientation(Qt::Horizontal), repeatAction(QAbstractSlider::SliderNoAction)
   222 #ifdef QT_KEYPAD_NAVIGATION
   219 #ifdef QT_KEYPAD_NAVIGATION
   223       , isAutoRepeating(false)
   220       , isAutoRepeating(false)
   686 void QAbstractSlider::sliderChange(SliderChange)
   683 void QAbstractSlider::sliderChange(SliderChange)
   687 {
   684 {
   688     update();
   685     update();
   689 }
   686 }
   690 
   687 
       
   688 bool QAbstractSliderPrivate::scrollByDelta(Qt::Orientation orientation, Qt::KeyboardModifiers modifiers, int delta)
       
   689 {
       
   690     Q_Q(QAbstractSlider);
       
   691     int stepsToScroll = 0;
       
   692     // in Qt scrolling to the right gives negative values.
       
   693     if (orientation == Qt::Horizontal)
       
   694         delta = -delta;
       
   695     qreal offset = qreal(delta) / 120;
       
   696 
       
   697     if ((modifiers & Qt::ControlModifier) || (modifiers & Qt::ShiftModifier)) {
       
   698         // Scroll one page regardless of delta:
       
   699         stepsToScroll = qBound(-pageStep, int(offset * pageStep), pageStep);
       
   700         offset_accumulated = 0;
       
   701     } else {
       
   702         // Calculate how many lines to scroll. Depending on what delta is (and
       
   703         // offset), we might end up with a fraction (e.g. scroll 1.3 lines). We can
       
   704         // only scroll whole lines, so we keep the reminder until next event.
       
   705         qreal stepsToScrollF =
       
   706 #ifndef QT_NO_WHEELEVENT
       
   707                 QApplication::wheelScrollLines() *
       
   708 #endif
       
   709                 offset * effectiveSingleStep();
       
   710         // Check if wheel changed direction since last event:
       
   711         if (offset_accumulated != 0 && (offset / offset_accumulated) < 0)
       
   712             offset_accumulated = 0;
       
   713 
       
   714         offset_accumulated += stepsToScrollF;
       
   715         stepsToScroll = qBound(-pageStep, int(offset_accumulated), pageStep);
       
   716         offset_accumulated -= int(offset_accumulated);
       
   717         if (stepsToScroll == 0)
       
   718             return false;
       
   719     }
       
   720 
       
   721     if (invertedControls)
       
   722         stepsToScroll = -stepsToScroll;
       
   723 
       
   724     int prevValue = value;
       
   725     position = overflowSafeAdd(stepsToScroll); // value will be updated by triggerAction()
       
   726     q->triggerAction(QAbstractSlider::SliderMove);
       
   727 
       
   728     if (prevValue == value) {
       
   729         offset_accumulated = 0;
       
   730         return false;
       
   731     }
       
   732     return true;
       
   733 }
   691 
   734 
   692 /*!
   735 /*!
   693     \reimp
   736     \reimp
   694 */
   737 */
   695 #ifndef QT_NO_WHEELEVENT
   738 #ifndef QT_NO_WHEELEVENT
   696 void QAbstractSlider::wheelEvent(QWheelEvent * e)
   739 void QAbstractSlider::wheelEvent(QWheelEvent * e)
   697 {
   740 {
   698     Q_D(QAbstractSlider);
   741     Q_D(QAbstractSlider);
   699     e->ignore();
   742     e->ignore();
   700 
   743     int delta = e->delta();
   701     int stepsToScroll = 0;
   744     if (d->scrollByDelta(e->orientation(), e->modifiers(), delta))
   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();
   745         e->accept();
   735 }
   746 }
   736 #endif
   747 
   737 #ifdef QT_KEYPAD_NAVIGATION
   748 #endif
   738 /*!
   749 
   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 */
       
   749 inline 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 */
       
   768 inline 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 /*!
   750 /*!
   777     \reimp
   751     \reimp
   778 */
   752 */
   779 void QAbstractSlider::keyPressEvent(QKeyEvent *ev)
   753 void QAbstractSlider::keyPressEvent(QKeyEvent *ev)
   780 {
   754 {
   836             // value if there is no left/right navigation possible and if this slider is not
   810             // value if there is no left/right navigation possible and if this slider is not
   837             // inside a tab widget.
   811             // inside a tab widget.
   838             if (QApplication::keypadNavigationEnabled()
   812             if (QApplication::keypadNavigationEnabled()
   839                     && (!hasEditFocus() && QApplication::navigationMode() == Qt::NavigationModeKeypadTabOrder
   813                     && (!hasEditFocus() && QApplication::navigationMode() == Qt::NavigationModeKeypadTabOrder
   840                     || d->orientation == Qt::Vertical
   814                     || d->orientation == Qt::Vertical
   841                     || !hasEditFocus() && (canKeypadNavigate(Qt::Horizontal) || inTabWidget(this)))) {
   815                     || !hasEditFocus()
       
   816                     && (QWidgetPrivate::canKeypadNavigate(Qt::Horizontal) || QWidgetPrivate::inTabWidget(this)))) {
   842                 ev->ignore();
   817                 ev->ignore();
   843                 return;
   818                 return;
   844             }
   819             }
   845             if (QApplication::keypadNavigationEnabled() && d->orientation == Qt::Vertical)
   820             if (QApplication::keypadNavigationEnabled() && d->orientation == Qt::Vertical)
   846                 action = d->invertedControls ? SliderSingleStepSub : SliderSingleStepAdd;
   821                 action = d->invertedControls ? SliderSingleStepSub : SliderSingleStepAdd;
   855 #ifdef QT_KEYPAD_NAVIGATION
   830 #ifdef QT_KEYPAD_NAVIGATION
   856             // Same logic as in Qt::Key_Left
   831             // Same logic as in Qt::Key_Left
   857             if (QApplication::keypadNavigationEnabled()
   832             if (QApplication::keypadNavigationEnabled()
   858                     && (!hasEditFocus() && QApplication::navigationMode() == Qt::NavigationModeKeypadTabOrder
   833                     && (!hasEditFocus() && QApplication::navigationMode() == Qt::NavigationModeKeypadTabOrder
   859                     || d->orientation == Qt::Vertical
   834                     || d->orientation == Qt::Vertical
   860                     || !hasEditFocus() && (canKeypadNavigate(Qt::Horizontal) || inTabWidget(this)))) {
   835                     || !hasEditFocus()
       
   836                     && (QWidgetPrivate::canKeypadNavigate(Qt::Horizontal) || QWidgetPrivate::inTabWidget(this)))) {
   861                 ev->ignore();
   837                 ev->ignore();
   862                 return;
   838                 return;
   863             }
   839             }
   864             if (QApplication::keypadNavigationEnabled() && d->orientation == Qt::Vertical)
   840             if (QApplication::keypadNavigationEnabled() && d->orientation == Qt::Vertical)
   865                 action = d->invertedControls ? SliderSingleStepAdd : SliderSingleStepSub;
   841                 action = d->invertedControls ? SliderSingleStepAdd : SliderSingleStepSub;
   875             // In QApplication::KeypadNavigationDirectional, we want to change the slider
   851             // In QApplication::KeypadNavigationDirectional, we want to change the slider
   876             // value if there is no up/down navigation possible.
   852             // value if there is no up/down navigation possible.
   877             if (QApplication::keypadNavigationEnabled()
   853             if (QApplication::keypadNavigationEnabled()
   878                     && (QApplication::navigationMode() == Qt::NavigationModeKeypadTabOrder
   854                     && (QApplication::navigationMode() == Qt::NavigationModeKeypadTabOrder
   879                     || d->orientation == Qt::Horizontal
   855                     || d->orientation == Qt::Horizontal
   880                     || !hasEditFocus() && canKeypadNavigate(Qt::Vertical))) {
   856                     || !hasEditFocus() && QWidgetPrivate::canKeypadNavigate(Qt::Vertical))) {
   881                 ev->ignore();
   857                 ev->ignore();
   882                 break;
   858                 break;
   883             }
   859             }
   884 #endif
   860 #endif
   885             action = d->invertedControls ? SliderSingleStepSub : SliderSingleStepAdd;
   861             action = d->invertedControls ? SliderSingleStepSub : SliderSingleStepAdd;
   888 #ifdef QT_KEYPAD_NAVIGATION
   864 #ifdef QT_KEYPAD_NAVIGATION
   889             // Same logic as in Qt::Key_Up
   865             // Same logic as in Qt::Key_Up
   890             if (QApplication::keypadNavigationEnabled()
   866             if (QApplication::keypadNavigationEnabled()
   891                     && (QApplication::navigationMode() == Qt::NavigationModeKeypadTabOrder
   867                     && (QApplication::navigationMode() == Qt::NavigationModeKeypadTabOrder
   892                     || d->orientation == Qt::Horizontal
   868                     || d->orientation == Qt::Horizontal
   893                     || !hasEditFocus() && canKeypadNavigate(Qt::Vertical))) {
   869                     || !hasEditFocus() && QWidgetPrivate::canKeypadNavigate(Qt::Vertical))) {
   894                 ev->ignore();
   870                 ev->ignore();
   895                 break;
   871                 break;
   896             }
   872             }
   897 #endif
   873 #endif
   898             action = d->invertedControls ? SliderSingleStepAdd : SliderSingleStepSub;
   874             action = d->invertedControls ? SliderSingleStepAdd : SliderSingleStepSub;