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_scale_widget.h"
00024 #include "qwt_scale_engine.h"
00025 #include "qwt_text_label.h"
00026 #include "qwt_legend.h"
00027 #include "qwt_dyngrid_layout.h"
00028 #include "qwt_plot_canvas.h"
00029 #include "qwt_paint_buffer.h"
00030 
00031 class QwtPlot::PrivateData
00032 {
00033 public:
00034 #if QT_VERSION < 0x040000
00035     QGuardedPtr<QwtTextLabel> lblTitle;
00036     QGuardedPtr<QwtPlotCanvas> canvas;
00037     QGuardedPtr<QwtLegend> legend;
00038 #else
00039     QPointer<QwtTextLabel> lblTitle;
00040     QPointer<QwtPlotCanvas> canvas;
00041     QPointer<QwtLegend> legend;
00042 #endif
00043     QwtPlotLayout *layout;
00044 
00045     bool autoReplot;
00046 };
00047 
00052 QwtPlot::QwtPlot(QWidget *parent):
00053     QFrame(parent)
00054 {
00055     initPlot(QwtText());
00056 }
00057 
00063 QwtPlot::QwtPlot(const QwtText &title, QWidget *parent):
00064     QFrame(parent)
00065 {
00066     initPlot(title);
00067 }
00068 
00069 #if QT_VERSION < 0x040000
00070 
00075 QwtPlot::QwtPlot(QWidget *parent, const char *name):
00076     QFrame(parent, name)
00077 {   
00078     initPlot(QwtText());
00079 }   
00080 #endif
00081 
00082 
00084 QwtPlot::~QwtPlot()
00085 {
00086     detachItems(QwtPlotItem::Rtti_PlotItem, autoDelete());
00087 
00088     delete d_data->layout;
00089     deleteAxesData();
00090     delete d_data;
00091 }
00092 
00097 void QwtPlot::initPlot(const QwtText &title)
00098 {
00099     d_data = new PrivateData;
00100 
00101 #if QT_VERSION < 0x040000
00102     setWFlags(Qt::WNoAutoErase);
00103 #endif 
00104 
00105     d_data->layout = new QwtPlotLayout;
00106 
00107     d_data->autoReplot = false;
00108 
00109     d_data->lblTitle = new QwtTextLabel(title, this);
00110     d_data->lblTitle->setFont(QFont(fontInfo().family(), 14, QFont::Bold));
00111 
00112     QwtText text(title);
00113     int flags = Qt::AlignCenter;
00114 #if QT_VERSION < 0x040000
00115     flags |= Qt::WordBreak | Qt::ExpandTabs;
00116 #else
00117     flags |= Qt::TextWordWrap;
00118 #endif
00119     text.setRenderFlags(flags);
00120     d_data->lblTitle->setText(text);
00121 
00122     d_data->legend = NULL;
00123 
00124     initAxesData();
00125 
00126     d_data->canvas = new QwtPlotCanvas(this);
00127     d_data->canvas->setFrameStyle(QFrame::Panel|QFrame::Sunken);
00128     d_data->canvas->setLineWidth(2);
00129     d_data->canvas->setMidLineWidth(0);
00130 
00131     updateTabOrder();
00132 
00133     setSizePolicy(QSizePolicy::MinimumExpanding, 
00134         QSizePolicy::MinimumExpanding);
00135 }
00136 
00140 bool QwtPlot::event(QEvent *e)
00141 {
00142     bool ok = QFrame::event(e);
00143     switch(e->type())
00144     {
00145 #if QT_VERSION < 0x040000
00146         case QEvent::LayoutHint:
00147 #else
00148         case QEvent::LayoutRequest:
00149 #endif
00150             updateLayout();
00151             break;
00152 #if QT_VERSION >= 0x040000
00153         case QEvent::PolishRequest:
00154             polish();
00155             break;
00156 #endif
00157         default:;
00158     }
00159     return ok;
00160 }
00161 
00163 void QwtPlot::autoRefresh()
00164 {
00165     if (d_data->autoReplot)
00166         replot();
00167 }
00168 
00184 void QwtPlot::setAutoReplot(bool tf)
00185 {
00186     d_data->autoReplot = tf;
00187 }
00188 
00190 bool QwtPlot::autoReplot() const
00191 {
00192     return d_data->autoReplot; 
00193 }
00194 
00199 void QwtPlot::setTitle(const QString &title)
00200 {
00201     if ( title != d_data->lblTitle->text().text() )
00202     {
00203         d_data->lblTitle->setText(title);
00204         updateLayout();
00205     }
00206 }
00207 
00212 void QwtPlot::setTitle(const QwtText &title)
00213 {
00214     if ( title != d_data->lblTitle->text() )
00215     {
00216         d_data->lblTitle->setText(title);
00217         updateLayout();
00218     }
00219 }
00220 
00222 QwtText QwtPlot::title() const
00223 {
00224     return d_data->lblTitle->text();
00225 }
00226 
00228 QwtPlotLayout *QwtPlot::plotLayout()
00229 {
00230     return d_data->layout;
00231 }
00232 
00234 const QwtPlotLayout *QwtPlot::plotLayout() const
00235 {
00236     return d_data->layout;
00237 }
00238 
00240 QwtTextLabel *QwtPlot::titleLabel()
00241 {
00242     return d_data->lblTitle;
00243 }
00244 
00248 const QwtTextLabel *QwtPlot::titleLabel() const
00249 {
00250     return d_data->lblTitle;
00251 }
00252 
00257 QwtLegend *QwtPlot::legend()
00258 { 
00259     return d_data->legend;
00260 }   
00261 
00266 const QwtLegend *QwtPlot::legend() const
00267 { 
00268     return d_data->legend;
00269 }   
00270 
00271 
00275 QwtPlotCanvas *QwtPlot::canvas()
00276 { 
00277     return d_data->canvas;
00278 }   
00279 
00283 const QwtPlotCanvas *QwtPlot::canvas() const
00284 { 
00285     return d_data->canvas;
00286 }
00287 
00289 void QwtPlot::polish()
00290 {
00291     replot();
00292 
00293 #if QT_VERSION < 0x040000
00294     QFrame::polish();
00295 #endif
00296 }
00297 
00303 QSize QwtPlot::sizeHint() const
00304 {
00305     int dw = 0;
00306     int dh = 0;
00307     for ( int axisId = 0; axisId < axisCnt; axisId++ )
00308     {
00309         if ( axisEnabled(axisId) )
00310         {   
00311             const int niceDist = 40;
00312             const QwtScaleWidget *scaleWidget = axisWidget(axisId);
00313             const QwtScaleDiv &scaleDiv = scaleWidget->scaleDraw()->scaleDiv();
00314             const int majCnt = scaleDiv.ticks(QwtScaleDiv::MajorTick).count();
00315 
00316             if ( axisId == yLeft || axisId == yRight )
00317             {
00318                 int hDiff = (majCnt - 1) * niceDist 
00319                     - scaleWidget->minimumSizeHint().height();
00320                 if ( hDiff > dh )
00321                     dh = hDiff;
00322             }
00323             else
00324             {
00325                 int wDiff = (majCnt - 1) * niceDist 
00326                     - scaleWidget->minimumSizeHint().width();
00327                 if ( wDiff > dw )
00328                     dw = wDiff;
00329             }
00330         }
00331     }
00332     return minimumSizeHint() + QSize(dw, dh);
00333 }
00334 
00338 QSize QwtPlot::minimumSizeHint() const
00339 {
00340     QSize hint = d_data->layout->minimumSizeHint(this);
00341     hint += QSize(2 * frameWidth(), 2 * frameWidth());
00342 
00343     return hint;
00344 }
00345 
00347 void QwtPlot::resizeEvent(QResizeEvent *e)
00348 {
00349     QFrame::resizeEvent(e);
00350     updateLayout();
00351 }
00352 
00363 void QwtPlot::replot()
00364 {
00365     bool doAutoReplot = autoReplot();
00366     setAutoReplot(false);
00367 
00368     updateAxes();
00369 
00370     /*
00371       Maybe the layout needs to be updated, because of changed
00372       axes labels. We need to process them here before painting
00373       to avoid that scales and canvas get out of sync.
00374      */
00375 #if QT_VERSION >= 0x040000
00376     QApplication::sendPostedEvents(this, QEvent::LayoutRequest);
00377 #else
00378     QApplication::sendPostedEvents(this, QEvent::LayoutHint);
00379 #endif
00380 
00381     QwtPlotCanvas &canvas = *d_data->canvas;
00382 
00383     canvas.invalidatePaintCache();
00384 
00385     /*
00386       In case of cached or packed painting the canvas
00387       is repainted completely and doesn't need to be erased.
00388      */
00389     const bool erase = 
00390         !canvas.testPaintAttribute(QwtPlotCanvas::PaintPacked) 
00391         && !canvas.testPaintAttribute(QwtPlotCanvas::PaintCached);
00392 
00393 #if QT_VERSION >= 0x040000
00394     const bool noBackgroundMode = canvas.testAttribute(Qt::WA_NoBackground);
00395     if ( !erase && !noBackgroundMode )
00396         canvas.setAttribute(Qt::WA_NoBackground, true);
00397 
00398     canvas.repaint(canvas.contentsRect());
00399 
00400     if ( !erase && !noBackgroundMode )
00401         canvas.setAttribute(Qt::WA_NoBackground, false);
00402 #else
00403     canvas.repaint(canvas.contentsRect(), erase);
00404 #endif
00405 
00406     setAutoReplot(doAutoReplot);
00407 }
00408 
00413 void QwtPlot::updateLayout()
00414 {
00415     d_data->layout->activate(this, contentsRect());
00416 
00417     //
00418     // resize and show the visible widgets
00419     //
00420     if (!d_data->lblTitle->text().isEmpty())
00421     {
00422         d_data->lblTitle->setGeometry(d_data->layout->titleRect());
00423         if (!d_data->lblTitle->isVisible())
00424             d_data->lblTitle->show();
00425     }
00426     else
00427         d_data->lblTitle->hide();
00428 
00429     for (int axisId = 0; axisId < axisCnt; axisId++ )
00430     {
00431         if (axisEnabled(axisId) )
00432         {
00433             axisWidget(axisId)->setGeometry(d_data->layout->scaleRect(axisId));
00434 
00435             if ( axisId == xBottom || axisId == xTop )
00436             {
00437                 QRegion r(d_data->layout->scaleRect(axisId));
00438                 if ( axisEnabled(yLeft) )
00439                     r = r.subtract(QRegion(d_data->layout->scaleRect(yLeft)));
00440                 if ( axisEnabled(yRight) )
00441                     r = r.subtract(QRegion(d_data->layout->scaleRect(yRight)));
00442                 r.translate(-d_data->layout->scaleRect(axisId).x(), 
00443                     -d_data->layout->scaleRect(axisId).y());
00444 
00445                 axisWidget(axisId)->setMask(r);
00446             }
00447             if (!axisWidget(axisId)->isVisible())
00448                 axisWidget(axisId)->show();
00449         }
00450         else
00451             axisWidget(axisId)->hide();
00452     }
00453 
00454     if ( d_data->legend && 
00455         d_data->layout->legendPosition() != ExternalLegend )
00456     {
00457         if (d_data->legend->itemCount() > 0)
00458         {
00459             d_data->legend->setGeometry(d_data->layout->legendRect());
00460             d_data->legend->show();
00461         }
00462         else
00463             d_data->legend->hide();
00464     }
00465 
00466     d_data->canvas->setGeometry(d_data->layout->canvasRect());
00467 }
00468 
00477 void QwtPlot::updateTabOrder()
00478 {
00479 #if QT_VERSION >= 0x040000
00480     using namespace Qt; // QWidget::NoFocus/Qt::NoFocus
00481 #else
00482     if ( d_data->canvas->focusPolicy() == NoFocus )
00483         return;
00484 #endif
00485     if ( d_data->legend.isNull()  
00486         || d_data->layout->legendPosition() == ExternalLegend
00487         || d_data->legend->legendItems().count() == 0 )
00488     {
00489         return;
00490     }
00491 
00492     // Depending on the position of the legend the 
00493     // tab order will be changed that the canvas is
00494     // next to the last legend item, or before
00495     // the first one. 
00496 
00497     const bool canvasFirst = 
00498         d_data->layout->legendPosition() == QwtPlot::BottomLegend ||
00499         d_data->layout->legendPosition() == QwtPlot::RightLegend;
00500 
00501     QWidget *previous = NULL; 
00502 
00503     QWidget *w;
00504 #if QT_VERSION >= 0x040000
00505     w = d_data->canvas;
00506     while ( ( w = w->nextInFocusChain() ) != d_data->canvas )
00507 #else
00508     if ( focusData() == NULL )
00509         return;
00510 
00511     while ( focusData()->next() != d_data->canvas );
00512     while ( (w = focusData()->next()) != d_data->canvas )
00513 #endif
00514     {
00515         bool isLegendItem = false;
00516         if ( w->focusPolicy() != NoFocus 
00517             && w->parent() && w->parent() == d_data->legend->contentsWidget() )
00518         {
00519             isLegendItem = true;
00520         }
00521 
00522         if ( canvasFirst )
00523         {
00524             if ( isLegendItem )
00525                 break;
00526 
00527             previous = w;
00528         }
00529         else
00530         {
00531             if ( isLegendItem )
00532                 previous = w;
00533             else
00534             {
00535                 if ( previous )
00536                     break;
00537             }
00538         }
00539     }
00540 
00541     if ( previous && previous != d_data->canvas)
00542         setTabOrder(previous, d_data->canvas);
00543 }
00544 
00554 void QwtPlot::drawCanvas(QPainter *painter)
00555 {
00556     QwtScaleMap maps[axisCnt];
00557     for ( int axisId = 0; axisId < axisCnt; axisId++ )
00558         maps[axisId] = canvasMap(axisId);
00559 
00560     drawItems(painter, 
00561         d_data->canvas->contentsRect(), maps, QwtPlotPrintFilter());
00562 }
00563 
00572 void QwtPlot::drawItems(QPainter *painter, const QRect &rect, 
00573         const QwtScaleMap map[axisCnt], 
00574         const QwtPlotPrintFilter &pfilter) const
00575 {
00576     const QwtPlotItemList& itmList = itemList();
00577     for ( QwtPlotItemIterator it = itmList.begin();
00578         it != itmList.end(); ++it )
00579     {
00580         QwtPlotItem *item = *it;
00581         if ( item && item->isVisible() )
00582         {
00583             if ( !(pfilter.options() & QwtPlotPrintFilter::PrintGrid)
00584                 && item->rtti() == QwtPlotItem::Rtti_PlotGrid )
00585             {
00586                 continue;
00587             }
00588 
00589             painter->save();
00590 
00591 #if QT_VERSION >= 0x040000
00592             painter->setRenderHint(QPainter::Antialiasing,
00593                 item->testRenderHint(QwtPlotItem::RenderAntialiased) );
00594 #endif
00595 
00596             item->draw(painter, 
00597                 map[item->xAxis()], map[item->yAxis()],
00598                 rect);
00599 
00600             painter->restore();
00601         }
00602     }
00603 }
00604 
00612 QwtScaleMap QwtPlot::canvasMap(int axisId) const
00613 {
00614     QwtScaleMap map;
00615     if ( !d_data->canvas )
00616         return map;
00617 
00618     map.setTransformation(axisScaleEngine(axisId)->transformation());
00619 
00620     const QwtScaleDiv *sd = axisScaleDiv(axisId);
00621     map.setScaleInterval(sd->lBound(), sd->hBound());
00622 
00623     if ( axisEnabled(axisId) )
00624     {
00625         const QwtScaleWidget *s = axisWidget(axisId);
00626         if ( axisId == yLeft || axisId == yRight )
00627         {
00628             int y = s->y() + s->startBorderDist() - d_data->canvas->y();
00629             int h = s->height() - s->startBorderDist() - s->endBorderDist();
00630             map.setPaintInterval(y + h, y);
00631         }
00632         else
00633         {
00634             int x = s->x() + s->startBorderDist() - d_data->canvas->x();
00635             int w = s->width() - s->startBorderDist() - s->endBorderDist();
00636             map.setPaintInterval(x, x + w);
00637         }
00638     }
00639     else
00640     {
00641         const int margin = plotLayout()->canvasMargin(axisId);
00642 
00643         const QRect &canvasRect = d_data->canvas->contentsRect();
00644         if ( axisId == yLeft || axisId == yRight )
00645         {
00646             map.setPaintInterval(canvasRect.bottom() - margin, 
00647                 canvasRect.top() + margin);
00648         }
00649         else
00650         {
00651             map.setPaintInterval(canvasRect.left() + margin, 
00652                 canvasRect.right() - margin);
00653         }
00654     }
00655     return map;
00656 }
00657 
00665 void QwtPlot::setMargin(int margin)
00666 {
00667     if ( margin < 0 )
00668         margin = 0;
00669 
00670     if ( margin != d_data->layout->margin() )
00671     {
00672         d_data->layout->setMargin(margin);
00673         updateLayout();
00674     }
00675 }
00676 
00681 int QwtPlot::margin() const
00682 {
00683     return d_data->layout->margin();
00684 }
00685 
00694 void QwtPlot::setCanvasBackground(const QColor &c)
00695 {
00696     QPalette p = d_data->canvas->palette();
00697 
00698     for ( int i = 0; i < QPalette::NColorGroups; i++ )
00699     {
00700 #if QT_VERSION < 0x040000
00701         p.setColor((QPalette::ColorGroup)i, QColorGroup::Background, c);
00702 #else
00703         p.setColor((QPalette::ColorGroup)i, QPalette::Background, c);
00704 #endif
00705     }
00706 
00707     canvas()->setPalette(p);
00708 }
00709 
00716 const QColor & QwtPlot::canvasBackground() const
00717 {
00718 #if QT_VERSION < 0x040000
00719     return canvas()->palette().color(
00720         QPalette::Normal, QColorGroup::Background);
00721 #else
00722     return canvas()->palette().color(
00723         QPalette::Normal, QPalette::Background);
00724 #endif
00725 }
00726 
00733 void QwtPlot::setCanvasLineWidth(int w)
00734 {
00735     canvas()->setLineWidth(w);
00736     updateLayout();
00737 }
00738  
00744 int QwtPlot::canvasLineWidth() const
00745 { 
00746     return canvas()->lineWidth();
00747 }
00748 
00753 bool QwtPlot::axisValid(int axisId)
00754 {
00755     return ((axisId >= QwtPlot::yLeft) && (axisId < QwtPlot::axisCnt));
00756 }
00757 
00762 void QwtPlot::legendItemClicked()
00763 {
00764     if ( d_data->legend && sender()->isWidgetType() )
00765     {
00766         QwtPlotItem *plotItem = 
00767             (QwtPlotItem*)d_data->legend->find((QWidget *)sender());
00768         if ( plotItem )
00769             emit legendClicked(plotItem);
00770     }
00771 }
00772 
00777 void QwtPlot::legendItemChecked(bool on)
00778 {
00779     if ( d_data->legend && sender()->isWidgetType() )
00780     {
00781         QwtPlotItem *plotItem = 
00782             (QwtPlotItem*)d_data->legend->find((QWidget *)sender());
00783         if ( plotItem )
00784             emit legendChecked(plotItem, on);
00785     }
00786 }
00787 
00789 void QwtPlot::clear()
00790 {
00791     detachItems(QwtPlotItem::Rtti_PlotCurve);
00792     detachItems(QwtPlotItem::Rtti_PlotMarker);
00793 }
00794 
00822 void QwtPlot::insertLegend(QwtLegend *legend, 
00823     QwtPlot::LegendPosition pos, double ratio)
00824 {
00825     d_data->layout->setLegendPosition(pos, ratio);
00826 
00827     if ( legend != d_data->legend )
00828     {
00829         if ( d_data->legend && d_data->legend->parent() == this )
00830             delete d_data->legend;
00831 
00832         d_data->legend = legend;
00833 
00834         if ( d_data->legend )
00835         {
00836             if ( pos != ExternalLegend )
00837             {
00838                 if ( d_data->legend->parent() != this )
00839                 {
00840 #if QT_VERSION < 0x040000
00841                     d_data->legend->reparent(this, QPoint(0, 0));
00842 #else
00843                     d_data->legend->setParent(this);
00844 #endif
00845                 }
00846             }
00847 
00848             const QwtPlotItemList& itmList = itemList();
00849             for ( QwtPlotItemIterator it = itmList.begin();
00850                 it != itmList.end(); ++it )
00851             {
00852                 (*it)->updateLegend(d_data->legend);
00853             }
00854 
00855             QLayout *l = d_data->legend->contentsWidget()->layout();
00856             if ( l && l->inherits("QwtDynGridLayout") )
00857             {
00858                 QwtDynGridLayout *tl = (QwtDynGridLayout *)l;
00859                 switch(d_data->layout->legendPosition())
00860                 {
00861                     case LeftLegend:
00862                     case RightLegend:
00863                         tl->setMaxCols(1); // 1 column: align vertical
00864                         break;
00865                     case TopLegend:
00866                     case BottomLegend:
00867                         tl->setMaxCols(0); // unlimited
00868                         break;
00869                     case ExternalLegend:
00870                         break;
00871                 }
00872             }
00873         }
00874         updateTabOrder();
00875     }
00876 
00877     updateLayout();
00878 }

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