地面站终端 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.

823 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
*
15 years ago
* 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_abstract_slider.h"
#include "qwt_abstract_scale_draw.h"
15 years ago
#include "qwt_math.h"
#include "qwt_scale_map.h"
#include <qevent.h>
15 years ago
#if QT_VERSION < 0x040601
#define qFabs(x) ::fabs(x)
15 years ago
#endif
static double qwtAlignToScaleDiv(
const QwtAbstractSlider *slider, double value )
{
const QwtScaleDiv &sd = slider->scaleDiv();
const int tValue = slider->transform( value );
if ( tValue == slider->transform( sd.lowerBound() ) )
return sd.lowerBound();
if ( tValue == slider->transform( sd.lowerBound() ) )
return sd.upperBound();
for ( int i = 0; i < QwtScaleDiv::NTickTypes; i++ )
{
const QList<double> ticks = sd.ticks( i );
for ( int j = 0; j < ticks.size(); j++ )
{
if ( slider->transform( ticks[ j ] ) == tValue )
return ticks[ j ];
}
}
return value;
}
15 years ago
class QwtAbstractSlider::PrivateData
{
public:
PrivateData():
isScrolling( false ),
isTracking( true ),
pendingValueChanged( false ),
readOnly( false ),
totalSteps( 100 ),
singleSteps( 1 ),
pageSteps( 10 ),
stepAlignment( true ),
isValid( false ),
value( 0.0 ),
wrapping( false ),
invertedControls( false )
{
15 years ago
}
bool isScrolling;
bool isTracking;
bool pendingValueChanged;
15 years ago
bool readOnly;
uint totalSteps;
uint singleSteps;
uint pageSteps;
bool stepAlignment;
bool isValid;
double value;
bool wrapping;
bool invertedControls;
15 years ago
};
/*!
\brief Constructor
The scale is initialized to [0.0, 100.0], the
number of steps is set to 100 with 1 and 10 and single
an page step sizes. Step alignment is enabled.
The initial value is invalid.
15 years ago
\param parent Parent widget
15 years ago
*/
QwtAbstractSlider::QwtAbstractSlider( QWidget *parent ):
QwtAbstractScale( parent )
15 years ago
{
d_data = new QwtAbstractSlider::PrivateData;
setScale( 0.0, 100.0 );
setFocusPolicy( Qt::StrongFocus );
15 years ago
}
//! Destructor
QwtAbstractSlider::~QwtAbstractSlider()
{
delete d_data;
}
/*!
Set the value to be valid/invalid
\param on When true, the value is invalidated
\sa setValue()
*/
void QwtAbstractSlider::setValid( bool on )
{
if ( on != d_data->isValid )
{
d_data->isValid = on;
sliderChange();
Q_EMIT valueChanged( d_data->value );
}
}
//! \return True, when the value is invalid
bool QwtAbstractSlider::isValid() const
{
return d_data->isValid;
}
15 years ago
/*!
En/Disable read only mode
In read only mode the slider can't be controlled by mouse
or keyboard.
\param on Enables in case of true
15 years ago
\sa isReadOnly()
\warning The focus policy is set to Qt::StrongFocus or Qt::NoFocus
15 years ago
*/
void QwtAbstractSlider::setReadOnly( bool on )
15 years ago
{
if ( d_data->readOnly != on )
{
d_data->readOnly = on;
setFocusPolicy( on ? Qt::StrongFocus : Qt::NoFocus );
update();
}
15 years ago
}
/*!
In read only mode the slider can't be controlled by mouse
or keyboard.
\return true if read only
\sa setReadOnly()
*/
bool QwtAbstractSlider::isReadOnly() const
{
return d_data->readOnly;
}
/*!
\brief Enables or disables tracking.
15 years ago
If tracking is enabled, the slider emits the valueChanged()
signal while the movable part of the slider is being dragged.
If tracking is disabled, the slider emits the valueChanged() signal
only when the user releases the slider.
15 years ago
Tracking is enabled by default.
\param on \c true (enable) or \c false (disable) tracking.
15 years ago
\sa isTracking(), sliderMoved()
*/
void QwtAbstractSlider::setTracking( bool on )
15 years ago
{
d_data->isTracking = on;
15 years ago
}
/*!
\return True, when tracking has been enabled
\sa setTracking()
15 years ago
*/
bool QwtAbstractSlider::isTracking() const
15 years ago
{
return d_data->isTracking;
15 years ago
}
/*!
Mouse press event handler
\param event Mouse event
*/
void QwtAbstractSlider::mousePressEvent( QMouseEvent *event )
15 years ago
{
if ( isReadOnly() )
{
event->ignore();
15 years ago
return;
}
if ( !d_data->isValid || lowerBound() == upperBound() )
return;
d_data->isScrolling = isScrollPosition( event->pos() );
if ( d_data->isScrolling )
{
d_data->pendingValueChanged = false;
Q_EMIT sliderPressed();
15 years ago
}
}
/*!
Mouse Move Event handler
\param event Mouse event
*/
void QwtAbstractSlider::mouseMoveEvent( QMouseEvent *event )
15 years ago
{
if ( isReadOnly() )
{
event->ignore();
15 years ago
return;
}
if ( d_data->isValid && d_data->isScrolling )
{
double value = scrolledTo( event->pos() );
if ( value != d_data->value )
{
value = boundedValue( value );
15 years ago
if ( d_data->stepAlignment )
{
value = alignedValue( value );
}
else
{
value = qwtAlignToScaleDiv( this, value );
}
15 years ago
if ( value != d_data->value )
{
d_data->value = value;
15 years ago
sliderChange();
Q_EMIT sliderMoved( d_data->value );
if ( d_data->isTracking )
Q_EMIT valueChanged( d_data->value );
else
d_data->pendingValueChanged = true;
}
}
15 years ago
}
}
/*!
Mouse Release Event handler
\param event Mouse event
15 years ago
*/
void QwtAbstractSlider::mouseReleaseEvent( QMouseEvent *event )
15 years ago
{
if ( isReadOnly() )
{
event->ignore();
return;
}
15 years ago
if ( d_data->isScrolling && d_data->isValid )
{
d_data->isScrolling = false;
15 years ago
if ( d_data->pendingValueChanged )
Q_EMIT valueChanged( d_data->value );
15 years ago
Q_EMIT sliderReleased();
}
15 years ago
}
/*!
Wheel Event handler
In/decreases the value by s number of steps. The direction
depends on the invertedControls() property.
When the control or shift modifier is pressed the wheel delta
( divided by 120 ) is mapped to an increment according to
pageSteps(). Otherwise it is mapped to singleSteps().
\param event Wheel event
15 years ago
*/
void QwtAbstractSlider::wheelEvent( QWheelEvent *event )
15 years ago
{
if ( isReadOnly() )
{
event->ignore();
15 years ago
return;
}
if ( !d_data->isValid || d_data->isScrolling )
15 years ago
return;
int numSteps = 0;
15 years ago
if ( ( event->modifiers() & Qt::ControlModifier) ||
( event->modifiers() & Qt::ShiftModifier ) )
{
// one page regardless of delta
numSteps = d_data->pageSteps;
if ( event->delta() < 0 )
numSteps = -numSteps;
}
else
{
const int numTurns = ( event->delta() / 120 );
numSteps = numTurns * d_data->singleSteps;
15 years ago
}
if ( d_data->invertedControls )
numSteps = -numSteps;
15 years ago
const double value = incrementedValue( d_data->value, numSteps );
if ( value != d_data->value )
{
d_data->value = value;
sliderChange();
15 years ago
Q_EMIT sliderMoved( d_data->value );
Q_EMIT valueChanged( d_data->value );
15 years ago
}
}
/*!
Handles key events
QwtAbstractSlider handles the following keys:
- Qt::Key_Left\n
Add/Subtract singleSteps() in direction to lowerBound();
- Qt::Key_Right\n
Add/Subtract singleSteps() in direction to upperBound();
- Qt::Key_Down\n
Subtract singleSteps(), when invertedControls() is false
- Qt::Key_Up\n
Add singleSteps(), when invertedControls() is false
- Qt::Key_PageDown\n
Subtract pageSteps(), when invertedControls() is false
- Qt::Key_PageUp\n
Add pageSteps(), when invertedControls() is false
- Qt::Key_Home\n
Set the value to the minimum()
- Qt::Key_End\n
Set the value to the maximum()
\param event Key event
15 years ago
\sa isReadOnly()
*/
void QwtAbstractSlider::keyPressEvent( QKeyEvent *event )
15 years ago
{
if ( isReadOnly() )
{
event->ignore();
15 years ago
return;
}
if ( !d_data->isValid || d_data->isScrolling )
15 years ago
return;
int numSteps = 0;
double value = d_data->value;
15 years ago
switch ( event->key() )
{
case Qt::Key_Left:
{
numSteps = -static_cast<int>( d_data->singleSteps );
if ( isInverted() )
numSteps = -numSteps;
15 years ago
break;
}
case Qt::Key_Right:
{
numSteps = d_data->singleSteps;
if ( isInverted() )
numSteps = -numSteps;
15 years ago
break;
}
case Qt::Key_Down:
{
numSteps = -static_cast<int>( d_data->singleSteps );
if ( d_data->invertedControls )
numSteps = -numSteps;
break;
}
case Qt::Key_Up:
{
numSteps = d_data->singleSteps;
if ( d_data->invertedControls )
numSteps = -numSteps;
break;
}
case Qt::Key_PageUp:
{
numSteps = d_data->pageSteps;
if ( d_data->invertedControls )
numSteps = -numSteps;
break;
}
case Qt::Key_PageDown:
{
numSteps = -static_cast<int>( d_data->pageSteps );
if ( d_data->invertedControls )
numSteps = -numSteps;
break;
}
case Qt::Key_Home:
{
value = minimum();
break;
}
case Qt::Key_End:
{
value = maximum();
break;
}
default:;
{
event->ignore();
15 years ago
}
}
if ( numSteps != 0 )
{
value = incrementedValue( d_data->value, numSteps );
}
if ( value != d_data->value )
{
d_data->value = value;
sliderChange();
Q_EMIT sliderMoved( d_data->value );
Q_EMIT valueChanged( d_data->value );
15 years ago
}
}
15 years ago
/*!
\brief Set the number of steps
The range of the slider is divided into a number of steps from
which the value increments according to user inputs depend.
The default setting is 100.
\param stepCount Number of steps
\sa totalSteps(), setSingleSteps(), setPageSteps()
*/
void QwtAbstractSlider::setTotalSteps( uint stepCount )
{
d_data->totalSteps = stepCount;
15 years ago
}
/*!
\return Number of steps
\sa setTotalSteps(), singleSteps(), pageSteps()
*/
uint QwtAbstractSlider::totalSteps() const
{
return d_data->totalSteps;
}
15 years ago
/*!
\brief Set the number of steps for a single increment
15 years ago
The range of the slider is divided into a number of steps from
which the value increments according to user inputs depend.
\param stepCount Number of steps
\sa singleSteps(), setTotalSteps(), setPageSteps()
*/
void QwtAbstractSlider::setSingleSteps( uint stepCount )
15 years ago
{
d_data->singleSteps = stepCount;
}
15 years ago
/*!
\return Number of steps
\sa setSingleSteps(), totalSteps(), pageSteps()
*/
uint QwtAbstractSlider::singleSteps() const
{
return d_data->singleSteps;
}
/*!
\brief Set the number of steps for a page increment
The range of the slider is divided into a number of steps from
which the value increments according to user inputs depend.
\param stepCount Number of steps
\sa pageSteps(), setTotalSteps(), setSingleSteps()
*/
void QwtAbstractSlider::setPageSteps( uint stepCount )
{
d_data->pageSteps = stepCount;
}
15 years ago
/*!
\return Number of steps
\sa setPageSteps(), totalSteps(), singleSteps()
*/
uint QwtAbstractSlider::pageSteps() const
{
return d_data->pageSteps;
}
15 years ago
/*!
\brief Enable step alignment
15 years ago
When step alignment is enabled values resulting from slider
movements are aligned to the step size.
15 years ago
\param on Enable step alignment when true
\sa stepAlignment()
15 years ago
*/
void QwtAbstractSlider::setStepAlignment( bool on )
{
if ( on != d_data->stepAlignment )
{
d_data->stepAlignment = on;
}
}
/*!
\return True, when step alignment is enabled
\sa setStepAlignment()
*/
bool QwtAbstractSlider::stepAlignment() const
15 years ago
{
return d_data->stepAlignment;
15 years ago
}
/*!
Set the slider to the specified value
\param value New value
\sa setValid(), sliderChange(), valueChanged()
15 years ago
*/
void QwtAbstractSlider::setValue( double value )
{
value = qBound( minimum(), value, maximum() );
const bool changed = ( d_data->value != value ) || !d_data->isValid;
d_data->value = value;
d_data->isValid = true;
if ( changed )
{
sliderChange();
Q_EMIT valueChanged( d_data->value );
}
15 years ago
}
//! Returns the current value.
double QwtAbstractSlider::value() const
{
return d_data->value;
}
15 years ago
/*!
If wrapping is true stepping up from upperBound() value will
take you to the minimum() value and vice versa.
15 years ago
\param on En/Disable wrapping
\sa wrapping()
15 years ago
*/
void QwtAbstractSlider::setWrapping( bool on )
{
d_data->wrapping = on;
}
/*!
\return True, when wrapping is set
\sa setWrapping()
*/
bool QwtAbstractSlider::wrapping() const
15 years ago
{
return d_data->wrapping;
15 years ago
}
/*!
Invert wheel and key events
Usually scrolling the mouse wheel "up" and using keys like page
up will increase the slider's value towards its maximum.
When invertedControls() is enabled the value is scrolled
towards its minimum.
Inverting the controls might be f.e. useful for a vertical slider
with an inverted scale ( decreasing from top to bottom ).
\param on Invert controls, when true
\sa invertedControls(), keyEvent(), wheelEvent()
*/
void QwtAbstractSlider::setInvertedControls( bool on )
{
d_data->invertedControls = on;
}
/*!
\return True, when the controls are inverted
\sa setInvertedControls()
*/
bool QwtAbstractSlider::invertedControls() const
{
return d_data->invertedControls;
}
15 years ago
/*!
Increment the slider
15 years ago
The step size depends on the number of totalSteps()
\param stepCount Number of steps
\sa setTotalSteps(), incrementedValue()
*/
void QwtAbstractSlider::incrementValue( int stepCount )
15 years ago
{
const double value = incrementedValue(
d_data->value, stepCount );
if ( value != d_data->value )
{
d_data->value = value;
sliderChange();
}
15 years ago
}
/*!
Increment a value
\param value Value
\param stepCount Number of steps
\return Incremented value
*/
double QwtAbstractSlider::incrementedValue(
double value, int stepCount ) const
15 years ago
{
if ( d_data->totalSteps == 0 )
return value;
const QwtTransform *transformation =
scaleMap().transformation();
if ( transformation == NULL )
{
const double range = maximum() - minimum();
value += stepCount * range / d_data->totalSteps;
}
else
{
QwtScaleMap map = scaleMap();
map.setPaintInterval( 0, d_data->totalSteps );
// we need equidant steps according to
// paint device coordinates
const double range = transformation->transform( maximum() )
- transformation->transform( minimum() );
const double stepSize = range / d_data->totalSteps;
double v = transformation->transform( value );
v = qRound( v / stepSize ) * stepSize;
v += stepCount * range / d_data->totalSteps;
value = transformation->invTransform( v );
}
value = boundedValue( value );
if ( d_data->stepAlignment )
value = alignedValue( value );
return value;
}
double QwtAbstractSlider::boundedValue( double value ) const
{
const double vmin = minimum();
const double vmax = maximum();
if ( d_data->wrapping && vmin != vmax )
{
const int fullCircle = 360 * 16;
const double pd = scaleMap().pDist();
if ( int( pd / fullCircle ) * fullCircle == pd )
{
// full circle scales: min and max are the same
const double range = vmax - vmin;
if ( value < vmin )
{
value += ::ceil( ( vmin - value ) / range ) * range;
}
else if ( value > vmax )
{
value -= ::ceil( ( value - vmax ) / range ) * range;
}
}
else
{
if ( value < vmin )
value = vmax;
else if ( value > vmax )
value = vmin;
}
}
else
{
value = qBound( vmin, value, vmax );
}
return value;
15 years ago
}
double QwtAbstractSlider::alignedValue( double value ) const
15 years ago
{
if ( d_data->totalSteps == 0 )
return value;
double stepSize;
if ( scaleMap().transformation() == NULL )
{
stepSize = ( maximum() - minimum() ) / d_data->totalSteps;
if ( stepSize > 0.0 )
{
value = lowerBound() +
qRound( ( value - lowerBound() ) / stepSize ) * stepSize;
}
}
else
{
stepSize = ( scaleMap().p2() - scaleMap().p1() ) / d_data->totalSteps;
if ( stepSize > 0.0 )
{
double v = scaleMap().transform( value );
v = scaleMap().p1() +
qRound( ( v - scaleMap().p1() ) / stepSize ) * stepSize;
value = scaleMap().invTransform( v );
}
}
if ( qAbs( stepSize ) > 1e-12 )
{
if ( qFuzzyCompare( value + 1.0, 1.0 ) )
{
// correct rounding error if value = 0
value = 0.0;
}
else
{
// correct rounding error at the border
if ( qFuzzyCompare( value, upperBound() ) )
value = upperBound();
else if ( qFuzzyCompare( value, lowerBound() ) )
value = lowerBound();
}
}
return value;
}
15 years ago
/*!
Update the slider according to modifications of the scale
*/
void QwtAbstractSlider::scaleChange()
15 years ago
{
const double value = qBound( minimum(), d_data->value, maximum() );
const bool changed = ( value != d_data->value );
if ( changed )
{
d_data->value = value;
}
if ( d_data->isValid || changed )
Q_EMIT valueChanged( d_data->value );
updateGeometry();
update();
15 years ago
}
//! Calling update()
void QwtAbstractSlider::sliderChange()
15 years ago
{
update();
15 years ago
}