Skip to content
Snippets Groups Projects
qwt_counter.cpp 17.5 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
     *
     * This library is free software; you can redistribute it and/or
     * modify it under the terms of the Qwt License, Version 1.0
     *****************************************************************************/
    
    
    Bryant's avatar
    Bryant committed
    #include "qwt_arrow_button.h"
    #include "qwt_math.h"
    #include "qwt_counter.h"
    
    pixhawk's avatar
    pixhawk committed
    #include <qlayout.h>
    #include <qlineedit.h>
    #include <qvalidator.h>
    #include <qevent.h>
    #include <qstyle.h>
    
    class QwtCounter::PrivateData
    {
    public:
        PrivateData():
    
    Bryant's avatar
    Bryant committed
            minimum( 0.0 ),
            maximum( 0.0 ),
            singleStep( 1.0 ),
            isValid( false ),
            value( 0.0 ),
            wrapping( false )
        {
    
    pixhawk's avatar
    pixhawk committed
            increment[Button1] = 1;
            increment[Button2] = 10;
            increment[Button3] = 100;
        }
    
        QwtArrowButton *buttonDown[ButtonCnt];
        QwtArrowButton *buttonUp[ButtonCnt];
        QLineEdit *valueEdit;
    
        int increment[ButtonCnt];
    
    Bryant's avatar
    Bryant committed
        int numButtons;
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
        double minimum;
        double maximum;
        double singleStep;
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
        bool isValid;
        double value;
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
        bool wrapping;
    };
    
    pixhawk's avatar
    pixhawk committed
    
    /*!
    
    Bryant's avatar
    Bryant committed
      The counter is initialized with a range is set to [0.0, 1.0] with 
      0.01 as single step size. The value is invalid.
    
    
    pixhawk's avatar
    pixhawk committed
      The default number of buttons is set to 2. The default increments are:
      \li Button 1: 1 step
      \li Button 2: 10 steps
      \li Button 3: 100 steps
    
      \param parent
     */
    
    Bryant's avatar
    Bryant committed
    QwtCounter::QwtCounter( QWidget *parent ):
        QWidget( parent )
    
    pixhawk's avatar
    pixhawk committed
    {
        initCounter();
    }
    
    void QwtCounter::initCounter()
    {
        d_data = new PrivateData;
    
    
    Bryant's avatar
    Bryant committed
        QHBoxLayout *layout = new QHBoxLayout( this );
        layout->setSpacing( 0 );
        layout->setMargin( 0 );
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
        for ( int i = ButtonCnt - 1; i >= 0; i-- )
        {
    
    pixhawk's avatar
    pixhawk committed
            QwtArrowButton *btn =
    
    Bryant's avatar
    Bryant committed
                new QwtArrowButton( i + 1, Qt::DownArrow, this );
            btn->setFocusPolicy( Qt::NoFocus );
            btn->installEventFilter( this );
            layout->addWidget( btn );
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
            connect( btn, SIGNAL( released() ), SLOT( btnReleased() ) );
            connect( btn, SIGNAL( clicked() ), SLOT( btnClicked() ) );
    
    pixhawk's avatar
    pixhawk committed
    
            d_data->buttonDown[i] = btn;
        }
    
    
    Bryant's avatar
    Bryant committed
        d_data->valueEdit = new QLineEdit( this );
        d_data->valueEdit->setReadOnly( false );
        d_data->valueEdit->setValidator( new QDoubleValidator( d_data->valueEdit ) );
        layout->addWidget( d_data->valueEdit );
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
        connect( d_data->valueEdit, SIGNAL( editingFinished() ),
             SLOT( textChanged() ) );
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
        layout->setStretchFactor( d_data->valueEdit, 10 );
    
        for ( int i = 0; i < ButtonCnt; i++ )
        {
    
    pixhawk's avatar
    pixhawk committed
            QwtArrowButton *btn =
    
    Bryant's avatar
    Bryant committed
                new QwtArrowButton( i + 1, Qt::UpArrow, this );
            btn->setFocusPolicy( Qt::NoFocus );
            btn->installEventFilter( this );
            layout->addWidget( btn );
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
            connect( btn, SIGNAL( released() ), SLOT( btnReleased() ) );
            connect( btn, SIGNAL( clicked() ), SLOT( btnClicked() ) );
    
    pixhawk's avatar
    pixhawk committed
            d_data->buttonUp[i] = btn;
        }
    
    
    Bryant's avatar
    Bryant committed
        setNumButtons( 2 );
        setRange( 0.0, 1.0 );
        setSingleStep( 0.001 );
        setValue( 0.0 );
    
    pixhawk's avatar
    pixhawk committed
    
        setSizePolicy(
    
    Bryant's avatar
    Bryant committed
            QSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed ) );
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
        setFocusProxy( d_data->valueEdit );
        setFocusPolicy( Qt::StrongFocus );
    
    pixhawk's avatar
    pixhawk committed
    }
    
    //! Destructor
    QwtCounter::~QwtCounter()
    {
        delete d_data;
    }
    
    
    Bryant's avatar
    Bryant committed
    /*! 
      Set the counter to be in valid/invalid state
    
      When the counter is set to invalid, no numbers are displayed and
      the buttons are disabled.
    
      \param on If true the counter will be set as valid 
    
      \sa setValue(), isValid()
    */
    void QwtCounter::setValid( bool on )
    {
        if ( on != d_data->isValid )
        {
            d_data->isValid = on;
    
            updateButtons();
    
            if ( d_data->isValid )
            {
                showNumber( value() );
                Q_EMIT valueChanged( value() );
            }
            else
            {
                d_data->valueEdit->setText( QString::null );
            }
        }   
    }   
    
    /*! 
      \return True, if the value is valid
      \sa setValid(), setValue()
     */
    bool QwtCounter::isValid() const
    {
        return d_data->isValid;
    }   
    
    /*!
      \brief Allow/disallow the user to manually edit the value
    
      \param on True disable editing
      \sa isReadOnly()
    */
    void QwtCounter::setReadOnly( bool on )
    {
        d_data->valueEdit->setReadOnly( on );
    }
    
    /*! 
       \return True, when the line line edit is read only. (default is no)
      \sa setReadOnly()
     */
    bool QwtCounter::isReadOnly() const
    {
        return d_data->valueEdit->isReadOnly();
    }
    
    
    pixhawk's avatar
    pixhawk committed
    /*!
    
    Bryant's avatar
    Bryant committed
      \brief Set a new value without adjusting to the step raster
    
      The state of the counter is set to be valid.
    
      \param value New value
    
      \sa isValid(), value(), valueChanged()
      \warning The value is clipped when it lies outside the range.
    
    pixhawk's avatar
    pixhawk committed
    */
    
    Bryant's avatar
    Bryant committed
    
    void QwtCounter::setValue( double value )
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        const double vmin = qMin( d_data->minimum, d_data->maximum );
        const double vmax = qMax( d_data->minimum, d_data->maximum );
    
        value = qBound( vmin, value, vmax );
    
        if ( !d_data->isValid || value != d_data->value )
        {
            d_data->isValid = true;
            d_data->value = value;
    
            showNumber( value );
            updateButtons();
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
            Q_EMIT valueChanged( value );
    
    pixhawk's avatar
    pixhawk committed
        }
    
    Bryant's avatar
    Bryant committed
    }
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
    /*!
      \return Current value of the counter
      \sa setValue(), valueChanged()
     */
    double QwtCounter::value() const
    {
        return d_data->value;
    
    pixhawk's avatar
    pixhawk committed
    }
    
    
    Bryant's avatar
    Bryant committed
    /*!
      \brief Set the minimum and maximum values
    
      The maximum is adjusted if necessary to ensure that the range remains valid.
      The value might be modified to be inside of the range.
    
      \param min Minimum value
      \param max Maximum value
    
      \sa minimum(), maximum()
     */
    void QwtCounter::setRange( double min, double max )
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        max = qMax( min, max );
    
        if ( d_data->maximum == max && d_data->minimum == min )
    
    pixhawk's avatar
    pixhawk committed
            return;
    
    
    Bryant's avatar
    Bryant committed
        d_data->minimum = min;
        d_data->maximum = max;
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
        setSingleStep( singleStep() );
    
        const double value = qBound( min, d_data->value, max );
    
        if ( value != d_data->value )
        {
            d_data->value = value;
    
            if ( d_data->isValid )
            {
                showNumber( value );
                Q_EMIT valueChanged( value );
            }
        }
    
        updateButtons();
    
    pixhawk's avatar
    pixhawk committed
    }
    
    
    Bryant's avatar
    Bryant committed
    /*!
      Set the minimum value of the range
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
      \param value Minimum value
      \sa setRange(), setMaximum(), minimum()
    
      \note The maximum is adjusted if necessary to ensure that the range remains valid.
    
    pixhawk's avatar
    pixhawk committed
    */
    
    Bryant's avatar
    Bryant committed
    void QwtCounter::setMinimum( double value )
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        setRange( value, maximum() );
    }
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
    /*!
      \return The minimum of the range
      \sa setRange(), setMinimum(), maximum()
    */
    double QwtCounter::minimum() const
    {
        return d_data->minimum;
    
    pixhawk's avatar
    pixhawk committed
    }
    
    
    Bryant's avatar
    Bryant committed
    /*!
      Set the maximum value of the range
    
      \param value Maximum value
      \sa setRange(), setMinimum(), maximum()
    */
    void QwtCounter::setMaximum( double value )
    
    Bryant's avatar
    Bryant committed
        setRange( minimum(), value );
    
    pixhawk's avatar
    pixhawk committed
    }
    
    /*!
    
    Bryant's avatar
    Bryant committed
      \return The maximum of the range
      \sa setRange(), setMaximum(), minimum()
    
    pixhawk's avatar
    pixhawk committed
    */
    
    Bryant's avatar
    Bryant committed
    double QwtCounter::maximum() const
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        return d_data->maximum;
    
    pixhawk's avatar
    pixhawk committed
    }
    
    /*!
    
    Bryant's avatar
    Bryant committed
      \brief Set the step size of the counter
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
      A value <= 0.0 disables stepping
    
      \param stepSize Single step size
      \sa singleStep()
    
    pixhawk's avatar
    pixhawk committed
    */
    
    Bryant's avatar
    Bryant committed
    void QwtCounter::setSingleStep( double stepSize )
    {
        d_data->singleStep = qMax( stepSize, 0.0 );
    }
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
    /*!
      \return Single step size
      \sa setSingleStep()
     */
    double QwtCounter::singleStep() const
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        return d_data->singleStep;
    }
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
    /*!
      \brief En/Disable wrapping
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
      If wrapping is true stepping up from maximum() 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()
     */
    void QwtCounter::setWrapping( bool on )
    {
        d_data->wrapping = on;
    
    pixhawk's avatar
    pixhawk committed
    }
    
    
    Bryant's avatar
    Bryant committed
    /*!
      \return True, when wrapping is set
      \sa setWrapping()
     */
    bool QwtCounter::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
    /*!
      Specify the number of buttons on each side of the label
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
      \param numButtons Number of buttons
      \sa numButtons()
    */
    void QwtCounter::setNumButtons( int numButtons )
    {
        if ( numButtons < 0 || numButtons > QwtCounter::ButtonCnt )
            return;
    
    Bryant's avatar
    Bryant committed
        for ( int i = 0; i < QwtCounter::ButtonCnt; i++ )
        {
            if ( i < numButtons )
            {
                d_data->buttonDown[i]->show();
                d_data->buttonUp[i]->show();
            }
            else
            {
                d_data->buttonDown[i]->hide();
                d_data->buttonUp[i]->hide();
    
    pixhawk's avatar
    pixhawk committed
            }
        }
    
    
    Bryant's avatar
    Bryant committed
        d_data->numButtons = numButtons;
    }
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
    /*!
      \return The number of buttons on each side of the widget.
      \sa setNumButtons()
    */
    int QwtCounter::numButtons() const
    {
        return d_data->numButtons;
    
    pixhawk's avatar
    pixhawk committed
    }
    
    /*!
      Specify the number of steps by which the value
      is incremented or decremented when a specified button
      is pushed.
    
    
    Bryant's avatar
    Bryant committed
      \param button Button index
      \param numSteps Number of steps
    
      \sa incSteps()
    
    pixhawk's avatar
    pixhawk committed
    */
    
    Bryant's avatar
    Bryant committed
    void QwtCounter::setIncSteps( QwtCounter::Button button, int numSteps )
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        if ( button >= 0 && button < QwtCounter::ButtonCnt )
            d_data->increment[ button ] = numSteps;
    
    pixhawk's avatar
    pixhawk committed
    }
    
    /*!
    
    Bryant's avatar
    Bryant committed
      \return The number of steps by which a specified button increments the value
              or 0 if the button is invalid.
      \param button Button index
    
      \sa setIncSteps()
    
    pixhawk's avatar
    pixhawk committed
    */
    
    Bryant's avatar
    Bryant committed
    int QwtCounter::incSteps( QwtCounter::Button button ) const
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        if ( button >= 0 && button < QwtCounter::ButtonCnt )
            return d_data->increment[ button ];
    
    pixhawk's avatar
    pixhawk committed
    
        return 0;
    }
    
    
    Bryant's avatar
    Bryant committed
    
    
    pixhawk's avatar
    pixhawk committed
    /*!
    
    Bryant's avatar
    Bryant committed
      Set the number of increment steps for button 1
      \param nSteps Number of steps
    
    pixhawk's avatar
    pixhawk committed
    */
    
    Bryant's avatar
    Bryant committed
    void QwtCounter::setStepButton1( int nSteps )
    {
        setIncSteps( QwtCounter::Button1, nSteps );
    }
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
    //! returns the number of increment steps for button 1
    int QwtCounter::stepButton1() const
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        return incSteps( QwtCounter::Button1 );
    }
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
    /*!
      Set the number of increment steps for button 2
      \param nSteps Number of steps
    */
    void QwtCounter::setStepButton2( int nSteps )
    {
        setIncSteps( QwtCounter::Button2, nSteps );
    }
    
    //! returns the number of increment steps for button 2
    int QwtCounter::stepButton2() const
    {
        return incSteps( QwtCounter::Button2 );
    
    pixhawk's avatar
    pixhawk committed
    }
    
    /*!
    
    Bryant's avatar
    Bryant committed
      Set the number of increment steps for button 3
      \param nSteps Number of steps
    
    pixhawk's avatar
    pixhawk committed
    */
    
    Bryant's avatar
    Bryant committed
    void QwtCounter::setStepButton3( int nSteps )
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        setIncSteps( QwtCounter::Button3, nSteps );
    }
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
    //! returns the number of increment steps for button 3
    int QwtCounter::stepButton3() const
    {
        return incSteps( QwtCounter::Button3 );
    }
    
    //! Set from lineedit
    void QwtCounter::textChanged()
    {
        bool converted = false;
    
        const double value = d_data->valueEdit->text().toDouble( &converted );
        if ( converted )
            setValue( value );
    }
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
    /*!
       Handle QEvent::PolishRequest events
       \param event Event
       \return see QWidget::event()
    */
    bool QwtCounter::event( QEvent *event )
    {
        if ( event->type() == QEvent::PolishRequest )
        {
            const int w = d_data->valueEdit->fontMetrics().width( "W" ) + 8;
            for ( int i = 0; i < ButtonCnt; i++ )
            {
                d_data->buttonDown[i]->setMinimumWidth( w );
                d_data->buttonUp[i]->setMinimumWidth( w );
            }
        }
    
        return QWidget::event( event );
    
    pixhawk's avatar
    pixhawk committed
    }
    
    /*!
    
    Bryant's avatar
    Bryant committed
      Handle key events
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
      - Ctrl + Qt::Key_Home\n
        Step to minimum()
      - Ctrl + Qt::Key_End\n
        Step to maximum()
      - Qt::Key_Up\n
        Increment by incSteps(QwtCounter::Button1)
      - Qt::Key_Down\n
        Decrement by incSteps(QwtCounter::Button1)
      - Qt::Key_PageUp\n
        Increment by incSteps(QwtCounter::Button2)
      - Qt::Key_PageDown\n
        Decrement by incSteps(QwtCounter::Button2)
      - Shift + Qt::Key_PageUp\n
        Increment by incSteps(QwtCounter::Button3)
      - Shift + Qt::Key_PageDown\n
        Decrement by incSteps(QwtCounter::Button3)
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
      \param event Key event
    
    pixhawk's avatar
    pixhawk committed
    */
    
    Bryant's avatar
    Bryant committed
    void QwtCounter::keyPressEvent ( QKeyEvent *event )
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        bool accepted = true;
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
        switch ( event->key() )
        {
            case Qt::Key_Home:
            {
                if ( event->modifiers() & Qt::ControlModifier )
                    setValue( minimum() );
                else
                    accepted = false;
                break;
            }
            case Qt::Key_End:
            {
                if ( event->modifiers() & Qt::ControlModifier )
                    setValue( maximum() );
                else
                    accepted = false;
                break;
            }
            case Qt::Key_Up:
            {
                incrementValue( d_data->increment[0] );
                break;
    
    pixhawk's avatar
    pixhawk committed
            }
    
    Bryant's avatar
    Bryant committed
            case Qt::Key_Down:
            {
                incrementValue( -d_data->increment[0] );
                break;
            }
            case Qt::Key_PageUp:
            case Qt::Key_PageDown:
            {
                int increment = d_data->increment[0];
                if ( d_data->numButtons >= 2 )
                    increment = d_data->increment[1];
                if ( d_data->numButtons >= 3 )
                {
                    if ( event->modifiers() & Qt::ShiftModifier )
                        increment = d_data->increment[2];
                }
                if ( event->key() == Qt::Key_PageDown )
                    increment = -increment;
                incrementValue( increment );
                break;
            }
            default:
            {
                accepted = false;
    
    pixhawk's avatar
    pixhawk committed
            }
        }
    
    Bryant's avatar
    Bryant committed
    
        if ( accepted )
        {
            event->accept();
            return;
        }
    
        QWidget::keyPressEvent ( event );
    
    pixhawk's avatar
    pixhawk committed
    }
    
    /*!
    
    Bryant's avatar
    Bryant committed
      Handle wheel events
      \param event Wheel event
    
    pixhawk's avatar
    pixhawk committed
    */
    
    Bryant's avatar
    Bryant committed
    void QwtCounter::wheelEvent( QWheelEvent *event )
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        event->accept();
    
        if ( d_data->numButtons <= 0 )
    
    pixhawk's avatar
    pixhawk committed
            return;
    
    
    Bryant's avatar
    Bryant committed
        int increment = d_data->increment[0];
        if ( d_data->numButtons >= 2 )
        {
            if ( event->modifiers() & Qt::ControlModifier )
                increment = d_data->increment[1];
        }
        if ( d_data->numButtons >= 3 )
        {
            if ( event->modifiers() & Qt::ShiftModifier )
                increment = d_data->increment[2];
        }
    
        for ( int i = 0; i < d_data->numButtons; i++ )
        {
            if ( d_data->buttonDown[i]->geometry().contains( event->pos() ) ||
                d_data->buttonUp[i]->geometry().contains( event->pos() ) )
            {
                increment = d_data->increment[i];
            }
        }
    
        const int wheel_delta = 120;
    
    #if 1
        int delta = event->delta();
        if ( delta >= 2 * wheel_delta )
            delta /= 2; // Never saw an abs(delta) < 240
    #endif
    
        incrementValue( delta / wheel_delta * increment );
    }
    
    void QwtCounter::incrementValue( int numSteps )
    {
        const double min = d_data->minimum;
        const double max = d_data->maximum;
        double stepSize = d_data->singleStep;
    
        if ( !d_data->isValid || min >= max || stepSize <= 0.0 )
            return;
    
    
    #if 1
        stepSize = qMax( stepSize, 1.0e-10 * ( max - min ) );
    #endif
    
        double value = d_data->value + numSteps * stepSize;
    
        if ( d_data->wrapping )
        {
            const double range = max - min;
    
            if ( value < min )
            {
                value += ::ceil( ( min - value ) / range ) * range;
    
    pixhawk's avatar
    pixhawk committed
            }
    
    Bryant's avatar
    Bryant committed
            else if ( value > max )
            {
                value -= ::ceil( ( value - max ) / range ) * range;
            }
        }
        else
        {
            value = qBound( min, value, max );
    
    pixhawk's avatar
    pixhawk committed
        }
    
    
    Bryant's avatar
    Bryant committed
        value = min + qRound( ( value - min ) / stepSize ) * stepSize;
    
        if ( stepSize > 1e-12 )
        {
            if ( qFuzzyCompare( value + 1.0, 1.0 ) )
            {
                // correct rounding error if value = 0
                value = 0.0;
            }
            else if ( qFuzzyCompare( value, max ) )
            {
                // correct rounding error at the border
                value = max;
            }
        }
    
        if ( value != d_data->value )
        {
            d_data->value = value;
            showNumber( d_data->value );
            updateButtons();
    
            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 Update buttons according to the current value
    
      When the QwtCounter under- or over-flows, the focus is set to the smallest
      up- or down-button and counting is disabled.
    
      Counting is re-enabled on a button release event (mouse or space bar).
    
    pixhawk's avatar
    pixhawk committed
    */
    
    Bryant's avatar
    Bryant committed
    void QwtCounter::updateButtons()
    
    Bryant's avatar
    Bryant committed
        if ( d_data->isValid )
        {
            // 1. save enabled state of the smallest down- and up-button
            // 2. change enabled state on under- or over-flow
    
            for ( int i = 0; i < QwtCounter::ButtonCnt; i++ )
            {
                d_data->buttonDown[i]->setEnabled( value() > minimum() );
                d_data->buttonUp[i]->setEnabled( value() < maximum() );
            }
        }
        else
        {
            for ( int i = 0; i < QwtCounter::ButtonCnt; i++ )
            {
                d_data->buttonDown[i]->setEnabled( false );
                d_data->buttonUp[i]->setEnabled( false );
            }
        }
    
    pixhawk's avatar
    pixhawk committed
    }
    
    Bryant's avatar
    Bryant committed
    /*!
      Display number string
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
      \param number Number
    */
    void QwtCounter::showNumber( double number )
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        QString text;
        text.setNum( number );
    
    pixhawk's avatar
    pixhawk committed
    
        const int cursorPos = d_data->valueEdit->cursorPosition();
    
    Bryant's avatar
    Bryant committed
        d_data->valueEdit->setText( text );
        d_data->valueEdit->setCursorPosition( cursorPos );
    
    pixhawk's avatar
    pixhawk committed
    }
    
    //!  Button clicked
    void QwtCounter::btnClicked()
    {
    
    Bryant's avatar
    Bryant committed
        for ( int i = 0; i < ButtonCnt; i++ )
        {
    
    pixhawk's avatar
    pixhawk committed
            if ( d_data->buttonUp[i] == sender() )
    
    Bryant's avatar
    Bryant committed
                incrementValue( d_data->increment[i] );
    
    pixhawk's avatar
    pixhawk committed
    
            if ( d_data->buttonDown[i] == sender() )
    
    Bryant's avatar
    Bryant committed
                incrementValue( -d_data->increment[i] );
    
    pixhawk's avatar
    pixhawk committed
        }
    }
    
    //!  Button released
    void QwtCounter::btnReleased()
    {
    
    Bryant's avatar
    Bryant committed
        Q_EMIT buttonReleased( value() );
    
    pixhawk's avatar
    pixhawk committed
    }
    
    //! A size hint
    QSize QwtCounter::sizeHint() const
    {
        QString tmp;
    
    
    Bryant's avatar
    Bryant committed
        int w = tmp.setNum( minimum() ).length();
        int w1 = tmp.setNum( maximum() ).length();
    
    pixhawk's avatar
    pixhawk committed
        if ( w1 > w )
            w = w1;
    
    Bryant's avatar
    Bryant committed
        w1 = tmp.setNum( minimum() + singleStep() ).length();
    
    pixhawk's avatar
    pixhawk committed
        if ( w1 > w )
            w = w1;
    
    Bryant's avatar
    Bryant committed
        w1 = tmp.setNum( maximum() - singleStep() ).length();
    
    pixhawk's avatar
    pixhawk committed
        if ( w1 > w )
            w = w1;
    
    
    Bryant's avatar
    Bryant committed
        tmp.fill( '9', w );
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
        QFontMetrics fm( d_data->valueEdit->font() );
        w = fm.width( tmp ) + 2;
    
    pixhawk's avatar
    pixhawk committed
        if ( d_data->valueEdit->hasFrame() )
    
    Bryant's avatar
    Bryant committed
            w += 2 * style()->pixelMetric( QStyle::PM_DefaultFrameWidth );
    
    pixhawk's avatar
    pixhawk committed
    
        // Now we replace default sizeHint contribution of d_data->valueEdit by
        // what we really need.
    
        w += QWidget::sizeHint().width() - d_data->valueEdit->sizeHint().width();
    
    
    Bryant's avatar
    Bryant committed
        const int h = qMin( QWidget::sizeHint().height(),
            d_data->valueEdit->minimumSizeHint().height() );
        return QSize( w, h );
    
    pixhawk's avatar
    pixhawk committed
    }