823 lines
18 KiB
C++
823 lines
18 KiB
C++
|
/* -*- 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_abstract_slider.h"
|
||
|
#include "qwt_abstract_scale_draw.h"
|
||
|
#include "qwt_math.h"
|
||
|
#include "qwt_scale_map.h"
|
||
|
#include <qevent.h>
|
||
|
|
||
|
#if QT_VERSION < 0x040601
|
||
|
#define qFabs(x) ::fabs(x)
|
||
|
#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.upperBound() ) )
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
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 )
|
||
|
{
|
||
|
}
|
||
|
|
||
|
bool isScrolling;
|
||
|
bool isTracking;
|
||
|
bool pendingValueChanged;
|
||
|
|
||
|
bool readOnly;
|
||
|
|
||
|
uint totalSteps;
|
||
|
uint singleSteps;
|
||
|
uint pageSteps;
|
||
|
bool stepAlignment;
|
||
|
|
||
|
bool isValid;
|
||
|
double value;
|
||
|
|
||
|
bool wrapping;
|
||
|
bool invertedControls;
|
||
|
};
|
||
|
|
||
|
/*!
|
||
|
\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.
|
||
|
|
||
|
\param parent Parent widget
|
||
|
*/
|
||
|
QwtAbstractSlider::QwtAbstractSlider( QWidget *parent ):
|
||
|
QwtAbstractScale( parent )
|
||
|
{
|
||
|
d_data = new QwtAbstractSlider::PrivateData;
|
||
|
|
||
|
setScale( 0.0, 100.0 );
|
||
|
setFocusPolicy( Qt::StrongFocus );
|
||
|
}
|
||
|
|
||
|
//! 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;
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
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
|
||
|
\sa isReadOnly()
|
||
|
|
||
|
\warning The focus policy is set to Qt::StrongFocus or Qt::NoFocus
|
||
|
*/
|
||
|
void QwtAbstractSlider::setReadOnly( bool on )
|
||
|
{
|
||
|
if ( d_data->readOnly != on )
|
||
|
{
|
||
|
d_data->readOnly = on;
|
||
|
setFocusPolicy( on ? Qt::StrongFocus : Qt::NoFocus );
|
||
|
|
||
|
update();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
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.
|
||
|
|
||
|
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.
|
||
|
|
||
|
Tracking is enabled by default.
|
||
|
\param on \c true (enable) or \c false (disable) tracking.
|
||
|
|
||
|
\sa isTracking(), sliderMoved()
|
||
|
*/
|
||
|
void QwtAbstractSlider::setTracking( bool on )
|
||
|
{
|
||
|
d_data->isTracking = on;
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
\return True, when tracking has been enabled
|
||
|
\sa setTracking()
|
||
|
*/
|
||
|
bool QwtAbstractSlider::isTracking() const
|
||
|
{
|
||
|
return d_data->isTracking;
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
Mouse press event handler
|
||
|
\param event Mouse event
|
||
|
*/
|
||
|
void QwtAbstractSlider::mousePressEvent( QMouseEvent *event )
|
||
|
{
|
||
|
if ( isReadOnly() )
|
||
|
{
|
||
|
event->ignore();
|
||
|
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();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
Mouse Move Event handler
|
||
|
\param event Mouse event
|
||
|
*/
|
||
|
void QwtAbstractSlider::mouseMoveEvent( QMouseEvent *event )
|
||
|
{
|
||
|
if ( isReadOnly() )
|
||
|
{
|
||
|
event->ignore();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if ( d_data->isValid && d_data->isScrolling )
|
||
|
{
|
||
|
double value = scrolledTo( event->pos() );
|
||
|
if ( value != d_data->value )
|
||
|
{
|
||
|
value = boundedValue( value );
|
||
|
|
||
|
if ( d_data->stepAlignment )
|
||
|
{
|
||
|
value = alignedValue( value );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
value = qwtAlignToScaleDiv( this, value );
|
||
|
}
|
||
|
|
||
|
if ( value != d_data->value )
|
||
|
{
|
||
|
d_data->value = value;
|
||
|
|
||
|
sliderChange();
|
||
|
|
||
|
Q_EMIT sliderMoved( d_data->value );
|
||
|
|
||
|
if ( d_data->isTracking )
|
||
|
Q_EMIT valueChanged( d_data->value );
|
||
|
else
|
||
|
d_data->pendingValueChanged = true;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
Mouse Release Event handler
|
||
|
\param event Mouse event
|
||
|
*/
|
||
|
void QwtAbstractSlider::mouseReleaseEvent( QMouseEvent *event )
|
||
|
{
|
||
|
if ( isReadOnly() )
|
||
|
{
|
||
|
event->ignore();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if ( d_data->isScrolling && d_data->isValid )
|
||
|
{
|
||
|
d_data->isScrolling = false;
|
||
|
|
||
|
if ( d_data->pendingValueChanged )
|
||
|
Q_EMIT valueChanged( d_data->value );
|
||
|
|
||
|
Q_EMIT sliderReleased();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
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
|
||
|
*/
|
||
|
void QwtAbstractSlider::wheelEvent( QWheelEvent *event )
|
||
|
{
|
||
|
if ( isReadOnly() )
|
||
|
{
|
||
|
event->ignore();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if ( !d_data->isValid || d_data->isScrolling )
|
||
|
return;
|
||
|
|
||
|
int numSteps = 0;
|
||
|
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
if ( d_data->invertedControls )
|
||
|
numSteps = -numSteps;
|
||
|
|
||
|
const double 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 );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
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
|
||
|
\sa isReadOnly()
|
||
|
*/
|
||
|
void QwtAbstractSlider::keyPressEvent( QKeyEvent *event )
|
||
|
{
|
||
|
if ( isReadOnly() )
|
||
|
{
|
||
|
event->ignore();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if ( !d_data->isValid || d_data->isScrolling )
|
||
|
return;
|
||
|
|
||
|
int numSteps = 0;
|
||
|
double value = d_data->value;
|
||
|
|
||
|
switch ( event->key() )
|
||
|
{
|
||
|
case Qt::Key_Left:
|
||
|
{
|
||
|
numSteps = -static_cast<int>( d_data->singleSteps );
|
||
|
if ( isInverted() )
|
||
|
numSteps = -numSteps;
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
case Qt::Key_Right:
|
||
|
{
|
||
|
numSteps = d_data->singleSteps;
|
||
|
if ( isInverted() )
|
||
|
numSteps = -numSteps;
|
||
|
|
||
|
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();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
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 );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
\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;
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
\return Number of steps
|
||
|
\sa setTotalSteps(), singleSteps(), pageSteps()
|
||
|
*/
|
||
|
uint QwtAbstractSlider::totalSteps() const
|
||
|
{
|
||
|
return d_data->totalSteps;
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
\brief Set the number of steps for a single 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 singleSteps(), setTotalSteps(), setPageSteps()
|
||
|
*/
|
||
|
|
||
|
void QwtAbstractSlider::setSingleSteps( uint stepCount )
|
||
|
{
|
||
|
d_data->singleSteps = stepCount;
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
\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;
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
\return Number of steps
|
||
|
\sa setPageSteps(), totalSteps(), singleSteps()
|
||
|
*/
|
||
|
uint QwtAbstractSlider::pageSteps() const
|
||
|
{
|
||
|
return d_data->pageSteps;
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
\brief Enable step alignment
|
||
|
|
||
|
When step alignment is enabled values resulting from slider
|
||
|
movements are aligned to the step size.
|
||
|
|
||
|
\param on Enable step alignment when true
|
||
|
\sa stepAlignment()
|
||
|
*/
|
||
|
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
|
||
|
{
|
||
|
return d_data->stepAlignment;
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
Set the slider to the specified value
|
||
|
|
||
|
\param value New value
|
||
|
\sa setValid(), sliderChange(), valueChanged()
|
||
|
*/
|
||
|
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 );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//! Returns the current value.
|
||
|
double QwtAbstractSlider::value() const
|
||
|
{
|
||
|
return d_data->value;
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
If wrapping is true stepping up from upperBound() value will
|
||
|
take you to the minimum() value and vice versa.
|
||
|
|
||
|
\param on En/Disable wrapping
|
||
|
\sa wrapping()
|
||
|
*/
|
||
|
void QwtAbstractSlider::setWrapping( bool on )
|
||
|
{
|
||
|
d_data->wrapping = on;
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
\return True, when wrapping is set
|
||
|
\sa setWrapping()
|
||
|
*/
|
||
|
bool QwtAbstractSlider::wrapping() const
|
||
|
{
|
||
|
return d_data->wrapping;
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
Increment the slider
|
||
|
|
||
|
The step size depends on the number of totalSteps()
|
||
|
|
||
|
\param stepCount Number of steps
|
||
|
\sa setTotalSteps(), incrementedValue()
|
||
|
*/
|
||
|
void QwtAbstractSlider::incrementValue( int stepCount )
|
||
|
{
|
||
|
const double value = incrementedValue(
|
||
|
d_data->value, stepCount );
|
||
|
|
||
|
if ( value != d_data->value )
|
||
|
{
|
||
|
d_data->value = value;
|
||
|
sliderChange();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
Increment a value
|
||
|
|
||
|
\param value Value
|
||
|
\param stepCount Number of steps
|
||
|
|
||
|
\return Incremented value
|
||
|
*/
|
||
|
double QwtAbstractSlider::incrementedValue(
|
||
|
double value, int stepCount ) const
|
||
|
{
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
double QwtAbstractSlider::alignedValue( double value ) const
|
||
|
{
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
Update the slider according to modifications of the scale
|
||
|
*/
|
||
|
void QwtAbstractSlider::scaleChange()
|
||
|
{
|
||
|
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();
|
||
|
}
|
||
|
|
||
|
//! Calling update()
|
||
|
void QwtAbstractSlider::sliderChange()
|
||
|
{
|
||
|
update();
|
||
|
}
|