00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "signalplotter.h"
00024
00025 #include <math.h>
00026 #include <string.h>
00027
00028 #include <QList>
00029 #include <QPalette>
00030 #include <QtGui/QPainter>
00031 #include <QtGui/QPixmap>
00032 #include <QtGui/QPainterPath>
00033 #include <QtGui/QPolygon>
00034
00035 #include <KDebug>
00036 #include <KGlobal>
00037 #include <KLocale>
00038 #include <KApplication>
00039 #include <KStandardDirs>
00040
00041 #include <plasma/svg.h>
00042
00043 namespace Plasma
00044 {
00045
00046 class SignalPlotterPrivate
00047 {
00048 public:
00049 SignalPlotterPrivate()
00050 : svgBackground(0)
00051 { }
00052
00053 ~SignalPlotterPrivate()
00054 {
00055 delete svgBackground;
00056 }
00057
00058 int precision;
00059 uint samples;
00060 uint bezierCurveOffset;
00061
00062 double scaledBy;
00063 double verticalMin;
00064 double verticalMax;
00065 double niceVertMin;
00066 double niceVertMax;
00067 double niceVertRange;
00068
00069 bool fillPlots;
00070 bool showLabels;
00071 bool showTopBar;
00072 bool stackPlots;
00073 bool useAutoRange;
00074 bool showThinFrame;
00075
00076 bool showVerticalLines;
00077 bool verticalLinesScroll;
00078 uint verticalLinesOffset;
00079 uint verticalLinesDistance;
00080 QColor verticalLinesColor;
00081
00082 bool showHorizontalLines;
00083 uint horizontalScale;
00084 uint horizontalLinesCount;
00085 QColor horizontalLinesColor;
00086
00087 Svg *svgBackground;
00088 QString svgFilename;
00089
00090 QColor fontColor;
00091 QColor backgroundColor;
00092 QPixmap backgroundPixmap;
00093
00094 QFont font;
00095 QString title;
00096 QString unit;
00097
00098 QList<PlotColor> plotColors;
00099 QList<QList<double> > plotData;
00100 };
00101
00102 SignalPlotter::SignalPlotter(QGraphicsItem *parent)
00103 : QGraphicsWidget(parent),
00104 d(new SignalPlotterPrivate)
00105 {
00106 d->precision = 0;
00107 d->bezierCurveOffset = 0;
00108 d->samples = 0;
00109 d->verticalMin = d->verticalMax = 0.0;
00110 d->niceVertMin = d->niceVertMax = 0.0;
00111 d->niceVertRange = 0;
00112 d->useAutoRange = true;
00113 d->scaledBy = 1;
00114 d->showThinFrame = true;
00115
00116
00117 setMinimumSize(QSizeF(16, 16));
00118
00119 d->showVerticalLines = true;
00120 d->verticalLinesColor = QColor("black");
00121 d->verticalLinesDistance = 30;
00122 d->verticalLinesScroll = true;
00123 d->verticalLinesOffset = 0;
00124 d->horizontalScale = 1;
00125
00126 d->showHorizontalLines = true;
00127 d->horizontalLinesColor = QColor("black");
00128 d->horizontalLinesCount = 5;
00129
00130 d->showLabels = true;
00131 d->showTopBar = true;
00132 d->stackPlots = true;
00133 d->fillPlots = true;
00134
00135 d->svgBackground = 0;
00136 d->backgroundColor = QColor(0,0,0);
00137
00138 setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
00139 }
00140
00141 SignalPlotter::~SignalPlotter()
00142 {
00143 delete d;
00144 }
00145
00146 QString SignalPlotter::unit() const
00147 {
00148 return d->unit;
00149 }
00150 void SignalPlotter::setUnit(const QString &unit)
00151 {
00152 d->unit= unit;
00153 }
00154
00155 void SignalPlotter::addPlot(const QColor &color)
00156 {
00157
00158
00159 foreach (QList<double> data, d->plotData) {
00160 data.append(0);
00161 }
00162 PlotColor newColor;
00163 newColor.color = color;
00164 newColor.darkColor = color.dark(150);
00165 d->plotColors.append(newColor);
00166 }
00167
00168 void SignalPlotter::addSample(const QList<double>& sampleBuf)
00169 {
00170 if (d->samples < 4) {
00171
00172
00173 kDebug(1215) << "Error - d->samples is only " << d->samples << endl;
00174 updateDataBuffers();
00175 kDebug(1215) << "d->samples is now " << d->samples << endl;
00176 if (d->samples < 4)
00177 return;
00178 }
00179 d->plotData.prepend(sampleBuf);
00180 Q_ASSERT(sampleBuf.count() == d->plotColors.count());
00181 if ((uint)d->plotData.size() > d->samples) {
00182 d->plotData.removeLast();
00183 if ((uint)d->plotData.size() > d->samples)
00184 d->plotData.removeLast();
00185 }
00186
00187 if (d->bezierCurveOffset >= 2) d->bezierCurveOffset = 0;
00188 else d->bezierCurveOffset++;
00189
00190 Q_ASSERT((uint)d->plotData.size() >= d->bezierCurveOffset);
00191
00192
00193
00194 if (d->verticalLinesScroll) {
00195 d->verticalLinesOffset = (d->verticalLinesOffset + d->horizontalScale)
00196 % d->verticalLinesDistance;
00197 }
00198 update();
00199 }
00200
00201 void SignalPlotter::reorderPlots(const QList<uint>& newOrder)
00202 {
00203 if (newOrder.count() != d->plotColors.count()) {
00204 kDebug(1215) << "neworder has " << newOrder.count() << " and plot colors is " << d->plotColors.count() << endl;
00205 return;
00206 }
00207 foreach (QList<double> data, d->plotData) {
00208 if (newOrder.count() != data.count()) {
00209 kDebug(1215) << "Serious problem in move sample. plotdata[i] has " << data.count() << " and neworder has " << newOrder.count() << endl;
00210 } else {
00211 QList<double> newPlot;
00212 for (int i = 0; i < newOrder.count(); i++) {
00213 int newIndex = newOrder[i];
00214 newPlot.append(data.at(newIndex));
00215 }
00216 data = newPlot;
00217 }
00218 }
00219 QList<PlotColor> newPlotColors;
00220 for (int i = 0; i < newOrder.count(); i++) {
00221 int newIndex = newOrder[i];
00222 PlotColor newColor = d->plotColors.at(newIndex);
00223 newPlotColors.append(newColor);
00224 }
00225 d->plotColors = newPlotColors;
00226 }
00227
00228 void SignalPlotter::setVerticalRange(double min, double max)
00229 {
00230 d->verticalMin = min;
00231 d->verticalMax = max;
00232 calculateNiceRange();
00233 }
00234
00235 QList<PlotColor> &SignalPlotter::plotColors()
00236 {
00237 return d->plotColors;
00238 }
00239
00240 void SignalPlotter::removePlot(uint pos)
00241 {
00242 if (pos >= (uint)d->plotColors.size()) return;
00243 d->plotColors.removeAt(pos);
00244
00245 foreach (QList<double> data, d->plotData) {
00246 if ((uint)data.size() >= pos)
00247 data.removeAt(pos);
00248 }
00249 }
00250
00251 void SignalPlotter::scale(qreal delta)
00252 {
00253 if (d->scaledBy == delta) return;
00254 d->scaledBy = delta;
00255 d->backgroundPixmap = QPixmap();
00256 calculateNiceRange();
00257 }
00258
00259 qreal SignalPlotter::scaledBy() const
00260 {
00261 return d->scaledBy;
00262 }
00263
00264 void SignalPlotter::setTitle(const QString &title)
00265 {
00266 if (d->title == title) return;
00267 d->title = title;
00268 d->backgroundPixmap = QPixmap();
00269 }
00270
00271 QString SignalPlotter::title() const
00272 {
00273 return d->title;
00274 }
00275
00276 void SignalPlotter::setUseAutoRange(bool value)
00277 {
00278 d->useAutoRange = value;
00279 calculateNiceRange();
00280
00281 }
00282
00283 bool SignalPlotter::useAutoRange() const
00284 {
00285 return d->useAutoRange;
00286 }
00287
00288 double SignalPlotter::verticalMinValue() const
00289 {
00290 return d->verticalMin;
00291 }
00292
00293 double SignalPlotter::verticalMaxValue() const
00294 {
00295 return d->verticalMax;
00296 }
00297
00298 void SignalPlotter::setHorizontalScale(uint scale)
00299 {
00300 if (scale == d->horizontalScale)
00301 return;
00302
00303 d->horizontalScale = scale;
00304 updateDataBuffers();
00305 d->backgroundPixmap = QPixmap();
00306 }
00307
00308 uint SignalPlotter::horizontalScale() const
00309 {
00310 return d->horizontalScale;
00311 }
00312
00313 void SignalPlotter::setShowVerticalLines(bool value)
00314 {
00315 if (d->showVerticalLines == value) return;
00316 d->showVerticalLines = value;
00317 d->backgroundPixmap = QPixmap();
00318 }
00319
00320 bool SignalPlotter::showVerticalLines() const
00321 {
00322 return d->showVerticalLines;
00323 }
00324
00325 void SignalPlotter::setVerticalLinesColor(const QColor &color)
00326 {
00327 if (d->verticalLinesColor == color) return;
00328 d->verticalLinesColor = color;
00329 d->backgroundPixmap = QPixmap();
00330 }
00331
00332 QColor SignalPlotter::verticalLinesColor() const
00333 {
00334 return d->verticalLinesColor;
00335 }
00336
00337 void SignalPlotter::setVerticalLinesDistance(uint distance)
00338 {
00339 if (distance == d->verticalLinesDistance) return;
00340 d->verticalLinesDistance = distance;
00341 d->backgroundPixmap = QPixmap();
00342 }
00343
00344 uint SignalPlotter::verticalLinesDistance() const
00345 {
00346 return d->verticalLinesDistance;
00347 }
00348
00349 void SignalPlotter::setVerticalLinesScroll(bool value)
00350 {
00351 if (value == d->verticalLinesScroll) return;
00352 d->verticalLinesScroll = value;
00353 d->backgroundPixmap = QPixmap();
00354 }
00355
00356 bool SignalPlotter::verticalLinesScroll() const
00357 {
00358 return d->verticalLinesScroll;
00359 }
00360
00361 void SignalPlotter::setShowHorizontalLines(bool value)
00362 {
00363 if (value == d->showHorizontalLines) return;
00364 d->showHorizontalLines = value;
00365 d->backgroundPixmap = QPixmap();
00366 }
00367
00368 bool SignalPlotter::showHorizontalLines() const
00369 {
00370 return d->showHorizontalLines;
00371 }
00372
00373 void SignalPlotter::setFontColor(const QColor &color)
00374 {
00375 d->fontColor = color;
00376 }
00377
00378 QColor SignalPlotter::fontColor() const
00379 {
00380 return d->fontColor;
00381 }
00382
00383 void SignalPlotter::setHorizontalLinesColor(const QColor &color)
00384 {
00385 if (color == d->horizontalLinesColor) return;
00386 d->horizontalLinesColor = color;
00387 d->backgroundPixmap = QPixmap();
00388 }
00389
00390 QColor SignalPlotter::horizontalLinesColor() const
00391 {
00392 return d->horizontalLinesColor;
00393 }
00394
00395 void SignalPlotter::setHorizontalLinesCount(uint count)
00396 {
00397 if (count == d->horizontalLinesCount) return;
00398 d->horizontalLinesCount = count;
00399 d->backgroundPixmap = QPixmap();
00400 calculateNiceRange();
00401 }
00402
00403 uint SignalPlotter::horizontalLinesCount() const
00404 {
00405 return d->horizontalLinesCount;
00406 }
00407
00408 void SignalPlotter::setShowLabels(bool value)
00409 {
00410 if (value == d->showLabels) return;
00411 d->showLabels = value;
00412 d->backgroundPixmap = QPixmap();
00413 }
00414
00415 bool SignalPlotter::showLabels() const
00416 {
00417 return d->showLabels;
00418 }
00419
00420 void SignalPlotter::setShowTopBar(bool value)
00421 {
00422 if (d->showTopBar == value) return;
00423 d->showTopBar = value;
00424 d->backgroundPixmap = QPixmap();
00425 }
00426
00427 bool SignalPlotter::showTopBar() const
00428 {
00429 return d->showTopBar;
00430 }
00431
00432 void SignalPlotter::setFont(const QFont &font)
00433 {
00434 d->font = font;
00435 d->backgroundPixmap = QPixmap();
00436 }
00437
00438 QFont SignalPlotter::font() const
00439 {
00440 return d->font;
00441 }
00442
00443 QString SignalPlotter::svgBackground()
00444 {
00445 return d->svgFilename;
00446 }
00447
00448 void SignalPlotter::setSvgBackground(const QString &filename)
00449 {
00450 if (d->svgFilename == filename) return;
00451
00452 if (!filename.isEmpty() && filename[0] == '/') {
00453 KStandardDirs* kstd = KGlobal::dirs();
00454 d->svgFilename = kstd->findResource("data", "ksysguard/" + filename);
00455 } else {
00456 d->svgFilename = filename;
00457 }
00458
00459 if (!d->svgFilename.isEmpty())
00460 {
00461 if (d->svgBackground) delete d->svgBackground;
00462 d->svgBackground = new Svg();
00463 d->svgBackground->setImagePath(d->svgFilename);
00464 }
00465
00466 }
00467
00468 void SignalPlotter::setBackgroundColor(const QColor &color)
00469 {
00470 if (color == d->backgroundColor) return;
00471 d->backgroundColor = color;
00472 d->backgroundPixmap = QPixmap();
00473 }
00474
00475 QColor SignalPlotter::backgroundColor() const
00476 {
00477 return d->backgroundColor;
00478 }
00479
00480 void SignalPlotter::setThinFrame(bool set)
00481 {
00482 if (d->showThinFrame == set) return;
00483 d->showThinFrame = set;
00484 d->backgroundPixmap = QPixmap();
00485 }
00486
00487 void SignalPlotter::setStackPlots(bool stack)
00488 {
00489 d->stackPlots = stack;
00490 d->fillPlots = stack;
00491 }
00492
00493 bool SignalPlotter::stackPlots() const
00494 {
00495 return d->stackPlots;
00496 }
00497
00498 void SignalPlotter::updateDataBuffers()
00499 {
00500
00501
00502
00503
00504
00505
00506
00507 d->samples = static_cast<uint>(((size().width() - 2) /
00508 d->horizontalScale) + 4.5);
00509 }
00510
00511 QPixmap SignalPlotter::getSnapshotImage(uint w, uint height)
00512 {
00513 uint horizontalStep = (uint) ((1.0*w/size().width())+0.5);
00514 uint newWidth = (uint) (horizontalStep * size().width());
00515 QPixmap image = QPixmap(newWidth, height);
00516 QPainter p(&image);
00517 drawWidget(&p, newWidth, height, newWidth);
00518 return image;
00519 }
00520
00521 void SignalPlotter::setGeometry(const QRectF &geometry)
00522 {
00523
00524 QGraphicsWidget::setGeometry(geometry);
00525 updateDataBuffers();
00526 }
00527
00528 void SignalPlotter::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
00529 {
00530 Q_UNUSED(option);
00531 Q_UNUSED(widget);
00532
00533 uint w = (uint) size().width();
00534 uint h = (uint) size().height();
00535
00536
00537 if (w <= 2)
00538 return;
00539
00540 drawWidget(painter, w, h, d->horizontalScale);
00541 }
00542
00543 void SignalPlotter::drawWidget(QPainter *p, uint w, uint height, int horizontalScale)
00544 {
00545 uint h = height;
00546 p->setFont(d->font);
00547
00548 uint fontheight = p->fontMetrics().height();
00549 if (d->verticalMin < d->niceVertMin || d->verticalMax > d->niceVertMax || d->verticalMax < (d->niceVertRange*0.75 + d->niceVertMin) || d->niceVertRange == 0)
00550 calculateNiceRange();
00551 QPen pen;
00552 pen.setWidth(1);
00553 pen.setCapStyle(Qt::RoundCap);
00554 p->setPen(pen);
00555
00556 uint top = p->pen().width() / 2;
00557 h-= top;
00558
00559
00560
00561
00562 bool showTopBar = d->showTopBar && h > (fontheight +5);
00563 if (showTopBar) {
00564 top += fontheight;
00565 h -= fontheight;
00566 }
00567 if (d->backgroundPixmap.isNull() || (uint)d->backgroundPixmap.size().height() != height || (uint)d->backgroundPixmap.size().width() != w) {
00568 d->backgroundPixmap = QPixmap(w, height);
00569 QPainter pCache(&d->backgroundPixmap);
00570 pCache.setRenderHint(QPainter::Antialiasing, false);
00571 pCache.setFont(d->font);
00572
00573 drawBackground(&pCache, w, height);
00574
00575 if (d->showThinFrame) {
00576 drawThinFrame(&pCache, w, height);
00577
00578 h--;
00579 w--;
00580 pCache.setClipRect(0, 0, w, height-1);
00581 }
00582
00583 if (showTopBar) {
00584 int separatorX = w / 2;
00585 drawTopBarFrame(&pCache, separatorX, top);
00586 }
00587
00588
00589
00590 if (!d->verticalLinesScroll && d->showVerticalLines && w > 60)
00591 drawVerticalLines(&pCache, top, w, h);
00592
00593 if (d->showHorizontalLines)
00594 drawHorizontalLines(&pCache, top, w, h);
00595
00596 } else {
00597 if (d->showThinFrame) {
00598
00599 h--;
00600 w--;
00601 }
00602 }
00603 p->drawPixmap(0,0, d->backgroundPixmap);
00604 p->setRenderHint(QPainter::Antialiasing, true);
00605
00606 if (showTopBar) {
00607 int separatorX = w / 2;
00608 int topBarWidth = w - separatorX -2;
00609 drawTopBarContents(p, separatorX, topBarWidth, top -1);
00610 }
00611
00612 p->setClipRect(0, top, w, h);
00613
00614 if (d->verticalLinesScroll && d->showVerticalLines && w > 60)
00615 drawVerticalLines(p, top, w, h);
00616
00617 drawPlots(p, top, w, h, horizontalScale);
00618
00619 if (d->showLabels && w > 60 && h > (fontheight + 1))
00620 drawAxisText(p, top, h);
00621
00622 }
00623
00624 void SignalPlotter::drawBackground(QPainter *p, int w, int h)
00625 {
00626 p->fillRect(0,0,w, h, d->backgroundColor);
00627 if (d->svgBackground)
00628 {
00629 d->svgBackground->resize(w, h);
00630 d->svgBackground->paint(p, 0, 0);
00631 }
00632 }
00633
00634 void SignalPlotter::drawThinFrame(QPainter *p, int w, int h)
00635 {
00636
00637
00638 p->setPen(kapp->palette().color(QPalette::Light));
00639 p->drawLine(0, h - 1, w - 1, h - 1);
00640 p->drawLine(w - 1, 0, w - 1, h - 1);
00641 }
00642
00643 void SignalPlotter::calculateNiceRange()
00644 {
00645 d->niceVertRange = d->verticalMax - d->verticalMin;
00646
00647
00648 if (d->niceVertRange < 0.000001)
00649 d->niceVertRange = 1.0;
00650
00651 d->niceVertMin = d->verticalMin;
00652 if (d->verticalMin != 0.0) {
00653 double dim = pow(10, floor(log10(fabs(d->verticalMin)))) / 2;
00654 if (d->verticalMin < 0.0)
00655 d->niceVertMin = dim * floor(d->verticalMin / dim);
00656 else
00657 d->niceVertMin = dim * ceil(d->verticalMin / dim);
00658 d->niceVertRange = d->verticalMax - d->niceVertMin;
00659 if (d->niceVertRange < 0.000001)
00660 d->niceVertRange = 1.0;
00661 }
00662
00663 double step = d->niceVertRange / (d->scaledBy*(d->horizontalLinesCount+1));
00664 int logdim = (int)floor(log10(step));
00665 double dim = pow((double)10.0, logdim) / 2;
00666 int a = (int)ceil(step / dim);
00667 if (logdim >= 0)
00668 d->precision = 0;
00669 else if (a % 2 == 0){
00670 d->precision =-logdim;
00671 } else {
00672 d->precision = 1-logdim;
00673 }
00674 d->niceVertRange = d->scaledBy*dim * a * (d->horizontalLinesCount+1);
00675 d->niceVertMax = d->niceVertMin + d->niceVertRange;
00676 }
00677
00678
00679 void SignalPlotter::drawTopBarFrame(QPainter *p, int separatorX, int height)
00680 {
00681
00682
00683
00684 p->setPen(Qt::NoPen);
00685 p->setPen(d->fontColor);
00686 p->drawText(0, 1, separatorX, height, Qt::AlignCenter, d->title);
00687 p->setPen(d->horizontalLinesColor);
00688 p->drawLine(separatorX - 1, 1, separatorX - 1, height-1);
00689 }
00690
00691 void SignalPlotter::drawTopBarContents(QPainter *p, int x, int width, int height)
00692 {
00693
00694 double bias = -d->niceVertMin;
00695 double scaleFac = width / d->niceVertRange;
00696
00697
00698 if (!d->plotData.isEmpty()) {
00699 QList<double> newestData = d->plotData.first();
00700 for (int i = newestData.count()-1; i >= 0; --i) {
00701 double newest_datapoint = newestData.at(i);
00702 int start = x + (int)(bias * scaleFac);
00703 int end = x + (int)((bias += newest_datapoint) * scaleFac);
00704 int start2 = qMin(start,end);
00705 end = qMax(start,end);
00706 start = start2;
00707
00708
00709
00710
00711
00712 p->setPen(Qt::NoPen);
00713 QLinearGradient linearGrad(QPointF(start,1), QPointF(end, 1));
00714 linearGrad.setColorAt(0, d->plotColors[i].darkColor);
00715 linearGrad.setColorAt(1, d->plotColors[i].color);
00716 p->fillRect(start, 1, end - start, height-1, QBrush(linearGrad));
00717 }
00718 }
00719 }
00720
00721 void SignalPlotter::drawVerticalLines(QPainter *p, int top, int w, int h)
00722 {
00723 p->setPen(d->verticalLinesColor);
00724 for (int x = d->verticalLinesOffset; x < (w - 2); x += d->verticalLinesDistance)
00725 p->drawLine(w - x, top, w - x, h + top -1);
00726 }
00727
00728 void SignalPlotter::drawPlots(QPainter *p, int top, int w, int h, int horizontalScale)
00729 {
00730 Q_ASSERT(d->niceVertRange != 0); if (d->niceVertRange == 0) d->niceVertRange = 1;
00731 double scaleFac = (h-1) / d->niceVertRange;
00732
00733 int xPos = 0;
00734 QList< QList<double> >::Iterator it = d->plotData.begin();
00735
00736 p->setPen(Qt::NoPen);
00737
00738
00739
00740
00741
00742
00743
00744
00745
00746
00747
00748
00749 if (d->useAutoRange)
00750 d->verticalMin = d->verticalMax = 0.0;
00751
00752
00753
00754
00755
00756
00757
00758
00759
00760
00761 for (uint i = 0; it != d->plotData.end() && i < d->samples; ++i) {
00762 QPen pen;
00763 pen.setWidth(1);
00764 pen.setCapStyle(Qt::FlatCap);
00765
00766
00767
00768
00769 QList<double> datapoints = *it;
00770 QList<double> prev_datapoints = datapoints;
00771 QList<double> prev_prev_datapoints = datapoints;
00772 QList<double> prev_prev_prev_datapoints = datapoints;
00773
00774 if (i == 0 && d->bezierCurveOffset>0) {
00775
00776
00777 xPos += horizontalScale*d->bezierCurveOffset;
00778 if (d->bezierCurveOffset == 1) {
00779 prev_datapoints = *it;
00780 ++it;
00781 if (it != d->plotData.end()) {
00782 prev_prev_prev_datapoints = prev_prev_datapoints = *it;
00783 } else {
00784 prev_prev_prev_datapoints = prev_prev_datapoints = prev_datapoints;
00785 }
00786 } else {
00787
00788 prev_datapoints = *it;
00789 Q_ASSERT(it != d->plotData.end());
00790 ++it;
00791 prev_prev_datapoints = *it;
00792 Q_ASSERT(it != d->plotData.end());
00793 ++it;
00794 if (it != d->plotData.end()) {
00795 prev_prev_prev_datapoints = *it;
00796 } else {
00797 prev_prev_prev_datapoints = prev_prev_datapoints;
00798 }
00799 }
00800 } else {
00801
00802 xPos += horizontalScale*3;
00803 it++;
00804 if (it != d->plotData.end()) {
00805 prev_datapoints = *it;
00806 it++;
00807 if (it != d->plotData.end()) {
00808 prev_prev_datapoints = *it;
00809 it++;
00810 if (it != d->plotData.end()) {
00811
00812 prev_prev_prev_datapoints = *it;
00813 } else {
00814
00815 prev_prev_prev_datapoints = prev_prev_datapoints;
00816 }
00817 } else {
00818 prev_prev_prev_datapoints = prev_prev_datapoints = prev_datapoints;
00819 }
00820 } else {
00821 prev_prev_prev_datapoints = prev_prev_datapoints = prev_datapoints = datapoints;
00822 }
00823 }
00824
00825 float x0 = w - xPos + 3.0*horizontalScale;
00826 float x1 = w - xPos + 2.0*horizontalScale;
00827 float x2 = w - xPos + 1.0*horizontalScale;
00828 float x3 = w - xPos;
00829 float y0 = h -1 + top;
00830 float y1 = y0;
00831 float y2 = y0;
00832 float y3 = y0;
00833
00834 int offset = 0;
00835 double max_y=0;
00836 double min_y=0;
00837 for (int j = qMin(datapoints.size(), d->plotColors.size())-1; j >=0 ; --j) {
00838 if (d->useAutoRange) {
00839
00840
00841 double current_maxvalue = qMax(datapoints[j], qMax(prev_datapoints[j], qMax(prev_prev_datapoints[j], prev_prev_prev_datapoints[j])));
00842 double current_minvalue = qMin(datapoints[j], qMin(prev_datapoints[j], qMin(prev_prev_datapoints[j], prev_prev_prev_datapoints[j])));
00843 d->verticalMax = qMax(d->verticalMax, current_maxvalue);
00844 d->verticalMin = qMin(d->verticalMin, current_maxvalue);
00845 if (d->stackPlots) {
00846 max_y += current_maxvalue;
00847 min_y += current_minvalue;
00848 }
00849 }
00850
00851
00852 if (j < prev_prev_prev_datapoints.count() &&
00853 j < prev_prev_datapoints.count() &&
00854 j < prev_datapoints.count()) {
00855
00856 QPolygon curve(4);
00857
00858
00859
00860
00861 float delta_y0;
00862 delta_y0 = (datapoints[j] - d->niceVertMin)*scaleFac;
00863
00864 float delta_y1;
00865 delta_y1 = (prev_datapoints[j] - d->niceVertMin)*scaleFac;
00866
00867 float delta_y2;
00868 delta_y2 = (prev_prev_datapoints[j] - d->niceVertMin)*scaleFac;
00869
00870 float delta_y3;
00871 delta_y3 = (prev_prev_prev_datapoints[j] - d->niceVertMin)*scaleFac;
00872
00873 QPainterPath path;
00874 if (d->stackPlots && offset) {
00875
00876 if (delta_y0 < 3) delta_y0=3;
00877 if (delta_y1 < 3) delta_y1=3;
00878 if (delta_y2 < 3) delta_y2=3;
00879 if (delta_y3 < 3) delta_y3=3;
00880 }
00881 path.moveTo(x0,y0-delta_y0);
00882 path.cubicTo(x1,y1-delta_y1,x2,y2-delta_y2,x3,y3-delta_y3);
00883
00884 if (d->fillPlots) {
00885 QPainterPath path2(path);
00886 QLinearGradient myGradient(0,(h-1+top),0,(h-1+top)/5);
00887 Q_ASSERT(d->plotColors.size() >= j);
00888 QColor c0(d->plotColors[j].darkColor);
00889 QColor c1(d->plotColors[j].color);
00890 c0.setAlpha(150);
00891 c1.setAlpha(150);
00892 myGradient.setColorAt(0, c0);
00893 myGradient.setColorAt(1, c1);
00894
00895 path2.lineTo(x3,y3-offset);
00896 if (d->stackPlots)
00897 path2.cubicTo(x2,y2-offset,x1,y1-offset,x0,y0-offset);
00898 else
00899 path2.lineTo(x0,y0-1);
00900 p->setBrush(myGradient);
00901 p->setPen(Qt::NoPen);
00902 p->drawPath(path2);
00903 }
00904 p->setBrush(Qt::NoBrush);
00905 Q_ASSERT(d->plotColors.size() >= j);
00906 pen.setColor(d->plotColors[j].color);
00907 p->setPen(pen);
00908 p->drawPath(path);
00909
00910 if (d->stackPlots) {
00911
00912
00913
00914 y0-=delta_y0;
00915 y1-=delta_y1;
00916 y2-=delta_y2;
00917 y3-=delta_y3;
00918 offset = 1;
00919 }
00920 }
00921 if (d->useAutoRange && d->stackPlots) {
00922 d->verticalMax = qMax(max_y, d->verticalMax);
00923 d->verticalMin = qMin(min_y, d->verticalMin);
00924 }
00925 }
00926 }
00927 }
00928
00929 void SignalPlotter::drawAxisText(QPainter *p, int top, int h)
00930 {
00931
00932
00933 QString val;
00934
00935
00936
00937
00938
00939 p->setPen(d->fontColor);
00940 double stepsize = d->niceVertRange/(d->scaledBy*(d->horizontalLinesCount+1));
00941 int step = (int)ceil((d->horizontalLinesCount+1) * (p->fontMetrics().height() + p->fontMetrics().leading()/2.0) / h);
00942 if (step ==0) step = 1;
00943 for (int y = d->horizontalLinesCount+1; y >= 1; y-= step) {
00944 int y_coord = top + (y * (h-1)) / (d->horizontalLinesCount+1);
00945 if (y_coord - p->fontMetrics().ascent() < top) continue;
00946 double value;
00947 if ((uint)y == d->horizontalLinesCount+1)
00948 value = d->niceVertMin;
00949 else
00950 value = d->niceVertMax/d->scaledBy - y * stepsize;
00951
00952 QString number = KGlobal::locale()->formatNumber(value, d->precision);
00953 val = QString("%1 %2").arg(number, d->unit);
00954 p->drawText(6, y_coord - 3, val);
00955 }
00956 }
00957
00958 void SignalPlotter::drawHorizontalLines(QPainter *p, int top, int w, int h)
00959 {
00960 p->setPen(d->horizontalLinesColor);
00961 for (uint y = 0; y <= d->horizontalLinesCount+1; y++) {
00962
00963 int y_coord = top + (y * (h-1)) / (d->horizontalLinesCount+1);
00964 p->drawLine(0, y_coord, w - 2, y_coord);
00965 }
00966 }
00967
00968 double SignalPlotter::lastValue(uint i) const
00969 {
00970 if (d->plotData.isEmpty() || d->plotData.first().size() <= (int) i) return 0;
00971 return d->plotData.first()[i];
00972 }
00973
00974 QString SignalPlotter::lastValueAsString(uint i) const
00975 {
00976 if (d->plotData.isEmpty()) return QString();
00977 double value = d->plotData.first()[i] / d->scaledBy;
00978 QString number = KGlobal::locale()->formatNumber(value, (value >= 100)?0:2);
00979 return QString("%1 %2").arg(number, d->unit);
00980 }
00981
00982 }