qwt_dial.cpp
Go to the documentation of this file.
00001 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
00002  * Qwt Widget Library
00003  * Copyright (C) 1997   Josef Wilgen
00004  * Copyright (C) 2002   Uwe Rathmann
00005  *
00006  * This library is free software; you can redistribute it and/or
00007  * modify it under the terms of the Qwt License, Version 1.0
00008  *****************************************************************************/
00009 
00010 #include "qwt_dial.h"
00011 #include "qwt_dial_needle.h"
00012 #include "qwt_math.h"
00013 #include "qwt_scale_engine.h"
00014 #include "qwt_scale_map.h"
00015 #include "qwt_round_scale_draw.h"
00016 #include "qwt_painter.h"
00017 #include <qpainter.h>
00018 #include <qpalette.h>
00019 #include <qpixmap.h>
00020 #include <qevent.h>
00021 #include <qalgorithms.h>
00022 #include <qmath.h>
00023 #include <qstyle.h>
00024 #include <qstyleoption.h>
00025 #include <qapplication.h>
00026 
00027 static inline double qwtAngleDist( double a1, double a2 )
00028 {
00029     double dist = qAbs( a2 - a1 );
00030     if ( dist > 360.0 )
00031         dist -= 360.0;
00032 
00033     return dist;
00034 }
00035 
00036 static inline bool qwtIsOnArc( double angle, double min, double max )
00037 {
00038     if ( min < max )
00039     {
00040         return ( angle >= min ) && ( angle <= max );
00041     }
00042     else
00043     {
00044         return ( angle >= min ) || ( angle <= max );
00045     }
00046 }
00047 
00048 static inline double qwtBoundedAngle( double min, double angle, double max )
00049 {
00050     double from = qwtNormalizeDegrees( min );
00051     double to = qwtNormalizeDegrees( max );
00052 
00053     double a;
00054 
00055     if ( qwtIsOnArc( angle, from, to ) )
00056     {
00057         a = angle;
00058         if ( a < min )
00059             a += 360.0;
00060     }
00061     else
00062     {
00063         if ( qwtAngleDist( angle, from ) <
00064             qwtAngleDist( angle, to ) )
00065         {
00066             a = min;
00067         }
00068         else
00069         {
00070             a = max;
00071         }
00072     }
00073 
00074     return a;
00075 }
00076 
00077 class QwtDial::PrivateData
00078 {
00079 public:
00080     PrivateData():
00081         frameShadow( Sunken ),
00082         lineWidth( 0 ),
00083         mode( RotateNeedle ),
00084         origin( 90.0 ),
00085         minScaleArc( 0.0 ),
00086         maxScaleArc( 0.0 ),
00087         needle( NULL ),
00088         arcOffset( 0.0 ),
00089         mouseOffset( 0.0 )
00090     {
00091     }
00092 
00093     ~PrivateData()
00094     {
00095         delete needle;
00096     }
00097     Shadow frameShadow;
00098     int lineWidth;
00099 
00100     QwtDial::Mode mode;
00101 
00102     double origin;
00103     double minScaleArc;
00104     double maxScaleArc;
00105 
00106     QwtDialNeedle *needle;
00107 
00108     double arcOffset;
00109     double mouseOffset;
00110 
00111     QPixmap pixmapCache;
00112 };
00113 
00126 QwtDial::QwtDial( QWidget* parent ):
00127     QwtAbstractSlider( parent )
00128 {
00129     d_data = new PrivateData;
00130 
00131     setFocusPolicy( Qt::TabFocus );
00132 
00133     QPalette p = palette();
00134     for ( int i = 0; i < QPalette::NColorGroups; i++ )
00135     {
00136         const QPalette::ColorGroup colorGroup =
00137             static_cast<QPalette::ColorGroup>( i );
00138 
00139         // Base: background color of the circle inside the frame.
00140         // WindowText: background color of the circle inside the scale
00141 
00142         p.setColor( colorGroup, QPalette::WindowText,
00143             p.color( colorGroup, QPalette::Base ) );
00144     }
00145     setPalette( p );
00146 
00147     QwtRoundScaleDraw* scaleDraw = new QwtRoundScaleDraw();
00148     scaleDraw->setRadius( 0 );
00149 
00150     setScaleDraw( scaleDraw );
00151 
00152     setScaleArc( 0.0, 360.0 ); // scale as a full circle
00153 
00154     setScaleMaxMajor( 10 );
00155     setScaleMaxMinor( 5 );
00156 
00157     setValue( 0.0 );
00158 }
00159 
00161 QwtDial::~QwtDial()
00162 {
00163     delete d_data;
00164 }
00165 
00172 void QwtDial::setFrameShadow( Shadow shadow )
00173 {
00174     if ( shadow != d_data->frameShadow )
00175     {
00176         invalidateCache();
00177 
00178         d_data->frameShadow = shadow;
00179         if ( lineWidth() > 0 )
00180             update();
00181     }
00182 }
00183 
00188 QwtDial::Shadow QwtDial::frameShadow() const
00189 {
00190     return d_data->frameShadow;
00191 }
00192 
00199 void QwtDial::setLineWidth( int lineWidth )
00200 {
00201     if ( lineWidth < 0 )
00202         lineWidth = 0;
00203 
00204     if ( d_data->lineWidth != lineWidth )
00205     {
00206         invalidateCache();
00207 
00208         d_data->lineWidth = lineWidth;
00209         update();
00210     }
00211 }
00212 
00217 int QwtDial::lineWidth() const
00218 {
00219     return d_data->lineWidth;
00220 }
00221 
00226 QRect QwtDial::innerRect() const
00227 {
00228     const int lw = lineWidth();
00229     return boundingRect().adjusted( lw, lw, -lw, -lw );
00230 }
00231 
00236 QRect QwtDial::boundingRect() const
00237 {
00238     const QRect cr = contentsRect();
00239 
00240     const double dim = qMin( cr.width(), cr.height() );
00241 
00242     QRect inner( 0, 0, dim, dim );
00243     inner.moveCenter( cr.center() );
00244 
00245     return inner;
00246 }
00247 
00252 QRect QwtDial::scaleInnerRect() const
00253 {
00254     QRect rect = innerRect();
00255 
00256     const QwtAbstractScaleDraw *sd = scaleDraw();
00257     if ( sd )
00258     {
00259         int scaleDist = qCeil( sd->extent( font() ) );
00260         scaleDist++; // margin
00261 
00262         rect.adjust( scaleDist, scaleDist, -scaleDist, -scaleDist );
00263     }
00264 
00265     return rect;
00266 }
00267 
00280 void QwtDial::setMode( Mode mode )
00281 {
00282     if ( mode != d_data->mode )
00283     {
00284         invalidateCache();
00285 
00286         d_data->mode = mode;
00287         sliderChange();
00288     }
00289 }
00290 
00295 QwtDial::Mode QwtDial::mode() const
00296 {
00297     return d_data->mode;
00298 }
00299 
00303 void QwtDial::invalidateCache()
00304 {
00305     d_data->pixmapCache = QPixmap();
00306 }
00307 
00312 void QwtDial::paintEvent( QPaintEvent *event )
00313 {
00314     QPainter painter( this );
00315     painter.setClipRegion( event->region() );
00316 
00317     QStyleOption opt;
00318     opt.init(this);
00319     style()->drawPrimitive(QStyle::PE_Widget, &opt, &painter, this);
00320 
00321     if ( d_data->mode == QwtDial::RotateScale )
00322     {
00323         painter.save();
00324         painter.setRenderHint( QPainter::Antialiasing, true );
00325 
00326         drawContents( &painter );
00327 
00328         painter.restore();
00329     }
00330 
00331     const QRect r = contentsRect();
00332     if ( r.size() != d_data->pixmapCache.size() )
00333     {
00334         d_data->pixmapCache = QwtPainter::backingStore( this, r.size() );
00335         d_data->pixmapCache.fill( Qt::transparent );
00336 
00337         QPainter p( &d_data->pixmapCache );
00338         p.setRenderHint( QPainter::Antialiasing, true );
00339         p.translate( -r.topLeft() );
00340             
00341         if ( d_data->mode != QwtDial::RotateScale )
00342             drawContents( &p );
00343 
00344         if ( lineWidth() > 0 )
00345             drawFrame( &p );
00346 
00347         if ( d_data->mode != QwtDial::RotateNeedle )
00348             drawNeedle( &p );
00349     }
00350 
00351     painter.drawPixmap( r.topLeft(), d_data->pixmapCache );
00352 
00353     if ( d_data->mode == QwtDial::RotateNeedle )
00354         drawNeedle( &painter );
00355 
00356     if ( hasFocus() )
00357         drawFocusIndicator( &painter );
00358 }
00359 
00364 void QwtDial::drawFocusIndicator( QPainter *painter ) const
00365 {
00366     QwtPainter::drawFocusRect( painter, this, boundingRect() );
00367 }
00368 
00375 void QwtDial::drawFrame( QPainter *painter )
00376 {
00377     QwtPainter::drawRoundFrame( painter, boundingRect(),
00378         palette(), lineWidth(), d_data->frameShadow );
00379 }
00380 
00393 void QwtDial::drawContents( QPainter *painter ) const
00394 {
00395     if ( testAttribute( Qt::WA_NoSystemBackground ) ||
00396         palette().brush( QPalette::Base ) !=
00397             palette().brush( QPalette::Window ) )
00398     {
00399         const QRectF br = boundingRect();
00400 
00401         painter->save();
00402         painter->setPen( Qt::NoPen );
00403         painter->setBrush( palette().brush( QPalette::Base ) );
00404         painter->drawEllipse( br );
00405         painter->restore();
00406     }
00407 
00408     const QRectF insideScaleRect = scaleInnerRect();
00409     if ( palette().brush( QPalette::WindowText ) !=
00410             palette().brush( QPalette::Base ) )
00411     {
00412         painter->save();
00413         painter->setPen( Qt::NoPen );
00414         painter->setBrush( palette().brush( QPalette::WindowText ) );
00415         painter->drawEllipse( insideScaleRect );
00416         painter->restore();
00417     }
00418 
00419     const QPointF center = insideScaleRect.center();
00420     const double radius = 0.5 * insideScaleRect.width();
00421 
00422     painter->save();
00423     drawScale( painter, center, radius );
00424     painter->restore();
00425 
00426     painter->save();
00427     drawScaleContents( painter, center, radius );
00428     painter->restore();
00429 }
00430 
00440 void QwtDial::drawNeedle( QPainter *painter, const QPointF &center,
00441     double radius, double direction, QPalette::ColorGroup colorGroup ) const
00442 {
00443     if ( d_data->needle )
00444     {
00445         direction = 360.0 - direction; // counter clockwise
00446         d_data->needle->draw( painter, center, radius, direction, colorGroup );
00447     }
00448 }
00449 
00450 void QwtDial::drawNeedle( QPainter *painter ) const
00451 {
00452     if ( !isValid() )
00453         return;
00454 
00455     QPalette::ColorGroup colorGroup;
00456     if ( isEnabled() )
00457         colorGroup = hasFocus() ? QPalette::Active : QPalette::Inactive;
00458     else
00459         colorGroup = QPalette::Disabled;
00460 
00461     const QRectF sr = scaleInnerRect();
00462 
00463     painter->save();
00464     painter->setRenderHint( QPainter::Antialiasing, true );
00465     drawNeedle( painter, sr.center(), 0.5 * sr.width(),
00466         scaleMap().transform( value() ) + 270.0, colorGroup );
00467     painter->restore();
00468 }
00469 
00477 void QwtDial::drawScale( QPainter *painter, 
00478     const QPointF &center, double radius ) const
00479 {
00480     QwtRoundScaleDraw *sd = const_cast<QwtRoundScaleDraw *>( scaleDraw() );
00481     if ( sd == NULL )
00482         return;
00483 
00484     sd->setRadius( radius );
00485     sd->moveCenter( center );
00486 
00487     QPalette pal = palette();
00488 
00489     const QColor textColor = pal.color( QPalette::Text );
00490     pal.setColor( QPalette::WindowText, textColor ); // ticks, backbone
00491 
00492     painter->setFont( font() );
00493     painter->setPen( QPen( textColor, sd->penWidth() ) );
00494 
00495     painter->setBrush( Qt::red );
00496     sd->draw( painter, pal );
00497 }
00498 
00508 void QwtDial::drawScaleContents( QPainter *painter,
00509     const QPointF &center, double radius ) const
00510 {
00511     Q_UNUSED(painter);
00512     Q_UNUSED(center);
00513     Q_UNUSED(radius);
00514 }
00515 
00524 void QwtDial::setNeedle( QwtDialNeedle *needle )
00525 {
00526     if ( needle != d_data->needle )
00527     {
00528         if ( d_data->needle )
00529             delete d_data->needle;
00530 
00531         d_data->needle = needle;
00532         update();
00533     }
00534 }
00535 
00540 const QwtDialNeedle *QwtDial::needle() const
00541 {
00542     return d_data->needle;
00543 }
00544 
00549 QwtDialNeedle *QwtDial::needle()
00550 {
00551     return d_data->needle;
00552 }
00553 
00555 QwtRoundScaleDraw *QwtDial::scaleDraw()
00556 {
00557     return static_cast<QwtRoundScaleDraw *>( abstractScaleDraw() );
00558 }
00559 
00561 const QwtRoundScaleDraw *QwtDial::scaleDraw() const
00562 {
00563     return static_cast<const QwtRoundScaleDraw *>( abstractScaleDraw() );
00564 }
00565 
00576 void QwtDial::setScaleDraw( QwtRoundScaleDraw *scaleDraw )
00577 {
00578     setAbstractScaleDraw( scaleDraw );
00579     sliderChange();
00580 }
00581 
00590 void QwtDial::setScaleArc( double minArc, double maxArc )
00591 {
00592     if ( minArc != 360.0 && minArc != -360.0 )
00593         minArc = ::fmod( minArc, 360.0 );
00594     if ( maxArc != 360.0 && maxArc != -360.0 )
00595         maxArc = ::fmod( maxArc, 360.0 );
00596 
00597     double minScaleArc = qMin( minArc, maxArc );
00598     double maxScaleArc = qMax( minArc, maxArc );
00599 
00600     if ( maxScaleArc - minScaleArc > 360.0 )
00601         maxScaleArc = minScaleArc + 360.0;
00602 
00603     if ( ( minScaleArc != d_data->minScaleArc ) || 
00604         ( maxScaleArc != d_data->maxScaleArc ) )
00605     {
00606         d_data->minScaleArc = minScaleArc;
00607         d_data->maxScaleArc = maxScaleArc;
00608 
00609         invalidateCache();
00610         sliderChange();
00611     }
00612 }
00613 
00620 void QwtDial::setMinScaleArc( double min )
00621 {
00622     setScaleArc( min, d_data->maxScaleArc );
00623 }
00624 
00629 double QwtDial::minScaleArc() const
00630 {
00631     return d_data->minScaleArc;
00632 }
00633 
00640 void QwtDial::setMaxScaleArc( double max )
00641 {
00642     setScaleArc( d_data->minScaleArc, max );
00643 }
00644 
00649 double QwtDial::maxScaleArc() const
00650 {
00651     return d_data->maxScaleArc;
00652 }
00653 
00662 void QwtDial::setOrigin( double origin )
00663 {
00664     invalidateCache();
00665 
00666     d_data->origin = origin;
00667     sliderChange();
00668 }
00669 
00676 double QwtDial::origin() const
00677 {
00678     return d_data->origin;
00679 }
00680 
00685 QSize QwtDial::sizeHint() const
00686 {
00687     int sh = 0;
00688     if ( scaleDraw() )
00689         sh = qCeil( scaleDraw()->extent( font() ) );
00690 
00691     const int d = 6 * sh + 2 * lineWidth();
00692 
00693     QSize hint( d, d ); 
00694     if ( !isReadOnly() )
00695         hint = hint.expandedTo( QApplication::globalStrut() );
00696 
00697     return hint;
00698 }
00699 
00704 QSize QwtDial::minimumSizeHint() const
00705 {
00706     int sh = 0;
00707     if ( scaleDraw() )
00708         sh = qCeil( scaleDraw()->extent( font() ) );
00709 
00710     const int d = 3 * sh + 2 * lineWidth();
00711 
00712     return QSize( d, d );
00713 }
00714 
00723 bool QwtDial::isScrollPosition( const QPoint &pos ) const
00724 {
00725     const QRegion region( innerRect(), QRegion::Ellipse );
00726     if ( region.contains( pos ) && ( pos != innerRect().center() ) )
00727     {
00728         double angle = QLineF( rect().center(), pos ).angle();
00729         if ( d_data->mode == QwtDial::RotateScale )
00730             angle = 360.0 - angle;
00731 
00732         double valueAngle = 
00733             qwtNormalizeDegrees( 90.0 - scaleMap().transform( value() ) );
00734 
00735         d_data->mouseOffset = qwtNormalizeDegrees( angle - valueAngle );
00736         d_data->arcOffset = scaleMap().p1();
00737 
00738         return true;
00739     }
00740 
00741     return false;
00742 }
00743 
00753 double QwtDial::scrolledTo( const QPoint &pos ) const
00754 {
00755     double angle = QLineF( rect().center(), pos ).angle();
00756     if ( d_data->mode == QwtDial::RotateScale )
00757     {
00758         angle += scaleMap().p1() - d_data->arcOffset;
00759         angle = 360.0 - angle;
00760     }
00761 
00762     angle = qwtNormalizeDegrees( angle - d_data->mouseOffset );
00763     angle = qwtNormalizeDegrees( 90.0 - angle );
00764 
00765     if ( scaleMap().pDist() >= 360.0 )
00766     {
00767         if ( angle < scaleMap().p1() )
00768             angle += 360.0;
00769 
00770         if ( !wrapping() )
00771         {
00772             double boundedAngle = angle;
00773 
00774             const double arc = angle - scaleMap().transform( value() );
00775             if ( qAbs( arc ) > 180.0 )
00776             {
00777                 boundedAngle = ( arc > 0 ) 
00778                     ? scaleMap().p1() : scaleMap().p2();
00779             }
00780 
00781             d_data->mouseOffset += ( boundedAngle - angle );
00782 
00783             angle = boundedAngle;
00784         }
00785     }
00786     else
00787     {
00788         const double boundedAngle =
00789             qwtBoundedAngle( scaleMap().p1(), angle, scaleMap().p2() );
00790 
00791         if ( !wrapping() )
00792             d_data->mouseOffset += ( boundedAngle - angle );
00793 
00794         angle = boundedAngle;
00795     }
00796 
00797     return scaleMap().invTransform( angle );
00798 }
00799 
00806 void QwtDial::changeEvent( QEvent *event )
00807 {
00808     switch( event->type() )
00809     {
00810         case QEvent::EnabledChange:
00811         case QEvent::FontChange:
00812         case QEvent::StyleChange:
00813         case QEvent::PaletteChange:
00814         case QEvent::LanguageChange:
00815         case QEvent::LocaleChange:
00816         {
00817             invalidateCache();
00818             break;
00819         }
00820         default:
00821             break;
00822     }
00823     
00824     QwtAbstractSlider::changeEvent( event );
00825 }
00826 
00831 void QwtDial::wheelEvent( QWheelEvent *event )
00832 {
00833     const QRegion region( innerRect(), QRegion::Ellipse );
00834     if ( region.contains( event->pos() ) )
00835         QwtAbstractSlider::wheelEvent( event );
00836 }
00837 
00838 void QwtDial::setAngleRange( double angle, double span )
00839 {
00840     QwtRoundScaleDraw *sd = const_cast<QwtRoundScaleDraw *>( scaleDraw() );
00841     if ( sd  )
00842     {
00843         angle = qwtNormalizeDegrees( angle - 270.0 );
00844         sd->setAngleRange( angle, angle + span );
00845     }
00846 }
00847 
00852 void QwtDial::scaleChange()
00853 {
00854     invalidateCache();
00855     QwtAbstractSlider::scaleChange();
00856 }
00857 
00858 void QwtDial::sliderChange()
00859 {
00860     setAngleRange( d_data->origin + d_data->minScaleArc,
00861         d_data->maxScaleArc - d_data->minScaleArc );
00862 
00863     if ( mode() == RotateScale )
00864     {
00865         const double arc = scaleMap().transform( value() ) - scaleMap().p1();
00866         setAngleRange( d_data->origin - arc,
00867             d_data->maxScaleArc - d_data->minScaleArc );
00868     }
00869 
00870     QwtAbstractSlider::sliderChange();
00871 }


plotjuggler
Author(s): Davide Faconti
autogenerated on Fri Sep 1 2017 02:41:56