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_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
00385
00386
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
00400
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
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;
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
00498
00499
00500
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);
00868 break;
00869 case TopLegend:
00870 case BottomLegend:
00871 tl->setMaxCols(0);
00872 break;
00873 case ExternalLegend:
00874 break;
00875 }
00876 }
00877 }
00878 updateTabOrder();
00879 }
00880
00881 updateLayout();
00882 }