00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include "qwt_slider.h"
00011 #include "qwt_painter.h"
00012 #include "qwt_scale_draw.h"
00013 #include "qwt_scale_map.h"
00014 #include <qevent.h>
00015 #include <qdrawutil.h>
00016 #include <qpainter.h>
00017 #include <qalgorithms.h>
00018 #include <qmath.h>
00019 #include <qstyle.h>
00020 #include <qstyleoption.h>
00021 #include <qapplication.h>
00022
00023 static QSize qwtHandleSize( const QSize &size,
00024 Qt::Orientation orientation, bool hasTrough )
00025 {
00026 QSize handleSize = size;
00027
00028 if ( handleSize.isEmpty() )
00029 {
00030 const int handleThickness = 16;
00031 handleSize.setWidth( 2 * handleThickness );
00032 handleSize.setHeight( handleThickness );
00033
00034 if ( !hasTrough )
00035 handleSize.transpose();
00036
00037 if ( orientation == Qt::Vertical )
00038 handleSize.transpose();
00039 }
00040
00041 return handleSize;
00042 }
00043
00044 static QwtScaleDraw::Alignment qwtScaleDrawAlignment(
00045 Qt::Orientation orientation, QwtSlider::ScalePosition scalePos )
00046 {
00047 QwtScaleDraw::Alignment align;
00048
00049 if ( orientation == Qt::Vertical )
00050 {
00051
00052 if ( scalePos == QwtSlider::LeadingScale )
00053 align = QwtScaleDraw::RightScale;
00054 else
00055 align = QwtScaleDraw::LeftScale;
00056 }
00057 else
00058 {
00059
00060 if ( scalePos == QwtSlider::TrailingScale )
00061 align = QwtScaleDraw::TopScale;
00062 else
00063 align = QwtScaleDraw::BottomScale;
00064 }
00065
00066 return align;
00067 }
00068
00069 class QwtSlider::PrivateData
00070 {
00071 public:
00072 PrivateData():
00073 repeatTimerId( 0 ),
00074 updateInterval( 150 ),
00075 stepsIncrement( 0 ),
00076 pendingValueChange( false ),
00077 borderWidth( 2 ),
00078 spacing( 4 ),
00079 scalePosition( QwtSlider::TrailingScale ),
00080 hasTrough( true ),
00081 hasGroove( false ),
00082 mouseOffset( 0 )
00083 {
00084 }
00085
00086 int repeatTimerId;
00087 bool timerTick;
00088 int updateInterval;
00089 int stepsIncrement;
00090 bool pendingValueChange;
00091
00092 QRect sliderRect;
00093
00094 QSize handleSize;
00095 int borderWidth;
00096 int spacing;
00097
00098 Qt::Orientation orientation;
00099 QwtSlider::ScalePosition scalePosition;
00100
00101 bool hasTrough;
00102 bool hasGroove;
00103
00104 int mouseOffset;
00105
00106 mutable QSize sizeHintCache;
00107 };
00118 QwtSlider::QwtSlider( QWidget *parent ):
00119 QwtAbstractSlider( parent )
00120 {
00121 initSlider( Qt::Vertical );
00122 }
00123
00135 QwtSlider::QwtSlider( Qt::Orientation orientation, QWidget *parent ):
00136 QwtAbstractSlider( parent )
00137 {
00138 initSlider( orientation );
00139 }
00140
00142 QwtSlider::~QwtSlider()
00143 {
00144 delete d_data;
00145 }
00146
00147 void QwtSlider::initSlider( Qt::Orientation orientation )
00148 {
00149 if ( orientation == Qt::Vertical )
00150 setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Expanding );
00151 else
00152 setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed );
00153
00154 setAttribute( Qt::WA_WState_OwnSizePolicy, false );
00155
00156 d_data = new QwtSlider::PrivateData;
00157
00158 d_data->orientation = orientation;
00159
00160 scaleDraw()->setAlignment(
00161 qwtScaleDrawAlignment( orientation, d_data->scalePosition ) );
00162 scaleDraw()->setLength( 100 );
00163
00164 setScale( 0.0, 100.0 );
00165 setValue( 0.0 );
00166 }
00167
00174 void QwtSlider::setOrientation( Qt::Orientation orientation )
00175 {
00176 if ( orientation == d_data->orientation )
00177 return;
00178
00179 d_data->orientation = orientation;
00180
00181 scaleDraw()->setAlignment(
00182 qwtScaleDrawAlignment( orientation, d_data->scalePosition ) );
00183
00184 if ( !testAttribute( Qt::WA_WState_OwnSizePolicy ) )
00185 {
00186 QSizePolicy sp = sizePolicy();
00187 sp.transpose();
00188 setSizePolicy( sp );
00189
00190 setAttribute( Qt::WA_WState_OwnSizePolicy, false );
00191 }
00192
00193 if ( testAttribute( Qt::WA_WState_Polished ) )
00194 layoutSlider( true );
00195 }
00196
00201 Qt::Orientation QwtSlider::orientation() const
00202 {
00203 return d_data->orientation;
00204 }
00205
00212 void QwtSlider::setScalePosition( ScalePosition scalePosition )
00213 {
00214 if ( d_data->scalePosition == scalePosition )
00215 return;
00216
00217 d_data->scalePosition = scalePosition;
00218 scaleDraw()->setAlignment(
00219 qwtScaleDrawAlignment( d_data->orientation, scalePosition ) );
00220
00221 if ( testAttribute( Qt::WA_WState_Polished ) )
00222 layoutSlider( true );
00223 }
00224
00229 QwtSlider::ScalePosition QwtSlider::scalePosition() const
00230 {
00231 return d_data->scalePosition;
00232 }
00233
00243 void QwtSlider::setBorderWidth( int width )
00244 {
00245 if ( width < 0 )
00246 width = 0;
00247
00248 if ( width != d_data->borderWidth )
00249 {
00250 d_data->borderWidth = width;
00251
00252 if ( testAttribute( Qt::WA_WState_Polished ) )
00253 layoutSlider( true );
00254 }
00255 }
00256
00261 int QwtSlider::borderWidth() const
00262 {
00263 return d_data->borderWidth;
00264 }
00265
00277 void QwtSlider::setSpacing( int spacing )
00278 {
00279 if ( spacing <= 0 )
00280 spacing = 0;
00281
00282 if ( spacing != d_data->spacing )
00283 {
00284 d_data->spacing = spacing;
00285
00286 if ( testAttribute( Qt::WA_WState_Polished ) )
00287 layoutSlider( true );
00288 }
00289 }
00290
00295 int QwtSlider::spacing() const
00296 {
00297 return d_data->spacing;
00298 }
00299
00310 void QwtSlider::setHandleSize( const QSize &size )
00311 {
00312 if ( size != d_data->handleSize )
00313 {
00314 d_data->handleSize = size;
00315
00316 if ( testAttribute( Qt::WA_WState_Polished ) )
00317 layoutSlider( true );
00318 }
00319 }
00320
00325 QSize QwtSlider::handleSize() const
00326 {
00327 return d_data->handleSize;
00328 }
00329
00343 void QwtSlider::setScaleDraw( QwtScaleDraw *scaleDraw )
00344 {
00345 const QwtScaleDraw *previousScaleDraw = this->scaleDraw();
00346 if ( scaleDraw == NULL || scaleDraw == previousScaleDraw )
00347 return;
00348
00349 if ( previousScaleDraw )
00350 scaleDraw->setAlignment( previousScaleDraw->alignment() );
00351
00352 setAbstractScaleDraw( scaleDraw );
00353
00354 if ( testAttribute( Qt::WA_WState_Polished ) )
00355 layoutSlider( true );
00356 }
00357
00362 const QwtScaleDraw *QwtSlider::scaleDraw() const
00363 {
00364 return static_cast<const QwtScaleDraw *>( abstractScaleDraw() );
00365 }
00366
00371 QwtScaleDraw *QwtSlider::scaleDraw()
00372 {
00373 return static_cast<QwtScaleDraw *>( abstractScaleDraw() );
00374 }
00375
00377 void QwtSlider::scaleChange()
00378 {
00379 QwtAbstractSlider::scaleChange();
00380
00381 if ( testAttribute( Qt::WA_WState_Polished ) )
00382 layoutSlider( true );
00383 }
00384
00394 void QwtSlider::setUpdateInterval( int interval )
00395 {
00396 d_data->updateInterval = qMax( interval, 50 );
00397 }
00398
00403 int QwtSlider::updateInterval() const
00404 {
00405 return d_data->updateInterval;
00406 }
00407
00414 void QwtSlider::drawSlider(
00415 QPainter *painter, const QRect &sliderRect ) const
00416 {
00417 QRect innerRect( sliderRect );
00418
00419 if ( d_data->hasTrough )
00420 {
00421 const int bw = d_data->borderWidth;
00422 innerRect = sliderRect.adjusted( bw, bw, -bw, -bw );
00423
00424 painter->fillRect( innerRect, palette().brush( QPalette::Mid ) );
00425 qDrawShadePanel( painter, sliderRect, palette(), true, bw, NULL );
00426 }
00427
00428 if ( d_data->hasGroove )
00429 {
00430 const QSize handleSize = qwtHandleSize( d_data->handleSize,
00431 d_data->orientation, d_data->hasTrough );
00432
00433 const int slotExtent = 4;
00434 const int slotMargin = 4;
00435
00436 QRect slotRect;
00437 if ( orientation() == Qt::Horizontal )
00438 {
00439 int slotOffset = qMax( 1, handleSize.width() / 2 - slotMargin );
00440 int slotHeight = slotExtent + ( innerRect.height() % 2 );
00441
00442 slotRect.setWidth( innerRect.width() - 2 * slotOffset );
00443 slotRect.setHeight( slotHeight );
00444 }
00445 else
00446 {
00447 int slotOffset = qMax( 1, handleSize.height() / 2 - slotMargin );
00448 int slotWidth = slotExtent + ( innerRect.width() % 2 );
00449
00450 slotRect.setWidth( slotWidth );
00451 slotRect.setHeight( innerRect.height() - 2 * slotOffset );
00452
00453 }
00454
00455 slotRect.moveCenter( innerRect.center() );
00456
00457 QBrush brush = palette().brush( QPalette::Dark );
00458 qDrawShadePanel( painter, slotRect, palette(), true, 1 , &brush );
00459 }
00460
00461 if ( isValid() )
00462 drawHandle( painter, handleRect(), transform( value() ) );
00463 }
00464
00472 void QwtSlider::drawHandle( QPainter *painter,
00473 const QRect &handleRect, int pos ) const
00474 {
00475 const int bw = d_data->borderWidth;
00476
00477 qDrawShadePanel( painter,
00478 handleRect, palette(), false, bw,
00479 &palette().brush( QPalette::Button ) );
00480
00481 pos++;
00482 if ( orientation() == Qt::Horizontal )
00483 {
00484 qDrawShadeLine( painter, pos, handleRect.top() + bw,
00485 pos, handleRect.bottom() - bw, palette(), true, 1 );
00486 }
00487 else
00488 {
00489 qDrawShadeLine( painter, handleRect.left() + bw, pos,
00490 handleRect.right() - bw, pos, palette(), true, 1 );
00491 }
00492 }
00493
00502 bool QwtSlider::isScrollPosition( const QPoint &pos ) const
00503 {
00504 if ( handleRect().contains( pos ) )
00505 {
00506 const double v = ( orientation() == Qt::Horizontal )
00507 ? pos.x() : pos.y();
00508
00509 d_data->mouseOffset = v - transform( value() );
00510 return true;
00511 }
00512
00513 return false;
00514 }
00515
00525 double QwtSlider::scrolledTo( const QPoint &pos ) const
00526 {
00527 int p = ( orientation() == Qt::Horizontal )
00528 ? pos.x() : pos.y();
00529
00530 p -= d_data->mouseOffset;
00531
00532 int min = transform( lowerBound() );
00533 int max = transform( upperBound() );
00534 if ( min > max )
00535 qSwap( min, max );
00536
00537 p = qBound( min, p, max );
00538
00539 return scaleMap().invTransform( p );
00540 }
00541
00546 void QwtSlider::mousePressEvent( QMouseEvent *event )
00547 {
00548 if ( isReadOnly() )
00549 {
00550 event->ignore();
00551 return;
00552 }
00553
00554 const QPoint pos = event->pos();
00555
00556 if ( isValid() && d_data->sliderRect.contains( pos ) )
00557 {
00558 if ( !handleRect().contains( pos ) )
00559 {
00560 const int markerPos = transform( value() );
00561
00562 d_data->stepsIncrement = pageSteps();
00563
00564 if ( d_data->orientation == Qt::Horizontal )
00565 {
00566 if ( pos.x() < markerPos )
00567 d_data->stepsIncrement = -d_data->stepsIncrement;
00568 }
00569 else
00570 {
00571 if ( pos.y() < markerPos )
00572 d_data->stepsIncrement = -d_data->stepsIncrement;
00573 }
00574
00575 if ( isInverted() )
00576 d_data->stepsIncrement = -d_data->stepsIncrement;
00577
00578 const double v = value();
00579 incrementValue( d_data->stepsIncrement );
00580
00581 if ( v != value() )
00582 {
00583 if ( isTracking() )
00584 Q_EMIT valueChanged( value() );
00585 else
00586 d_data->pendingValueChange = true;
00587
00588 Q_EMIT sliderMoved( value() );
00589 }
00590
00591 d_data->timerTick = false;
00592 d_data->repeatTimerId = startTimer( qMax( 250, 2 * updateInterval() ) );
00593
00594 return;
00595 }
00596 }
00597
00598 QwtAbstractSlider::mousePressEvent( event );
00599 }
00600
00605 void QwtSlider::mouseReleaseEvent( QMouseEvent *event )
00606 {
00607 if ( d_data->repeatTimerId > 0 )
00608 {
00609 killTimer( d_data->repeatTimerId );
00610 d_data->repeatTimerId = 0;
00611 d_data->timerTick = false;
00612 d_data->stepsIncrement = 0;
00613 }
00614
00615 if ( d_data->pendingValueChange )
00616 {
00617 d_data->pendingValueChange = false;
00618 Q_EMIT valueChanged( value() );
00619 }
00620
00621 QwtAbstractSlider::mouseReleaseEvent( event );
00622 }
00623
00632 void QwtSlider::timerEvent( QTimerEvent *event )
00633 {
00634 if ( event->timerId() != d_data->repeatTimerId )
00635 {
00636 QwtAbstractSlider::timerEvent( event );
00637 return;
00638 }
00639
00640 if ( !isValid() )
00641 {
00642 killTimer( d_data->repeatTimerId );
00643 d_data->repeatTimerId = 0;
00644 return;
00645 }
00646
00647 const double v = value();
00648 incrementValue( d_data->stepsIncrement );
00649
00650 if ( v != value() )
00651 {
00652 if ( isTracking() )
00653 Q_EMIT valueChanged( value() );
00654 else
00655 d_data->pendingValueChange = true;
00656
00657 Q_EMIT sliderMoved( value() );
00658 }
00659
00660 if ( !d_data->timerTick )
00661 {
00662
00663 killTimer( d_data->repeatTimerId );
00664 d_data->repeatTimerId = startTimer( updateInterval() );
00665
00666 d_data->timerTick = true;
00667 }
00668 }
00669
00674 void QwtSlider::paintEvent( QPaintEvent *event )
00675 {
00676 QPainter painter( this );
00677 painter.setClipRegion( event->region() );
00678
00679 QStyleOption opt;
00680 opt.init(this);
00681 style()->drawPrimitive(QStyle::PE_Widget, &opt, &painter, this);
00682
00683 if ( d_data->scalePosition != QwtSlider::NoScale )
00684 {
00685 if ( !d_data->sliderRect.contains( event->rect() ) )
00686 scaleDraw()->draw( &painter, palette() );
00687 }
00688
00689 drawSlider( &painter, d_data->sliderRect );
00690
00691 if ( hasFocus() )
00692 QwtPainter::drawFocusRect( &painter, this, d_data->sliderRect );
00693 }
00694
00699 void QwtSlider::resizeEvent( QResizeEvent *event )
00700 {
00701 layoutSlider( false );
00702 QwtAbstractSlider::resizeEvent( event );
00703 }
00704
00711 bool QwtSlider::event( QEvent *event )
00712 {
00713 if ( event->type() == QEvent::PolishRequest )
00714 layoutSlider( false );
00715
00716 return QwtAbstractSlider::event( event );
00717 }
00718
00723 void QwtSlider::changeEvent( QEvent *event )
00724 {
00725 if ( event->type() == QEvent::StyleChange ||
00726 event->type() == QEvent::FontChange )
00727 {
00728 if ( testAttribute( Qt::WA_WState_Polished ) )
00729 layoutSlider( true );
00730 }
00731
00732 QwtAbstractSlider::changeEvent( event );
00733 }
00734
00742 void QwtSlider::layoutSlider( bool update_geometry )
00743 {
00744 int bw = 0;
00745 if ( d_data->hasTrough )
00746 bw = d_data->borderWidth;
00747
00748 const QSize handleSize = qwtHandleSize( d_data->handleSize,
00749 d_data->orientation, d_data->hasTrough );
00750
00751 QRect sliderRect = contentsRect();
00752
00753
00754
00755
00756
00757
00758
00759
00760
00761
00762
00763
00764
00765
00766 int scaleMargin = 0;
00767 if ( d_data->scalePosition != QwtSlider::NoScale )
00768 {
00769 int d1, d2;
00770 scaleDraw()->getBorderDistHint( font(), d1, d2 );
00771
00772 scaleMargin = qMax( d1, d2 ) - bw;
00773 }
00774
00775 int scaleX, scaleY, scaleLength;
00776
00777 if ( d_data->orientation == Qt::Horizontal )
00778 {
00779 const int handleMargin = handleSize.width() / 2 - 1;
00780 if ( scaleMargin > handleMargin )
00781 {
00782 int off = scaleMargin - handleMargin;
00783 sliderRect.adjust( off, 0, -off, 0 );
00784 }
00785
00786 scaleX = sliderRect.left() + bw + handleSize.width() / 2 - 1;
00787 scaleLength = sliderRect.width() - handleSize.width();
00788 }
00789 else
00790 {
00791 int handleMargin = handleSize.height() / 2 - 1;
00792 if ( scaleMargin > handleMargin )
00793 {
00794 int off = scaleMargin - handleMargin;
00795 sliderRect.adjust( 0, off, 0, -off );
00796 }
00797
00798 scaleY = sliderRect.top() + bw + handleSize.height() / 2 - 1;
00799 scaleLength = sliderRect.height() - handleSize.height();
00800 }
00801
00802 scaleLength -= 2 * bw;
00803
00804
00805
00806 if ( d_data->orientation == Qt::Horizontal )
00807 {
00808 const int h = handleSize.height() + 2 * bw;
00809
00810 if ( d_data->scalePosition == QwtSlider::TrailingScale )
00811 {
00812 sliderRect.setTop( sliderRect.bottom() + 1 - h );
00813 scaleY = sliderRect.top() - d_data->spacing;
00814 }
00815 else
00816 {
00817 sliderRect.setHeight( h );
00818 scaleY = sliderRect.bottom() + 1 + d_data->spacing;
00819 }
00820 }
00821 else
00822 {
00823 const int w = handleSize.width() + 2 * bw;
00824
00825 if ( d_data->scalePosition == QwtSlider::LeadingScale )
00826 {
00827 sliderRect.setWidth( w );
00828 scaleX = sliderRect.right() + 1 + d_data->spacing;
00829 }
00830 else
00831 {
00832 sliderRect.setLeft( sliderRect.right() + 1 - w );
00833 scaleX = sliderRect.left() - d_data->spacing;
00834 }
00835 }
00836
00837 d_data->sliderRect = sliderRect;
00838
00839 scaleDraw()->move( scaleX, scaleY );
00840 scaleDraw()->setLength( scaleLength );
00841
00842 if ( update_geometry )
00843 {
00844 d_data->sizeHintCache = QSize();
00845 updateGeometry();
00846 update();
00847 }
00848 }
00849
00859 void QwtSlider::setTrough( bool on )
00860 {
00861 if ( d_data->hasTrough != on )
00862 {
00863 d_data->hasTrough = on;
00864
00865 if ( testAttribute( Qt::WA_WState_Polished ) )
00866 layoutSlider( true );
00867 }
00868 }
00869
00874 bool QwtSlider::hasTrough() const
00875 {
00876 return d_data->hasTrough;
00877 }
00878
00888 void QwtSlider::setGroove( bool on )
00889 {
00890 if ( d_data->hasGroove != on )
00891 {
00892 d_data->hasGroove = on;
00893
00894 if ( testAttribute( Qt::WA_WState_Polished ) )
00895 layoutSlider( true );
00896 }
00897 }
00898
00903 bool QwtSlider::hasGroove() const
00904 {
00905 return d_data->hasGroove;
00906 }
00907
00911 QSize QwtSlider::sizeHint() const
00912 {
00913 const QSize hint = minimumSizeHint();
00914 return hint.expandedTo( QApplication::globalStrut() );
00915 }
00916
00921 QSize QwtSlider::minimumSizeHint() const
00922 {
00923 if ( !d_data->sizeHintCache.isEmpty() )
00924 return d_data->sizeHintCache;
00925
00926 const QSize handleSize = qwtHandleSize( d_data->handleSize,
00927 d_data->orientation, d_data->hasTrough );
00928
00929 int bw = 0;
00930 if ( d_data->hasTrough )
00931 bw = d_data->borderWidth;
00932
00933 int sliderLength = 0;
00934 int scaleExtent = 0;
00935
00936 if ( d_data->scalePosition != QwtSlider::NoScale )
00937 {
00938 int d1, d2;
00939 scaleDraw()->getBorderDistHint( font(), d1, d2 );
00940
00941 const int scaleBorderDist = 2 * ( qMax( d1, d2 ) - bw );
00942
00943 int handleBorderDist;
00944 if ( d_data->orientation == Qt::Horizontal )
00945 handleBorderDist = handleSize.width();
00946 else
00947 handleBorderDist = handleSize.height();
00948
00949 sliderLength = scaleDraw()->minLength( font() );
00950 if ( handleBorderDist > scaleBorderDist )
00951 {
00952
00953 sliderLength += handleBorderDist - scaleBorderDist;
00954 }
00955
00956 scaleExtent += d_data->spacing;
00957 scaleExtent += qCeil( scaleDraw()->extent( font() ) );
00958 }
00959
00960 sliderLength = qMax( sliderLength, 84 );
00961
00962 int w = 0;
00963 int h = 0;
00964
00965 if ( d_data->orientation == Qt::Horizontal )
00966 {
00967 w = sliderLength;
00968 h = handleSize.height() + 2 * bw + scaleExtent;
00969 }
00970 else
00971 {
00972 w = handleSize.width() + 2 * bw + scaleExtent;
00973 h = sliderLength;
00974 }
00975
00976
00977 int left, right, top, bottom;
00978 getContentsMargins( &left, &top, &right, &bottom );
00979
00980 w += left + right;
00981 h += top + bottom;
00982
00983 d_data->sizeHintCache = QSize( w, h );
00984 return d_data->sizeHintCache;
00985 }
00986
00990 QRect QwtSlider::handleRect() const
00991 {
00992 if ( !isValid() )
00993 return QRect();
00994
00995 const int markerPos = transform( value() );
00996
00997 QPoint center = d_data->sliderRect.center();
00998 if ( d_data->orientation == Qt::Horizontal )
00999 center.setX( markerPos );
01000 else
01001 center.setY( markerPos );
01002
01003 QRect rect;
01004 rect.setSize( qwtHandleSize( d_data->handleSize,
01005 d_data->orientation, d_data->hasTrough ) );
01006 rect.moveCenter( center );
01007
01008 return rect;
01009 }
01010
01014 QRect QwtSlider::sliderRect() const
01015 {
01016 return d_data->sliderRect;
01017 }