/* -*- 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 #include #include #include #include #include "qwt_math.h" #include "qwt_counter.h" #include "qwt_arrow_button.h" class QwtCounter::PrivateData { public: PrivateData(): editable(true) { 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) { 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) { 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--) { 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()) ); #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++) { #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())); 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++ ) { 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() { if ( !d_data->editable ) return; bool converted = false; const double value = d_data->valueEdit->text().toDouble(&converted); if ( converted ) setValue( value ); } /** \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 ) return; d_data->editable = editable; d_data->valueEdit->setReadOnly(!editable); } //! returns whether the line edit is edatble. (default is yes) bool QwtCounter::editable() const { return d_data->editable; } /*! Handle PolishRequest events */ bool QwtCounter::event ( QEvent * e ) { #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: #if QT_VERSION >= 0x040000 if ( e->modifiers() & Qt::ControlModifier ) #else if ( e->state() & Qt::ControlButton ) #endif setValue(minValue()); else accepted = false; break; case Qt::Key_End: #if QT_VERSION >= 0x040000 if ( e->modifiers() & Qt::ControlModifier ) #else if ( e->state() & Qt::ControlButton ) #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 ) { #if QT_VERSION >= 0x040000 if ( e->modifiers() & Qt::ShiftModifier ) #else if ( e->state() & Qt::ShiftButton ) #endif increment = d_data->increment[2]; } if ( e->key() == Qt::Key_PageDown ) increment = -increment; incValue(increment); break; } default: accepted = false; } if ( accepted ) { 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 ) { #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 ) { #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++ ) { if ( d_data->buttonDown[i]->geometry().contains(e->pos()) || d_data->buttonUp[i]->geometry().contains(e->pos()) ) { 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; } /*! \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]; 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() ) { // 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++ ) { d_data->buttonDown[i]->setEnabled(value() > minValue()); d_data->buttonUp[i]->setEnabled(value() < maxValue()); } } else { for ( int i = 0; i < ButtonCnt; i++ ) { 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 ) { d_data->buttonDown[i]->show(); d_data->buttonUp[i]->show(); } else { 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; } //! 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++ ) { 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(); #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()); return QSize(w, h); } //! returns the step size double QwtCounter::step() const { return QwtDoubleRange::step(); } //! 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(); }