Main Page | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Class Members | File Members | Related Pages

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 <qfocusdata.h>
00013 #else
00014 #include <qpaintengine.h>
00015 #endif
00016 #include <qapplication.h>
00017 #include <qevent.h>
00018 #include "qwt_plot.h"
00019 #include "qwt_plot_dict.h"
00020 #include "qwt_plot_layout.h"
00021 #include "qwt_rect.h"
00022 #include "qwt_scale_widget.h"
00023 #include "qwt_scale_engine.h"
00024 #include "qwt_text_label.h"
00025 #include "qwt_legend.h"
00026 #include "qwt_dyngrid_layout.h"
00027 #include "qwt_plot_canvas.h"
00028 #include "qwt_paint_buffer.h"
00029 
00030 class QwtPlot::PrivateData
00031 {
00032 public:
00033     QwtTextLabel *lblTitle;
00034     QwtPlotCanvas *canvas;
00035     QwtLegend *legend;
00036     QwtPlotLayout *layout;
00037 
00038     bool autoReplot;
00039 };
00040 
00046 QwtPlot::QwtPlot(QWidget *parent):
00047     QFrame(parent)
00048 {
00049     initPlot(QwtText());
00050 }
00051 
00052 
00058 QwtPlot::QwtPlot(const QwtText &title, QWidget *parent) :
00059     QFrame(parent)
00060 {
00061     initPlot(title);
00062 }
00063 
00065 QwtPlot::~QwtPlot()
00066 {
00067     detachItems(QwtPlotItem::Rtti_PlotItem, autoDelete());
00068 
00069     delete d_data->layout;
00070     deleteAxesData();
00071     delete d_data;
00072 }
00073 
00078 void QwtPlot::initPlot(const QwtText &title)
00079 {
00080     d_data = new PrivateData;
00081 
00082 #if QT_VERSION < 0x040000
00083     setWFlags(Qt::WNoAutoErase);
00084 #endif 
00085 
00086     d_data->layout = new QwtPlotLayout;
00087 
00088     d_data->autoReplot = false;
00089 
00090     d_data->lblTitle = new QwtTextLabel(title, this);
00091     d_data->lblTitle->setFont(QFont(fontInfo().family(), 14, QFont::Bold));
00092 
00093     QwtText text(title);
00094     int flags = Qt::AlignCenter;
00095 #if QT_VERSION < 0x040000
00096     flags |= Qt::WordBreak | Qt::ExpandTabs;
00097 #else
00098     flags |= Qt::TextWordWrap;
00099 #endif
00100     text.setFlags(flags);
00101     d_data->lblTitle->setText(text);
00102 
00103     d_data->legend = NULL;
00104 
00105     initAxesData();
00106 
00107     d_data->canvas = new QwtPlotCanvas(this);
00108     d_data->canvas->setFrameStyle(QFrame::Panel|QFrame::Sunken);
00109     d_data->canvas->setLineWidth(2);
00110     d_data->canvas->setMidLineWidth(0);
00111 
00112     updateTabOrder();
00113 
00114     setSizePolicy(QSizePolicy::MinimumExpanding, 
00115         QSizePolicy::MinimumExpanding);
00116 }
00117 
00121 bool QwtPlot::event(QEvent *e)
00122 {
00123     bool ok = QFrame::event(e);
00124     switch(e->type())
00125     {
00126 #if QT_VERSION < 0x040000
00127         case QEvent::LayoutHint:
00128 #else
00129         case QEvent::LayoutRequest:
00130 #endif
00131             updateLayout();
00132             break;
00133 #if QT_VERSION >= 0x040000
00134         case QEvent::PolishRequest:
00135             polish();
00136             break;
00137 #endif
00138         default:;
00139     }
00140     return ok;
00141 }
00142 
00147 void QwtPlot::autoRefresh()
00148 {
00149     if (d_data->autoReplot)
00150         replot();
00151 }
00152 
00167 void QwtPlot::setAutoReplot(bool tf)
00168 {
00169     d_data->autoReplot = tf;
00170 }
00171 
00175 bool QwtPlot::autoReplot() const
00176 {
00177     return d_data->autoReplot; 
00178 }
00179 
00184 void QwtPlot::setTitle(const QString &t)
00185 {
00186     d_data->lblTitle->setText(t);
00187 }
00188 
00193 void QwtPlot::setTitle(const QwtText &t)
00194 {
00195     d_data->lblTitle->setText(t);
00196 }
00197 
00202 QwtText QwtPlot::title() const
00203 {
00204     return d_data->lblTitle->text();
00205 }
00206 
00210 QwtPlotLayout *QwtPlot::plotLayout()
00211 {
00212     return d_data->layout;
00213 }
00214 
00218 const QwtPlotLayout *QwtPlot::plotLayout() const
00219 {
00220     return d_data->layout;
00221 }
00222 
00226 QwtTextLabel *QwtPlot::titleLabel()
00227 {
00228     return d_data->lblTitle;
00229 }
00230 
00234 const QwtTextLabel *QwtPlot::titleLabel() const
00235 {
00236     return d_data->lblTitle;
00237 }
00238 
00243 QwtLegend *QwtPlot::legend()
00244 { 
00245     return d_data->legend;
00246 }   
00247 
00252 const QwtLegend *QwtPlot::legend() const
00253 { 
00254     return d_data->legend;
00255 }   
00256 
00257 
00261 QwtPlotCanvas *QwtPlot::canvas()
00262 { 
00263     return d_data->canvas;
00264 }   
00265 
00269 const QwtPlotCanvas *QwtPlot::canvas() const
00270 { 
00271     return d_data->canvas;
00272 }
00273 
00274 void QwtPlot::polish()
00275 {
00276     replot();
00277 
00278 #if QT_VERSION < 0x040000
00279     QFrame::polish();
00280 #endif
00281 }
00282 
00288 QSize QwtPlot::sizeHint() const
00289 {
00290     int dw = 0;
00291     int dh = 0;
00292     for ( int axisId = 0; axisId < axisCnt; axisId++ )
00293     {
00294         if ( axisEnabled(axisId) )
00295         {   
00296             const int niceDist = 40;
00297             const QwtScaleWidget *scaleWidget = axisWidget(axisId);
00298             const QwtScaleDiv &scaleDiv = scaleWidget->scaleDraw()->scaleDiv();
00299             const int majCnt = scaleDiv.ticks(QwtScaleDiv::MajorTick).count();
00300 
00301             if ( axisId == yLeft || axisId == yRight )
00302             {
00303                 int hDiff = (majCnt - 1) * niceDist 
00304                     - scaleWidget->minimumSizeHint().height();
00305                 if ( hDiff > dh )
00306                     dh = hDiff;
00307             }
00308             else
00309             {
00310                 int wDiff = (majCnt - 1) * niceDist 
00311                     - scaleWidget->minimumSizeHint().width();
00312                 if ( wDiff > dw )
00313                     dw = wDiff;
00314             }
00315         }
00316     }
00317     return minimumSizeHint() + QSize(dw, dh);
00318 }
00319 
00323 QSize QwtPlot::minimumSizeHint() const
00324 {
00325     QSize hint = d_data->layout->minimumSizeHint(this);
00326     hint += QSize(2 * frameWidth(), 2 * frameWidth());
00327 
00328     return hint;
00329 }
00330 
00332 void QwtPlot::resizeEvent(QResizeEvent *e)
00333 {
00334     QFrame::resizeEvent(e);
00335     updateLayout();
00336 }
00337 
00348 void QwtPlot::replot()
00349 {
00350     bool doAutoReplot = autoReplot();
00351     setAutoReplot(false);
00352 
00353     updateAxes();
00354 
00355     /*
00356       Maybe the layout needs to be updated, because of changed
00357       axes labels. We need to process them here before painting
00358       to avoid that scales and canvas get out of sync.
00359      */
00360 #if QT_VERSION >= 0x040000
00361     QApplication::sendPostedEvents(this, QEvent::LayoutRequest);
00362 #else
00363     QApplication::sendPostedEvents(this, QEvent::LayoutHint);
00364 #endif
00365 
00366     QwtPlotCanvas &canvas = *d_data->canvas;
00367 
00368     canvas.invalidatePaintCache();
00369 
00370     /*
00371       In case of cached or packed painting the canvas
00372       is repainted completely and doesn't need to be erased.
00373      */
00374     const bool erase = 
00375         !canvas.testPaintAttribute(QwtPlotCanvas::PaintPacked) 
00376         && !canvas.testPaintAttribute(QwtPlotCanvas::PaintCached);
00377 
00378 #if QT_VERSION >= 0x040000
00379     const bool noBackgroundMode = canvas.testAttribute(Qt::WA_NoBackground);
00380     if ( !erase && !noBackgroundMode )
00381         canvas.setAttribute(Qt::WA_NoBackground, true);
00382 
00383     canvas.repaint(canvas.contentsRect());
00384 
00385     if ( !erase && !noBackgroundMode )
00386         canvas.setAttribute(Qt::WA_NoBackground, false);
00387 #else
00388     canvas.repaint(canvas.contentsRect(), erase);
00389 #endif
00390 
00391     setAutoReplot(doAutoReplot);
00392 }
00393 
00398 void QwtPlot::updateLayout()
00399 {
00400     d_data->layout->activate(this, contentsRect());
00401 
00402     //
00403     // resize and show the visible widgets
00404     //
00405     if (!d_data->lblTitle->text().isEmpty())
00406     {
00407         d_data->lblTitle->setGeometry(d_data->layout->titleRect());
00408         if (!d_data->lblTitle->isVisible())
00409             d_data->lblTitle->show();
00410     }
00411     else
00412         d_data->lblTitle->hide();
00413 
00414     for (int axisId = 0; axisId < axisCnt; axisId++ )
00415     {
00416         if (axisEnabled(axisId) )
00417         {
00418             axisWidget(axisId)->setGeometry(d_data->layout->scaleRect(axisId));
00419 
00420             if ( axisId == xBottom || axisId == xTop )
00421             {
00422                 QRegion r(d_data->layout->scaleRect(axisId));
00423                 if ( axisEnabled(yLeft) )
00424                     r = r.subtract(QRegion(d_data->layout->scaleRect(yLeft)));
00425                 if ( axisEnabled(yRight) )
00426                     r = r.subtract(QRegion(d_data->layout->scaleRect(yRight)));
00427                 r.translate(-d_data->layout->scaleRect(axisId).x(), 
00428                     -d_data->layout->scaleRect(axisId).y());
00429 
00430                 axisWidget(axisId)->setMask(r);
00431             }
00432             if (!axisWidget(axisId)->isVisible())
00433                 axisWidget(axisId)->show();
00434         }
00435         else
00436             axisWidget(axisId)->hide();
00437     }
00438 
00439     if ( d_data->legend )
00440     {
00441         if (d_data->legend->itemCount() > 0)
00442         {
00443             d_data->legend->setGeometry(d_data->layout->legendRect());
00444             d_data->legend->show();
00445         }
00446         else
00447             d_data->legend->hide();
00448     }
00449 
00450     d_data->canvas->setGeometry(d_data->layout->canvasRect());
00451 }
00452 
00454 
00455 void QwtPlot::updateTabOrder()
00456 {
00457 #if QT_VERSION >= 0x040000
00458     using namespace Qt; // QWidget::NoFocus/Qt::NoFocus
00459 #endif
00460     if ( !legend() || legend()->legendItems().count() == 0
00461         || d_data->canvas->focusPolicy() == NoFocus )
00462     {
00463         return;
00464     }
00465 
00466     // Depending on the position of the legend the 
00467     // tab order will be changed that the canvas is
00468     // next to the last legend item, or before
00469     // the first one. 
00470 
00471     const bool canvasFirst = 
00472         d_data->layout->legendPosition() == QwtPlot::BottomLegend ||
00473         d_data->layout->legendPosition() == QwtPlot::RightLegend;
00474 
00475     QWidget *previous = NULL; 
00476 
00477     QWidget *w;
00478 #if QT_VERSION >= 0x040000
00479     while ( nextInFocusChain() != d_data->canvas );
00480     while ( (w = nextInFocusChain()) != d_data->canvas )
00481 #else
00482     if ( focusData() == NULL )
00483         return;
00484 
00485     while ( focusData()->next() != d_data->canvas );
00486     while ( (w = focusData()->next()) != d_data->canvas )
00487 #endif
00488     {
00489         bool isLegendItem = false;
00490         if ( w->focusPolicy() != NoFocus 
00491             && w->parent() && w->parent() == d_data->legend->contentsWidget() )
00492         {
00493             isLegendItem = true;
00494         }
00495 
00496         if ( canvasFirst )
00497         {
00498             if ( isLegendItem )
00499                 break;
00500 
00501             previous = w;
00502         }
00503         else
00504         {
00505             if ( isLegendItem )
00506                 previous = w;
00507             else
00508             {
00509                 if ( previous )
00510                     break;
00511             }
00512         }
00513     }
00514 
00515     if ( previous && previous != d_data->canvas)
00516         setTabOrder(previous, d_data->canvas);
00517 }
00518 
00529 void QwtPlot::drawCanvas(QPainter *painter)
00530 {
00531     QwtArray<QwtScaleMap> maps(axisCnt);
00532     for ( int axisId = 0; axisId < axisCnt; axisId++ )
00533         maps[axisId] = canvasMap(axisId);
00534 
00535     drawItems(painter, 
00536         d_data->canvas->contentsRect(), maps, QwtPlotPrintFilter());
00537 }
00538 
00547 void QwtPlot::drawItems(QPainter *painter, const QRect &rect, 
00548         const QwtArray<QwtScaleMap> &map, 
00549         const QwtPlotPrintFilter &pfilter) const
00550 {
00551     painter->save();
00552 
00553     const QwtPlotItemList& itmList = itemList();
00554     for ( QwtPlotItemIterator it = itmList.begin();
00555         it != itmList.end(); ++it )
00556     {
00557         QwtPlotItem *item = *it;
00558         if ( item && item->isVisible() )
00559         {
00560             if ( !(pfilter.options() & QwtPlotPrintFilter::PrintGrid)
00561                 && item->rtti() == QwtPlotItem::Rtti_PlotGrid )
00562             {
00563                 continue;
00564             }
00565 
00566 #if QT_VERSION >= 0x040000
00567             const QPaintEngine *pe = painter->device()->paintEngine();
00568             if (pe->hasFeature(QPaintEngine::Antialiasing) )
00569             {
00570                 painter->setRenderHint(QPainter::Antialiasing,
00571                     item->testRenderHint(QwtPlotItem::RenderAntialiased) );
00572             }
00573 #endif
00574 
00575             item->draw(painter, 
00576                 map[item->xAxis()], map[item->yAxis()],
00577                 rect);
00578         }
00579     }
00580 
00581     painter->restore();
00582 }
00583 
00591 QwtScaleMap QwtPlot::canvasMap(int axisId) const
00592 {
00593     QwtScaleMap map;
00594     if ( !d_data->canvas )
00595         return map;
00596 
00597     map.setTransformation(axisScaleEngine(axisId)->transformation());
00598 
00599     const QwtScaleDiv *sd = axisScaleDiv(axisId);
00600     map.setScaleInterval(sd->lBound(), sd->hBound());
00601 
00602     if ( axisEnabled(axisId) )
00603     {
00604         const QwtScaleWidget *s = axisWidget(axisId);
00605         if ( axisId == yLeft || axisId == yRight )
00606         {
00607             int y = s->y() + s->startBorderDist() - d_data->canvas->y();
00608             int h = s->height() - s->startBorderDist() - s->endBorderDist();
00609             map.setPaintInterval(y + h - 1, y);
00610         }
00611         else
00612         {
00613             int x = s->x() + s->startBorderDist() - d_data->canvas->x();
00614             int w = s->width() - s->startBorderDist() - s->endBorderDist();
00615             map.setPaintInterval(x, x + w - 1);
00616         }
00617     }
00618     else
00619     {
00620         const int margin = plotLayout()->canvasMargin(axisId);
00621 
00622         const QRect &canvasRect = d_data->canvas->contentsRect();
00623         if ( axisId == yLeft || axisId == yRight )
00624         {
00625             map.setPaintInterval(canvasRect.bottom() - margin, 
00626                 canvasRect.top() + margin);
00627         }
00628         else
00629         {
00630             map.setPaintInterval(canvasRect.left() + margin, 
00631                 canvasRect.right() - margin);
00632         }
00633     }
00634     return map;
00635 }
00636 
00644 void QwtPlot::setMargin(int margin)
00645 {
00646     if ( margin < 0 )
00647         margin = 0;
00648 
00649     if ( margin != d_data->layout->margin() )
00650     {
00651         d_data->layout->setMargin(margin);
00652         updateLayout();
00653     }
00654 }
00655 
00660 int QwtPlot::margin() const
00661 {
00662     return d_data->layout->margin();
00663 }
00664 
00673 void QwtPlot::setCanvasBackground(const QColor &c)
00674 {
00675     QPalette p = d_data->canvas->palette();
00676 
00677     for ( int i = 0; i < QPalette::NColorGroups; i++ )
00678     {
00679 #if QT_VERSION < 0x040000
00680         p.setColor((QPalette::ColorGroup)i, QColorGroup::Background, c);
00681 #else
00682         p.setColor((QPalette::ColorGroup)i, QPalette::Background, c);
00683 #endif
00684     }
00685 
00686     canvas()->setPalette(p);
00687 }
00688 
00695 const QColor & QwtPlot::canvasBackground() const
00696 {
00697 #if QT_VERSION < 0x040000
00698     return canvas()->palette().color(
00699         QPalette::Normal, QColorGroup::Background);
00700 #else
00701     return canvas()->palette().color(
00702         QPalette::Normal, QPalette::Background);
00703 #endif
00704 }
00705 
00712 void QwtPlot::setCanvasLineWidth(int w)
00713 {
00714     canvas()->setLineWidth(w);
00715 }
00716  
00722 int QwtPlot::canvasLineWidth() const
00723 { 
00724     return canvas()->lineWidth();
00725 }
00726 
00731 bool QwtPlot::axisValid(int axisId)
00732 {
00733     return ((axisId >= QwtPlot::yLeft) && (axisId < QwtPlot::axisCnt));
00734 }
00735 
00741 void QwtPlot::legendItemClicked()
00742 {
00743     if ( d_data->legend && sender()->isWidgetType() )
00744     {
00745         QwtPlotItem *plotItem = d_data->legend->find((QWidget *)sender());
00746         if ( plotItem )
00747             emit legendClicked(plotItem);
00748     }
00749 }
00750 
00751 void QwtPlot::legendItemChecked(bool on)
00752 {
00753     if ( d_data->legend && sender()->isWidgetType() )
00754     {
00755         QwtPlotItem *plotItem = d_data->legend->find((QWidget *)sender());
00756         if ( plotItem )
00757             emit legendChecked(plotItem, on);
00758     }
00759 }
00760 
00762 void QwtPlot::clear()
00763 {
00764     detachItems(QwtPlotItem::Rtti_PlotCurve);
00765     detachItems(QwtPlotItem::Rtti_PlotMarker);
00766 }
00767 
00794 void QwtPlot::insertLegend(QwtLegend *legend, 
00795     QwtPlot::LegendPosition pos, double ratio)
00796 {
00797     d_data->layout->setLegendPosition(pos, ratio);
00798 
00799     if ( legend != d_data->legend )
00800     {
00801         delete d_data->legend;
00802         d_data->legend = legend;
00803 
00804         if ( d_data->legend )
00805         {
00806             if ( d_data->legend->parent() != this )
00807             {
00808 #if QT_VERSION < 0x040000
00809                 d_data->legend->reparent(this, QPoint(0, 0));
00810 #else
00811                 d_data->legend->setParent(this);
00812 #endif
00813             }
00814 
00815             const QwtPlotItemList& itmList = itemList();
00816             for ( QwtPlotItemIterator it = itmList.begin();
00817                 it != itmList.end(); ++it )
00818             {
00819                 (*it)->updateLegend(d_data->legend);
00820             }
00821 
00822             QLayout *l = d_data->legend->contentsWidget()->layout();
00823             if ( l && l->inherits("QwtDynGridLayout") )
00824             {
00825                 QwtDynGridLayout *tl = (QwtDynGridLayout *)l;
00826                 if ( d_data->layout->legendPosition() == QwtPlot::TopLegend ||
00827                     d_data->layout->legendPosition() == QwtPlot::BottomLegend )
00828                 {
00829                     tl->setMaxCols(0); // unlimited
00830                 }
00831                 else
00832                     tl->setMaxCols(1); // 1 column: align vertical
00833             }
00834         }
00835         updateTabOrder();
00836     }
00837 
00838     updateLayout();
00839 }

Generated on Mon Jan 30 22:16:25 2006 for Qwt User's Guide by  doxygen 1.4.4