src/qvgui/qvhistogram.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 <qstring.h>
00011 #include <qpainter.h>
00012 #include <qwt_plot.h>
00013 #include <qwt_interval_data.h>
00014 #include <qwt_painter.h>
00015 #include <qwt_scale_map.h>
00016 #include <qvgui/qvhistogram.h>
00017 
00018 #ifndef DOXYGEN_IGNORE_THIS
00019 class QVHistogram::PrivateData
00020 {
00021 public:
00022     int attributes;
00023     QwtIntervalData data;
00024     QColor color;
00025     double reference;
00026 };
00027 #endif
00028 
00029 QVHistogram::QVHistogram(const QwtText &title):
00030     QwtPlotItem(title)
00031 {
00032     init();
00033 }
00034 
00035 QVHistogram::QVHistogram(const QString &title):
00036     QwtPlotItem(QwtText(title))
00037 {
00038     init();
00039 }
00040 
00041 QVHistogram::~QVHistogram()
00042 {
00043     delete d_data;
00044 }
00045 
00046 void QVHistogram::init()
00047 {
00048     d_data = new PrivateData();
00049     d_data->reference = 0.0;
00050     d_data->attributes = QVHistogram::Auto;
00051 
00052     setItemAttribute(QwtPlotItem::AutoScale, true);
00053     setItemAttribute(QwtPlotItem::Legend, true);
00054 
00055     setZ(20.0);
00056 }
00057 
00058 void QVHistogram::setBaseline(double reference)
00059 {
00060     if ( d_data->reference != reference )
00061     {
00062         d_data->reference = reference;
00063         itemChanged();
00064     }
00065 }
00066 
00067 double QVHistogram::baseline() const
00068 {
00069     return d_data->reference;
00070 }
00071 
00072 void QVHistogram::setData(const QwtIntervalData &data)
00073 {
00074     d_data->data = data;
00075     itemChanged();
00076 }
00077 
00078 const QwtIntervalData &QVHistogram::data() const
00079 {
00080     return d_data->data;
00081 }
00082 
00083 void QVHistogram::setColor(const QColor &color)
00084 {
00085     if ( d_data->color != color )
00086     {
00087         d_data->color = color;
00088         itemChanged();
00089     }
00090 }
00091 
00092 QColor QVHistogram::color() const
00093 {
00094     return d_data->color;
00095 }
00096 
00097 QwtDoubleRect QVHistogram::boundingRect() const
00098 {
00099     QwtDoubleRect rect = d_data->data.boundingRect();
00100     if ( !rect.isValid() ) 
00101         return rect;
00102 
00103     if ( d_data->attributes & Xfy ) 
00104     {
00105         rect = QwtDoubleRect( rect.y(), rect.x(), 
00106             rect.height(), rect.width() );
00107 
00108         if ( rect.left() > d_data->reference ) 
00109             rect.setLeft( d_data->reference );
00110         else if ( rect.right() < d_data->reference ) 
00111             rect.setRight( d_data->reference );
00112     } 
00113     else 
00114     {
00115         if ( rect.bottom() < d_data->reference ) 
00116             rect.setBottom( d_data->reference );
00117         else if ( rect.top() > d_data->reference ) 
00118             rect.setTop( d_data->reference );
00119     }
00120 
00121     return rect;
00122 }
00123 
00124 
00125 int QVHistogram::rtti() const
00126 {
00127     return QwtPlotItem::Rtti_PlotHistogram;
00128 }
00129 
00130 void QVHistogram::setHistogramAttribute(HistogramAttribute attribute, bool on)
00131 {
00132     if ( bool(d_data->attributes & attribute) == on )
00133         return;
00134 
00135     if ( on )
00136         d_data->attributes |= attribute;
00137     else
00138         d_data->attributes &= ~attribute;
00139 
00140     itemChanged();
00141 }
00142 
00143 bool QVHistogram::testHistogramAttribute(HistogramAttribute attribute) const
00144 {
00145     return d_data->attributes & attribute;
00146 }
00147 
00148 void QVHistogram::draw(QPainter *painter, const QwtScaleMap &xMap, 
00149     const QwtScaleMap &yMap, const QRect &) const
00150 {
00151     const QwtIntervalData &iData = d_data->data;
00152 
00153     painter->setPen(QPen(d_data->color));
00154 
00155     const int x0 = xMap.transform(baseline());
00156     const int y0 = yMap.transform(baseline());
00157 
00158     for ( int i = 0; i < (int)iData.size(); i++ )
00159     {
00160         if ( d_data->attributes & QVHistogram::Xfy )
00161         {
00162             const int x2 = xMap.transform(iData.value(i));
00163             if ( x2 == x0 )
00164                 continue;
00165 
00166             int y1 = yMap.transform( iData.interval(i).minValue());
00167             int y2 = yMap.transform( iData.interval(i).maxValue());
00168             if ( y1 > y2 )
00169                 qSwap(y1, y2);
00170 
00171             if ( i < (int)iData.size() - 2 )
00172             {
00173                 const int yy1 = yMap.transform(iData.interval(i+1).minValue());
00174                 const int yy2 = yMap.transform(iData.interval(i+1).maxValue());
00175 
00176                 if ( y2 == qwtMin(yy1, yy2) )
00177                 {
00178                     const int xx2 = xMap.transform(
00179                         iData.interval(i+1).minValue());
00180                     if ( xx2 != x0 && ( (xx2 < x0 && x2 < x0) ||
00181                                           (xx2 > x0 && x2 > x0) ) )
00182                     {
00183                        // One pixel distance between neighboured bars
00184                        y2++;
00185                     }
00186                 }
00187             }
00188 
00189             drawBar(painter, Qt::Horizontal,
00190                 QRect(x0, y1, x2 - x0, y2 - y1));
00191         }
00192         else
00193         {
00194             const int y2 = yMap.transform(iData.value(i));
00195             if ( y2 == y0 )
00196                 continue;
00197 
00198             int x1 = xMap.transform(iData.interval(i).minValue());
00199             int x2 = xMap.transform(iData.interval(i).maxValue());
00200             if ( x1 > x2 )
00201                 qSwap(x1, x2);
00202 
00203             if ( i < (int)iData.size() - 2 )
00204             {
00205                 const int xx1 = xMap.transform(iData.interval(i+1).minValue());
00206                 const int xx2 = xMap.transform(iData.interval(i+1).maxValue());
00207 
00208                 if ( x2 == qwtMin(xx1, xx2) )
00209                 {
00210                     const int yy2 = yMap.transform(iData.value(i+1));
00211                     if ( yy2 != y0 && ( (yy2 < y0 && y2 < y0) ||
00212                                     (yy2 > y0 && y2 > y0) ) )
00213                     {
00214                         // One pixel distance between neighboured bars
00215                         x2--;
00216                     }
00217                 }
00218             }
00219             drawBar(painter, Qt::Vertical,
00220                 QRect(x1, y0, x2 - x1, y2 - y0) );
00221         }
00222     }
00223 }
00224 
00225 void QVHistogram::drawBar(QPainter *painter,
00226    Qt::Orientation, const QRect& rect) const
00227 {
00228    painter->save();
00229 
00230    const QColor color(painter->pen().color());
00231 #if QT_VERSION >= 0x040000
00232    const QRect r = rect.normalized();
00233 #else
00234    const QRect r = rect.normalize();
00235 #endif
00236 
00237    const int factor = 125;
00238    const QColor light(color.light(factor));
00239    const QColor dark(color.dark(factor));
00240 
00241    painter->setBrush(color);
00242    painter->setPen(Qt::NoPen);
00243    QwtPainter::drawRect(painter, r.x() + 1, r.y() + 1,
00244       r.width() - 2, r.height() - 2);
00245    painter->setBrush(Qt::NoBrush);
00246 
00247    painter->setPen(QPen(light, 2));
00248 #if QT_VERSION >= 0x040000
00249    QwtPainter::drawLine(painter,
00250       r.left() + 1, r.top() + 2, r.right() + 1, r.top() + 2);
00251 #else
00252    QwtPainter::drawLine(painter,
00253       r.left(), r.top() + 2, r.right() + 1, r.top() + 2);
00254 #endif
00255 
00256    painter->setPen(QPen(dark, 2));
00257 #if QT_VERSION >= 0x040000
00258    QwtPainter::drawLine(painter, 
00259       r.left() + 1, r.bottom(), r.right() + 1, r.bottom());
00260 #else
00261    QwtPainter::drawLine(painter, 
00262       r.left(), r.bottom(), r.right() + 1, r.bottom());
00263 #endif
00264 
00265    painter->setPen(QPen(light, 1));
00266 
00267 #if QT_VERSION >= 0x040000
00268    QwtPainter::drawLine(painter, 
00269       r.left(), r.top() + 1, r.left(), r.bottom());
00270    QwtPainter::drawLine(painter,
00271       r.left() + 1, r.top() + 2, r.left() + 1, r.bottom() - 1);
00272 #else
00273    QwtPainter::drawLine(painter, 
00274       r.left(), r.top() + 1, r.left(), r.bottom() + 1);
00275    QwtPainter::drawLine(painter,
00276       r.left() + 1, r.top() + 2, r.left() + 1, r.bottom());
00277 #endif
00278 
00279    painter->setPen(QPen(dark, 1));
00280 
00281 #if QT_VERSION >= 0x040000
00282    QwtPainter::drawLine(painter, 
00283       r.right() + 1, r.top() + 1, r.right() + 1, r.bottom());
00284    QwtPainter::drawLine(painter, 
00285       r.right(), r.top() + 2, r.right(), r.bottom() - 1);
00286 #else
00287    QwtPainter::drawLine(painter, 
00288       r.right() + 1, r.top() + 1, r.right() + 1, r.bottom() + 1);
00289    QwtPainter::drawLine(painter, 
00290       r.right(), r.top() + 2, r.right(), r.bottom());
00291 #endif
00292 
00293    painter->restore();
00294 }