00001
00002
00003
00004
00005
00006
00007
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
00372
00373
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
00387
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
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;
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
00493
00494
00495
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);
00864 break;
00865 case TopLegend:
00866 case BottomLegend:
00867 tl->setMaxCols(0);
00868 break;
00869 case ExternalLegend:
00870 break;
00871 }
00872 }
00873 }
00874 updateTabOrder();
00875 }
00876
00877 updateLayout();
00878 }