123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597 |
- /* -*- 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_math.h"
- #include <qevent.h>
- #include <qdatetime.h>
- #if QT_VERSION < 0x040601
- #define qFabs(x) ::fabs(x)
- #define qExp(x) ::exp(x)
- #endif
- class QwtAbstractSlider::PrivateData
- {
- public:
- PrivateData():
- scrollMode( ScrNone ),
- mouseOffset( 0.0 ),
- tracking( true ),
- tmrID( 0 ),
- updTime( 150 ),
- mass( 0.0 ),
- readOnly( false )
- {
- }
- int scrollMode;
- double mouseOffset;
- int direction;
- int tracking;
- int tmrID;
- int updTime;
- int timerTick;
- QTime time;
- double speed;
- double mass;
- Qt::Orientation orientation;
- bool readOnly;
- };
- /*!
- \brief Constructor
- \param orientation Orientation
- \param parent Parent widget
- */
- QwtAbstractSlider::QwtAbstractSlider(
- Qt::Orientation orientation, QWidget *parent ):
- QWidget( parent, NULL )
- {
- d_data = new QwtAbstractSlider::PrivateData;
- d_data->orientation = orientation;
- setFocusPolicy( Qt::TabFocus );
- }
- //! Destructor
- QwtAbstractSlider::~QwtAbstractSlider()
- {
- if ( d_data->tmrID )
- killTimer( d_data->tmrID );
- delete d_data;
- }
- /*!
- En/Disable read only mode
- In read only mode the slider can't be controlled by mouse
- or keyboard.
- \param readOnly Enables in case of true
- \sa isReadOnly()
- */
- void QwtAbstractSlider::setReadOnly( bool readOnly )
- {
- d_data->readOnly = readOnly;
- 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 Set the orientation.
- \param o Orientation. Allowed values are
- Qt::Horizontal and Qt::Vertical.
- */
- void QwtAbstractSlider::setOrientation( Qt::Orientation o )
- {
- d_data->orientation = o;
- }
- /*!
- \return Orientation
- \sa setOrientation()
- */
- Qt::Orientation QwtAbstractSlider::orientation() const
- {
- return d_data->orientation;
- }
- //! Stop updating if automatic scrolling is active
- void QwtAbstractSlider::stopMoving()
- {
- if ( d_data->tmrID )
- {
- killTimer( d_data->tmrID );
- d_data->tmrID = 0;
- }
- }
- /*!
- \brief Specify the update interval for automatic scrolling
- \param t update interval in milliseconds
- \sa getScrollMode()
- */
- void QwtAbstractSlider::setUpdateTime( int t )
- {
- if ( t < 50 )
- t = 50;
- d_data->updTime = t;
- }
- /*!
- Mouse press event handler
- \param e Mouse event
- */
- void QwtAbstractSlider::mousePressEvent( QMouseEvent *e )
- {
- if ( isReadOnly() )
- {
- e->ignore();
- return;
- }
- if ( !isValid() )
- return;
- const QPoint &p = e->pos();
- d_data->timerTick = 0;
- getScrollMode( p, d_data->scrollMode, d_data->direction );
- stopMoving();
- switch ( d_data->scrollMode )
- {
- case ScrPage:
- case ScrTimer:
- d_data->mouseOffset = 0;
- d_data->tmrID = startTimer( qMax( 250, 2 * d_data->updTime ) );
- break;
- case ScrMouse:
- d_data->time.start();
- d_data->speed = 0;
- d_data->mouseOffset = getValue( p ) - value();
- Q_EMIT sliderPressed();
- break;
- default:
- d_data->mouseOffset = 0;
- d_data->direction = 0;
- break;
- }
- }
- //! Emits a valueChanged() signal if necessary
- void QwtAbstractSlider::buttonReleased()
- {
- if ( ( !d_data->tracking ) || ( value() != prevValue() ) )
- Q_EMIT valueChanged( value() );
- }
- /*!
- Mouse Release Event handler
- \param e Mouse event
- */
- void QwtAbstractSlider::mouseReleaseEvent( QMouseEvent *e )
- {
- if ( isReadOnly() )
- {
- e->ignore();
- return;
- }
- if ( !isValid() )
- return;
- const double inc = step();
- switch ( d_data->scrollMode )
- {
- case ScrMouse:
- {
- setPosition( e->pos() );
- d_data->direction = 0;
- d_data->mouseOffset = 0;
- if ( d_data->mass > 0.0 )
- {
- const int ms = d_data->time.elapsed();
- if ( ( qFabs( d_data->speed ) > 0.0 ) && ( ms < 50 ) )
- d_data->tmrID = startTimer( d_data->updTime );
- }
- else
- {
- d_data->scrollMode = ScrNone;
- buttonReleased();
- }
- Q_EMIT sliderReleased();
- break;
- }
- case ScrDirect:
- {
- setPosition( e->pos() );
- d_data->direction = 0;
- d_data->mouseOffset = 0;
- d_data->scrollMode = ScrNone;
- buttonReleased();
- break;
- }
- case ScrPage:
- {
- stopMoving();
- if ( !d_data->timerTick )
- QwtDoubleRange::incPages( d_data->direction );
- d_data->timerTick = 0;
- buttonReleased();
- d_data->scrollMode = ScrNone;
- break;
- }
- case ScrTimer:
- {
- stopMoving();
- if ( !d_data->timerTick )
- QwtDoubleRange::fitValue( value() + double( d_data->direction ) * inc );
- d_data->timerTick = 0;
- buttonReleased();
- d_data->scrollMode = ScrNone;
- break;
- }
- default:
- {
- d_data->scrollMode = ScrNone;
- buttonReleased();
- }
- }
- }
- /*!
- Move the slider to a specified point, adjust the value
- and emit signals if necessary.
- */
- void QwtAbstractSlider::setPosition( const QPoint &p )
- {
- QwtDoubleRange::fitValue( getValue( p ) - d_data->mouseOffset );
- }
- /*!
- \brief Enables or disables tracking.
- If tracking is enabled, the slider emits a
- valueChanged() signal whenever its value
- changes (the default behaviour). If tracking
- is disabled, the value changed() signal will only
- be emitted if:<ul>
- <li>the user releases the mouse
- button and the value has changed or
- <li>at the end of automatic scrolling.</ul>
- Tracking is enabled by default.
- \param enable \c true (enable) or \c false (disable) tracking.
- */
- void QwtAbstractSlider::setTracking( bool enable )
- {
- d_data->tracking = enable;
- }
- /*!
- Mouse Move Event handler
- \param e Mouse event
- */
- void QwtAbstractSlider::mouseMoveEvent( QMouseEvent *e )
- {
- if ( isReadOnly() )
- {
- e->ignore();
- return;
- }
- if ( !isValid() )
- return;
- if ( d_data->scrollMode == ScrMouse )
- {
- setPosition( e->pos() );
- if ( d_data->mass > 0.0 )
- {
- double ms = double( d_data->time.elapsed() );
- if ( ms < 1.0 )
- ms = 1.0;
- d_data->speed = ( exactValue() - exactPrevValue() ) / ms;
- d_data->time.start();
- }
- if ( value() != prevValue() )
- Q_EMIT sliderMoved( value() );
- }
- }
- /*!
- Wheel Event handler
- \param e Whell event
- */
- void QwtAbstractSlider::wheelEvent( QWheelEvent *e )
- {
- if ( isReadOnly() )
- {
- e->ignore();
- return;
- }
- if ( !isValid() )
- return;
- int mode = ScrNone, direction = 0;
- // Give derived classes a chance to say ScrNone
- getScrollMode( e->pos(), mode, direction );
- if ( mode != ScrNone )
- {
- // Most mouse types work in steps of 15 degrees, in which case
- // the delta value is a multiple of 120
- const int inc = e->delta() / 120;
- QwtDoubleRange::incPages( inc );
- if ( value() != prevValue() )
- Q_EMIT sliderMoved( value() );
- }
- }
- /*!
- Handles key events
- - Key_Down, KeyLeft\n
- Decrement by 1
- - Key_Up, Key_Right\n
- Increment by 1
- \param e Key event
- \sa isReadOnly()
- */
- void QwtAbstractSlider::keyPressEvent( QKeyEvent *e )
- {
- if ( isReadOnly() )
- {
- e->ignore();
- return;
- }
- if ( !isValid() )
- return;
- int increment = 0;
- switch ( e->key() )
- {
- case Qt::Key_Down:
- if ( orientation() == Qt::Vertical )
- increment = -1;
- break;
- case Qt::Key_Up:
- if ( orientation() == Qt::Vertical )
- increment = 1;
- break;
- case Qt::Key_Left:
- if ( orientation() == Qt::Horizontal )
- increment = -1;
- break;
- case Qt::Key_Right:
- if ( orientation() == Qt::Horizontal )
- increment = 1;
- break;
- default:;
- e->ignore();
- }
- if ( increment != 0 )
- {
- QwtDoubleRange::incValue( increment );
- if ( value() != prevValue() )
- Q_EMIT sliderMoved( value() );
- }
- }
- /*!
- Qt timer event
- \param e Timer event
- */
- void QwtAbstractSlider::timerEvent( QTimerEvent * )
- {
- const double inc = step();
- switch ( d_data->scrollMode )
- {
- case ScrMouse:
- {
- if ( d_data->mass > 0.0 )
- {
- d_data->speed *= qExp( - double( d_data->updTime ) * 0.001 / d_data->mass );
- const double newval =
- exactValue() + d_data->speed * double( d_data->updTime );
- QwtDoubleRange::fitValue( newval );
- // stop if d_data->speed < one step per second
- if ( qFabs( d_data->speed ) < 0.001 * qFabs( step() ) )
- {
- d_data->speed = 0;
- stopMoving();
- buttonReleased();
- }
- }
- else
- stopMoving();
- break;
- }
- case ScrPage:
- {
- QwtDoubleRange::incPages( d_data->direction );
- if ( !d_data->timerTick )
- {
- killTimer( d_data->tmrID );
- d_data->tmrID = startTimer( d_data->updTime );
- }
- break;
- }
- case ScrTimer:
- {
- QwtDoubleRange::fitValue( value() + double( d_data->direction ) * inc );
- if ( !d_data->timerTick )
- {
- killTimer( d_data->tmrID );
- d_data->tmrID = startTimer( d_data->updTime );
- }
- break;
- }
- default:
- {
- stopMoving();
- break;
- }
- }
- d_data->timerTick = 1;
- }
- /*!
- Notify change of value
- This function can be reimplemented by derived classes
- in order to keep track of changes, i.e. repaint the widget.
- The default implementation emits a valueChanged() signal
- if tracking is enabled.
- */
- void QwtAbstractSlider::valueChange()
- {
- if ( d_data->tracking )
- Q_EMIT valueChanged( value() );
- }
- /*!
- \brief Set the slider's mass for flywheel effect.
- If the slider's mass is greater then 0, it will continue
- to move after the mouse button has been released. Its speed
- decreases with time at a rate depending on the slider's mass.
- A large mass means that it will continue to move for a
- long time.
- Derived widgets may overload this function to make it public.
- \param val New mass in kg
- \bug If the mass is smaller than 1g, it is set to zero.
- The maximal mass is limited to 100kg.
- \sa mass()
- */
- void QwtAbstractSlider::setMass( double val )
- {
- if ( val < 0.001 )
- d_data->mass = 0.0;
- else if ( val > 100.0 )
- d_data->mass = 100.0;
- else
- d_data->mass = val;
- }
- /*!
- \return mass
- \sa setMass()
- */
- double QwtAbstractSlider::mass() const
- {
- return d_data->mass;
- }
- /*!
- \brief Move the slider to a specified value
- This function can be used to move the slider to a value
- which is not an integer multiple of the step size.
- \param val new value
- \sa fitValue()
- */
- void QwtAbstractSlider::setValue( double val )
- {
- if ( d_data->scrollMode == ScrMouse )
- stopMoving();
- QwtDoubleRange::setValue( val );
- }
- /*!
- \brief Set the slider's value to the nearest integer multiple
- of the step size.
- \param value Value
- \sa setValue(), incValue()
- */
- void QwtAbstractSlider::fitValue( double value )
- {
- if ( d_data->scrollMode == ScrMouse )
- stopMoving();
- QwtDoubleRange::fitValue( value );
- }
- /*!
- \brief Increment the value by a specified number of steps
- \param steps number of steps
- \sa setValue()
- */
- void QwtAbstractSlider::incValue( int steps )
- {
- if ( d_data->scrollMode == ScrMouse )
- stopMoving();
- QwtDoubleRange::incValue( steps );
- }
- /*!
- \sa mouseOffset()
- */
- void QwtAbstractSlider::setMouseOffset( double offset )
- {
- d_data->mouseOffset = offset;
- }
- /*!
- \sa setMouseOffset()
- */
- double QwtAbstractSlider::mouseOffset() const
- {
- return d_data->mouseOffset;
- }
- //! sa ScrollMode
- int QwtAbstractSlider::scrollMode() const
- {
- return d_data->scrollMode;
- }
|