qwt_thermo.cpp

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 <qpainter.h>
00011 #include <qevent.h>
00012 #include <qstyle.h>
00013 #include <qpixmap.h>
00014 #include <qdrawutil.h>
00015 #include "qwt_math.h"
00016 #include "qwt_scale_engine.h"
00017 #include "qwt_scale_draw.h"
00018 #include "qwt_scale_map.h"
00019 #include "qwt_paint_buffer.h"
00020 #include "qwt_thermo.h"
00021 
00022 class QwtThermo::PrivateData
00023 {
00024 public:
00025     PrivateData():
00026         fillBrush(Qt::black),
00027         alarmBrush(Qt::white),
00028         orientation(Qt::Vertical),
00029         scalePos(QwtThermo::LeftScale),
00030         borderWidth(2),
00031         scaleDist(3),
00032         thermoWidth(10),
00033         minValue(0.0),
00034         maxValue(1.0),
00035         value(0.0),
00036         alarmLevel(0.0),
00037         alarmEnabled(false)
00038     {
00039         map.setScaleInterval(minValue, maxValue);
00040     }
00041 
00042     QwtScaleMap map;
00043     QRect thermoRect;
00044     QBrush fillBrush;
00045     QBrush alarmBrush;
00046 
00047     Qt::Orientation orientation;
00048     ScalePos scalePos;
00049     int borderWidth;
00050     int scaleDist;
00051     int thermoWidth;
00052 
00053     double minValue;
00054     double maxValue;
00055     double value;
00056     double alarmLevel;
00057     bool alarmEnabled;
00058 };
00059 
00064 QwtThermo::QwtThermo(QWidget *parent): 
00065     QWidget(parent)
00066 {
00067     initThermo();
00068 }
00069 
00070 #if QT_VERSION < 0x040000
00071 
00076 QwtThermo::QwtThermo(QWidget *parent, const char *name): 
00077     QWidget(parent, name)
00078 {
00079     initThermo();
00080 }
00081 #endif
00082 
00083 void QwtThermo::initThermo()
00084 {
00085 #if QT_VERSION < 0x040000
00086     setWFlags(Qt::WNoAutoErase);
00087 #endif
00088     d_data = new PrivateData;
00089     setRange(d_data->minValue, d_data->maxValue, false);
00090 
00091     QSizePolicy policy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
00092     if (d_data->orientation == Qt::Vertical) 
00093         policy.transpose();
00094 
00095     setSizePolicy(policy);
00096     
00097 #if QT_VERSION >= 0x040000
00098     setAttribute(Qt::WA_WState_OwnSizePolicy, false);
00099 #else
00100     clearWState( WState_OwnSizePolicy );
00101 #endif
00102 }
00103 
00105 QwtThermo::~QwtThermo()
00106 {
00107     delete d_data;
00108 }
00109 
00111 void QwtThermo::setMaxValue(double v) 
00112 { 
00113     setRange(d_data->minValue, v); 
00114 }
00115 
00117 double QwtThermo::maxValue() const 
00118 { 
00119     return d_data->maxValue; 
00120 }
00121 
00123 void QwtThermo::setMinValue(double v) 
00124 { 
00125     setRange(v, d_data->maxValue); 
00126 }
00127 
00129 double QwtThermo::minValue() const 
00130 { 
00131     return d_data->minValue; 
00132 }
00133 
00135 void QwtThermo::setValue(double v)
00136 {
00137     if (d_data->value != v)
00138     {
00139         d_data->value = v;
00140         update();
00141     }
00142 }
00143 
00145 double QwtThermo::value() const 
00146 { 
00147     return d_data->value; 
00148 }
00149 
00161 void QwtThermo::setScaleDraw(QwtScaleDraw *scaleDraw)
00162 {
00163     setAbstractScaleDraw(scaleDraw);
00164 }
00165 
00170 const QwtScaleDraw *QwtThermo::scaleDraw() const
00171 {
00172     return (QwtScaleDraw *)abstractScaleDraw();
00173 }
00174 
00179 QwtScaleDraw *QwtThermo::scaleDraw() 
00180 {
00181     return (QwtScaleDraw *)abstractScaleDraw();
00182 }
00183 
00185 void QwtThermo::paintEvent(QPaintEvent *e)
00186 {
00187     // Use double-buffering
00188     const QRect &ur = e->rect();
00189     if ( ur.isValid() )
00190     {
00191 #if QT_VERSION < 0x040000
00192         QwtPaintBuffer paintBuffer(this, ur);
00193         draw(paintBuffer.painter(), ur);
00194 #else
00195         QPainter painter(this);
00196         draw(&painter, ur);
00197 #endif
00198     }
00199 }
00200 
00202 void QwtThermo::draw(QPainter *p, const QRect& ur)
00203 {
00204     if ( !d_data->thermoRect.contains(ur) )
00205     {
00206         if (d_data->scalePos != NoScale)
00207         {
00208 #if QT_VERSION < 0x040000
00209             scaleDraw()->draw(p, colorGroup());
00210 #else
00211             scaleDraw()->draw(p, palette());
00212 #endif
00213         }
00214 
00215         qDrawShadePanel(p,
00216             d_data->thermoRect.x() - d_data->borderWidth,
00217             d_data->thermoRect.y() - d_data->borderWidth,
00218             d_data->thermoRect.width() + 2*d_data->borderWidth,
00219             d_data->thermoRect.height() + 2*d_data->borderWidth,
00220 #if QT_VERSION < 0x040000
00221             colorGroup(), 
00222 #else
00223             palette(), 
00224 #endif
00225             true, d_data->borderWidth,0);
00226     }
00227     drawThermo(p);
00228 }
00229 
00231 void QwtThermo::resizeEvent(QResizeEvent *)
00232 {
00233     layoutThermo( false );
00234 }
00235 
00242 void QwtThermo::layoutThermo( bool update_geometry )
00243 {
00244     QRect r = rect();
00245     int mbd = 0;
00246     if ( d_data->scalePos != NoScale )
00247     {
00248         int d1, d2;
00249         scaleDraw()->getBorderDistHint(font(), d1, d2);
00250         mbd = qwtMax(d1, d2);
00251     }
00252 
00253     if ( d_data->orientation == Qt::Horizontal )
00254     {
00255         switch ( d_data->scalePos )
00256         {
00257             case TopScale:
00258             {
00259                 d_data->thermoRect.setRect(
00260                     r.x() + mbd + d_data->borderWidth,
00261                     r.y() + r.height()
00262                     - d_data->thermoWidth - 2*d_data->borderWidth,
00263                     r.width() - 2*(d_data->borderWidth + mbd),
00264                     d_data->thermoWidth);
00265                 scaleDraw()->setAlignment(QwtScaleDraw::TopScale);
00266                 scaleDraw()->move( d_data->thermoRect.x(),
00267                     d_data->thermoRect.y() - d_data->borderWidth 
00268                         - d_data->scaleDist);
00269                 scaleDraw()->setLength(d_data->thermoRect.width());
00270                 break;
00271             }
00272 
00273             case BottomScale:
00274             case NoScale: // like Bottom but without scale
00275             default:   // inconsistent orientation and scale position
00276                        // Mapping between values and pixels requires
00277                        // initialization of the scale geometry
00278             {
00279                 d_data->thermoRect.setRect(
00280                     r.x() + mbd + d_data->borderWidth,
00281                     r.y() + d_data->borderWidth,
00282                     r.width() - 2*(d_data->borderWidth + mbd),
00283                     d_data->thermoWidth);
00284                 scaleDraw()->setAlignment(QwtScaleDraw::BottomScale);
00285                 scaleDraw()->move(
00286                     d_data->thermoRect.x(),
00287                     d_data->thermoRect.y() + d_data->thermoRect.height()
00288                         + d_data->borderWidth + d_data->scaleDist );
00289                 scaleDraw()->setLength(d_data->thermoRect.width());
00290                 break;
00291             }
00292         }
00293         d_data->map.setPaintInterval(d_data->thermoRect.x(),
00294             d_data->thermoRect.x() + d_data->thermoRect.width() - 1);
00295     }
00296     else // Qt::Vertical
00297     {
00298         switch ( d_data->scalePos )
00299         {
00300             case RightScale:
00301             {
00302                 d_data->thermoRect.setRect(
00303                     r.x() + d_data->borderWidth,
00304                     r.y() + mbd + d_data->borderWidth,
00305                     d_data->thermoWidth,
00306                     r.height() - 2*(d_data->borderWidth + mbd));
00307                 scaleDraw()->setAlignment(QwtScaleDraw::RightScale);
00308                 scaleDraw()->move(
00309                     d_data->thermoRect.x() + d_data->thermoRect.width()
00310                         + d_data->borderWidth + d_data->scaleDist,
00311                     d_data->thermoRect.y());
00312                 scaleDraw()->setLength(d_data->thermoRect.height());
00313                 break;
00314             }
00315 
00316             case LeftScale:
00317             case NoScale: // like Left but without scale
00318             default:   // inconsistent orientation and scale position
00319                        // Mapping between values and pixels requires
00320                        // initialization of the scale geometry
00321             {
00322                 d_data->thermoRect.setRect(
00323                     r.x() + r.width() - 2*d_data->borderWidth - d_data->thermoWidth,
00324                     r.y() + mbd + d_data->borderWidth,
00325                     d_data->thermoWidth,
00326                     r.height() - 2*(d_data->borderWidth + mbd));
00327                 scaleDraw()->setAlignment(QwtScaleDraw::LeftScale);
00328                 scaleDraw()->move(
00329                     d_data->thermoRect.x() - d_data->scaleDist 
00330                         - d_data->borderWidth,
00331                     d_data->thermoRect.y() );
00332                 scaleDraw()->setLength(d_data->thermoRect.height());
00333                 break;
00334             }
00335         }
00336         d_data->map.setPaintInterval(
00337             d_data->thermoRect.y() + d_data->thermoRect.height() - 1,
00338             d_data->thermoRect.y());
00339     }
00340     if ( update_geometry )
00341     {
00342         updateGeometry();
00343         update();
00344     }
00345 }
00346 
00365 void QwtThermo::setOrientation(Qt::Orientation o, ScalePos s)
00366 {
00367     if ( o == d_data->orientation && s == d_data->scalePos )
00368         return;
00369 
00370     switch(o)
00371     {
00372         case Qt::Horizontal:
00373         {
00374             if ((s == NoScale) || (s == BottomScale) || (s == TopScale))
00375                 d_data->scalePos = s;
00376             else
00377                 d_data->scalePos = NoScale;
00378             break;
00379         }
00380         case Qt::Vertical:
00381         {
00382             if ((s == NoScale) || (s == LeftScale) || (s == RightScale))
00383                 d_data->scalePos = s;
00384             else
00385                 d_data->scalePos = NoScale;
00386             break;
00387         }
00388     }
00389 
00390     if ( o != d_data->orientation )
00391     {
00392 #if QT_VERSION >= 0x040000
00393         if ( !testAttribute(Qt::WA_WState_OwnSizePolicy) )
00394 #else
00395         if ( !testWState( WState_OwnSizePolicy ) )
00396 #endif
00397         {
00398             QSizePolicy sp = sizePolicy();
00399             sp.transpose();
00400             setSizePolicy(sp);
00401 
00402 #if QT_VERSION >= 0x040000
00403             setAttribute(Qt::WA_WState_OwnSizePolicy, false);
00404 #else
00405             clearWState( WState_OwnSizePolicy );
00406 #endif
00407         }
00408     }
00409 
00410     d_data->orientation = o;
00411     layoutThermo();
00412 }
00413 
00428 void QwtThermo::setScalePosition(ScalePos s)
00429 {
00430     if ((s == BottomScale) || (s == TopScale))
00431         setOrientation(Qt::Horizontal, s);
00432     else if ((s == LeftScale) || (s == RightScale))
00433         setOrientation(Qt::Vertical, s);
00434     else
00435         setOrientation(d_data->orientation, NoScale);
00436 }
00437 
00439 QwtThermo::ScalePos QwtThermo::scalePosition() const
00440 {
00441     return d_data->scalePos;
00442 }
00443 
00445 void QwtThermo::fontChange(const QFont &f)
00446 {
00447     QWidget::fontChange( f );
00448     layoutThermo();
00449 }
00450 
00452 void QwtThermo::scaleChange()
00453 {
00454     update();
00455     layoutThermo();
00456 }
00457 
00459 void QwtThermo::drawThermo(QPainter *p)
00460 {
00461     int alarm  = 0, taval = 0;
00462 
00463     QRect fRect;
00464     QRect aRect;
00465     QRect bRect;
00466 
00467     int inverted = ( d_data->maxValue < d_data->minValue );
00468 
00469     //
00470     //  Determine if value exceeds alarm threshold.
00471     //  Note: The alarm value is allowed to lie
00472     //        outside the interval (minValue, maxValue).
00473     //
00474     if (d_data->alarmEnabled)
00475     {
00476         if (inverted)
00477         {
00478             alarm = ((d_data->alarmLevel >= d_data->maxValue)
00479                  && (d_data->alarmLevel <= d_data->minValue)
00480                  && (d_data->value >= d_data->alarmLevel));
00481         
00482         }
00483         else
00484         {
00485             alarm = (( d_data->alarmLevel >= d_data->minValue)
00486                  && (d_data->alarmLevel <= d_data->maxValue)
00487                  && (d_data->value >= d_data->alarmLevel));
00488         }
00489     }
00490 
00491     //
00492     //  transform values
00493     //
00494     int tval = transform(d_data->value);
00495 
00496     if (alarm)
00497        taval = transform(d_data->alarmLevel);
00498 
00499     //
00500     //  calculate recangles
00501     //
00502     if ( d_data->orientation == Qt::Horizontal )
00503     {
00504         if (inverted)
00505         {
00506             bRect.setRect(d_data->thermoRect.x(), d_data->thermoRect.y(),
00507                   tval - d_data->thermoRect.x(),
00508                   d_data->thermoRect.height());
00509         
00510             if (alarm)
00511             {
00512                 aRect.setRect(tval, d_data->thermoRect.y(),
00513                       taval - tval + 1,
00514                       d_data->thermoRect.height());
00515                 fRect.setRect(taval + 1, d_data->thermoRect.y(),
00516                       d_data->thermoRect.x() + d_data->thermoRect.width() - (taval + 1),
00517                       d_data->thermoRect.height());
00518             }
00519             else
00520             {
00521                 fRect.setRect(tval, d_data->thermoRect.y(),
00522                       d_data->thermoRect.x() + d_data->thermoRect.width() - tval,
00523                       d_data->thermoRect.height());
00524             }
00525         }
00526         else
00527         {
00528             bRect.setRect(tval + 1, d_data->thermoRect.y(),
00529                   d_data->thermoRect.width() - (tval + 1 - d_data->thermoRect.x()),
00530                   d_data->thermoRect.height());
00531         
00532             if (alarm)
00533             {
00534                 aRect.setRect(taval, d_data->thermoRect.y(),
00535                       tval - taval + 1,
00536                       d_data->thermoRect.height());
00537                 fRect.setRect(d_data->thermoRect.x(), d_data->thermoRect.y(),
00538                       taval - d_data->thermoRect.x(),
00539                       d_data->thermoRect.height());
00540             }
00541             else
00542             {
00543                 fRect.setRect(d_data->thermoRect.x(), d_data->thermoRect.y(),
00544                       tval - d_data->thermoRect.x() + 1,
00545                       d_data->thermoRect.height());
00546             }
00547         
00548         }
00549     }
00550     else // Qt::Vertical
00551     {
00552         if (tval < d_data->thermoRect.y())
00553             tval = d_data->thermoRect.y();
00554         else 
00555         {
00556             if (tval > d_data->thermoRect.y() + d_data->thermoRect.height())
00557                 tval = d_data->thermoRect.y() + d_data->thermoRect.height();
00558         }
00559 
00560         if (inverted)
00561         {
00562             bRect.setRect(d_data->thermoRect.x(), tval + 1,
00563             d_data->thermoRect.width(),
00564             d_data->thermoRect.height() - (tval + 1 - d_data->thermoRect.y()));
00565 
00566             if (alarm)
00567             {
00568                 aRect.setRect(d_data->thermoRect.x(), taval,
00569                     d_data->thermoRect.width(),
00570                     tval - taval + 1);
00571                 fRect.setRect(d_data->thermoRect.x(), d_data->thermoRect.y(),
00572                     d_data->thermoRect.width(),
00573                 taval - d_data->thermoRect.y());
00574             }
00575             else
00576             {
00577                 fRect.setRect(d_data->thermoRect.x(), d_data->thermoRect.y(),
00578                     d_data->thermoRect.width(),
00579                     tval - d_data->thermoRect.y() + 1);
00580             }
00581         }
00582         else
00583         {
00584             bRect.setRect(d_data->thermoRect.x(), d_data->thermoRect.y(),
00585             d_data->thermoRect.width(),
00586             tval - d_data->thermoRect.y());
00587             if (alarm)
00588             {
00589                 aRect.setRect(d_data->thermoRect.x(),tval,
00590                     d_data->thermoRect.width(),
00591                     taval - tval + 1);
00592                 fRect.setRect(d_data->thermoRect.x(),taval + 1,
00593                     d_data->thermoRect.width(),
00594                     d_data->thermoRect.y() + d_data->thermoRect.height() - (taval + 1));
00595             }
00596             else
00597             {
00598                 fRect.setRect(d_data->thermoRect.x(),tval,
00599                     d_data->thermoRect.width(),
00600                 d_data->thermoRect.y() + d_data->thermoRect.height() - tval);
00601             }
00602         }
00603     }
00604 
00605     //
00606     // paint thermometer
00607     //
00608     const QColor bgColor =
00609 #if QT_VERSION < 0x040000
00610         colorGroup().color(QColorGroup::Background);
00611 #else
00612         palette().color(QPalette::Background);
00613 #endif
00614     p->fillRect(bRect, bgColor);
00615 
00616     if (alarm)
00617        p->fillRect(aRect, d_data->alarmBrush);
00618 
00619     p->fillRect(fRect, d_data->fillBrush);
00620 }
00621 
00623 void QwtThermo::setBorderWidth(int w)
00624 {
00625     if ((w >= 0) && (w < (qwtMin(d_data->thermoRect.width(), 
00626         d_data->thermoRect.height()) + d_data->borderWidth) / 2  - 1))
00627     {
00628         d_data->borderWidth = w;
00629         layoutThermo();
00630     }
00631 }
00632 
00634 int QwtThermo::borderWidth() const
00635 {
00636     return d_data->borderWidth;
00637 }
00638 
00645 void QwtThermo::setRange(double vmin, double vmax, bool logarithmic)
00646 {
00647     d_data->minValue = vmin;
00648     d_data->maxValue = vmax;
00649 
00650     if ( logarithmic )
00651         setScaleEngine(new QwtLog10ScaleEngine);
00652     else
00653         setScaleEngine(new QwtLinearScaleEngine);
00654 
00655     /*
00656       There are two different maps, one for the scale, the other
00657       for the values. This is confusing and will be changed
00658       in the future. TODO ...
00659      */
00660 
00661     d_data->map.setTransformation(scaleEngine()->transformation());
00662     d_data->map.setScaleInterval(d_data->minValue, d_data->maxValue);
00663 
00664     if (autoScale())
00665         rescale(d_data->minValue, d_data->maxValue);
00666 
00667     layoutThermo();
00668 }
00669 
00674 void QwtThermo::setFillBrush(const QBrush& brush)
00675 {
00676     d_data->fillBrush = brush;
00677     update();
00678 }
00679 
00681 const QBrush& QwtThermo::fillBrush() const
00682 {
00683     return d_data->fillBrush;
00684 }
00685 
00690 void QwtThermo::setFillColor(const QColor &c)
00691 {
00692     d_data->fillBrush.setColor(c);
00693     update();
00694 }
00695 
00697 const QColor &QwtThermo::fillColor() const
00698 {
00699     return d_data->fillBrush.color();
00700 }
00701 
00706 void QwtThermo::setAlarmBrush(const QBrush& brush)
00707 {
00708     d_data->alarmBrush = brush;
00709     update();
00710 }
00711 
00713 const QBrush& QwtThermo::alarmBrush() const
00714 {
00715     return d_data->alarmBrush;
00716 }
00717 
00722 void QwtThermo::setAlarmColor(const QColor &c)
00723 {
00724     d_data->alarmBrush.setColor(c);
00725     update();
00726 }
00727 
00729 const QColor &QwtThermo::alarmColor() const
00730 {
00731     return d_data->alarmBrush.color();
00732 }
00733 
00735 void QwtThermo::setAlarmLevel(double v)
00736 {
00737     d_data->alarmLevel = v;
00738     d_data->alarmEnabled = 1;
00739     update();
00740 }
00741 
00743 double QwtThermo::alarmLevel() const
00744 {
00745     return d_data->alarmLevel;
00746 }
00747 
00749 void QwtThermo::setPipeWidth(int w)
00750 {
00751     if (w > 0)
00752     {
00753         d_data->thermoWidth = w;
00754         layoutThermo();
00755     }
00756 }
00757 
00759 int QwtThermo::pipeWidth() const
00760 {
00761     return d_data->thermoWidth;
00762 }
00763 
00764 
00779 void QwtThermo::setMargin(int)
00780 {
00781 }
00782 
00783 
00788 void QwtThermo::setAlarmEnabled(bool tf)
00789 {
00790     d_data->alarmEnabled = tf;
00791     update();
00792 }
00793 
00795 bool QwtThermo::alarmEnabled() const
00796 {
00797     return d_data->alarmEnabled;
00798 }
00799 
00804 QSize QwtThermo::sizeHint() const
00805 {
00806     return minimumSizeHint();
00807 }
00808 
00814 QSize QwtThermo::minimumSizeHint() const
00815 {
00816     int w = 0, h = 0;
00817 
00818     if ( d_data->scalePos != NoScale )
00819     {
00820         const int sdExtent = scaleDraw()->extent( QPen(), font() );
00821         const int sdLength = scaleDraw()->minLength( QPen(), font() );
00822 
00823         w = sdLength;
00824         h = d_data->thermoWidth + sdExtent + 
00825             d_data->borderWidth + d_data->scaleDist;
00826 
00827     }
00828     else // no scale
00829     {
00830         w = 200;
00831         h = d_data->thermoWidth;
00832     }
00833 
00834     if ( d_data->orientation == Qt::Vertical )
00835         qSwap(w, h);
00836 
00837     w += 2 * d_data->borderWidth;
00838     h += 2 * d_data->borderWidth;
00839 
00840     return QSize( w, h );
00841 }
00842 
00843 int QwtThermo::transform(double value) const
00844 {
00845     const double min = qwtMin(d_data->map.s1(), d_data->map.s2());
00846     const double max = qwtMax(d_data->map.s1(), d_data->map.s2());
00847 
00848     if ( value > max )
00849         value = max;
00850     if ( value < min )
00851         value = min;
00852 
00853     return d_data->map.transform(value);
00854 }

Generated on Sun Mar 22 16:54:08 2009 for Qwt User's Guide by  doxygen 1.5.0