Skip to content
Snippets Groups Projects
qwt_abstract_slider.cpp 18 KiB
Newer Older
  • Learn to ignore specific revisions
  • pixhawk's avatar
    pixhawk committed
    /* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
     * Qwt Widget Library
     * Copyright (C) 1997   Josef Wilgen
     * Copyright (C) 2002   Uwe Rathmann
    
    pixhawk's avatar
    pixhawk committed
     * This library is free software; you can redistribute it and/or
     * modify it under the terms of the Qwt License, Version 1.0
     *****************************************************************************/
    
    #include "qwt_abstract_slider.h"
    
    Bryant's avatar
    Bryant committed
    #include "qwt_abstract_scale_draw.h"
    
    pixhawk's avatar
    pixhawk committed
    #include "qwt_math.h"
    
    Bryant's avatar
    Bryant committed
    #include "qwt_scale_map.h"
    #include <qevent.h>
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
    #if QT_VERSION < 0x040601
    #define qFabs(x) ::fabs(x)
    
    pixhawk's avatar
    pixhawk committed
    #endif
    
    
    Bryant's avatar
    Bryant committed
    static double qwtAlignToScaleDiv( 
        const QwtAbstractSlider *slider, double value )
    {
        const QwtScaleDiv &sd = slider->scaleDiv();
    
        const int tValue = slider->transform( value );
    
        if ( tValue == slider->transform( sd.lowerBound() ) )
            return sd.lowerBound();
    
        if ( tValue == slider->transform( sd.lowerBound() ) )
            return sd.upperBound();
    
        for ( int i = 0; i < QwtScaleDiv::NTickTypes; i++ )
        {
            const QList<double> ticks = sd.ticks( i );
            for ( int j = 0; j < ticks.size(); j++ )
            {
                if ( slider->transform( ticks[ j ] ) == tValue )
                    return ticks[ j ];
            }
        }
    
        return value;
    }
    
    
    pixhawk's avatar
    pixhawk committed
    class QwtAbstractSlider::PrivateData
    {
    public:
        PrivateData():
    
    Bryant's avatar
    Bryant committed
            isScrolling( false ),
            isTracking( true ),
            pendingValueChanged( false ),
            readOnly( false ),
            totalSteps( 100 ),
            singleSteps( 1 ),
            pageSteps( 10 ),
            stepAlignment( true ),
            isValid( false ),
            value( 0.0 ),
            wrapping( false ),
            invertedControls( false )
        {
    
    pixhawk's avatar
    pixhawk committed
        }
    
    
    Bryant's avatar
    Bryant committed
        bool isScrolling;
        bool isTracking;
        bool pendingValueChanged;
    
    
    pixhawk's avatar
    pixhawk committed
        bool readOnly;
    
    Bryant's avatar
    Bryant committed
    
        uint totalSteps;
        uint singleSteps;
        uint pageSteps;
        bool stepAlignment;
    
        bool isValid;
        double value;
    
        bool wrapping;
        bool invertedControls;
    
    pixhawk's avatar
    pixhawk committed
    };
    
    
    Bryant's avatar
    Bryant committed
      \brief Constructor
    
      The scale is initialized to [0.0, 100.0], the
      number of steps is set to 100 with 1 and 10 and single
      an page step sizes. Step alignment is enabled.
    
      The initial value is invalid.
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
      \param parent Parent widget
    
    pixhawk's avatar
    pixhawk committed
    */
    
    Bryant's avatar
    Bryant committed
    QwtAbstractSlider::QwtAbstractSlider( QWidget *parent ):
        QwtAbstractScale( parent )
    
    pixhawk's avatar
    pixhawk committed
    {
        d_data = new QwtAbstractSlider::PrivateData;
    
    
    Bryant's avatar
    Bryant committed
        setScale( 0.0, 100.0 );
        setFocusPolicy( Qt::StrongFocus );
    
    pixhawk's avatar
    pixhawk committed
    }
    
    //! Destructor
    QwtAbstractSlider::~QwtAbstractSlider()
    {
        delete d_data;
    }
    
    
    Bryant's avatar
    Bryant committed
    /*! 
      Set the value to be valid/invalid
    
      \param on When true, the value is invalidated
    
      \sa setValue()
    */
    void QwtAbstractSlider::setValid( bool on )
    {
        if ( on != d_data->isValid )
        {
            d_data->isValid = on;
            sliderChange();
    
            Q_EMIT valueChanged( d_data->value );
        }   
    }   
    
    //! \return True, when the value is invalid
    bool QwtAbstractSlider::isValid() const
    {
        return d_data->isValid;
    }   
    
    
    pixhawk's avatar
    pixhawk committed
    /*!
      En/Disable read only mode
    
      In read only mode the slider can't be controlled by mouse
      or keyboard.
    
    
    Bryant's avatar
    Bryant committed
      \param on Enables in case of true
    
    pixhawk's avatar
    pixhawk committed
      \sa isReadOnly()
    
    Bryant's avatar
    Bryant committed
    
      \warning The focus policy is set to Qt::StrongFocus or Qt::NoFocus
    
    pixhawk's avatar
    pixhawk committed
    */
    
    Bryant's avatar
    Bryant committed
    void QwtAbstractSlider::setReadOnly( bool on )
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        if ( d_data->readOnly != on )
        {
            d_data->readOnly = on;
            setFocusPolicy( on ? Qt::StrongFocus : Qt::NoFocus );
    
            update();
        }
    
    pixhawk's avatar
    pixhawk committed
    }
    
    /*!
      In read only mode the slider can't be controlled by mouse
      or keyboard.
    
      \return true if read only
      \sa setReadOnly()
    */
    bool QwtAbstractSlider::isReadOnly() const
    {
        return d_data->readOnly;
    }
    
    /*!
    
    Bryant's avatar
    Bryant committed
      \brief Enables or disables tracking.
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
      If tracking is enabled, the slider emits the valueChanged() 
      signal while the movable part of the slider is being dragged. 
      If tracking is disabled, the slider emits the valueChanged() signal 
      only when the user releases the slider.
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
      Tracking is enabled by default.
      \param on \c true (enable) or \c false (disable) tracking.
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
      \sa isTracking(), sliderMoved()
    */
    void QwtAbstractSlider::setTracking( bool on )
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        d_data->isTracking = on;
    
    pixhawk's avatar
    pixhawk committed
    }
    
    /*!
    
    Bryant's avatar
    Bryant committed
      \return True, when tracking has been enabled
      \sa setTracking()
    
    pixhawk's avatar
    pixhawk committed
    */
    
    Bryant's avatar
    Bryant committed
    bool QwtAbstractSlider::isTracking() const
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        return d_data->isTracking;
    
    pixhawk's avatar
    pixhawk committed
    }
    
    
    Bryant's avatar
    Bryant committed
    /*!
       Mouse press event handler
       \param event Mouse event
    */
    void QwtAbstractSlider::mousePressEvent( QMouseEvent *event )
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        if ( isReadOnly() )
        {
            event->ignore();
    
    pixhawk's avatar
    pixhawk committed
            return;
        }
    
    
    Bryant's avatar
    Bryant committed
        if ( !d_data->isValid || lowerBound() == upperBound() )
            return;
    
    Bryant's avatar
    Bryant committed
        d_data->isScrolling = isScrollPosition( event->pos() );
    
    Bryant's avatar
    Bryant committed
        if ( d_data->isScrolling )
        {
            d_data->pendingValueChanged = false;
    
    Bryant's avatar
    Bryant committed
            Q_EMIT sliderPressed();
    
    pixhawk's avatar
    pixhawk committed
        }
    }
    
    
    Bryant's avatar
    Bryant committed
    /*!
       Mouse Move Event handler
       \param event Mouse event
    */
    void QwtAbstractSlider::mouseMoveEvent( QMouseEvent *event )
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        if ( isReadOnly() )
        {
            event->ignore();
    
    pixhawk's avatar
    pixhawk committed
            return;
        }
    
    
    Bryant's avatar
    Bryant committed
        if ( d_data->isValid && d_data->isScrolling )
        {
            double value = scrolledTo( event->pos() );
            if ( value != d_data->value )
            {
                value = boundedValue( value );
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
                if ( d_data->stepAlignment )
                {
                    value = alignedValue( value );
                }
                else
                {
                    value = qwtAlignToScaleDiv( this, value );
                }
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
                if ( value != d_data->value )
                {
                    d_data->value = value;
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
                    sliderChange();
    
    Bryant's avatar
    Bryant committed
                    Q_EMIT sliderMoved( d_data->value );
    
    Bryant's avatar
    Bryant committed
                    if ( d_data->isTracking )
                        Q_EMIT valueChanged( d_data->value );
                    else
                        d_data->pendingValueChanged = true;
                }
            }
    
    pixhawk's avatar
    pixhawk committed
        }
    }
    
    /*!
    
    Bryant's avatar
    Bryant committed
       Mouse Release Event handler
       \param event Mouse event
    
    pixhawk's avatar
    pixhawk committed
    */
    
    Bryant's avatar
    Bryant committed
    void QwtAbstractSlider::mouseReleaseEvent( QMouseEvent *event )
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        if ( isReadOnly() )
        {
            event->ignore();
            return;
        }
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
        if ( d_data->isScrolling && d_data->isValid )
        {
            d_data->isScrolling = false;
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
            if ( d_data->pendingValueChanged )
                Q_EMIT valueChanged( d_data->value );
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
            Q_EMIT sliderReleased();
        }
    
    pixhawk's avatar
    pixhawk committed
    }
    
    
    Bryant's avatar
    Bryant committed
       Wheel Event handler
    
       In/decreases the value by s number of steps. The direction 
       depends on the invertedControls() property.
    
       When the control or shift modifier is pressed the wheel delta
       ( divided by 120 ) is mapped to an increment according to
       pageSteps(). Otherwise it is mapped to singleSteps().
    
       \param event Wheel event
    
    pixhawk's avatar
    pixhawk committed
    */
    
    Bryant's avatar
    Bryant committed
    void QwtAbstractSlider::wheelEvent( QWheelEvent *event )
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        if ( isReadOnly() )
        {
            event->ignore();
    
    pixhawk's avatar
    pixhawk committed
            return;
        }
    
    
    Bryant's avatar
    Bryant committed
        if ( !d_data->isValid || d_data->isScrolling )
    
    pixhawk's avatar
    pixhawk committed
            return;
    
    
    Bryant's avatar
    Bryant committed
        int numSteps = 0;
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
        if ( ( event->modifiers() & Qt::ControlModifier) ||
            ( event->modifiers() & Qt::ShiftModifier ) )
        {
            // one page regardless of delta
            numSteps = d_data->pageSteps;
            if ( event->delta() < 0 )
                numSteps = -numSteps;
        }
        else
        {
            const int numTurns = ( event->delta() / 120 );
            numSteps = numTurns * d_data->singleSteps;
    
    pixhawk's avatar
    pixhawk committed
        }
    
    
    Bryant's avatar
    Bryant committed
        if ( d_data->invertedControls )
            numSteps = -numSteps;
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
        const double value = incrementedValue( d_data->value, numSteps );
        if ( value != d_data->value )
        {
            d_data->value = value;
            sliderChange();
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
            Q_EMIT sliderMoved( d_data->value );
            Q_EMIT valueChanged( d_data->value );
    
    pixhawk's avatar
    pixhawk committed
        }
    }
    
    /*!
      Handles key events
    
    
    Bryant's avatar
    Bryant committed
      QwtAbstractSlider handles the following keys:
    
      - Qt::Key_Left\n
        Add/Subtract singleSteps() in direction to lowerBound();
      - Qt::Key_Right\n
        Add/Subtract singleSteps() in direction to upperBound();
      - Qt::Key_Down\n
        Subtract singleSteps(), when invertedControls() is false
      - Qt::Key_Up\n
        Add singleSteps(), when invertedControls() is false
      - Qt::Key_PageDown\n
        Subtract pageSteps(), when invertedControls() is false
      - Qt::Key_PageUp\n
        Add pageSteps(), when invertedControls() is false
      - Qt::Key_Home\n
        Set the value to the minimum()
      - Qt::Key_End\n
        Set the value to the maximum()
    
      \param event Key event
    
    pixhawk's avatar
    pixhawk committed
      \sa isReadOnly()
    */
    
    Bryant's avatar
    Bryant committed
    void QwtAbstractSlider::keyPressEvent( QKeyEvent *event )
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        if ( isReadOnly() )
        {
            event->ignore();
    
    pixhawk's avatar
    pixhawk committed
            return;
        }
    
    
    Bryant's avatar
    Bryant committed
        if ( !d_data->isValid || d_data->isScrolling )
    
    pixhawk's avatar
    pixhawk committed
            return;
    
    
    Bryant's avatar
    Bryant committed
        int numSteps = 0;
        double value = d_data->value;
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
        switch ( event->key() )
        {
            case Qt::Key_Left:
            {
                numSteps = -static_cast<int>( d_data->singleSteps );
                if ( isInverted() )
                    numSteps = -numSteps;
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
                break;
            }
            case Qt::Key_Right:
            {
                numSteps = d_data->singleSteps;
                if ( isInverted() )
                    numSteps = -numSteps;
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
                break;
            }
            case Qt::Key_Down:
            {
                numSteps = -static_cast<int>( d_data->singleSteps );
                if ( d_data->invertedControls )
                    numSteps = -numSteps;
                break;
            }
            case Qt::Key_Up:
            {
                numSteps = d_data->singleSteps;
                if ( d_data->invertedControls )
                    numSteps = -numSteps;
    
    Bryant's avatar
    Bryant committed
                break;
    
    Bryant's avatar
    Bryant committed
            case Qt::Key_PageUp:
            {
                numSteps = d_data->pageSteps;
                if ( d_data->invertedControls )
                    numSteps = -numSteps;
                break;
            }
            case Qt::Key_PageDown:
            {
                numSteps = -static_cast<int>( d_data->pageSteps );
                if ( d_data->invertedControls )
                    numSteps = -numSteps;
                break;
            }
            case Qt::Key_Home:
            {
                value = minimum();
                break;
            }
            case Qt::Key_End:
            {
                value = maximum();
                break;
            }
            default:;
            {
                event->ignore();
    
    pixhawk's avatar
    pixhawk committed
            }
    
    Bryant's avatar
    Bryant committed
    
        if ( numSteps != 0 )
        {
            value = incrementedValue( d_data->value, numSteps );
    
    Bryant's avatar
    Bryant committed
    
        if ( value != d_data->value )
        {
            d_data->value = value;
            sliderChange();
    
            Q_EMIT sliderMoved( d_data->value );
            Q_EMIT valueChanged( d_data->value );
    
    pixhawk's avatar
    pixhawk committed
        }
    
    Bryant's avatar
    Bryant committed
    }
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
    /*!
      \brief Set the number of steps
    
      The range of the slider is divided into a number of steps from
      which the value increments according to user inputs depend. 
    
      The default setting is 100.
    
      \param stepCount Number of steps
    
      \sa totalSteps(), setSingleSteps(), setPageSteps()
     */
    void QwtAbstractSlider::setTotalSteps( uint stepCount )
    {
        d_data->totalSteps = stepCount;
    
    pixhawk's avatar
    pixhawk committed
    }
    
    
    Bryant's avatar
    Bryant committed
    /*!
      \return Number of steps
      \sa setTotalSteps(), singleSteps(), pageSteps()
     */
    uint QwtAbstractSlider::totalSteps() const
    {
        return d_data->totalSteps;
    }
    
    pixhawk's avatar
    pixhawk committed
    
    /*!
    
    Bryant's avatar
    Bryant committed
      \brief Set the number of steps for a single increment
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
      The range of the slider is divided into a number of steps from
      which the value increments according to user inputs depend. 
    
      \param stepCount Number of steps
    
      \sa singleSteps(), setTotalSteps(), setPageSteps()
     */
    
    void QwtAbstractSlider::setSingleSteps( uint stepCount )
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        d_data->singleSteps = stepCount;
    }   
    
    pixhawk's avatar
    pixhawk committed
    
    /*!
    
    Bryant's avatar
    Bryant committed
      \return Number of steps
      \sa setSingleSteps(), totalSteps(), pageSteps()
     */
    uint QwtAbstractSlider::singleSteps() const
    {
        return d_data->singleSteps;
    }   
    
    /*! 
      \brief Set the number of steps for a page increment
        
      The range of the slider is divided into a number of steps from
      which the value increments according to user inputs depend. 
    
      \param stepCount Number of steps
    
      \sa pageSteps(), setTotalSteps(), setSingleSteps()
     */
    
    void QwtAbstractSlider::setPageSteps( uint stepCount )
    {
        d_data->pageSteps = stepCount;
    }
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
    /*!
      \return Number of steps
      \sa setPageSteps(), totalSteps(), singleSteps()
     */
    uint QwtAbstractSlider::pageSteps() const
    {
        return d_data->pageSteps;
    }
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
    /*!
      \brief Enable step alignment
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
      When step alignment is enabled values resulting from slider
      movements are aligned to the step size.
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
      \param on Enable step alignment when true
      \sa stepAlignment()
    
    pixhawk's avatar
    pixhawk committed
    */
    
    Bryant's avatar
    Bryant committed
    void QwtAbstractSlider::setStepAlignment( bool on )
    {   
        if ( on != d_data->stepAlignment )
        {
            d_data->stepAlignment = on;
        }
    }   
        
    /*!
      \return True, when step alignment is enabled
      \sa setStepAlignment()
     */
    bool QwtAbstractSlider::stepAlignment() const
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        return d_data->stepAlignment;
    
    pixhawk's avatar
    pixhawk committed
    }
    
    /*!
    
    Bryant's avatar
    Bryant committed
      Set the slider to the specified value
    
      \param value New value
      \sa setValid(), sliderChange(), valueChanged()
    
    pixhawk's avatar
    pixhawk committed
    */
    
    Bryant's avatar
    Bryant committed
    void QwtAbstractSlider::setValue( double value )
    
    Bryant's avatar
    Bryant committed
        value = qBound( minimum(), value, maximum() );
    
        const bool changed = ( d_data->value != value ) || !d_data->isValid;
    
        d_data->value = value;
        d_data->isValid = true;
    
        if ( changed )
        {
            sliderChange();
            Q_EMIT valueChanged( d_data->value );
        }
    
    pixhawk's avatar
    pixhawk committed
    }
    
    
    Bryant's avatar
    Bryant committed
    //! Returns the current value.
    double QwtAbstractSlider::value() const
    {
        return d_data->value;
    }
    
    pixhawk's avatar
    pixhawk committed
    
    /*!
    
    Bryant's avatar
    Bryant committed
      If wrapping is true stepping up from upperBound() value will 
      take you to the minimum() value and vice versa. 
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
      \param on En/Disable wrapping
      \sa wrapping()
    
    pixhawk's avatar
    pixhawk committed
    */
    
    Bryant's avatar
    Bryant committed
    void QwtAbstractSlider::setWrapping( bool on )
    {
        d_data->wrapping = on;
    }   
    
    /*!
      \return True, when wrapping is set
      \sa setWrapping()
     */ 
    bool QwtAbstractSlider::wrapping() const
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        return d_data->wrapping;
    
    pixhawk's avatar
    pixhawk committed
    }
    
    
    Bryant's avatar
    Bryant committed
    /*!
      Invert wheel and key events
    
      Usually scrolling the mouse wheel "up" and using keys like page 
      up will increase the slider's value towards its maximum. 
      When invertedControls() is enabled the value is scrolled
      towards its minimum.
    
      Inverting the controls might be f.e. useful for a vertical slider
      with an inverted scale ( decreasing from top to bottom ).
    
      \param on Invert controls, when true
    
      \sa invertedControls(), keyEvent(), wheelEvent()
     */
    void QwtAbstractSlider::setInvertedControls( bool on )
    {
        d_data->invertedControls = on;
    }
    
    /*!
     \return True, when the controls are inverted
     \sa setInvertedControls()
     */
    bool QwtAbstractSlider::invertedControls() const
    {
        return d_data->invertedControls;
    }
    
    pixhawk's avatar
    pixhawk committed
    
    /*!
    
    Bryant's avatar
    Bryant committed
      Increment the slider
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
      The step size depends on the number of totalSteps()
    
      \param stepCount Number of steps
      \sa setTotalSteps(), incrementedValue()
     */
    void QwtAbstractSlider::incrementValue( int stepCount )
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        const double value = incrementedValue( 
            d_data->value, stepCount );
    
        if ( value != d_data->value )
        {
            d_data->value = value;
            sliderChange();
        }
    
    pixhawk's avatar
    pixhawk committed
    }
    
    /*!
    
    Bryant's avatar
    Bryant committed
      Increment a value 
    
      \param value Value 
      \param stepCount Number of steps
    
      \return Incremented value
     */
    double QwtAbstractSlider::incrementedValue( 
        double value, int stepCount ) const
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        if ( d_data->totalSteps == 0 )
            return value;
    
        const QwtTransform *transformation =
            scaleMap().transformation();
    
        if ( transformation == NULL )
        {
            const double range = maximum() - minimum();
            value += stepCount * range / d_data->totalSteps;
        }
        else
        {
            QwtScaleMap map = scaleMap();
            map.setPaintInterval( 0, d_data->totalSteps );
    
            // we need equidant steps according to
            // paint device coordinates
            const double range = transformation->transform( maximum() ) 
                - transformation->transform( minimum() );
    
            const double stepSize = range / d_data->totalSteps;
    
            double v = transformation->transform( value );
    
            v = qRound( v / stepSize ) * stepSize; 
            v += stepCount * range / d_data->totalSteps;
    
            value = transformation->invTransform( v );
        }
    
        value = boundedValue( value );
    
        if ( d_data->stepAlignment )
            value = alignedValue( value );
    
        return value;
    }
    
    double QwtAbstractSlider::boundedValue( double value ) const
    {
        const double vmin = minimum();
        const double vmax = maximum();
    
        if ( d_data->wrapping && vmin != vmax )
        {
            const int fullCircle = 360 * 16;
    
            const double pd = scaleMap().pDist();
            if ( int( pd / fullCircle ) * fullCircle == pd )
            {
                // full circle scales: min and max are the same
                const double range = vmax - vmin;
    
                if ( value < vmin )
                {
                    value += ::ceil( ( vmin - value ) / range ) * range;
                }
                else if ( value > vmax )
                {
                    value -= ::ceil( ( value - vmax ) / range ) * range;
                }
            }
            else
            {
                if ( value < vmin )
                    value = vmax;
                else if ( value > vmax )
                    value = vmin;
            }
        }
        else
        {
            value = qBound( vmin, value, vmax );
        }
    
        return value;
    
    pixhawk's avatar
    pixhawk committed
    }
    
    
    Bryant's avatar
    Bryant committed
    double QwtAbstractSlider::alignedValue( double value ) const
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        if ( d_data->totalSteps == 0 )
            return value;
    
        double stepSize;
    
        if ( scaleMap().transformation() == NULL )
        {
            stepSize = ( maximum() - minimum() ) / d_data->totalSteps;
            if ( stepSize > 0.0 )
            {
                value = lowerBound() + 
                    qRound( ( value - lowerBound() ) / stepSize ) * stepSize;
            }
        }
        else
        {
            stepSize = ( scaleMap().p2() - scaleMap().p1() ) / d_data->totalSteps;
    
            if ( stepSize > 0.0 )
            {
                double v = scaleMap().transform( value );
    
                v = scaleMap().p1() +
                    qRound( ( v - scaleMap().p1() ) / stepSize ) * stepSize;
    
                value = scaleMap().invTransform( v );
            }
        }
    
        if ( qAbs( stepSize ) > 1e-12 )
        {
            if ( qFuzzyCompare( value + 1.0, 1.0 ) )
            {
                // correct rounding error if value = 0
                value = 0.0;
            }
            else
            {
                // correct rounding error at the border
                if ( qFuzzyCompare( value, upperBound() ) )
                    value = upperBound();
                else if ( qFuzzyCompare( value, lowerBound() ) )
                    value = lowerBound();
            }
        }
    
        return value;
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
    /*!
      Update the slider according to modifications of the scale
     */
    void QwtAbstractSlider::scaleChange()
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        const double value = qBound( minimum(), d_data->value, maximum() );
    
        const bool changed = ( value != d_data->value );
        if ( changed )
        {
            d_data->value = value;
        }
    
        if ( d_data->isValid || changed )
            Q_EMIT valueChanged( d_data->value );
    
        updateGeometry();
        update();
    
    pixhawk's avatar
    pixhawk committed
    }
    
    
    Bryant's avatar
    Bryant committed
    //! Calling update()
    void QwtAbstractSlider::sliderChange()
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        update();
    
    pixhawk's avatar
    pixhawk committed
    }