地面站终端 App
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

786 lines
0 B

15 years ago
/* -*- 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
*****************************************************************************/
#include "qwt_arrow_button.h"
#include "qwt_math.h"
#include "qwt_counter.h"
15 years ago
#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 )
{
15 years ago
increment[Button1] = 1;
increment[Button2] = 10;
increment[Button3] = 100;
}
QwtArrowButton *buttonDown[ButtonCnt];
QwtArrowButton *buttonUp[ButtonCnt];
QLineEdit *valueEdit;
int increment[ButtonCnt];
int numButtons;
15 years ago
double minimum;
double maximum;
double singleStep;
15 years ago
bool isValid;
double value;
15 years ago
bool wrapping;
};
15 years ago
/*!
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.
15 years ago
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 )
15 years ago
{
initCounter();
}
void QwtCounter::initCounter()
{
d_data = new PrivateData;
QHBoxLayout *layout = new QHBoxLayout( this );
layout->setSpacing( 0 );
layout->setMargin( 0 );
15 years ago
for ( int i = ButtonCnt - 1; i >= 0; i-- )
{
15 years ago
QwtArrowButton *btn =
new QwtArrowButton( i + 1, Qt::DownArrow, this );
btn->setFocusPolicy( Qt::NoFocus );
btn->installEventFilter( this );
layout->addWidget( btn );
15 years ago
connect( btn, SIGNAL( released() ), SLOT( btnReleased() ) );
connect( btn, SIGNAL( clicked() ), SLOT( btnClicked() ) );
15 years ago
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 );
15 years ago
connect( d_data->valueEdit, SIGNAL( editingFinished() ),
SLOT( textChanged() ) );
15 years ago
layout->setStretchFactor( d_data->valueEdit, 10 );
for ( int i = 0; i < ButtonCnt; i++ )
{
15 years ago
QwtArrowButton *btn =
new QwtArrowButton( i + 1, Qt::UpArrow, this );
btn->setFocusPolicy( Qt::NoFocus );
btn->installEventFilter( this );
layout->addWidget( btn );
15 years ago
connect( btn, SIGNAL( released() ), SLOT( btnReleased() ) );
connect( btn, SIGNAL( clicked() ), SLOT( btnClicked() ) );
15 years ago
d_data->buttonUp[i] = btn;
}
setNumButtons( 2 );
setRange( 0.0, 1.0 );
setSingleStep( 0.001 );
setValue( 0.0 );
15 years ago
setSizePolicy(
QSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed ) );
15 years ago
setFocusProxy( d_data->valueEdit );
setFocusPolicy( Qt::StrongFocus );
15 years ago
}
//! Destructor
QwtCounter::~QwtCounter()
{
delete d_data;
}
/*!
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();
}
15 years ago
/*!
\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.
15 years ago
*/
void QwtCounter::setValue( double value )
15 years ago
{
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();
15 years ago
Q_EMIT valueChanged( value );
15 years ago
}
}
15 years ago
/*!
\return Current value of the counter
\sa setValue(), valueChanged()
*/
double QwtCounter::value() const
{
return d_data->value;
15 years ago
}
/*!
\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 )
15 years ago
{
max = qMax( min, max );
if ( d_data->maximum == max && d_data->minimum == min )
15 years ago
return;
d_data->minimum = min;
d_data->maximum = max;
15 years ago
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();
15 years ago
}
/*!
Set the minimum value of the range
15 years ago
\param value Minimum value
\sa setRange(), setMaximum(), minimum()
\note The maximum is adjusted if necessary to ensure that the range remains valid.
15 years ago
*/
void QwtCounter::setMinimum( double value )
15 years ago
{
setRange( value, maximum() );
}
15 years ago
/*!
\return The minimum of the range
\sa setRange(), setMinimum(), maximum()
*/
double QwtCounter::minimum() const
{
return d_data->minimum;
15 years ago
}
/*!
Set the maximum value of the range
\param value Maximum value
\sa setRange(), setMinimum(), maximum()
*/
void QwtCounter::setMaximum( double value )
{
setRange( minimum(), value );
15 years ago
}
/*!
\return The maximum of the range
\sa setRange(), setMaximum(), minimum()
15 years ago
*/
double QwtCounter::maximum() const
15 years ago
{
return d_data->maximum;
15 years ago
}
/*!
\brief Set the step size of the counter
15 years ago
A value <= 0.0 disables stepping
\param stepSize Single step size
\sa singleStep()
15 years ago
*/
void QwtCounter::setSingleStep( double stepSize )
{
d_data->singleStep = qMax( stepSize, 0.0 );
}
15 years ago
/*!
\return Single step size
\sa setSingleStep()
*/
double QwtCounter::singleStep() const
15 years ago
{
return d_data->singleStep;
}
15 years ago
/*!
\brief En/Disable wrapping
15 years ago
If wrapping is true stepping up from maximum() value will take
you to the minimum() value and vice versa.
15 years ago
\param on En/Disable wrapping
\sa wrapping()
*/
void QwtCounter::setWrapping( bool on )
{
d_data->wrapping = on;
15 years ago
}
/*!
\return True, when wrapping is set
\sa setWrapping()
*/
bool QwtCounter::wrapping() const
15 years ago
{
return d_data->wrapping;
}
15 years ago
/*!
Specify the number of buttons on each side of the label
15 years ago
\param numButtons Number of buttons
\sa numButtons()
*/
void QwtCounter::setNumButtons( int numButtons )
{
if ( numButtons < 0 || numButtons > QwtCounter::ButtonCnt )
return;
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();
15 years ago
}
}
d_data->numButtons = numButtons;
}
15 years ago
/*!
\return The number of buttons on each side of the widget.
\sa setNumButtons()
*/
int QwtCounter::numButtons() const
{
return d_data->numButtons;
15 years ago
}
/*!
Specify the number of steps by which the value
is incremented or decremented when a specified button
is pushed.
\param button Button index
\param numSteps Number of steps
\sa incSteps()
15 years ago
*/
void QwtCounter::setIncSteps( QwtCounter::Button button, int numSteps )
15 years ago
{
if ( button >= 0 && button < QwtCounter::ButtonCnt )
d_data->increment[ button ] = numSteps;
15 years ago
}
/*!
\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()
15 years ago
*/
int QwtCounter::incSteps( QwtCounter::Button button ) const
15 years ago
{
if ( button >= 0 && button < QwtCounter::ButtonCnt )
return d_data->increment[ button ];
15 years ago
return 0;
}
15 years ago
/*!
Set the number of increment steps for button 1
\param nSteps Number of steps
15 years ago
*/
void QwtCounter::setStepButton1( int nSteps )
{
setIncSteps( QwtCounter::Button1, nSteps );
}
15 years ago
//! returns the number of increment steps for button 1
int QwtCounter::stepButton1() const
15 years ago
{
return incSteps( QwtCounter::Button1 );
}
15 years ago
/*!
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 );
15 years ago
}
/*!
Set the number of increment steps for button 3
\param nSteps Number of steps
15 years ago
*/
void QwtCounter::setStepButton3( int nSteps )
15 years ago
{
setIncSteps( QwtCounter::Button3, nSteps );
}
15 years ago
//! 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 );
}
15 years ago
/*!
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 );
15 years ago
}
/*!
Handle key events
15 years ago
- 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)
15 years ago
\param event Key event
15 years ago
*/
void QwtCounter::keyPressEvent ( QKeyEvent *event )
15 years ago
{
bool accepted = true;
15 years ago
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;
15 years ago
}
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;
15 years ago
}
}
if ( accepted )
{
event->accept();
return;
}
QWidget::keyPressEvent ( event );
15 years ago
}
/*!
Handle wheel events
\param event Wheel event
15 years ago
*/
void QwtCounter::wheelEvent( QWheelEvent *event )
15 years ago
{
event->accept();
if ( d_data->numButtons <= 0 )
15 years ago
return;
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;
15 years ago
}
else if ( value > max )
{
value -= ::ceil( ( value - max ) / range ) * range;
}
}
else
{
value = qBound( min, value, max );
15 years ago
}
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 );
}
15 years ago
}
15 years ago
/*!
\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).
15 years ago
*/
void QwtCounter::updateButtons()
{
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 );
}
}
15 years ago
}
/*!
Display number string
15 years ago
\param number Number
*/
void QwtCounter::showNumber( double number )
15 years ago
{
QString text;
text.setNum( number );
15 years ago
const int cursorPos = d_data->valueEdit->cursorPosition();
d_data->valueEdit->setText( text );
d_data->valueEdit->setCursorPosition( cursorPos );
15 years ago
}
//! Button clicked
void QwtCounter::btnClicked()
{
for ( int i = 0; i < ButtonCnt; i++ )
{
15 years ago
if ( d_data->buttonUp[i] == sender() )
incrementValue( d_data->increment[i] );
15 years ago
if ( d_data->buttonDown[i] == sender() )
incrementValue( -d_data->increment[i] );
15 years ago
}
}
//! Button released
void QwtCounter::btnReleased()
{
Q_EMIT buttonReleased( value() );
15 years ago
}
//! A size hint
QSize QwtCounter::sizeHint() const
{
QString tmp;
int w = tmp.setNum( minimum() ).length();
int w1 = tmp.setNum( maximum() ).length();
15 years ago
if ( w1 > w )
w = w1;
w1 = tmp.setNum( minimum() + singleStep() ).length();
15 years ago
if ( w1 > w )
w = w1;
w1 = tmp.setNum( maximum() - singleStep() ).length();
15 years ago
if ( w1 > w )
w = w1;
tmp.fill( '9', w );
15 years ago
QFontMetrics fm( d_data->valueEdit->font() );
w = fm.width( tmp ) + 2;
15 years ago
if ( d_data->valueEdit->hasFrame() )
w += 2 * style()->pixelMetric( QStyle::PM_DefaultFrameWidth );
15 years ago
// 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 = qMin( QWidget::sizeHint().height(),
d_data->valueEdit->minimumSizeHint().height() );
return QSize( w, h );
15 years ago
}