qwt_plot.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 #if QT_VERSION < 0x040000
00012 #include <qguardedptr.h>
00013 #include <qfocusdata.h>
00014 #else
00015 #include <qpointer.h>
00016 #include <qpaintengine.h>
00017 #endif
00018 #include <qapplication.h>
00019 #include <qevent.h>
00020 #include "qwt_plot.h"
00021 #include "qwt_plot_dict.h"
00022 #include "qwt_plot_layout.h"
00023 #include "qwt_rect.h"
00024 #include "qwt_scale_widget.h"
00025 #include "qwt_scale_engine.h"
00026 #include "qwt_text_label.h"
00027 #include "qwt_legend.h"
00028 #include "qwt_dyngrid_layout.h"
00029 #include "qwt_plot_canvas.h"
00030 #include "qwt_paint_buffer.h"
00031 
00032 class QwtPlot::PrivateData
00033 {
00034 public:
00035 #if QT_VERSION < 0x040000
00036     QGuardedPtr<QwtTextLabel> lblTitle;
00037     QGuardedPtr<QwtPlotCanvas> canvas;
00038     QGuardedPtr<QwtLegend> legend;
00039 #else
00040     QPointer<QwtTextLabel> lblTitle;
00041     QPointer<QwtPlotCanvas> canvas;
00042     QPointer<QwtLegend> legend;
00043 #endif
00044     QwtPlotLayout *layout;
00045 
00046     bool autoReplot;
00047 };
00048 
00053 QwtPlot::QwtPlot(QWidget *parent):
00054     QFrame(parent)
00055 {
00056     initPlot(QwtText());
00057 }
00058 
00064 QwtPlot::QwtPlot(const QwtText &title, QWidget *parent):
00065     QFrame(parent)
00066 {
00067     initPlot(title);
00068 }
00069 
00070 #if QT_VERSION < 0x040000
00071 
00076 QwtPlot::QwtPlot(QWidget *parent, const char *name):
00077     QFrame(parent, name)
00078 {   
00079     initPlot(QwtText());
00080 }   
00081 #endif
00082 
00083 
00085 QwtPlot::~QwtPlot()
00086 {
00087     detachItems(QwtPlotItem::Rtti_PlotItem, autoDelete());
00088 
00089     delete d_data->layout;
00090     deleteAxesData();
00091     delete d_data;
00092 }
00093 
00098 void QwtPlot::initPlot(const QwtText &title)
00099 {
00100     d_data = new PrivateData;
00101 
00102 #if QT_VERSION < 0x040000
00103     setWFlags(Qt::WNoAutoErase);
00104 #endif 
00105 
00106     d_data->layout = new QwtPlotLayout;
00107 
00108     d_data->autoReplot = false;
00109 
00110     d_data->lblTitle = new QwtTextLabel(title, this);
00111     d_data->lblTitle->setFont(QFont(fontInfo().family(), 14, QFont::Bold));
00112 
00113     QwtText text(title);
00114     int flags = Qt::AlignCenter;
00115 #if QT_VERSION < 0x040000
00116     flags |= Qt::WordBreak | Qt::ExpandTabs;
00117 #else
00118     flags |= Qt::TextWordWrap;
00119 #endif
00120     text.setRenderFlags(flags);
00121     d_data->lblTitle->setText(text);
00122 
00123     d_data->legend = NULL;
00124 
00125     initAxesData();
00126 
00127     d_data->canvas = new QwtPlotCanvas(this);
00128     d_data->canvas->setFrameStyle(QFrame::Panel|QFrame::Sunken);
00129     d_data->canvas->setLineWidth(2);
00130     d_data->canvas->setMidLineWidth(0);
00131 
00132     updateTabOrder();
00133 
00134     setSizePolicy(QSizePolicy::MinimumExpanding, 
00135         QSizePolicy::MinimumExpanding);
00136 }
00137 
00141 bool QwtPlot::event(QEvent *e)
00142 {
00143     bool ok = QFrame::event(e);
00144     switch(e->type())
00145     {
00146 #if QT_VERSION < 0x040000
00147         case QEvent::LayoutHint:
00148 #else
00149         case QEvent::LayoutRequest:
00150 #endif
00151             updateLayout();
00152             break;
00153 #if QT_VERSION >= 0x040000
00154         case QEvent::PolishRequest:
00155             polish();
00156             break;
00157 #endif
00158         default:;
00159     }
00160     return ok;
00161 }
00162 
00167 void QwtPlot::autoRefresh()
00168 {
00169     if (d_data->autoReplot)
00170         replot();
00171 }
00172 
00187 void QwtPlot::setAutoReplot(bool tf)
00188 {
00189     d_data->autoReplot = tf;
00190 }
00191 
00195 bool QwtPlot::autoReplot() const
00196 {
00197     return d_data->autoReplot; 
00198 }
00199 
00204 void QwtPlot::setTitle(const QString &t)
00205 {
00206     if ( t != d_data->lblTitle->text().text() )
00207     {
00208         d_data->lblTitle->setText(t);
00209         updateLayout();
00210     }
00211 }
00212 
00217 void QwtPlot::setTitle(const QwtText &t)
00218 {
00219     if ( t != d_data->lblTitle->text() )
00220     {
00221         d_data->lblTitle->setText(t);
00222         updateLayout();
00223     }
00224 }
00225 
00230 QwtText QwtPlot::title() const
00231 {
00232     return d_data->lblTitle->text();
00233 }
00234 
00238 QwtPlotLayout *QwtPlot::plotLayout()
00239 {
00240     return d_data->layout;
00241 }
00242 
00246 const QwtPlotLayout *QwtPlot::plotLayout() const
00247 {
00248     return d_data->layout;
00249 }
00250 
00254 QwtTextLabel *QwtPlot::titleLabel()
00255 {
00256     return d_data->lblTitle;
00257 }
00258 
00262 const QwtTextLabel *QwtPlot::titleLabel() const
00263 {
00264     return d_data->lblTitle;
00265 }
00266 
00271 QwtLegend *QwtPlot::legend()
00272 { 
00273     return d_data->legend;
00274 }   
00275 
00280 const QwtLegend *QwtPlot::legend() const
00281 { 
00282     return d_data->legend;
00283 }   
00284 
00285 
00289 QwtPlotCanvas *QwtPlot::canvas()
00290 { 
00291     return d_data->canvas;
00292 }   
00293 
00297 const QwtPlotCanvas *QwtPlot::canvas() const
00298 { 
00299     return d_data->canvas;
00300 }
00301 
00302 void QwtPlot::polish()
00303 {
00304     replot();
00305 
00306 #if QT_VERSION < 0x040000
00307     QFrame::polish();
00308 #endif
00309 }
00310 
00316 QSize QwtPlot::sizeHint() const
00317 {
00318     int dw = 0;
00319     int dh = 0;
00320     for ( int axisId = 0; axisId < axisCnt; axisId++ )
00321     {
00322         if ( axisEnabled(axisId) )
00323         {   
00324             const int niceDist = 40;
00325             const QwtScaleWidget *scaleWidget = axisWidget(axisId);
00326             const QwtScaleDiv &scaleDiv = scaleWidget->scaleDraw()->scaleDiv();
00327             const int majCnt = scaleDiv.ticks(QwtScaleDiv::MajorTick).count();
00328 
00329             if ( axisId == yLeft || axisId == yRight )
00330             {
00331                 int hDiff = (majCnt - 1) * niceDist 
00332                     - scaleWidget->minimumSizeHint().height();
00333                 if ( hDiff > dh )
00334                     dh = hDiff;
00335             }
00336             else
00337             {
00338                 int wDiff = (majCnt - 1) * niceDist 
00339                     - scaleWidget->minimumSizeHint().width();
00340                 if ( wDiff > dw )
00341                     dw = wDiff;
00342             }
00343         }
00344     }
00345     return minimumSizeHint() + QSize(dw, dh);
00346 }
00347 
00351 QSize QwtPlot::minimumSizeHint() const
00352 {
00353     QSize hint = d_data->layout->minimumSizeHint(this);
00354     hint += QSize(2 * frameWidth(), 2 * frameWidth());
00355 
00356     return hint;
00357 }
00358 
00360 void QwtPlot::resizeEvent(QResizeEvent *e)
00361 {
00362     QFrame::resizeEvent(e);
00363     updateLayout();
00364 }
00365 
00376 void QwtPlot::replot()
00377 {
00378     bool doAutoReplot = autoReplot();
00379     setAutoReplot(false);
00380 
00381     updateAxes();
00382 
00383     /*
00384       Maybe the layout needs to be updated, because of changed
00385       axes labels. We need to process them here before painting
00386       to avoid that scales and canvas get out of sync.
00387      */
00388 #if QT_VERSION >= 0x040000
00389     QApplication::sendPostedEvents(this, QEvent::LayoutRequest);
00390 #else
00391     QApplication::sendPostedEvents(this, QEvent::LayoutHint);
00392 #endif
00393 
00394     QwtPlotCanvas &canvas = *d_data->canvas;
00395 
00396     canvas.invalidatePaintCache();
00397 
00398     /*
00399       In case of cached or packed painting the canvas
00400       is repainted completely and doesn't need to be erased.
00401      */
00402     const bool erase = 
00403         !canvas.testPaintAttribute(QwtPlotCanvas::PaintPacked) 
00404         && !canvas.testPaintAttribute(QwtPlotCanvas::PaintCached);
00405 
00406 #if QT_VERSION >= 0x040000
00407     const bool noBackgroundMode = canvas.testAttribute(Qt::WA_NoBackground);
00408     if ( !erase && !noBackgroundMode )
00409         canvas.setAttribute(Qt::WA_NoBackground, true);
00410 
00411     canvas.repaint(canvas.contentsRect());
00412 
00413     if ( !erase && !noBackgroundMode )
00414         canvas.setAttribute(Qt::WA_NoBackground, false);
00415 #else
00416     canvas.repaint(canvas.contentsRect(), erase);
00417 #endif
00418 
00419     setAutoReplot(doAutoReplot);
00420 }
00421 
00426 void QwtPlot::updateLayout()
00427 {
00428     d_data->layout->activate(this, contentsRect());
00429 
00430     //
00431     // resize and show the visible widgets
00432     //
00433     if (!d_data->lblTitle->text().isEmpty())
00434     {
00435         d_data->lblTitle->setGeometry(d_data->layout->titleRect());
00436         if (!d_data->lblTitle->isVisible())
00437             d_data->lblTitle->show();
00438     }
00439     else
00440         d_data->lblTitle->hide();
00441 
00442     for (int axisId = 0; axisId < axisCnt; axisId++ )
00443     {
00444         if (axisEnabled(axisId) )
00445         {
00446             axisWidget(axisId)->setGeometry(d_data->layout->scaleRect(axisId));
00447 
00448             if ( axisId == xBottom || axisId == xTop )
00449             {
00450                 QRegion r(d_data->layout->scaleRect(axisId));
00451                 if ( axisEnabled(yLeft) )
00452                     r = r.subtract(QRegion(d_data->layout->scaleRect(yLeft)));
00453                 if ( axisEnabled(yRight) )
00454                     r = r.subtract(QRegion(d_data->layout->scaleRect(yRight)));
00455                 r.translate(-d_data->layout->scaleRect(axisId).x(), 
00456                     -d_data->layout->scaleRect(axisId).y());
00457 
00458                 axisWidget(axisId)->setMask(r);
00459             }
00460             if (!axisWidget(axisId)->isVisible())
00461                 axisWidget(axisId)->show();
00462         }
00463         else
00464             axisWidget(axisId)->hide();
00465     }
00466 
00467     if ( d_data->legend && 
00468         d_data->layout->legendPosition() != ExternalLegend )
00469     {
00470         if (d_data->legend->itemCount() > 0)
00471         {
00472             d_data->legend->setGeometry(d_data->layout->legendRect());
00473             d_data->legend->show();
00474         }
00475         else
00476             d_data->legend->hide();
00477     }
00478 
00479     d_data->canvas->setGeometry(d_data->layout->canvasRect());
00480 }
00481 
00483 
00484 void QwtPlot::updateTabOrder()
00485 {
00486 #if QT_VERSION >= 0x040000
00487     using namespace Qt; // QWidget::NoFocus/Qt::NoFocus
00488 #endif
00489     if ( d_data->legend.isNull()  
00490         || d_data->layout->legendPosition() == ExternalLegend
00491         || d_data->legend->legendItems().count() == 0
00492         || d_data->canvas->focusPolicy() == NoFocus )
00493     {
00494         return;
00495     }
00496 
00497     // Depending on the position of the legend the 
00498     // tab order will be changed that the canvas is
00499     // next to the last legend item, or before
00500     // the first one. 
00501 
00502     const bool canvasFirst = 
00503         d_data->layout->legendPosition() == QwtPlot::BottomLegend ||
00504         d_data->layout->legendPosition() == QwtPlot::RightLegend;
00505 
00506     QWidget *previous = NULL; 
00507 
00508     QWidget *w;
00509 #if QT_VERSION >= 0x040000
00510     while ( nextInFocusChain() != d_data->canvas );
00511     while ( (w = nextInFocusChain()) != d_data->canvas )
00512 #else
00513     if ( focusData() == NULL )
00514         return;
00515 
00516     while ( focusData()->next() != d_data->canvas );
00517     while ( (w = focusData()->next()) != d_data->canvas )
00518 #endif
00519     {
00520         bool isLegendItem = false;
00521         if ( w->focusPolicy() != NoFocus 
00522             && w->parent() && w->parent() == d_data->legend->contentsWidget() )
00523         {
00524             isLegendItem = true;
00525         }
00526 
00527         if ( canvasFirst )
00528         {
00529             if ( isLegendItem )
00530                 break;
00531 
00532             previous = w;
00533         }
00534         else
00535         {
00536             if ( isLegendItem )
00537                 previous = w;
00538             else
00539             {
00540                 if ( previous )
00541                     break;
00542             }
00543         }
00544     }
00545 
00546     if ( previous && previous != d_data->canvas)
00547         setTabOrder(previous, d_data->canvas);
00548 }
00549 
00560 void QwtPlot::drawCanvas(QPainter *painter)
00561 {
00562     QwtScaleMap maps[axisCnt];
00563     for ( int axisId = 0; axisId < axisCnt; axisId++ )
00564         maps[axisId] = canvasMap(axisId);
00565 
00566     drawItems(painter, 
00567         d_data->canvas->contentsRect(), maps, QwtPlotPrintFilter());
00568 }
00569 
00578 void QwtPlot::drawItems(QPainter *painter, const QRect &rect, 
00579         const QwtScaleMap map[axisCnt], 
00580         const QwtPlotPrintFilter &pfilter) const
00581 {
00582     painter->save();
00583 
00584     const QwtPlotItemList& itmList = itemList();
00585     for ( QwtPlotItemIterator it = itmList.begin();
00586         it != itmList.end(); ++it )
00587     {
00588         QwtPlotItem *item = *it;
00589         if ( item && item->isVisible() )
00590         {
00591             if ( !(pfilter.options() & QwtPlotPrintFilter::PrintGrid)
00592                 && item->rtti() == QwtPlotItem::Rtti_PlotGrid )
00593             {
00594                 continue;
00595             }
00596 
00597 #if QT_VERSION >= 0x040000
00598             const QPaintEngine *pe = painter->device()->paintEngine();
00599             if (pe->hasFeature(QPaintEngine::Antialiasing) )
00600             {
00601                 painter->setRenderHint(QPainter::Antialiasing,
00602                     item->testRenderHint(QwtPlotItem::RenderAntialiased) );
00603             }
00604 #endif
00605 
00606             item->draw(painter, 
00607                 map[item->xAxis()], map[item->yAxis()],
00608                 rect);
00609         }
00610     }
00611 
00612     painter->restore();
00613 }
00614 
00622 QwtScaleMap QwtPlot::canvasMap(int axisId) const
00623 {
00624     QwtScaleMap map;
00625     if ( !d_data->canvas )
00626         return map;
00627 
00628     map.setTransformation(axisScaleEngine(axisId)->transformation());
00629 
00630     const QwtScaleDiv *sd = axisScaleDiv(axisId);
00631     map.setScaleInterval(sd->lBound(), sd->hBound());
00632 
00633     if ( axisEnabled(axisId) )
00634     {
00635         const QwtScaleWidget *s = axisWidget(axisId);
00636         if ( axisId == yLeft || axisId == yRight )
00637         {
00638             int y = s->y() + s->startBorderDist() - d_data->canvas->y();
00639             int h = s->height() - s->startBorderDist() - s->endBorderDist();
00640             map.setPaintInterval(y + h - 1, y);
00641         }
00642         else
00643         {
00644             int x = s->x() + s->startBorderDist() - d_data->canvas->x();
00645             int w = s->width() - s->startBorderDist() - s->endBorderDist();
00646             map.setPaintInterval(x, x + w - 1);
00647         }
00648     }
00649     else
00650     {
00651         const int margin = plotLayout()->canvasMargin(axisId);
00652 
00653         const QRect &canvasRect = d_data->canvas->contentsRect();
00654         if ( axisId == yLeft || axisId == yRight )
00655         {
00656             map.setPaintInterval(canvasRect.bottom() - margin, 
00657                 canvasRect.top() + margin);
00658         }
00659         else
00660         {
00661             map.setPaintInterval(canvasRect.left() + margin, 
00662                 canvasRect.right() - margin);
00663         }
00664     }
00665     return map;
00666 }
00667 
00675 void QwtPlot::setMargin(int margin)
00676 {
00677     if ( margin < 0 )
00678         margin = 0;
00679 
00680     if ( margin != d_data->layout->margin() )
00681     {
00682         d_data->layout->setMargin(margin);
00683         updateLayout();
00684     }
00685 }
00686 
00691 int QwtPlot::margin() const
00692 {
00693     return d_data->layout->margin();
00694 }
00695 
00704 void QwtPlot::setCanvasBackground(const QColor &c)
00705 {
00706     QPalette p = d_data->canvas->palette();
00707 
00708     for ( int i = 0; i < QPalette::NColorGroups; i++ )
00709     {
00710 #if QT_VERSION < 0x040000
00711         p.setColor((QPalette::ColorGroup)i, QColorGroup::Background, c);
00712 #else
00713         p.setColor((QPalette::ColorGroup)i, QPalette::Background, c);
00714 #endif
00715     }
00716 
00717     canvas()->setPalette(p);
00718 }
00719 
00726 const QColor & QwtPlot::canvasBackground() const
00727 {
00728 #if QT_VERSION < 0x040000
00729     return canvas()->palette().color(
00730         QPalette::Normal, QColorGroup::Background);
00731 #else
00732     return canvas()->palette().color(
00733         QPalette::Normal, QPalette::Background);
00734 #endif
00735 }
00736 
00743 void QwtPlot::setCanvasLineWidth(int w)
00744 {
00745     canvas()->setLineWidth(w);
00746     updateLayout();
00747 }
00748  
00754 int QwtPlot::canvasLineWidth() const
00755 { 
00756     return canvas()->lineWidth();
00757 }
00758 
00763 bool QwtPlot::axisValid(int axisId)
00764 {
00765     return ((axisId >= QwtPlot::yLeft) && (axisId < QwtPlot::axisCnt));
00766 }
00767 
00773 void QwtPlot::legendItemClicked()
00774 {
00775     if ( d_data->legend && sender()->isWidgetType() )
00776     {
00777         QwtPlotItem *plotItem = d_data->legend->find((QWidget *)sender());
00778         if ( plotItem )
00779             emit legendClicked(plotItem);
00780     }
00781 }
00782 
00783 void QwtPlot::legendItemChecked(bool on)
00784 {
00785     if ( d_data->legend && sender()->isWidgetType() )
00786     {
00787         QwtPlotItem *plotItem = d_data->legend->find((QWidget *)sender());
00788         if ( plotItem )
00789             emit legendChecked(plotItem, on);
00790     }
00791 }
00792 
00794 void QwtPlot::clear()
00795 {
00796     detachItems(QwtPlotItem::Rtti_PlotCurve);
00797     detachItems(QwtPlotItem::Rtti_PlotMarker);
00798 }
00799 
00826 void QwtPlot::insertLegend(QwtLegend *legend, 
00827     QwtPlot::LegendPosition pos, double ratio)
00828 {
00829     d_data->layout->setLegendPosition(pos, ratio);
00830 
00831     if ( legend != d_data->legend )
00832     {
00833         if ( d_data->legend && d_data->legend->parent() == this )
00834             delete d_data->legend;
00835 
00836         d_data->legend = legend;
00837 
00838         if ( d_data->legend )
00839         {
00840             if ( pos != ExternalLegend )
00841             {
00842                 if ( d_data->legend->parent() != this )
00843                 {
00844 #if QT_VERSION < 0x040000
00845                     d_data->legend->reparent(this, QPoint(0, 0));
00846 #else
00847                     d_data->legend->setParent(this);
00848 #endif
00849                 }
00850             }
00851 
00852             const QwtPlotItemList& itmList = itemList();
00853             for ( QwtPlotItemIterator it = itmList.begin();
00854                 it != itmList.end(); ++it )
00855             {
00856                 (*it)->updateLegend(d_data->legend);
00857             }
00858 
00859             QLayout *l = d_data->legend->contentsWidget()->layout();
00860             if ( l && l->inherits("QwtDynGridLayout") )
00861             {
00862                 QwtDynGridLayout *tl = (QwtDynGridLayout *)l;
00863                 switch(d_data->layout->legendPosition())
00864                 {
00865                     case LeftLegend:
00866                     case RightLegend:
00867                         tl->setMaxCols(1); // 1 column: align vertical
00868                         break;
00869                     case TopLegend:
00870                     case BottomLegend:
00871                         tl->setMaxCols(0); // unlimited
00872                         break;
00873                     case ExternalLegend:
00874                         break;
00875                 }
00876             }
00877         }
00878         updateTabOrder();
00879     }
00880 
00881     updateLayout();
00882 }

Generated on Mon Nov 6 20:32:57 2006 for Qwt User's Guide by  doxygen 1.4.6