Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include "qwt_abstract_slider.h"
00011 #include "qwt_abstract_scale_draw.h"
00012 #include "qwt_math.h"
00013 #include "qwt_scale_map.h"
00014 #include <qevent.h>
00015
00016 #if QT_VERSION < 0x040601
00017 #define qFabs(x) ::fabs(x)
00018 #endif
00019
00020 static double qwtAlignToScaleDiv(
00021 const QwtAbstractSlider *slider, double value )
00022 {
00023 const QwtScaleDiv &sd = slider->scaleDiv();
00024
00025 const int tValue = slider->transform( value );
00026
00027 if ( tValue == slider->transform( sd.lowerBound() ) )
00028 return sd.lowerBound();
00029
00030 if ( tValue == slider->transform( sd.lowerBound() ) )
00031 return sd.upperBound();
00032
00033 for ( int i = 0; i < QwtScaleDiv::NTickTypes; i++ )
00034 {
00035 const QList<double> ticks = sd.ticks( i );
00036 for ( int j = 0; j < ticks.size(); j++ )
00037 {
00038 if ( slider->transform( ticks[ j ] ) == tValue )
00039 return ticks[ j ];
00040 }
00041 }
00042
00043 return value;
00044 }
00045
00046 class QwtAbstractSlider::PrivateData
00047 {
00048 public:
00049 PrivateData():
00050 isScrolling( false ),
00051 isTracking( true ),
00052 pendingValueChanged( false ),
00053 readOnly( false ),
00054 totalSteps( 100 ),
00055 singleSteps( 1 ),
00056 pageSteps( 10 ),
00057 stepAlignment( true ),
00058 isValid( false ),
00059 value( 0.0 ),
00060 wrapping( false ),
00061 invertedControls( false )
00062 {
00063 }
00064
00065 bool isScrolling;
00066 bool isTracking;
00067 bool pendingValueChanged;
00068
00069 bool readOnly;
00070
00071 uint totalSteps;
00072 uint singleSteps;
00073 uint pageSteps;
00074 bool stepAlignment;
00075
00076 bool isValid;
00077 double value;
00078
00079 bool wrapping;
00080 bool invertedControls;
00081 };
00082
00094 QwtAbstractSlider::QwtAbstractSlider( QWidget *parent ):
00095 QwtAbstractScale( parent )
00096 {
00097 d_data = new QwtAbstractSlider::PrivateData;
00098
00099 setScale( 0.0, 100.0 );
00100 setFocusPolicy( Qt::StrongFocus );
00101 }
00102
00104 QwtAbstractSlider::~QwtAbstractSlider()
00105 {
00106 delete d_data;
00107 }
00108
00116 void QwtAbstractSlider::setValid( bool on )
00117 {
00118 if ( on != d_data->isValid )
00119 {
00120 d_data->isValid = on;
00121 sliderChange();
00122
00123 Q_EMIT valueChanged( d_data->value );
00124 }
00125 }
00126
00128 bool QwtAbstractSlider::isValid() const
00129 {
00130 return d_data->isValid;
00131 }
00132
00144 void QwtAbstractSlider::setReadOnly( bool on )
00145 {
00146 if ( d_data->readOnly != on )
00147 {
00148 d_data->readOnly = on;
00149 setFocusPolicy( on ? Qt::StrongFocus : Qt::NoFocus );
00150
00151 update();
00152 }
00153 }
00154
00162 bool QwtAbstractSlider::isReadOnly() const
00163 {
00164 return d_data->readOnly;
00165 }
00166
00180 void QwtAbstractSlider::setTracking( bool on )
00181 {
00182 d_data->isTracking = on;
00183 }
00184
00189 bool QwtAbstractSlider::isTracking() const
00190 {
00191 return d_data->isTracking;
00192 }
00193
00198 void QwtAbstractSlider::mousePressEvent( QMouseEvent *event )
00199 {
00200 if ( isReadOnly() )
00201 {
00202 event->ignore();
00203 return;
00204 }
00205
00206 if ( !d_data->isValid || lowerBound() == upperBound() )
00207 return;
00208
00209 d_data->isScrolling = isScrollPosition( event->pos() );
00210
00211 if ( d_data->isScrolling )
00212 {
00213 d_data->pendingValueChanged = false;
00214
00215 Q_EMIT sliderPressed();
00216 }
00217 }
00218
00223 void QwtAbstractSlider::mouseMoveEvent( QMouseEvent *event )
00224 {
00225 if ( isReadOnly() )
00226 {
00227 event->ignore();
00228 return;
00229 }
00230
00231 if ( d_data->isValid && d_data->isScrolling )
00232 {
00233 double value = scrolledTo( event->pos() );
00234 if ( value != d_data->value )
00235 {
00236 value = boundedValue( value );
00237
00238 if ( d_data->stepAlignment )
00239 {
00240 value = alignedValue( value );
00241 }
00242 else
00243 {
00244 value = qwtAlignToScaleDiv( this, value );
00245 }
00246
00247 if ( value != d_data->value )
00248 {
00249 d_data->value = value;
00250
00251 sliderChange();
00252
00253 Q_EMIT sliderMoved( d_data->value );
00254
00255 if ( d_data->isTracking )
00256 Q_EMIT valueChanged( d_data->value );
00257 else
00258 d_data->pendingValueChanged = true;
00259 }
00260 }
00261 }
00262 }
00263
00268 void QwtAbstractSlider::mouseReleaseEvent( QMouseEvent *event )
00269 {
00270 if ( isReadOnly() )
00271 {
00272 event->ignore();
00273 return;
00274 }
00275
00276 if ( d_data->isScrolling && d_data->isValid )
00277 {
00278 d_data->isScrolling = false;
00279
00280 if ( d_data->pendingValueChanged )
00281 Q_EMIT valueChanged( d_data->value );
00282
00283 Q_EMIT sliderReleased();
00284 }
00285 }
00286
00299 void QwtAbstractSlider::wheelEvent( QWheelEvent *event )
00300 {
00301 if ( isReadOnly() )
00302 {
00303 event->ignore();
00304 return;
00305 }
00306
00307 if ( !d_data->isValid || d_data->isScrolling )
00308 return;
00309
00310 int numSteps = 0;
00311
00312 if ( ( event->modifiers() & Qt::ControlModifier) ||
00313 ( event->modifiers() & Qt::ShiftModifier ) )
00314 {
00315
00316 numSteps = d_data->pageSteps;
00317 if ( event->delta() < 0 )
00318 numSteps = -numSteps;
00319 }
00320 else
00321 {
00322 const int numTurns = ( event->delta() / 120 );
00323 numSteps = numTurns * d_data->singleSteps;
00324 }
00325
00326 if ( d_data->invertedControls )
00327 numSteps = -numSteps;
00328
00329 const double value = incrementedValue( d_data->value, numSteps );
00330 if ( value != d_data->value )
00331 {
00332 d_data->value = value;
00333 sliderChange();
00334
00335 Q_EMIT sliderMoved( d_data->value );
00336 Q_EMIT valueChanged( d_data->value );
00337 }
00338 }
00339
00365 void QwtAbstractSlider::keyPressEvent( QKeyEvent *event )
00366 {
00367 if ( isReadOnly() )
00368 {
00369 event->ignore();
00370 return;
00371 }
00372
00373 if ( !d_data->isValid || d_data->isScrolling )
00374 return;
00375
00376 int numSteps = 0;
00377 double value = d_data->value;
00378
00379 switch ( event->key() )
00380 {
00381 case Qt::Key_Left:
00382 {
00383 numSteps = -static_cast<int>( d_data->singleSteps );
00384 if ( isInverted() )
00385 numSteps = -numSteps;
00386
00387 break;
00388 }
00389 case Qt::Key_Right:
00390 {
00391 numSteps = d_data->singleSteps;
00392 if ( isInverted() )
00393 numSteps = -numSteps;
00394
00395 break;
00396 }
00397 case Qt::Key_Down:
00398 {
00399 numSteps = -static_cast<int>( d_data->singleSteps );
00400 if ( d_data->invertedControls )
00401 numSteps = -numSteps;
00402 break;
00403 }
00404 case Qt::Key_Up:
00405 {
00406 numSteps = d_data->singleSteps;
00407 if ( d_data->invertedControls )
00408 numSteps = -numSteps;
00409
00410 break;
00411 }
00412 case Qt::Key_PageUp:
00413 {
00414 numSteps = d_data->pageSteps;
00415 if ( d_data->invertedControls )
00416 numSteps = -numSteps;
00417 break;
00418 }
00419 case Qt::Key_PageDown:
00420 {
00421 numSteps = -static_cast<int>( d_data->pageSteps );
00422 if ( d_data->invertedControls )
00423 numSteps = -numSteps;
00424 break;
00425 }
00426 case Qt::Key_Home:
00427 {
00428 value = minimum();
00429 break;
00430 }
00431 case Qt::Key_End:
00432 {
00433 value = maximum();
00434 break;
00435 }
00436 default:;
00437 {
00438 event->ignore();
00439 }
00440 }
00441
00442 if ( numSteps != 0 )
00443 {
00444 value = incrementedValue( d_data->value, numSteps );
00445 }
00446
00447 if ( value != d_data->value )
00448 {
00449 d_data->value = value;
00450 sliderChange();
00451
00452 Q_EMIT sliderMoved( d_data->value );
00453 Q_EMIT valueChanged( d_data->value );
00454 }
00455 }
00456
00469 void QwtAbstractSlider::setTotalSteps( uint stepCount )
00470 {
00471 d_data->totalSteps = stepCount;
00472 }
00473
00478 uint QwtAbstractSlider::totalSteps() const
00479 {
00480 return d_data->totalSteps;
00481 }
00482
00494 void QwtAbstractSlider::setSingleSteps( uint stepCount )
00495 {
00496 d_data->singleSteps = stepCount;
00497 }
00498
00503 uint QwtAbstractSlider::singleSteps() const
00504 {
00505 return d_data->singleSteps;
00506 }
00507
00519 void QwtAbstractSlider::setPageSteps( uint stepCount )
00520 {
00521 d_data->pageSteps = stepCount;
00522 }
00523
00528 uint QwtAbstractSlider::pageSteps() const
00529 {
00530 return d_data->pageSteps;
00531 }
00532
00542 void QwtAbstractSlider::setStepAlignment( bool on )
00543 {
00544 if ( on != d_data->stepAlignment )
00545 {
00546 d_data->stepAlignment = on;
00547 }
00548 }
00549
00554 bool QwtAbstractSlider::stepAlignment() const
00555 {
00556 return d_data->stepAlignment;
00557 }
00558
00565 void QwtAbstractSlider::setValue( double value )
00566 {
00567 value = qBound( minimum(), value, maximum() );
00568
00569 const bool changed = ( d_data->value != value ) || !d_data->isValid;
00570
00571 d_data->value = value;
00572 d_data->isValid = true;
00573
00574 if ( changed )
00575 {
00576 sliderChange();
00577 Q_EMIT valueChanged( d_data->value );
00578 }
00579 }
00580
00582 double QwtAbstractSlider::value() const
00583 {
00584 return d_data->value;
00585 }
00586
00594 void QwtAbstractSlider::setWrapping( bool on )
00595 {
00596 d_data->wrapping = on;
00597 }
00598
00603 bool QwtAbstractSlider::wrapping() const
00604 {
00605 return d_data->wrapping;
00606 }
00607
00623 void QwtAbstractSlider::setInvertedControls( bool on )
00624 {
00625 d_data->invertedControls = on;
00626 }
00627
00632 bool QwtAbstractSlider::invertedControls() const
00633 {
00634 return d_data->invertedControls;
00635 }
00636
00645 void QwtAbstractSlider::incrementValue( int stepCount )
00646 {
00647 const double value = incrementedValue(
00648 d_data->value, stepCount );
00649
00650 if ( value != d_data->value )
00651 {
00652 d_data->value = value;
00653 sliderChange();
00654 }
00655 }
00656
00665 double QwtAbstractSlider::incrementedValue(
00666 double value, int stepCount ) const
00667 {
00668 if ( d_data->totalSteps == 0 )
00669 return value;
00670
00671 const QwtTransform *transformation =
00672 scaleMap().transformation();
00673
00674 if ( transformation == NULL )
00675 {
00676 const double range = maximum() - minimum();
00677 value += stepCount * range / d_data->totalSteps;
00678 }
00679 else
00680 {
00681 QwtScaleMap map = scaleMap();
00682 map.setPaintInterval( 0, d_data->totalSteps );
00683
00684
00685
00686 const double range = transformation->transform( maximum() )
00687 - transformation->transform( minimum() );
00688
00689 const double stepSize = range / d_data->totalSteps;
00690
00691 double v = transformation->transform( value );
00692
00693 v = qRound( v / stepSize ) * stepSize;
00694 v += stepCount * range / d_data->totalSteps;
00695
00696 value = transformation->invTransform( v );
00697 }
00698
00699 value = boundedValue( value );
00700
00701 if ( d_data->stepAlignment )
00702 value = alignedValue( value );
00703
00704 return value;
00705 }
00706
00707 double QwtAbstractSlider::boundedValue( double value ) const
00708 {
00709 const double vmin = minimum();
00710 const double vmax = maximum();
00711
00712 if ( d_data->wrapping && vmin != vmax )
00713 {
00714 const int fullCircle = 360 * 16;
00715
00716 const double pd = scaleMap().pDist();
00717 if ( int( pd / fullCircle ) * fullCircle == pd )
00718 {
00719
00720 const double range = vmax - vmin;
00721
00722 if ( value < vmin )
00723 {
00724 value += ::ceil( ( vmin - value ) / range ) * range;
00725 }
00726 else if ( value > vmax )
00727 {
00728 value -= ::ceil( ( value - vmax ) / range ) * range;
00729 }
00730 }
00731 else
00732 {
00733 if ( value < vmin )
00734 value = vmax;
00735 else if ( value > vmax )
00736 value = vmin;
00737 }
00738 }
00739 else
00740 {
00741 value = qBound( vmin, value, vmax );
00742 }
00743
00744 return value;
00745 }
00746
00747 double QwtAbstractSlider::alignedValue( double value ) const
00748 {
00749 if ( d_data->totalSteps == 0 )
00750 return value;
00751
00752 double stepSize;
00753
00754 if ( scaleMap().transformation() == NULL )
00755 {
00756 stepSize = ( maximum() - minimum() ) / d_data->totalSteps;
00757 if ( stepSize > 0.0 )
00758 {
00759 value = lowerBound() +
00760 qRound( ( value - lowerBound() ) / stepSize ) * stepSize;
00761 }
00762 }
00763 else
00764 {
00765 stepSize = ( scaleMap().p2() - scaleMap().p1() ) / d_data->totalSteps;
00766
00767 if ( stepSize > 0.0 )
00768 {
00769 double v = scaleMap().transform( value );
00770
00771 v = scaleMap().p1() +
00772 qRound( ( v - scaleMap().p1() ) / stepSize ) * stepSize;
00773
00774 value = scaleMap().invTransform( v );
00775 }
00776 }
00777
00778 if ( qAbs( stepSize ) > 1e-12 )
00779 {
00780 if ( qFuzzyCompare( value + 1.0, 1.0 ) )
00781 {
00782
00783 value = 0.0;
00784 }
00785 else
00786 {
00787
00788 if ( qFuzzyCompare( value, upperBound() ) )
00789 value = upperBound();
00790 else if ( qFuzzyCompare( value, lowerBound() ) )
00791 value = lowerBound();
00792 }
00793 }
00794
00795 return value;
00796 }
00797
00801 void QwtAbstractSlider::scaleChange()
00802 {
00803 const double value = qBound( minimum(), d_data->value, maximum() );
00804
00805 const bool changed = ( value != d_data->value );
00806 if ( changed )
00807 {
00808 d_data->value = value;
00809 }
00810
00811 if ( d_data->isValid || changed )
00812 Q_EMIT valueChanged( d_data->value );
00813
00814 updateGeometry();
00815 update();
00816 }
00817
00819 void QwtAbstractSlider::sliderChange()
00820 {
00821 update();
00822 }