qwt_counter.cpp
/******************************************************************************
* 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
*****************************************************************************/
#include "qwt_arrow_button.h"
#include "qwt_counter.h"
#include "qwt_painter.h"
#include "qwt_math.h"
#include <qlayout.h>
#include <qlineedit.h>
#include <qvalidator.h>
#include <qevent.h>
#include <qstyle.h>
class QwtCounter::PrivateData
{
public:
PrivateData()
: minimum( 0.0 )
, maximum( 0.0 )
, singleStep( 1.0 )
, isValid( false )
, value( 0.0 )
, wrapping( false )
{
increment[Button1] = 1;
increment[Button2] = 10;
increment[Button3] = 100;
}
QwtArrowButton* buttonDown[ButtonCnt];
QwtArrowButton* buttonUp[ButtonCnt];
QLineEdit* valueEdit;
int increment[ButtonCnt];
int numButtons;
double minimum;
double maximum;
double singleStep;
bool isValid;
double value;
bool wrapping;
};
QwtCounter::QwtCounter( QWidget* parent )
: QWidget( parent )
{
initCounter();
}
void QwtCounter::initCounter()
{
m_data = new PrivateData;
QHBoxLayout* layout = new QHBoxLayout( this );
layout->setSpacing( 0 );
layout->setContentsMargins( QMargins() );
for ( int i = ButtonCnt - 1; i >= 0; i-- )
{
QwtArrowButton* btn =
new QwtArrowButton( i + 1, Qt::DownArrow, this );
btn->setFocusPolicy( Qt::NoFocus );
layout->addWidget( btn );
connect( btn, SIGNAL(released()), SLOT(btnReleased()) );
connect( btn, SIGNAL(clicked()), SLOT(btnClicked()) );
m_data->buttonDown[i] = btn;
}
m_data->valueEdit = new QLineEdit( this );
m_data->valueEdit->setReadOnly( false );
m_data->valueEdit->setValidator( new QDoubleValidator( m_data->valueEdit ) );
layout->addWidget( m_data->valueEdit );
connect( m_data->valueEdit, SIGNAL(editingFinished()), SLOT(textChanged()) );
layout->setStretchFactor( m_data->valueEdit, 10 );
for ( int i = 0; i < ButtonCnt; i++ )
{
QwtArrowButton* btn =
new QwtArrowButton( i + 1, Qt::UpArrow, this );
btn->setFocusPolicy( Qt::NoFocus );
layout->addWidget( btn );
connect( btn, SIGNAL(released()), SLOT(btnReleased()) );
connect( btn, SIGNAL(clicked()), SLOT(btnClicked()) );
m_data->buttonUp[i] = btn;
}
setNumButtons( 2 );
setRange( 0.0, 1.0 );
setSingleStep( 0.001 );
setValue( 0.0 );
setSizePolicy(
QSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed ) );
setFocusProxy( m_data->valueEdit );
setFocusPolicy( Qt::StrongFocus );
}
QwtCounter::~QwtCounter()
{
delete m_data;
}
void QwtCounter::setValid( bool on )
{
if ( on != m_data->isValid )
{
m_data->isValid = on;
updateButtons();
if ( m_data->isValid )
{
showNumber( value() );
Q_EMIT valueChanged( value() );
}
else
{
m_data->valueEdit->setText( QString() );
}
}
}
bool QwtCounter::isValid() const
{
return m_data->isValid;
}
void QwtCounter::setReadOnly( bool on )
{
m_data->valueEdit->setReadOnly( on );
}
bool QwtCounter::isReadOnly() const
{
return m_data->valueEdit->isReadOnly();
}
void QwtCounter::setValue( double value )
{
const double vmin = qwtMinF( m_data->minimum, m_data->maximum );
const double vmax = qwtMaxF( m_data->minimum, m_data->maximum );
value = qBound( vmin, value, vmax );
if ( !m_data->isValid || value != m_data->value )
{
m_data->isValid = true;
m_data->value = value;
showNumber( value );
updateButtons();
Q_EMIT valueChanged( value );
}
}
double QwtCounter::value() const
{
return m_data->value;
}
void QwtCounter::setRange( double min, double max )
{
max = qwtMaxF( min, max );
if ( m_data->maximum == max && m_data->minimum == min )
return;
m_data->minimum = min;
m_data->maximum = max;
setSingleStep( singleStep() );
const double value = qBound( min, m_data->value, max );
if ( value != m_data->value )
{
m_data->value = value;
if ( m_data->isValid )
{
showNumber( value );
Q_EMIT valueChanged( value );
}
}
updateButtons();
}
void QwtCounter::setMinimum( double value )
{
setRange( value, maximum() );
}
double QwtCounter::minimum() const
{
return m_data->minimum;
}
void QwtCounter::setMaximum( double value )
{
setRange( minimum(), value );
}
double QwtCounter::maximum() const
{
return m_data->maximum;
}
void QwtCounter::setSingleStep( double stepSize )
{
m_data->singleStep = qwtMaxF( stepSize, 0.0 );
}
double QwtCounter::singleStep() const
{
return m_data->singleStep;
}
void QwtCounter::setWrapping( bool on )
{
m_data->wrapping = on;
}
bool QwtCounter::wrapping() const
{
return m_data->wrapping;
}
void QwtCounter::setNumButtons( int numButtons )
{
if ( numButtons < 0 || numButtons > QwtCounter::ButtonCnt )
return;
for ( int i = 0; i < QwtCounter::ButtonCnt; i++ )
{
if ( i < numButtons )
{
m_data->buttonDown[i]->show();
m_data->buttonUp[i]->show();
}
else
{
m_data->buttonDown[i]->hide();
m_data->buttonUp[i]->hide();
}
}
m_data->numButtons = numButtons;
}
int QwtCounter::numButtons() const
{
return m_data->numButtons;
}
void QwtCounter::setIncSteps( QwtCounter::Button button, int numSteps )
{
if ( button >= 0 && button < QwtCounter::ButtonCnt )
m_data->increment[ button ] = numSteps;
}
int QwtCounter::incSteps( QwtCounter::Button button ) const
{
if ( button >= 0 && button < QwtCounter::ButtonCnt )
return m_data->increment[ button ];
return 0;
}
void QwtCounter::setStepButton1( int nSteps )
{
setIncSteps( QwtCounter::Button1, nSteps );
}
int QwtCounter::stepButton1() const
{
return incSteps( QwtCounter::Button1 );
}
void QwtCounter::setStepButton2( int nSteps )
{
setIncSteps( QwtCounter::Button2, nSteps );
}
int QwtCounter::stepButton2() const
{
return incSteps( QwtCounter::Button2 );
}
void QwtCounter::setStepButton3( int nSteps )
{
setIncSteps( QwtCounter::Button3, nSteps );
}
int QwtCounter::stepButton3() const
{
return incSteps( QwtCounter::Button3 );
}
void QwtCounter::textChanged()
{
bool converted = false;
const double value = m_data->valueEdit->text().toDouble( &converted );
if ( converted )
setValue( value );
}
bool QwtCounter::event( QEvent* event )
{
if ( event->type() == QEvent::PolishRequest )
{
const QFontMetrics fm = m_data->valueEdit->fontMetrics();
const int w = QwtPainter::horizontalAdvance( fm, "W" ) + 8;
for ( int i = 0; i < ButtonCnt; i++ )
{
m_data->buttonDown[i]->setMinimumWidth( w );
m_data->buttonUp[i]->setMinimumWidth( w );
}
}
return QWidget::event( event );
}
void QwtCounter::keyPressEvent ( QKeyEvent* event )
{
bool accepted = true;
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( m_data->increment[0] );
break;
}
case Qt::Key_Down:
{
incrementValue( -m_data->increment[0] );
break;
}
case Qt::Key_PageUp:
case Qt::Key_PageDown:
{
int increment = m_data->increment[0];
if ( m_data->numButtons >= 2 )
increment = m_data->increment[1];
if ( m_data->numButtons >= 3 )
{
if ( event->modifiers() & Qt::ShiftModifier )
increment = m_data->increment[2];
}
if ( event->key() == Qt::Key_PageDown )
increment = -increment;
incrementValue( increment );
break;
}
default:
{
accepted = false;
}
}
if ( accepted )
{
event->accept();
return;
}
QWidget::keyPressEvent ( event );
}
void QwtCounter::wheelEvent( QWheelEvent* event )
{
event->accept();
if ( m_data->numButtons <= 0 )
return;
int increment = m_data->increment[0];
if ( m_data->numButtons >= 2 )
{
if ( event->modifiers() & Qt::ControlModifier )
increment = m_data->increment[1];
}
if ( m_data->numButtons >= 3 )
{
if ( event->modifiers() & Qt::ShiftModifier )
increment = m_data->increment[2];
}
#if QT_VERSION < 0x050e00
const QPoint wheelPos = event->pos();
const int wheelDelta = event->delta();
#else
const QPoint wheelPos = event->position().toPoint();
const QPoint delta = event->angleDelta();
const int wheelDelta = ( qAbs( delta.x() ) > qAbs( delta.y() ) )
? delta.x() : delta.y();
#endif
for ( int i = 0; i < m_data->numButtons; i++ )
{
if ( m_data->buttonDown[i]->geometry().contains( wheelPos ) ||
m_data->buttonUp[i]->geometry().contains( wheelPos ) )
{
increment = m_data->increment[i];
}
}
incrementValue( wheelDelta / 120 * increment );
}
void QwtCounter::incrementValue( int numSteps )
{
const double min = m_data->minimum;
const double max = m_data->maximum;
double stepSize = m_data->singleStep;
if ( !m_data->isValid || min >= max || stepSize <= 0.0 )
return;
#if 1
stepSize = qwtMaxF( stepSize, 1.0e-10 * ( max - min ) );
#endif
double value = m_data->value + numSteps * stepSize;
if ( m_data->wrapping )
{
const double range = max - min;
if ( value < min )
{
value += std::ceil( ( min - value ) / range ) * range;
}
else if ( value > max )
{
value -= std::ceil( ( value - max ) / range ) * range;
}
}
else
{
value = qBound( min, value, max );
}
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 != m_data->value )
{
m_data->value = value;
showNumber( m_data->value );
updateButtons();
Q_EMIT valueChanged( m_data->value );
}
}
void QwtCounter::updateButtons()
{
if ( m_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++ )
{
m_data->buttonDown[i]->setEnabled( value() > minimum() );
m_data->buttonUp[i]->setEnabled( value() < maximum() );
}
}
else
{
for ( int i = 0; i < QwtCounter::ButtonCnt; i++ )
{
m_data->buttonDown[i]->setEnabled( false );
m_data->buttonUp[i]->setEnabled( false );
}
}
}
void QwtCounter::showNumber( double number )
{
QString text;
text.setNum( number );
const int cursorPos = m_data->valueEdit->cursorPosition();
m_data->valueEdit->setText( text );
m_data->valueEdit->setCursorPosition( cursorPos );
}
void QwtCounter::btnClicked()
{
for ( int i = 0; i < ButtonCnt; i++ )
{
if ( m_data->buttonUp[i] == sender() )
incrementValue( m_data->increment[i] );
if ( m_data->buttonDown[i] == sender() )
incrementValue( -m_data->increment[i] );
}
}
void QwtCounter::btnReleased()
{
Q_EMIT buttonReleased( value() );
}
QSize QwtCounter::sizeHint() const
{
QString tmp;
int w = tmp.setNum( minimum() ).length();
int w1 = tmp.setNum( maximum() ).length();
if ( w1 > w )
w = w1;
w1 = tmp.setNum( minimum() + singleStep() ).length();
if ( w1 > w )
w = w1;
w1 = tmp.setNum( maximum() - singleStep() ).length();
if ( w1 > w )
w = w1;
tmp.fill( '9', w );
w = QwtPainter::horizontalAdvance( m_data->valueEdit->fontMetrics(), tmp ) + 2;
if ( m_data->valueEdit->hasFrame() )
w += 2 * style()->pixelMetric( QStyle::PM_DefaultFrameWidth );
// Now we replace default sizeHint contribution of m_data->valueEdit by
// what we really need.
w += QWidget::sizeHint().width() - m_data->valueEdit->sizeHint().width();
const int h = qMin( QWidget::sizeHint().height(),
m_data->valueEdit->minimumSizeHint().height() );
return QSize( w, h );
}
#if QWT_MOC_INCLUDE
#include "moc_qwt_counter.cpp"
#endif
QwtArrowButton
Arrow Button.
Definition: qwt_arrow_button.h:24
QwtCounter::Button
Button
Button index.
Definition: qwt_counter.h:68
QwtCounter::Button1
@ Button1
Button intended for minor steps.
Definition: qwt_counter.h:70
QwtCounter::Button3
@ Button3
Button intended for large steps.
Definition: qwt_counter.h:76
QwtCounter::Button2
@ Button2
Button intended for medium steps.
Definition: qwt_counter.h:73
QwtCounter::ButtonCnt
@ ButtonCnt
Number of buttons.
Definition: qwt_counter.h:79
QwtCounter::setStepButton2
void setStepButton2(int nSteps)
Definition: qwt_counter.cpp:444
QwtCounter::minimum
double minimum() const
Definition: qwt_counter.cpp:286
QwtCounter::value
double value() const
Definition: qwt_counter.cpp:225
QwtCounter::stepButton3
int stepButton3() const
returns the number of increment steps for button 3
Definition: qwt_counter.cpp:465
QwtCounter::setValue
void setValue(double)
Set a new value without adjusting to the step raster.
Definition: qwt_counter.cpp:202
QwtCounter::setMinimum
void setMinimum(double)
Definition: qwt_counter.cpp:277
QwtCounter::sizeHint
virtual QSize sizeHint() const override
A size hint.
Definition: qwt_counter.cpp:759
QwtCounter::isReadOnly
bool isReadOnly() const
Definition: qwt_counter.cpp:186
QwtCounter::wrapping
bool wrapping() const
Definition: qwt_counter.cpp:351
QwtCounter::isValid
bool isValid() const
Definition: qwt_counter.cpp:166
QwtCounter::~QwtCounter
virtual ~QwtCounter()
Destructor.
Definition: qwt_counter.cpp:127
QwtCounter::buttonReleased
void buttonReleased(double value)
QwtCounter::setStepButton3
void setStepButton3(int nSteps)
Definition: qwt_counter.cpp:459
QwtCounter::maximum
double maximum() const
Definition: qwt_counter.cpp:306
QwtCounter::singleStep
double singleStep() const
Definition: qwt_counter.cpp:328
QwtCounter::setWrapping
void setWrapping(bool)
En/Disable wrapping.
Definition: qwt_counter.cpp:342
QwtCounter::setNumButtons
void setNumButtons(int)
Definition: qwt_counter.cpp:362
QwtCounter::incSteps
int incSteps(QwtCounter::Button) const
Definition: qwt_counter.cpp:416
QwtCounter::event
virtual bool event(QEvent *) override
Definition: qwt_counter.cpp:485
QwtCounter::setValid
void setValid(bool)
Definition: qwt_counter.cpp:142
QwtCounter::numButtons
int numButtons() const
Definition: qwt_counter.cpp:388
QwtCounter::keyPressEvent
virtual void keyPressEvent(QKeyEvent *) override
Definition: qwt_counter.cpp:524
QwtCounter::setIncSteps
void setIncSteps(QwtCounter::Button, int numSteps)
Definition: qwt_counter.cpp:403
QwtCounter::stepButton2
int stepButton2() const
returns the number of increment steps for button 2
Definition: qwt_counter.cpp:450
QwtCounter::setReadOnly
void setReadOnly(bool)
Allow/disallow the user to manually edit the value.
Definition: qwt_counter.cpp:177
QwtCounter::setRange
void setRange(double min, double max)
Set the minimum and maximum values.
Definition: qwt_counter.cpp:241
QwtCounter::valueChanged
void valueChanged(double value)
QwtCounter::setStepButton1
void setStepButton1(int nSteps)
Definition: qwt_counter.cpp:429
QwtCounter::QwtCounter
QwtCounter(QWidget *parent=NULL)
Definition: qwt_counter.cpp:65
QwtCounter::setSingleStep
void setSingleStep(double stepSize)
Set the step size of the counter.
Definition: qwt_counter.cpp:319
QwtCounter::setMaximum
void setMaximum(double)
Definition: qwt_counter.cpp:297
QwtCounter::wheelEvent
virtual void wheelEvent(QWheelEvent *) override
Definition: qwt_counter.cpp:591
QwtCounter::stepButton1
int stepButton1() const
returns the number of increment steps for button 1
Definition: qwt_counter.cpp:435
QwtPainter::horizontalAdvance
static int horizontalAdvance(const QFontMetrics &, const QString &)
Definition: qwt_painter.cpp:1379