qwt_thermo.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_thermo.h"
00011 #include "qwt_scale_engine.h"
00012 #include "qwt_scale_draw.h"
00013 #include "qwt_scale_map.h"
00014 #include "qwt_color_map.h"
00015 #include <qpainter.h>
00016 #include <qevent.h>
00017 #include <qdrawutil.h>
00018 #include <qstyle.h>
00019 #include <qstyleoption.h>
00020 #include <qmath.h>
00021 
00022 static inline void qwtDrawLine( QPainter *painter, int pos, 
00023     const QColor &color, const QRect &pipeRect, const QRect &liquidRect,
00024     Qt::Orientation orientation )
00025 {
00026     painter->setPen( color );
00027     if ( orientation == Qt::Horizontal )
00028     {
00029         if ( pos >= liquidRect.left() && pos < liquidRect.right() )
00030             painter->drawLine( pos, pipeRect.top(), pos, pipeRect.bottom() );
00031     }
00032     else
00033     {
00034         if ( pos >= liquidRect.top() && pos < liquidRect.bottom() )
00035             painter->drawLine( pipeRect.left(), pos, pipeRect.right(), pos );
00036     }
00037 }
00038 
00039 QVector<double> qwtTickList( const QwtScaleDiv &scaleDiv )
00040 {
00041     QVector<double> values;
00042 
00043     double lowerLimit = scaleDiv.interval().minValue();
00044     double upperLimit = scaleDiv.interval().maxValue();
00045 
00046     if ( upperLimit < lowerLimit )
00047         qSwap( lowerLimit, upperLimit );
00048 
00049     values += lowerLimit;
00050 
00051     for ( int tickType = QwtScaleDiv::MinorTick;
00052         tickType < QwtScaleDiv::NTickTypes; tickType++ )
00053     {
00054         const QList<double> ticks = scaleDiv.ticks( tickType );
00055 
00056         for ( int i = 0; i < ticks.count(); i++ )
00057         {
00058             const double v = ticks[i];
00059             if ( v > lowerLimit && v < upperLimit )
00060                 values += v;
00061         }       
00062     }   
00063 
00064     values += upperLimit;
00065     
00066     return values;
00067 }
00068 
00069 class QwtThermo::PrivateData
00070 {
00071 public:
00072     PrivateData():
00073         orientation( Qt::Vertical ),
00074         scalePosition( QwtThermo::TrailingScale ),
00075         spacing( 3 ),
00076         borderWidth( 2 ),
00077         pipeWidth( 10 ),
00078         alarmLevel( 0.0 ),
00079         alarmEnabled( false ),
00080         autoFillPipe( true ),
00081         originMode( QwtThermo::OriginMinimum ),
00082         origin( 0.0 ),
00083         colorMap( NULL ),
00084         value( 0.0 )
00085     {
00086         rangeFlags = QwtInterval::IncludeBorders;
00087     }
00088 
00089     ~PrivateData()
00090     {
00091         delete colorMap;
00092     }
00093 
00094     Qt::Orientation orientation;
00095     QwtThermo::ScalePosition scalePosition;
00096 
00097     int spacing;
00098     int borderWidth;
00099     int pipeWidth;
00100 
00101     QwtInterval::BorderFlags rangeFlags;
00102     double alarmLevel;
00103     bool alarmEnabled;
00104     bool autoFillPipe;
00105     QwtThermo::OriginMode originMode;
00106     double origin;
00107 
00108     QwtColorMap *colorMap;
00109 
00110     double value;
00111 };
00112 
00117 QwtThermo::QwtThermo( QWidget *parent ):
00118     QwtAbstractScale( parent )
00119 {
00120     d_data = new PrivateData;
00121 
00122     QSizePolicy policy( QSizePolicy::MinimumExpanding, QSizePolicy::Fixed );
00123     if ( d_data->orientation == Qt::Vertical )
00124         policy.transpose();
00125 
00126     setSizePolicy( policy );
00127 
00128     setAttribute( Qt::WA_WState_OwnSizePolicy, false );
00129     layoutThermo( true );
00130 }
00131 
00133 QwtThermo::~QwtThermo()
00134 {
00135     delete d_data;
00136 }
00137 
00153 void QwtThermo::setRangeFlags( QwtInterval::BorderFlags flags )
00154 {
00155     if ( d_data->rangeFlags != flags )
00156     {
00157         d_data->rangeFlags = flags;
00158         update();
00159     }
00160 }
00161 
00166 QwtInterval::BorderFlags QwtThermo::rangeFlags() const
00167 {
00168     return d_data->rangeFlags;
00169 }
00170 
00177 void QwtThermo::setValue( double value )
00178 {
00179     if ( d_data->value != value )
00180     {
00181         d_data->value = value;
00182         update();
00183     }
00184 }
00185 
00187 double QwtThermo::value() const
00188 {
00189     return d_data->value;
00190 }
00191 
00203 void QwtThermo::setScaleDraw( QwtScaleDraw *scaleDraw )
00204 {
00205     setAbstractScaleDraw( scaleDraw );
00206     layoutThermo( true );
00207 }
00208 
00213 const QwtScaleDraw *QwtThermo::scaleDraw() const
00214 {
00215     return static_cast<const QwtScaleDraw *>( abstractScaleDraw() );
00216 }
00217 
00222 QwtScaleDraw *QwtThermo::scaleDraw()
00223 {
00224     return static_cast<QwtScaleDraw *>( abstractScaleDraw() );
00225 }
00226 
00231 void QwtThermo::paintEvent( QPaintEvent *event )
00232 {
00233     QPainter painter( this );
00234     painter.setClipRegion( event->region() );
00235 
00236     QStyleOption opt;
00237     opt.init(this);
00238     style()->drawPrimitive(QStyle::PE_Widget, &opt, &painter, this);
00239 
00240     const QRect tRect = pipeRect();
00241 
00242     if ( !tRect.contains( event->rect() ) )
00243     {
00244         if ( d_data->scalePosition != QwtThermo::NoScale )
00245             scaleDraw()->draw( &painter, palette() );
00246     }
00247 
00248     const int bw = d_data->borderWidth;
00249 
00250     const QBrush brush = palette().brush( QPalette::Base );
00251     qDrawShadePanel( &painter, 
00252         tRect.adjusted( -bw, -bw, bw, bw ),
00253         palette(), true, bw, 
00254         d_data->autoFillPipe ? &brush : NULL );
00255 
00256     drawLiquid( &painter, tRect );
00257 }
00258 
00263 void QwtThermo::resizeEvent( QResizeEvent *event )
00264 {
00265     Q_UNUSED( event );
00266     layoutThermo( false );
00267 }
00268 
00273 void QwtThermo::changeEvent( QEvent *event )
00274 {
00275     switch( event->type() )
00276     {
00277         case QEvent::StyleChange:
00278         case QEvent::FontChange:
00279         {
00280             layoutThermo( true );
00281             break;
00282         }
00283         default:
00284             break;
00285     }
00286 }
00287 
00295 void QwtThermo::layoutThermo( bool update_geometry )
00296 {
00297     const QRect tRect = pipeRect();
00298     const int bw = d_data->borderWidth + d_data->spacing;
00299     const bool inverted = ( upperBound() < lowerBound() );
00300 
00301     int from, to;
00302 
00303     if ( d_data->orientation == Qt::Horizontal )
00304     {
00305         from = tRect.left();
00306         to = tRect.right();
00307 
00308         if ( d_data->rangeFlags & QwtInterval::ExcludeMinimum )
00309         {
00310             if ( inverted )
00311                 to++;
00312             else
00313                 from--;
00314         }
00315         if ( d_data->rangeFlags & QwtInterval::ExcludeMaximum )
00316         {
00317             if ( inverted )
00318                 from--;
00319             else
00320                 to++;
00321         }
00322 
00323         if ( d_data->scalePosition == QwtThermo::TrailingScale )
00324         {
00325             scaleDraw()->setAlignment( QwtScaleDraw::TopScale );
00326             scaleDraw()->move( from, tRect.top() - bw );
00327         }
00328         else
00329         {
00330             scaleDraw()->setAlignment( QwtScaleDraw::BottomScale );
00331             scaleDraw()->move( from, tRect.bottom() + bw );
00332         }
00333 
00334         scaleDraw()->setLength( qMax( to - from, 0 ) );
00335     }
00336     else // Qt::Vertical
00337     {
00338         from = tRect.top();
00339         to = tRect.bottom();
00340 
00341         if ( d_data->rangeFlags & QwtInterval::ExcludeMinimum )
00342         {
00343             if ( inverted )
00344                 from--;
00345             else
00346                 to++;
00347         }
00348         if ( d_data->rangeFlags & QwtInterval::ExcludeMaximum )
00349         {
00350             if ( inverted )
00351                 to++;
00352             else
00353                 from--;
00354         }
00355 
00356         if ( d_data->scalePosition == QwtThermo::LeadingScale )
00357         {
00358             scaleDraw()->setAlignment( QwtScaleDraw::RightScale );
00359             scaleDraw()->move( tRect.right() + bw, from );
00360         }
00361         else
00362         {
00363             scaleDraw()->setAlignment( QwtScaleDraw::LeftScale );
00364             scaleDraw()->move( tRect.left() - bw, from );
00365         }
00366 
00367         scaleDraw()->setLength( qMax( to - from, 0 ) );
00368     }
00369 
00370     if ( update_geometry )
00371     {
00372         updateGeometry();
00373         update();
00374     }
00375 }
00376 
00381 QRect QwtThermo::pipeRect() const
00382 {
00383     int mbd = 0;
00384     if ( d_data->scalePosition != QwtThermo::NoScale )
00385     {
00386         int d1, d2;
00387         scaleDraw()->getBorderDistHint( font(), d1, d2 );
00388         mbd = qMax( d1, d2 );
00389     }
00390     const int bw = d_data->borderWidth;
00391     const int scaleOff = bw + mbd;
00392 
00393     const QRect cr = contentsRect();
00394 
00395     QRect pipeRect = cr;
00396     if ( d_data->orientation == Qt::Horizontal )
00397     {
00398         pipeRect.adjust( scaleOff, 0, -scaleOff, 0 );
00399 
00400         if ( d_data->scalePosition == QwtThermo::TrailingScale )
00401             pipeRect.setTop( cr.top() + cr.height() - bw - d_data->pipeWidth );
00402         else
00403             pipeRect.setTop( bw );
00404 
00405         pipeRect.setHeight( d_data->pipeWidth );
00406     }
00407     else // Qt::Vertical
00408     {
00409         pipeRect.adjust( 0, scaleOff, 0, -scaleOff );
00410 
00411         if ( d_data->scalePosition == QwtThermo::LeadingScale )
00412             pipeRect.setLeft( bw );
00413         else 
00414             pipeRect.setLeft( cr.left() + cr.width() - bw - d_data->pipeWidth );
00415 
00416         pipeRect.setWidth( d_data->pipeWidth );
00417     }
00418 
00419     return pipeRect;
00420 }
00421 
00428 void QwtThermo::setOrientation( Qt::Orientation orientation )
00429 {
00430     if ( orientation == d_data->orientation )
00431         return;
00432 
00433     d_data->orientation = orientation;
00434 
00435     if ( !testAttribute( Qt::WA_WState_OwnSizePolicy ) )
00436     {
00437         QSizePolicy sp = sizePolicy();
00438         sp.transpose();
00439         setSizePolicy( sp );
00440 
00441         setAttribute( Qt::WA_WState_OwnSizePolicy, false );
00442     }
00443 
00444     layoutThermo( true );
00445 }
00446 
00451 Qt::Orientation QwtThermo::orientation() const
00452 {
00453     return d_data->orientation;
00454 }
00455 
00460 void QwtThermo::setOriginMode( OriginMode m )
00461 {
00462     if ( m == d_data->originMode )
00463         return;
00464 
00465     d_data->originMode = m;
00466     update();
00467 }
00468 
00473 QwtThermo::OriginMode QwtThermo::originMode() const
00474 {
00475     return d_data->originMode;
00476 }
00477 
00487 void QwtThermo::setOrigin( double origin )
00488 {
00489     if ( origin == d_data->origin )
00490         return;
00491 
00492     d_data->origin = origin;
00493     update();
00494 }
00495 
00500 double QwtThermo::origin() const
00501 {
00502     return d_data->origin;
00503 }
00504 
00511 void QwtThermo::setScalePosition( ScalePosition scalePosition )
00512 {
00513     if ( d_data->scalePosition == scalePosition )
00514         return;
00515 
00516     d_data->scalePosition = scalePosition;
00517 
00518     if ( testAttribute( Qt::WA_WState_Polished ) )
00519         layoutThermo( true );
00520 }
00521 
00526 QwtThermo::ScalePosition QwtThermo::scalePosition() const
00527 {
00528     return d_data->scalePosition;
00529 }
00530 
00532 void QwtThermo::scaleChange()
00533 {
00534     layoutThermo( true );
00535 }
00536 
00542 void QwtThermo::drawLiquid( 
00543     QPainter *painter, const QRect &pipeRect ) const
00544 {
00545     painter->save();
00546     painter->setClipRect( pipeRect, Qt::IntersectClip );
00547     painter->setPen( Qt::NoPen );
00548 
00549     const QwtScaleMap scaleMap = scaleDraw()->scaleMap();
00550 
00551     QRect liquidRect = fillRect( pipeRect );
00552 
00553     if ( d_data->colorMap != NULL )
00554     {
00555         const QwtInterval interval = scaleDiv().interval().normalized();
00556 
00557         // Because the positions of the ticks are rounded
00558         // we calculate the colors for the rounded tick values
00559 
00560         QVector<double> values = qwtTickList( scaleDraw()->scaleDiv() );
00561 
00562         if ( scaleMap.isInverting() )
00563             qSort( values.begin(), values.end(), qGreater<double>() );
00564         else
00565             qSort( values.begin(), values.end(), qLess<double>() );
00566 
00567         int from;
00568         if ( !values.isEmpty() )
00569         {
00570             from = qRound( scaleMap.transform( values[0] ) );
00571             qwtDrawLine( painter, from,
00572                 d_data->colorMap->color( interval, values[0] ),
00573                 pipeRect, liquidRect, d_data->orientation );
00574         }
00575 
00576         for ( int i = 1; i < values.size(); i++ )
00577         {
00578             const int to = qRound( scaleMap.transform( values[i] ) );
00579 
00580             for ( int pos = from + 1; pos < to; pos++ )
00581             {
00582                 const double v = scaleMap.invTransform( pos );
00583 
00584                 qwtDrawLine( painter, pos, 
00585                     d_data->colorMap->color( interval, v ),
00586                     pipeRect, liquidRect, d_data->orientation );
00587             }
00588 
00589             qwtDrawLine( painter, to,
00590                 d_data->colorMap->color( interval, values[i] ),
00591                 pipeRect, liquidRect, d_data->orientation );
00592 
00593             from = to;
00594         }
00595     }
00596     else
00597     {
00598         if ( !liquidRect.isEmpty() && d_data->alarmEnabled )
00599         {
00600             const QRect r = alarmRect( liquidRect );
00601             if ( !r.isEmpty() )
00602             {
00603                 painter->fillRect( r, palette().brush( QPalette::Highlight ) );
00604                 liquidRect = QRegion( liquidRect ).subtracted( r ).boundingRect();
00605             }
00606         }
00607 
00608         painter->fillRect( liquidRect, palette().brush( QPalette::ButtonText ) );
00609     }
00610 
00611     painter->restore();
00612 }
00613 
00625 void QwtThermo::setSpacing( int spacing )
00626 {
00627     if ( spacing <= 0 )
00628         spacing = 0;
00629 
00630     if ( spacing != d_data->spacing  )
00631     {
00632         d_data->spacing = spacing;
00633         layoutThermo( true );
00634     }
00635 }
00636 
00641 int QwtThermo::spacing() const
00642 {
00643     return d_data->spacing;
00644 }
00645 
00651 void QwtThermo::setBorderWidth( int width )
00652 {
00653     if ( width <= 0 )
00654         width = 0;
00655 
00656     if ( width != d_data->borderWidth  )
00657     {
00658         d_data->borderWidth = width;
00659         layoutThermo( true );
00660     }
00661 }
00662 
00667 int QwtThermo::borderWidth() const
00668 {
00669     return d_data->borderWidth;
00670 }
00671 
00679 void QwtThermo::setColorMap( QwtColorMap *colorMap )
00680 {
00681     if ( colorMap != d_data->colorMap )
00682     {
00683         delete d_data->colorMap;
00684         d_data->colorMap = colorMap;
00685     }
00686 }
00687 
00693 QwtColorMap *QwtThermo::colorMap()
00694 {
00695     return d_data->colorMap;
00696 }
00697 
00703 const QwtColorMap *QwtThermo::colorMap() const
00704 {
00705     return d_data->colorMap;
00706 }
00707 
00716 void QwtThermo::setFillBrush( const QBrush& brush )
00717 {
00718     QPalette pal = palette();
00719     pal.setBrush( QPalette::ButtonText, brush );
00720     setPalette( pal );
00721 }
00722 
00727 QBrush QwtThermo::fillBrush() const
00728 {
00729     return palette().brush( QPalette::ButtonText );
00730 }
00731 
00743 void QwtThermo::setAlarmBrush( const QBrush& brush )
00744 {
00745     QPalette pal = palette();
00746     pal.setBrush( QPalette::Highlight, brush );
00747     setPalette( pal );
00748 }
00749 
00757 QBrush QwtThermo::alarmBrush() const
00758 {
00759     return palette().brush( QPalette::Highlight );
00760 }
00761 
00771 void QwtThermo::setAlarmLevel( double level )
00772 {
00773     d_data->alarmLevel = level;
00774     d_data->alarmEnabled = 1;
00775     update();
00776 }
00777 
00785 double QwtThermo::alarmLevel() const
00786 {
00787     return d_data->alarmLevel;
00788 }
00789 
00796 void QwtThermo::setPipeWidth( int width )
00797 {
00798     if ( width > 0 )
00799     {
00800         d_data->pipeWidth = width;
00801         layoutThermo( true );
00802     }
00803 }
00804 
00809 int QwtThermo::pipeWidth() const
00810 {
00811     return d_data->pipeWidth;
00812 }
00813 
00821 void QwtThermo::setAlarmEnabled( bool on )
00822 {
00823     d_data->alarmEnabled = on;
00824     update();
00825 }
00826 
00833 bool QwtThermo::alarmEnabled() const
00834 {
00835     return d_data->alarmEnabled;
00836 }
00837 
00842 QSize QwtThermo::sizeHint() const
00843 {
00844     return minimumSizeHint();
00845 }
00846 
00852 QSize QwtThermo::minimumSizeHint() const
00853 {
00854     int w = 0, h = 0;
00855 
00856     if ( d_data->scalePosition != NoScale )
00857     {
00858         const int sdExtent = qCeil( scaleDraw()->extent( font() ) );
00859         const int sdLength = scaleDraw()->minLength( font() );
00860 
00861         w = sdLength;
00862         h = d_data->pipeWidth + sdExtent + d_data->spacing;
00863 
00864     }
00865     else // no scale
00866     {
00867         w = 200;
00868         h = d_data->pipeWidth;
00869     }
00870 
00871     if ( d_data->orientation == Qt::Vertical )
00872         qSwap( w, h );
00873 
00874     w += 2 * d_data->borderWidth;
00875     h += 2 * d_data->borderWidth;
00876 
00877     // finally add the margins
00878     int left, right, top, bottom;
00879     getContentsMargins( &left, &top, &right, &bottom );
00880     w += left + right;
00881     h += top + bottom;
00882 
00883     return QSize( w, h );
00884 }
00885 
00894 QRect QwtThermo::fillRect( const QRect &pipeRect ) const
00895 {
00896     double origin;        
00897     if ( d_data->originMode == OriginMinimum )
00898     {
00899         origin = qMin( lowerBound(), upperBound() );
00900     }
00901     else if ( d_data->originMode == OriginMaximum )
00902     {
00903         origin = qMax( lowerBound(), upperBound() );
00904     }
00905     else // OriginCustom
00906     {
00907         origin = d_data->origin;
00908     }
00909 
00910     const QwtScaleMap scaleMap = scaleDraw()->scaleMap();
00911 
00912     int from = qRound( scaleMap.transform( d_data->value ) );
00913     int to = qRound( scaleMap.transform( origin ) );
00914 
00915     if ( to < from )
00916         qSwap( from, to );
00917     
00918     QRect fillRect = pipeRect;
00919     if ( d_data->orientation == Qt::Horizontal )
00920     {
00921         fillRect.setLeft( from );
00922         fillRect.setRight( to );
00923     }
00924     else // Qt::Vertical
00925     {
00926         fillRect.setTop( from );
00927         fillRect.setBottom( to );
00928     }
00929 
00930     return fillRect.normalized();
00931 }
00932 
00941 QRect QwtThermo::alarmRect( const QRect &fillRect ) const
00942 {
00943     QRect alarmRect( 0, 0, -1, -1); // something invalid
00944 
00945     if ( !d_data->alarmEnabled )
00946         return alarmRect;
00947 
00948     const bool inverted = ( upperBound() < lowerBound() );
00949     
00950     bool increasing;
00951     if ( d_data->originMode == OriginCustom )
00952     {
00953         increasing = d_data->value > d_data->origin;
00954     }
00955     else
00956     {
00957         increasing = d_data->originMode == OriginMinimum;
00958     }
00959 
00960     const QwtScaleMap map = scaleDraw()->scaleMap();
00961     const int alarmPos = qRound( map.transform( d_data->alarmLevel ) );
00962     const int valuePos = qRound( map.transform( d_data->value ) );
00963     
00964     if ( d_data->orientation == Qt::Horizontal )
00965     {
00966         int v1, v2;
00967         if ( inverted )
00968         {
00969             v1 = fillRect.left();
00970 
00971             v2 = alarmPos - 1;
00972             v2 = qMin( v2, increasing ? fillRect.right() : valuePos );
00973         }
00974         else
00975         {
00976             v1 = alarmPos + 1;
00977             v1 = qMax( v1, increasing ? fillRect.left() : valuePos );
00978 
00979             v2 = fillRect.right();
00980 
00981         }
00982         alarmRect.setRect( v1, fillRect.top(), v2 - v1 + 1, fillRect.height() );
00983     }
00984     else
00985     {
00986         int v1, v2;
00987         if ( inverted )
00988         {
00989             v1 = alarmPos + 1;
00990             v1 = qMax( v1, increasing ? fillRect.top() : valuePos );
00991 
00992             v2 = fillRect.bottom();
00993         }
00994         else
00995         {
00996             v1 = fillRect.top();
00997 
00998             v2 = alarmPos - 1;
00999             v2 = qMin( v2, increasing ? fillRect.bottom() : valuePos );
01000         }
01001         alarmRect.setRect( fillRect.left(), v1, fillRect.width(), v2 - v1 + 1 );
01002     }
01003 
01004     return alarmRect;
01005 } 


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