Skip to content
Snippets Groups Projects
qwt_counter.cpp 13.6 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
     *****************************************************************************/
    
    // vim: expandtab
    
    #include <qlayout.h>
    #include <qlineedit.h>
    #include <qvalidator.h>
    #include <qevent.h>
    #include <qstyle.h>
    #include "qwt_math.h"
    #include "qwt_counter.h"
    #include "qwt_arrow_button.h"
    
    class QwtCounter::PrivateData
    {
    public:
        PrivateData():
    
            editable(true) {
    
    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];
        int nButtons;
    
        bool editable;
    };
    
    /*!
      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
     */
    QwtCounter::QwtCounter(QWidget *parent):
    
        QWidget(parent)
    
    pixhawk's avatar
    pixhawk committed
    {
        initCounter();
    }
    
    #if QT_VERSION < 0x040000
    /*!
      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
     */
    QwtCounter::QwtCounter(QWidget *parent, const char *name):
    
        QWidget(parent, name)
    
    pixhawk's avatar
    pixhawk committed
    {
        initCounter();
    }
    #endif
    
    void QwtCounter::initCounter()
    {
        d_data = new PrivateData;
    
    #if QT_VERSION >= 0x040000
        using namespace Qt;
    #endif
    
        QHBoxLayout *layout = new QHBoxLayout(this);
        layout->setSpacing(0);
        layout->setMargin(0);
    
        int i;
    
        for(i = ButtonCnt - 1; i >= 0; i--) {
    
    pixhawk's avatar
    pixhawk committed
            QwtArrowButton *btn =
                new QwtArrowButton(i+1, Qt::DownArrow,this);
            btn->setFocusPolicy(NoFocus);
            btn->installEventFilter(this);
            layout->addWidget(btn);
    
            connect(btn, SIGNAL(released()), SLOT(btnReleased()));
            connect(btn, SIGNAL(clicked()), SLOT(btnClicked()));
    
            d_data->buttonDown[i] = btn;
        }
    
        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);
    
    #if QT_VERSION >= 0x040000
    
        connect( d_data->valueEdit, SIGNAL(editingFinished()),
                 SLOT(textChanged()) );
    
    pixhawk's avatar
    pixhawk committed
    #else
        connect( d_data->valueEdit, SIGNAL(returnPressed()), SLOT(textChanged()) );
        connect( d_data->valueEdit, SIGNAL(lostFocus()), SLOT(textChanged()) );
    #endif
    
        layout->setStretchFactor(d_data->valueEdit, 10);
    
    
        for(i = 0; i < ButtonCnt; i++) {
    
    pixhawk's avatar
    pixhawk committed
    #if QT_VERSION >= 0x040000
            using namespace Qt;
    #endif
            QwtArrowButton *btn =
                new QwtArrowButton(i+1, Qt::UpArrow, this);
            btn->setFocusPolicy(NoFocus);
            btn->installEventFilter(this);
            layout->addWidget(btn);
    
            connect(btn, SIGNAL(released()), SLOT(btnReleased()));
            connect(btn, SIGNAL(clicked()), SLOT(btnClicked()));
    
    pixhawk's avatar
    pixhawk committed
            d_data->buttonUp[i] = btn;
        }
    
        setNumButtons(2);
        setRange(0.0,1.0,0.001);
        setValue(0.0);
    
        setSizePolicy(
            QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed));
    
        setFocusProxy(d_data->valueEdit);
        setFocusPolicy(StrongFocus);
    }
    
    //! Destructor
    QwtCounter::~QwtCounter()
    {
        delete d_data;
    }
    
    /*!
      Sets the minimum width for the buttons
    */
    void QwtCounter::polish()
    {
        const int w = d_data->valueEdit->fontMetrics().width("W") + 8;
    
    
        for ( int i = 0; i < ButtonCnt; i++ ) {
    
    pixhawk's avatar
    pixhawk committed
            d_data->buttonDown[i]->setMinimumWidth(w);
            d_data->buttonUp[i]->setMinimumWidth(w);
        }
    
    #if QT_VERSION < 0x040000
        QWidget::polish();
    #endif
    }
    
    //! Set from lineedit
    
    void QwtCounter::textChanged()
    
    pixhawk's avatar
    pixhawk committed
    {
    
        if ( !d_data->editable )
    
    pixhawk's avatar
    pixhawk committed
            return;
    
        bool converted = false;
    
        const double value = d_data->valueEdit->text().toDouble(&converted);
    
        if ( converted )
            setValue( value );
    
    pixhawk's avatar
    pixhawk committed
    }
    
    /**
      \brief Allow/disallow the user to manually edit the value
    
      \param editable true enables editing
      \sa editable()
    */
    void QwtCounter::setEditable(bool editable)
    {
    #if QT_VERSION >= 0x040000
        using namespace Qt;
    #endif
    
        if ( editable == d_data->editable )
    
    pixhawk's avatar
    pixhawk committed
            return;
    
        d_data->editable = editable;
        d_data->valueEdit->setReadOnly(!editable);
    }
    
    //! returns whether the line edit is edatble. (default is yes)
    
    bool QwtCounter::editable() const
    {
    
    pixhawk's avatar
    pixhawk committed
        return d_data->editable;
    }
    
    /*!
    
       Handle PolishRequest events
    
    pixhawk's avatar
    pixhawk committed
    */
    
    bool QwtCounter::event ( QEvent * e )
    
    pixhawk's avatar
    pixhawk committed
    {
    #if QT_VERSION >= 0x040000
        if ( e->type() == QEvent::PolishRequest )
            polish();
    #endif
        return QWidget::event(e);
    }
    
    /*!
      Handles key events
    
      - Ctrl + Qt::Key_Home
        Step to minValue()
      - Ctrl + Qt::Key_End
        Step to maxValue()
      - Qt::Key_Up
        Increment by incSteps(QwtCounter::Button1)
      - Qt::Key_Down
        Decrement by incSteps(QwtCounter::Button1)
      - Qt::Key_PageUp
        Increment by incSteps(QwtCounter::Button2)
      - Qt::Key_PageDown
        Decrement by incSteps(QwtCounter::Button2)
      - Shift + Qt::Key_PageUp
        Increment by incSteps(QwtCounter::Button3)
      - Shift + Qt::Key_PageDown
        Decrement by incSteps(QwtCounter::Button3)
    */
    
    void QwtCounter::keyPressEvent (QKeyEvent *e)
    {
        bool accepted = true;
    
    
        switch ( e->key() ) {
        case Qt::Key_Home:
    
    pixhawk's avatar
    pixhawk committed
    #if QT_VERSION >= 0x040000
    
            if ( e->modifiers() & Qt::ControlModifier )
    
    pixhawk's avatar
    pixhawk committed
    #else
    
            if ( e->state() & Qt::ControlButton )
    
    pixhawk's avatar
    pixhawk committed
    #endif
    
                setValue(minValue());
            else
                accepted = false;
            break;
        case Qt::Key_End:
    
    pixhawk's avatar
    pixhawk committed
    #if QT_VERSION >= 0x040000
    
            if ( e->modifiers() & Qt::ControlModifier )
    
    pixhawk's avatar
    pixhawk committed
    #else
    
            if ( e->state() & Qt::ControlButton )
    
    pixhawk's avatar
    pixhawk committed
    #endif
    
                setValue(maxValue());
            else
                accepted = false;
            break;
        case Qt::Key_Up:
            incValue(d_data->increment[0]);
            break;
        case Qt::Key_Down:
            incValue(-d_data->increment[0]);
            break;
        case Qt::Key_PageUp:
        case Qt::Key_PageDown: {
            int increment = d_data->increment[0];
            if ( d_data->nButtons >= 2 )
                increment = d_data->increment[1];
            if ( d_data->nButtons >= 3 ) {
    
    pixhawk's avatar
    pixhawk committed
    #if QT_VERSION >= 0x040000
    
                if ( e->modifiers() & Qt::ShiftModifier )
    
    pixhawk's avatar
    pixhawk committed
    #else
    
                if ( e->state() & Qt::ShiftButton )
    
    pixhawk's avatar
    pixhawk committed
    #endif
    
                    increment = d_data->increment[2];
    
    pixhawk's avatar
    pixhawk committed
            }
    
            if ( e->key() == Qt::Key_PageDown )
                increment = -increment;
            incValue(increment);
            break;
        }
        default:
            accepted = false;
    
    pixhawk's avatar
    pixhawk committed
        }
    
    
        if ( accepted ) {
    
    pixhawk's avatar
    pixhawk committed
            e->accept();
            return;
        }
    
        QWidget::keyPressEvent (e);
    }
    
    void QwtCounter::wheelEvent(QWheelEvent *e)
    {
        e->accept();
    
        if ( d_data->nButtons <= 0 )
            return;
    
        int increment = d_data->increment[0];
    
        if ( d_data->nButtons >= 2 ) {
    
    pixhawk's avatar
    pixhawk committed
    #if QT_VERSION >= 0x040000
            if ( e->modifiers() & Qt::ControlModifier )
    #else
            if ( e->state() & Qt::ControlButton )
    #endif
                increment = d_data->increment[1];
        }
    
        if ( d_data->nButtons >= 3 ) {
    
    pixhawk's avatar
    pixhawk committed
    #if QT_VERSION >= 0x040000
            if ( e->modifiers() & Qt::ShiftModifier )
    #else
            if ( e->state() & Qt::ShiftButton )
    #endif
                increment = d_data->increment[2];
        }
    
    
        for ( int i = 0; i < d_data->nButtons; i++ ) {
    
    pixhawk's avatar
    pixhawk committed
            if ( d_data->buttonDown[i]->geometry().contains(e->pos()) ||
    
                    d_data->buttonUp[i]->geometry().contains(e->pos()) ) {
    
    pixhawk's avatar
    pixhawk committed
                increment = d_data->increment[i];
            }
        }
    
        const int wheel_delta = 120;
    
        int delta = e->delta();
        if ( delta >= 2 * wheel_delta )
            delta /= 2; // Never saw an abs(delta) < 240
    
        incValue(delta / wheel_delta * increment);
    }
    
    /*!
      Specify the number of steps by which the value
      is incremented or decremented when a specified button
      is pushed.
    
      \param btn One of \c QwtCounter::Button1, \c QwtCounter::Button2,
                 \c QwtCounter::Button3
      \param nSteps Number of steps
    */
    void QwtCounter::setIncSteps(QwtCounter::Button btn, int nSteps)
    {
        if (( btn >= 0) && (btn < ButtonCnt))
    
            d_data->increment[btn] = nSteps;
    
    pixhawk's avatar
    pixhawk committed
    }
    
    /*!
      \return the number of steps by which a specified button increments the value
      or 0 if the button is invalid.
      \param btn One of \c QwtCounter::Button1, \c QwtCounter::Button2,
      \c QwtCounter::Button3
    */
    int QwtCounter::incSteps(QwtCounter::Button btn) const
    {
        if (( btn >= 0) && (btn < ButtonCnt))
    
            return d_data->increment[btn];
    
    pixhawk's avatar
    pixhawk committed
    
        return 0;
    }
    
    /*!
      \brief Set a new value
      \param v new value
      Calls QwtDoubleRange::setValue and does all visual updates.
      \sa QwtDoubleRange::setValue
    */
    
    void QwtCounter::setValue(double v)
    {
        QwtDoubleRange::setValue(v);
    
        showNum(value());
        updateButtons();
    }
    
    /*!
      \brief Notify a change of value
    */
    void QwtCounter::valueChange()
    {
        if ( isValid() )
            showNum(value());
        else
            d_data->valueEdit->setText(QString::null);
    
        updateButtons();
    
        if ( isValid() )
            emit valueChanged(value());
    }
    
    /*!
      \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).
    */
    void QwtCounter::updateButtons()
    {
    
        if ( isValid() ) {
    
    pixhawk's avatar
    pixhawk committed
            // 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 < ButtonCnt; i++ ) {
    
    pixhawk's avatar
    pixhawk committed
                d_data->buttonDown[i]->setEnabled(value() > minValue());
                d_data->buttonUp[i]->setEnabled(value() < maxValue());
            }
    
        } else {
            for ( int i = 0; i < ButtonCnt; i++ ) {
    
    pixhawk's avatar
    pixhawk committed
                d_data->buttonDown[i]->setEnabled(false);
                d_data->buttonUp[i]->setEnabled(false);
            }
        }
    }
    
    /*!
      \brief Specify the number of buttons on each side of the label
      \param n Number of buttons
    */
    void QwtCounter::setNumButtons(int n)
    {
        if ( n<0 || n>ButtonCnt )
            return;
    
    
        for ( int i = 0; i < ButtonCnt; i++ ) {
            if ( i < n ) {
    
    pixhawk's avatar
    pixhawk committed
                d_data->buttonDown[i]->show();
                d_data->buttonUp[i]->show();
    
    pixhawk's avatar
    pixhawk committed
                d_data->buttonDown[i]->hide();
                d_data->buttonUp[i]->hide();
            }
        }
    
        d_data->nButtons = n;
    }
    
    /*!
        \return The number of buttons on each side of the widget.
    */
    
    int QwtCounter::numButtons() const
    {
        return d_data->nButtons;
    
    pixhawk's avatar
    pixhawk committed
    }
    
    //!  Display number string
    void QwtCounter::showNum(double d)
    {
        QString v;
        v.setNum(d);
    
        const int cursorPos = d_data->valueEdit->cursorPosition();
        d_data->valueEdit->setText(v);
        d_data->valueEdit->setCursorPosition(cursorPos);
    }
    
    //!  Button clicked
    void QwtCounter::btnClicked()
    {
    
        for ( int i = 0; i < ButtonCnt; i++ ) {
    
    pixhawk's avatar
    pixhawk committed
            if ( d_data->buttonUp[i] == sender() )
                incValue(d_data->increment[i]);
    
            if ( d_data->buttonDown[i] == sender() )
                incValue(-d_data->increment[i]);
        }
    }
    
    //!  Button released
    void QwtCounter::btnReleased()
    {
        emit buttonReleased(value());
    }
    
    /*!
      \brief Notify change of range
    
      This function updates the enabled property of
      all buttons contained in QwtCounter.
    */
    void QwtCounter::rangeChange()
    {
        updateButtons();
    }
    
    //! A size hint
    QSize QwtCounter::sizeHint() const
    {
        QString tmp;
    
        int w = tmp.setNum(minValue()).length();
        int w1 = tmp.setNum(maxValue()).length();
        if ( w1 > w )
            w = w1;
        w1 = tmp.setNum(minValue() + step()).length();
        if ( w1 > w )
            w = w1;
        w1 = tmp.setNum(maxValue() - step()).length();
        if ( w1 > w )
            w = w1;
    
        tmp.fill('9', w);
    
        QFontMetrics fm(d_data->valueEdit->font());
        w = fm.width(tmp) + 2;
    #if QT_VERSION >= 0x040000
        if ( d_data->valueEdit->hasFrame() )
            w += 2 * style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
    #else
    
        w += 2 * d_data->valueEdit->frameWidth();
    
    pixhawk's avatar
    pixhawk committed
    #endif
    
        // Now we replace default sizeHint contribution of d_data->valueEdit by
        // what we really need.
    
        w += QWidget::sizeHint().width() - d_data->valueEdit->sizeHint().width();
    
    
        const int h = qwtMin(QWidget::sizeHint().height(),
                             d_data->valueEdit->minimumSizeHint().height());
    
    pixhawk's avatar
    pixhawk committed
        return QSize(w, h);
    }
    
    //! returns the step size
    double QwtCounter::step() const
    {
        return QwtDoubleRange::step();
    }
    
    pixhawk's avatar
    pixhawk committed
    //! sets the step size
    void QwtCounter::setStep(double s)
    {
        QwtDoubleRange::setStep(s);
    }
    
    //! returns the minimum value of the range
    double QwtCounter::minVal() const
    {
        return minValue();
    }
    
    //! sets the minimum value of the range
    void QwtCounter::setMinValue(double m)
    {
        setRange(m, maxValue(), step());
    }
    
    //! returns the maximum value of the range
    double QwtCounter::maxVal() const
    {
        return QwtDoubleRange::maxValue();
    }
    
    //! sets the maximum value of the range
    void QwtCounter::setMaxValue(double m)
    {
        setRange(minValue(), m, step());
    }
    
    //! set the number of increment steps for button 1
    void QwtCounter::setStepButton1(int nSteps)
    {
        setIncSteps(Button1, nSteps);
    }
    
    //! returns the number of increment steps for button 1
    int QwtCounter::stepButton1() const
    {
        return incSteps(Button1);
    }
    
    //! set the number of increment steps for button 2
    void QwtCounter::setStepButton2(int nSteps)
    {
        setIncSteps(Button2, nSteps);
    }
    
    //! returns the number of increment steps for button 2
    int QwtCounter::stepButton2() const
    {
        return incSteps(Button2);
    }
    
    //! set the number of increment steps for button 3
    void QwtCounter::setStepButton3(int nSteps)
    {
        setIncSteps(Button3, nSteps);
    }
    
    //! returns the number of increment steps for button 3
    int QwtCounter::stepButton3() const
    {
        return incSteps(Button3);
    }
    
    double QwtCounter::value() const
    {
        return QwtDoubleRange::value();
    }