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
00490 void QwtPlot::updateTabOrder()
00491 {
00492 #if QT_VERSION >= 0x040000
00493 using namespace Qt;
00494 #else
00495 if ( d_data->canvas->focusPolicy() == NoFocus )
00496 return;
00497 #endif
00498 if ( d_data->legend.isNull()
00499 || d_data->layout->legendPosition() == ExternalLegend
00500 || d_data->legend->legendItems().count() == 0 )
00501 {
00502 return;
00503 }
00504
00505
00506
00507
00508
00509
00510 const bool canvasFirst =
00511 d_data->layout->legendPosition() == QwtPlot::BottomLegend ||
00512 d_data->layout->legendPosition() == QwtPlot::RightLegend;
00513
00514 QWidget *previous = NULL;
00515
00516 QWidget *w;
00517 #if QT_VERSION >= 0x040000
00518 w = d_data->canvas;
00519 while ( ( w = w->nextInFocusChain() ) != d_data->canvas )
00520 #else
00521 if ( focusData() == NULL )
00522 return;
00523
00524 while ( focusData()->next() != d_data->canvas );
00525 while ( (w = focusData()->next()) != d_data->canvas )
00526 #endif
00527 {
00528 bool isLegendItem = false;
00529 if ( w->focusPolicy() != NoFocus
00530 && w->parent() && w->parent() == d_data->legend->contentsWidget() )
00531 {
00532 isLegendItem = true;
00533 }
00534
00535 if ( canvasFirst )
00536 {
00537 if ( isLegendItem )
00538 break;
00539
00540 previous = w;
00541 }
00542 else
00543 {
00544 if ( isLegendItem )
00545 previous = w;
00546 else
00547 {
00548 if ( previous )
00549 break;
00550 }
00551 }
00552 }
00553
00554 if ( previous && previous != d_data->canvas)
00555 setTabOrder(previous, d_data->canvas);
00556 }
00557
00568 void QwtPlot::drawCanvas(QPainter *painter)
00569 {
00570 QwtScaleMap maps[axisCnt];
00571 for ( int axisId = 0; axisId < axisCnt; axisId++ )
00572 maps[axisId] = canvasMap(axisId);
00573
00574 drawItems(painter,
00575 d_data->canvas->contentsRect(), maps, QwtPlotPrintFilter());
00576 }
00577
00586 void QwtPlot::drawItems(QPainter *painter, const QRect &rect,
00587 const QwtScaleMap map[axisCnt],
00588 const QwtPlotPrintFilter &pfilter) const
00589 {
00590 painter->save();
00591
00592 const QwtPlotItemList& itmList = itemList();
00593 for ( QwtPlotItemIterator it = itmList.begin();
00594 it != itmList.end(); ++it )
00595 {
00596 QwtPlotItem *item = *it;
00597 if ( item && item->isVisible() )
00598 {
00599 if ( !(pfilter.options() & QwtPlotPrintFilter::PrintGrid)
00600 && item->rtti() == QwtPlotItem::Rtti_PlotGrid )
00601 {
00602 continue;
00603 }
00604
00605 #if QT_VERSION >= 0x040000
00606 painter->setRenderHint(QPainter::Antialiasing,
00607 item->testRenderHint(QwtPlotItem::RenderAntialiased) );
00608 #endif
00609
00610 item->draw(painter,
00611 map[item->xAxis()], map[item->yAxis()],
00612 rect);
00613 }
00614 }
00615
00616 painter->restore();
00617 }
00618
00626 QwtScaleMap QwtPlot::canvasMap(int axisId) const
00627 {
00628 QwtScaleMap map;
00629 if ( !d_data->canvas )
00630 return map;
00631
00632 map.setTransformation(axisScaleEngine(axisId)->transformation());
00633
00634 const QwtScaleDiv *sd = axisScaleDiv(axisId);
00635 map.setScaleInterval(sd->lBound(), sd->hBound());
00636
00637 if ( axisEnabled(axisId) )
00638 {
00639 const QwtScaleWidget *s = axisWidget(axisId);
00640 if ( axisId == yLeft || axisId == yRight )
00641 {
00642 int y = s->y() + s->startBorderDist() - d_data->canvas->y();
00643 int h = s->height() - s->startBorderDist() - s->endBorderDist();
00644 map.setPaintInterval(y + h - 1, y);
00645 }
00646 else
00647 {
00648 int x = s->x() + s->startBorderDist() - d_data->canvas->x();
00649 int w = s->width() - s->startBorderDist() - s->endBorderDist();
00650 map.setPaintInterval(x, x + w - 1);
00651 }
00652 }
00653 else
00654 {
00655 const int margin = plotLayout()->canvasMargin(axisId);
00656
00657 const QRect &canvasRect = d_data->canvas->contentsRect();
00658 if ( axisId == yLeft || axisId == yRight )
00659 {
00660 map.setPaintInterval(canvasRect.bottom() - margin,
00661 canvasRect.top() + margin);
00662 }
00663 else
00664 {
00665 map.setPaintInterval(canvasRect.left() + margin,
00666 canvasRect.right() - margin);
00667 }
00668 }
00669 return map;
00670 }
00671
00679 void QwtPlot::setMargin(int margin)
00680 {
00681 if ( margin < 0 )
00682 margin = 0;
00683
00684 if ( margin != d_data->layout->margin() )
00685 {
00686 d_data->layout->setMargin(margin);
00687 updateLayout();
00688 }
00689 }
00690
00695 int QwtPlot::margin() const
00696 {
00697 return d_data->layout->margin();
00698 }
00699
00708 void QwtPlot::setCanvasBackground(const QColor &c)
00709 {
00710 QPalette p = d_data->canvas->palette();
00711
00712 for ( int i = 0; i < QPalette::NColorGroups; i++ )
00713 {
00714 #if QT_VERSION < 0x040000
00715 p.setColor((QPalette::ColorGroup)i, QColorGroup::Background, c);
00716 #else
00717 p.setColor((QPalette::ColorGroup)i, QPalette::Background, c);
00718 #endif
00719 }
00720
00721 canvas()->setPalette(p);
00722 }
00723
00730 const QColor & QwtPlot::canvasBackground() const
00731 {
00732 #if QT_VERSION < 0x040000
00733 return canvas()->palette().color(
00734 QPalette::Normal, QColorGroup::Background);
00735 #else
00736 return canvas()->palette().color(
00737 QPalette::Normal, QPalette::Background);
00738 #endif
00739 }
00740
00747 void QwtPlot::setCanvasLineWidth(int w)
00748 {
00749 canvas()->setLineWidth(w);
00750 updateLayout();
00751 }
00752
00758 int QwtPlot::canvasLineWidth() const
00759 {
00760 return canvas()->lineWidth();
00761 }
00762
00767 bool QwtPlot::axisValid(int axisId)
00768 {
00769 return ((axisId >= QwtPlot::yLeft) && (axisId < QwtPlot::axisCnt));
00770 }
00771
00777 void QwtPlot::legendItemClicked()
00778 {
00779 if ( d_data->legend && sender()->isWidgetType() )
00780 {
00781 QwtPlotItem *plotItem = d_data->legend->find((QWidget *)sender());
00782 if ( plotItem )
00783 emit legendClicked(plotItem);
00784 }
00785 }
00786
00787 void QwtPlot::legendItemChecked(bool on)
00788 {
00789 if ( d_data->legend && sender()->isWidgetType() )
00790 {
00791 QwtPlotItem *plotItem = d_data->legend->find((QWidget *)sender());
00792 if ( plotItem )
00793 emit legendChecked(plotItem, on);
00794 }
00795 }
00796
00798 void QwtPlot::clear()
00799 {
00800 detachItems(QwtPlotItem::Rtti_PlotCurve);
00801 detachItems(QwtPlotItem::Rtti_PlotMarker);
00802 }
00803
00830 void QwtPlot::insertLegend(QwtLegend *legend,
00831 QwtPlot::LegendPosition pos, double ratio)
00832 {
00833 d_data->layout->setLegendPosition(pos, ratio);
00834
00835 if ( legend != d_data->legend )
00836 {
00837 if ( d_data->legend && d_data->legend->parent() == this )
00838 delete d_data->legend;
00839
00840 d_data->legend = legend;
00841
00842 if ( d_data->legend )
00843 {
00844 if ( pos != ExternalLegend )
00845 {
00846 if ( d_data->legend->parent() != this )
00847 {
00848 #if QT_VERSION < 0x040000
00849 d_data->legend->reparent(this, QPoint(0, 0));
00850 #else
00851 d_data->legend->setParent(this);
00852 #endif
00853 }
00854 }
00855
00856 const QwtPlotItemList& itmList = itemList();
00857 for ( QwtPlotItemIterator it = itmList.begin();
00858 it != itmList.end(); ++it )
00859 {
00860 (*it)->updateLegend(d_data->legend);
00861 }
00862
00863 QLayout *l = d_data->legend->contentsWidget()->layout();
00864 if ( l && l->inherits("QwtDynGridLayout") )
00865 {
00866 QwtDynGridLayout *tl = (QwtDynGridLayout *)l;
00867 switch(d_data->layout->legendPosition())
00868 {
00869 case LeftLegend:
00870 case RightLegend:
00871 tl->setMaxCols(1);
00872 break;
00873 case TopLegend:
00874 case BottomLegend:
00875 tl->setMaxCols(0);
00876 break;
00877 case ExternalLegend:
00878 break;
00879 }
00880 }
00881 }
00882 updateTabOrder();
00883 }
00884
00885 updateLayout();
00886 }