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 
00150 void QwtThermo::setScaleDraw(QwtScaleDraw *scaleDraw)
00151 {
00152     setAbstractScaleDraw(scaleDraw);
00153 }
00154 
00155 const QwtScaleDraw *QwtThermo::scaleDraw() const
00156 {
00157     return (QwtScaleDraw *)abstractScaleDraw();
00158 }
00159 
00160 QwtScaleDraw *QwtThermo::scaleDraw() 
00161 {
00162     return (QwtScaleDraw *)abstractScaleDraw();
00163 }
00164 
00166 void QwtThermo::paintEvent(QPaintEvent *e)
00167 {
00168     // Use double-buffering
00169     const QRect &ur = e->rect();
00170     if ( ur.isValid() )
00171     {
00172 #if QT_VERSION < 0x040000
00173         QwtPaintBuffer paintBuffer(this, ur);
00174         draw(paintBuffer.painter(), ur);
00175 #else
00176         QPainter painter(this);
00177         draw(&painter, ur);
00178 #endif
00179     }
00180 }
00181 
00183 void QwtThermo::draw(QPainter *p, const QRect& ur)
00184 {
00185     if ( !d_data->thermoRect.contains(ur) )
00186     {
00187         if (d_data->scalePos != NoScale)
00188         {
00189 #if QT_VERSION < 0x040000
00190             scaleDraw()->draw(p, colorGroup());
00191 #else
00192             scaleDraw()->draw(p, palette());
00193 #endif
00194         }
00195 
00196         qDrawShadePanel(p,
00197             d_data->thermoRect.x() - d_data->borderWidth,
00198             d_data->thermoRect.y() - d_data->borderWidth,
00199             d_data->thermoRect.width() + 2*d_data->borderWidth,
00200             d_data->thermoRect.height() + 2*d_data->borderWidth,
00201 #if QT_VERSION < 0x040000
00202             colorGroup(), 
00203 #else
00204             palette(), 
00205 #endif
00206             true, d_data->borderWidth,0);
00207     }
00208     drawThermo(p);
00209 }
00210 
00212 void QwtThermo::resizeEvent(QResizeEvent *)
00213 {
00214     layoutThermo( false );
00215 }
00216 
00223 void QwtThermo::layoutThermo( bool update_geometry )
00224 {
00225     QRect r = rect();
00226     int mbd = 0;
00227     if ( d_data->scalePos != NoScale )
00228     {
00229         int d1, d2;
00230         scaleDraw()->getBorderDistHint(font(), d1, d2);
00231         mbd = qwtMax(d1, d2);
00232     }
00233 
00234     if ( d_data->orientation == Qt::Horizontal )
00235     {
00236         switch ( d_data->scalePos )
00237         {
00238             case TopScale:
00239             {
00240                 d_data->thermoRect.setRect(
00241                     r.x() + mbd + d_data->borderWidth,
00242                     r.y() + r.height()
00243                     - d_data->thermoWidth - 2*d_data->borderWidth,
00244                     r.width() - 2*(d_data->borderWidth + mbd),
00245                     d_data->thermoWidth);
00246                 scaleDraw()->setAlignment(QwtScaleDraw::TopScale);
00247                 scaleDraw()->move( d_data->thermoRect.x(),
00248                     d_data->thermoRect.y() - d_data->borderWidth 
00249                         - d_data->scaleDist);
00250                 scaleDraw()->setLength(d_data->thermoRect.width());
00251                 break;
00252             }
00253 
00254             case BottomScale:
00255             case NoScale: // like Bottom but without scale
00256             default:   // inconsistent orientation and scale position
00257                        // Mapping between values and pixels requires
00258                        // initialization of the scale geometry
00259             {
00260                 d_data->thermoRect.setRect(
00261                     r.x() + mbd + d_data->borderWidth,
00262                     r.y() + d_data->borderWidth,
00263                     r.width() - 2*(d_data->borderWidth + mbd),
00264                     d_data->thermoWidth);
00265                 scaleDraw()->setAlignment(QwtScaleDraw::BottomScale);
00266                 scaleDraw()->move(
00267                     d_data->thermoRect.x(),
00268                     d_data->thermoRect.y() + d_data->thermoRect.height()
00269                         + d_data->borderWidth + d_data->scaleDist );
00270                 scaleDraw()->setLength(d_data->thermoRect.width());
00271                 break;
00272             }
00273         }
00274         d_data->map.setPaintInterval(d_data->thermoRect.x(),
00275             d_data->thermoRect.x() + d_data->thermoRect.width() - 1);
00276     }
00277     else // Qt::Vertical
00278     {
00279         switch ( d_data->scalePos )
00280         {
00281             case RightScale:
00282             {
00283                 d_data->thermoRect.setRect(
00284                     r.x() + d_data->borderWidth,
00285                     r.y() + mbd + d_data->borderWidth,
00286                     d_data->thermoWidth,
00287                     r.height() - 2*(d_data->borderWidth + mbd));
00288                 scaleDraw()->setAlignment(QwtScaleDraw::RightScale);
00289                 scaleDraw()->move(
00290                     d_data->thermoRect.x() + d_data->thermoRect.width()
00291                         + d_data->borderWidth + d_data->scaleDist,
00292                     d_data->thermoRect.y());
00293                 scaleDraw()->setLength(d_data->thermoRect.height());
00294                 break;
00295             }
00296 
00297             case LeftScale:
00298             case NoScale: // like Left but without scale
00299             default:   // inconsistent orientation and scale position
00300                        // Mapping between values and pixels requires
00301                        // initialization of the scale geometry
00302             {
00303                 d_data->thermoRect.setRect(
00304                     r.x() + r.width() - 2*d_data->borderWidth - d_data->thermoWidth,
00305                     r.y() + mbd + d_data->borderWidth,
00306                     d_data->thermoWidth,
00307                     r.height() - 2*(d_data->borderWidth + mbd));
00308                 scaleDraw()->setAlignment(QwtScaleDraw::LeftScale);
00309                 scaleDraw()->move(
00310                     d_data->thermoRect.x() - d_data->scaleDist 
00311                         - d_data->borderWidth,
00312                     d_data->thermoRect.y() );
00313                 scaleDraw()->setLength(d_data->thermoRect.height());
00314                 break;
00315             }
00316         }
00317         d_data->map.setPaintInterval(
00318             d_data->thermoRect.y() + d_data->thermoRect.height() - 1,
00319             d_data->thermoRect.y());
00320     }
00321     if ( update_geometry )
00322     {
00323         updateGeometry();
00324         update();
00325     }
00326 }
00327 
00346 void QwtThermo::setOrientation(Qt::Orientation o, ScalePos s)
00347 {
00348     if ( o == d_data->orientation && s == d_data->scalePos )
00349         return;
00350 
00351     switch(o)
00352     {
00353         case Qt::Horizontal:
00354         {
00355             if ((s == NoScale) || (s == BottomScale) || (s == TopScale))
00356                 d_data->scalePos = s;
00357             else
00358                 d_data->scalePos = NoScale;
00359             break;
00360         }
00361         case Qt::Vertical:
00362         {
00363             if ((s == NoScale) || (s == LeftScale) || (s == RightScale))
00364                 d_data->scalePos = s;
00365             else
00366                 d_data->scalePos = NoScale;
00367             break;
00368         }
00369     }
00370 
00371     if ( o != d_data->orientation )
00372     {
00373 #if QT_VERSION >= 0x040000
00374         if ( !testAttribute(Qt::WA_WState_OwnSizePolicy) )
00375 #else
00376         if ( !testWState( WState_OwnSizePolicy ) )
00377 #endif
00378         {
00379             QSizePolicy sp = sizePolicy();
00380             sp.transpose();
00381             setSizePolicy(sp);
00382 
00383 #if QT_VERSION >= 0x040000
00384             setAttribute(Qt::WA_WState_OwnSizePolicy, false);
00385 #else
00386             clearWState( WState_OwnSizePolicy );
00387 #endif
00388         }
00389     }
00390 
00391     d_data->orientation = o;
00392     layoutThermo();
00393 }
00394 
00409 void QwtThermo::setScalePosition(ScalePos s)
00410 {
00411     if ((s == BottomScale) || (s == TopScale))
00412         setOrientation(Qt::Horizontal, s);
00413     else if ((s == LeftScale) || (s == RightScale))
00414         setOrientation(Qt::Vertical, s);
00415     else
00416         setOrientation(d_data->orientation, NoScale);
00417 }
00418 
00420 QwtThermo::ScalePos QwtThermo::scalePosition() const
00421 {
00422     return d_data->scalePos;
00423 }
00424 
00426 void QwtThermo::fontChange(const QFont &f)
00427 {
00428     QWidget::fontChange( f );
00429     layoutThermo();
00430 }
00431 
00433 void QwtThermo::scaleChange()
00434 {
00435     update();
00436     layoutThermo();
00437 }
00438 
00440 void QwtThermo::drawThermo(QPainter *p)
00441 {
00442     int alarm  = 0, taval = 0;
00443 
00444     QRect fRect;
00445     QRect aRect;
00446     QRect bRect;
00447 
00448     int inverted = ( d_data->maxValue < d_data->minValue );
00449 
00450     //
00451     //  Determine if value exceeds alarm threshold.
00452     //  Note: The alarm value is allowed to lie
00453     //        outside the interval (minValue, maxValue).
00454     //
00455     if (d_data->alarmEnabled)
00456     {
00457         if (inverted)
00458         {
00459             alarm = ((d_data->alarmLevel >= d_data->maxValue)
00460                  && (d_data->alarmLevel <= d_data->minValue)
00461                  && (d_data->value >= d_data->alarmLevel));
00462         
00463         }
00464         else
00465         {
00466             alarm = (( d_data->alarmLevel >= d_data->minValue)
00467                  && (d_data->alarmLevel <= d_data->maxValue)
00468                  && (d_data->value >= d_data->alarmLevel));
00469         }
00470     }
00471 
00472     //
00473     //  transform values
00474     //
00475     int tval = transform(d_data->value);
00476 
00477     if (alarm)
00478        taval = transform(d_data->alarmLevel);
00479 
00480     //
00481     //  calculate recangles
00482     //
00483     if ( d_data->orientation == Qt::Horizontal )
00484     {
00485         if (inverted)
00486         {
00487             bRect.setRect(d_data->thermoRect.x(), d_data->thermoRect.y(),
00488                   tval - d_data->thermoRect.x(),
00489                   d_data->thermoRect.height());
00490         
00491             if (alarm)
00492             {
00493                 aRect.setRect(tval, d_data->thermoRect.y(),
00494                       taval - tval + 1,
00495                       d_data->thermoRect.height());
00496                 fRect.setRect(taval + 1, d_data->thermoRect.y(),
00497                       d_data->thermoRect.x() + d_data->thermoRect.width() - (taval + 1),
00498                       d_data->thermoRect.height());
00499             }
00500             else
00501             {
00502                 fRect.setRect(tval, d_data->thermoRect.y(),
00503                       d_data->thermoRect.x() + d_data->thermoRect.width() - tval,
00504                       d_data->thermoRect.height());
00505             }
00506         }
00507         else
00508         {
00509             bRect.setRect(tval + 1, d_data->thermoRect.y(),
00510                   d_data->thermoRect.width() - (tval + 1 - d_data->thermoRect.x()),
00511                   d_data->thermoRect.height());
00512         
00513             if (alarm)
00514             {
00515                 aRect.setRect(taval, d_data->thermoRect.y(),
00516                       tval - taval + 1,
00517                       d_data->thermoRect.height());
00518                 fRect.setRect(d_data->thermoRect.x(), d_data->thermoRect.y(),
00519                       taval - d_data->thermoRect.x(),
00520                       d_data->thermoRect.height());
00521             }
00522             else
00523             {
00524                 fRect.setRect(d_data->thermoRect.x(), d_data->thermoRect.y(),
00525                       tval - d_data->thermoRect.x() + 1,
00526                       d_data->thermoRect.height());
00527             }
00528         
00529         }
00530     }
00531     else // Qt::Vertical
00532     {
00533         if (tval < d_data->thermoRect.y())
00534             tval = d_data->thermoRect.y();
00535         else 
00536         {
00537             if (tval > d_data->thermoRect.y() + d_data->thermoRect.height())
00538                 tval = d_data->thermoRect.y() + d_data->thermoRect.height();
00539         }
00540 
00541         if (inverted)
00542         {
00543             bRect.setRect(d_data->thermoRect.x(), tval + 1,
00544             d_data->thermoRect.width(),
00545             d_data->thermoRect.height() - (tval + 1 - d_data->thermoRect.y()));
00546 
00547             if (alarm)
00548             {
00549                 aRect.setRect(d_data->thermoRect.x(), taval,
00550                     d_data->thermoRect.width(),
00551                     tval - taval + 1);
00552                 fRect.setRect(d_data->thermoRect.x(), d_data->thermoRect.y(),
00553                     d_data->thermoRect.width(),
00554                 taval - d_data->thermoRect.y());
00555             }
00556             else
00557             {
00558                 fRect.setRect(d_data->thermoRect.x(), d_data->thermoRect.y(),
00559                     d_data->thermoRect.width(),
00560                     tval - d_data->thermoRect.y() + 1);
00561             }
00562         }
00563         else
00564         {
00565             bRect.setRect(d_data->thermoRect.x(), d_data->thermoRect.y(),
00566             d_data->thermoRect.width(),
00567             tval - d_data->thermoRect.y());
00568             if (alarm)
00569             {
00570                 aRect.setRect(d_data->thermoRect.x(),tval,
00571                     d_data->thermoRect.width(),
00572                     taval - tval + 1);
00573                 fRect.setRect(d_data->thermoRect.x(),taval + 1,
00574                     d_data->thermoRect.width(),
00575                     d_data->thermoRect.y() + d_data->thermoRect.height() - (taval + 1));
00576             }
00577             else
00578             {
00579                 fRect.setRect(d_data->thermoRect.x(),tval,
00580                     d_data->thermoRect.width(),
00581                 d_data->thermoRect.y() + d_data->thermoRect.height() - tval);
00582             }
00583         }
00584     }
00585 
00586     //
00587     // paint thermometer
00588     //
00589     const QColor bgColor =
00590 #if QT_VERSION < 0x040000
00591         colorGroup().color(QColorGroup::Background);
00592 #else
00593         palette().color(QPalette::Background);
00594 #endif
00595     p->fillRect(bRect, bgColor);
00596 
00597     if (alarm)
00598        p->fillRect(aRect, d_data->alarmBrush);
00599 
00600     p->fillRect(fRect, d_data->fillBrush);
00601 }
00602 
00604 void QwtThermo::setBorderWidth(int w)
00605 {
00606     if ((w >= 0) && (w < (qwtMin(d_data->thermoRect.width(), 
00607         d_data->thermoRect.height()) + d_data->borderWidth) / 2  - 1))
00608     {
00609         d_data->borderWidth = w;
00610         layoutThermo();
00611     }
00612 }
00613 
00615 int QwtThermo::borderWidth() const
00616 {
00617     return d_data->borderWidth;
00618 }
00619 
00626 void QwtThermo::setRange(double vmin, double vmax, bool logarithmic)
00627 {
00628     d_data->minValue = vmin;
00629     d_data->maxValue = vmax;
00630 
00631     if ( logarithmic )
00632         setScaleEngine(new QwtLog10ScaleEngine);
00633     else
00634         setScaleEngine(new QwtLinearScaleEngine);
00635 
00636     /*
00637       There are two different maps, one for the scale, the other
00638       for the values. This is confusing and will be changed
00639       in the future. TODO ...
00640      */
00641 
00642     d_data->map.setTransformation(scaleEngine()->transformation());
00643     d_data->map.setScaleInterval(d_data->minValue, d_data->maxValue);
00644 
00645     if (autoScale())
00646         rescale(d_data->minValue, d_data->maxValue);
00647 
00648     layoutThermo();
00649 }
00650 
00655 void QwtThermo::setFillBrush(const QBrush& brush)
00656 {
00657     d_data->fillBrush = brush;
00658     update();
00659 }
00660 
00662 const QBrush& QwtThermo::fillBrush() const
00663 {
00664     return d_data->fillBrush;
00665 }
00666 
00671 void QwtThermo::setFillColor(const QColor &c)
00672 {
00673     d_data->fillBrush.setColor(c);
00674     update();
00675 }
00676 
00678 const QColor &QwtThermo::fillColor() const
00679 {
00680     return d_data->fillBrush.color();
00681 }
00682 
00687 void QwtThermo::setAlarmBrush(const QBrush& brush)
00688 {
00689     d_data->alarmBrush = brush;
00690     update();
00691 }
00692 
00694 const QBrush& QwtThermo::alarmBrush() const
00695 {
00696     return d_data->alarmBrush;
00697 }
00698 
00703 void QwtThermo::setAlarmColor(const QColor &c)
00704 {
00705     d_data->alarmBrush.setColor(c);
00706     update();
00707 }
00708 
00710 const QColor &QwtThermo::alarmColor() const
00711 {
00712     return d_data->alarmBrush.color();
00713 }
00714 
00716 void QwtThermo::setAlarmLevel(double v)
00717 {
00718     d_data->alarmLevel = v;
00719     d_data->alarmEnabled = 1;
00720     update();
00721 }
00722 
00724 double QwtThermo::alarmLevel() const
00725 {
00726     return d_data->alarmLevel;
00727 }
00728 
00730 void QwtThermo::setPipeWidth(int w)
00731 {
00732     if (w > 0)
00733     {
00734         d_data->thermoWidth = w;
00735         layoutThermo();
00736     }
00737 }
00738 
00740 int QwtThermo::pipeWidth() const
00741 {
00742     return d_data->thermoWidth;
00743 }
00744 
00745 
00760 void QwtThermo::setMargin(int)
00761 {
00762 }
00763 
00764 
00769 void QwtThermo::setAlarmEnabled(bool tf)
00770 {
00771     d_data->alarmEnabled = tf;
00772     update();
00773 }
00774 
00776 bool QwtThermo::alarmEnabled() const
00777 {
00778     return d_data->alarmEnabled;
00779 }
00780 
00785 QSize QwtThermo::sizeHint() const
00786 {
00787     return minimumSizeHint();
00788 }
00789 
00795 QSize QwtThermo::minimumSizeHint() const
00796 {
00797     int w = 0, h = 0;
00798 
00799     if ( d_data->scalePos != NoScale )
00800     {
00801         const int sdExtent = scaleDraw()->extent( QPen(), font() );
00802         const int sdLength = scaleDraw()->minLength( QPen(), font() );
00803 
00804         w = sdLength;
00805         h = d_data->thermoWidth + sdExtent + 
00806             d_data->borderWidth + d_data->scaleDist;
00807 
00808     }
00809     else // no scale
00810     {
00811         w = 200;
00812         h = d_data->thermoWidth;
00813     }
00814 
00815     if ( d_data->orientation == Qt::Vertical )
00816         qSwap(w, h);
00817 
00818     w += 2 * d_data->borderWidth;
00819     h += 2 * d_data->borderWidth;
00820 
00821     return QSize( w, h );
00822 }
00823 
00824 int QwtThermo::transform(double value) const
00825 {
00826     const double min = qwtMin(d_data->map.s1(), d_data->map.s2());
00827     const double max = qwtMax(d_data->map.s1(), d_data->map.s2());
00828 
00829     if ( value > max )
00830         value = max;
00831     if ( value < min )
00832         value = min;
00833 
00834     return d_data->map.transform(value);
00835 }

Generated on Mon Feb 26 21:22:39 2007 for Qwt User's Guide by  doxygen 1.4.6