• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdelibs API Reference
  • KDE Home
  • Contact Us
 

Plasma

  • sources
  • kde-4.12
  • kdelibs
  • plasma
  • widgets
signalplotter.cpp
Go to the documentation of this file.
1 /*
2  * KSysGuard, the KDE System Guard
3  *
4  * Copyright 1999 - 2002 Chris Schlaeger <cs@kde.org>
5  * Copyright 2006 John Tapsell <tapsell@kde.org>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU Library General Public License as
9  * published by the Free Software Foundation; either version 2, or
10  * (at your option) any later version.
11 
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21  */
22 
23 #include "signalplotter.h"
24 
25 #include <math.h>
26 #include <string.h>
27 
28 #include <QApplication>
29 #include <QList>
30 #include <QPalette>
31 #include <QtGui/QPainter>
32 #include <QtGui/QPixmap>
33 #include <QtGui/QPainterPath>
34 #include <QtGui/QPolygon>
35 
36 #include <kdebug.h>
37 #include <kglobal.h>
38 #include <klocale.h>
39 #include <kstandarddirs.h>
40 #include <kiconloader.h>
41 
42 #include <plasma/svg.h>
43 #include <plasma/theme.h>
44 
45 namespace Plasma
46 {
47 
48 class SignalPlotterPrivate
49 {
50 public:
51  SignalPlotterPrivate()
52  : svgBackground(0)
53  { }
54 
55  ~SignalPlotterPrivate()
56  {
57  }
58 
59  void themeChanged()
60  {
61  Plasma::Theme *theme = Plasma::Theme::defaultTheme();
62  backgroundColor = theme->color(Theme::BackgroundColor);
63  fontColor = theme->color(Theme::TextColor);
64  borderColor = fontColor;
65  verticalLinesColor = fontColor;
66  verticalLinesColor.setAlphaF(0.4);
67  horizontalLinesColor = verticalLinesColor;
68  }
69 
70  int precision;
71  uint samples;
72  uint bezierCurveOffset;
73 
74  double scaledBy;
75  double verticalMin;
76  double verticalMax;
77  double niceVertMin;
78  double niceVertMax;
79  double niceVertRange;
80 
81  uint verticalLinesOffset;
82  uint verticalLinesDistance;
83  QColor verticalLinesColor;
84 
85  bool showHorizontalLines;
86  uint horizontalScale;
87  uint horizontalLinesCount;
88  QColor horizontalLinesColor;
89 
90  Svg *svgBackground;
91  QString svgFilename;
92 
93  QColor fontColor;
94  QColor borderColor;
95  QColor backgroundColor;
96  QPixmap backgroundPixmap;
97 
98  QFont font;
99  QString title;
100  QString unit;
101 
102  QList<PlotColor> plotColors;
103  QList<QList<double> > plotData;
104 
105  bool fillPlots : 1;
106  bool showLabels : 1;
107  bool showTopBar : 1;
108  bool stackPlots : 1;
109  bool useAutoRange : 1;
110  bool showThinFrame : 1;
111 
112  bool showVerticalLines : 1;
113  bool verticalLinesScroll : 1;
114 };
115 
116 SignalPlotter::SignalPlotter(QGraphicsItem *parent)
117  : QGraphicsWidget(parent),
118  d(new SignalPlotterPrivate)
119 {
120  d->precision = 0;
121  d->bezierCurveOffset = 0;
122  d->samples = 0;
123  d->verticalMin = d->verticalMax = 0.0;
124  d->niceVertMin = d->niceVertMax = 0.0;
125  d->niceVertRange = 0;
126  d->useAutoRange = true;
127  d->scaledBy = 1;
128  d->showThinFrame = true;
129 
130  d->showVerticalLines = true;
131  d->verticalLinesDistance = 30;
132  d->verticalLinesScroll = true;
133  d->verticalLinesOffset = 0;
134  d->horizontalScale = 1;
135 
136  d->showHorizontalLines = true;
137  d->horizontalLinesCount = 5;
138 
139  d->showLabels = true;
140  d->showTopBar = true;
141  d->stackPlots = true;
142  d->fillPlots = true;
143 
144  // Anything smaller than this does not make sense.
145  setMinimumSize(QSizeF(KIconLoader::SizeSmall, KIconLoader::SizeSmall));
146 
147  setSvgBackground("widgets/plot-background");
148 
149  connect(Plasma::Theme::defaultTheme(), SIGNAL(themeChanged()), SLOT(themeChanged()));
150  d->themeChanged();
151 
152  setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
153 }
154 
155 SignalPlotter::~SignalPlotter()
156 {
157  delete d;
158 }
159 
160 QString SignalPlotter::unit() const
161 {
162  return d->unit;
163 }
164 void SignalPlotter::setUnit(const QString &unit)
165 {
166  d->unit= unit;
167 }
168 
169 void SignalPlotter::addPlot(const QColor &color)
170 {
171  // When we add a new plot, go back and set the data for this plot to 0 for
172  // all the other times. This is because it makes it easier for moveSensors.
173  foreach (QList<double> data, d->plotData) {
174  data.append(0);
175  }
176  PlotColor newColor;
177  newColor.color = color;
178  newColor.darkColor = color.dark(150);
179  d->plotColors.append(newColor);
180 }
181 
182 void SignalPlotter::addSample(const QList<double>& sampleBuf)
183 {
184  if (d->samples < 4) {
185  // It might be possible, under some race conditions, for addSample
186  // to be called before d->samples is set. This is just to be safe.
187  kDebug() << "Error - d->samples is only " << d->samples;
188  updateDataBuffers();
189  kDebug() << "d->samples is now " << d->samples;
190  if (d->samples < 4) {
191  return;
192  }
193  }
194  d->plotData.prepend(sampleBuf);
195  Q_ASSERT(sampleBuf.count() == d->plotColors.count());
196  if ((uint)d->plotData.size() > d->samples) {
197  d->plotData.removeLast(); // we have too many. Remove the last item
198  if ((uint)d->plotData.size() > d->samples) {
199  // If we still have too many, then we have resized the widget.
200  // Remove one more. That way we will slowly resize to the new size
201  d->plotData.removeLast();
202  }
203  }
204 
205  if (d->bezierCurveOffset >= 2) {
206  d->bezierCurveOffset = 0;
207  } else {
208  d->bezierCurveOffset++;
209  }
210 
211  Q_ASSERT((uint)d->plotData.size() >= d->bezierCurveOffset);
212 
213  // If the vertical lines are scrolling, increment the offset
214  // so they move with the data.
215  if (d->verticalLinesScroll) {
216  d->verticalLinesOffset =
217  (d->verticalLinesOffset + d->horizontalScale) % d->verticalLinesDistance;
218  }
219  update();
220 }
221 
222 void SignalPlotter::reorderPlots(const QList<uint>& newOrder)
223 {
224  if (newOrder.count() != d->plotColors.count()) {
225  kDebug() << "neworder has " << newOrder.count()
226  << " and plot colors is " << d->plotColors.count();
227  return;
228  }
229  foreach (QList<double> data, d->plotData) {
230  if (newOrder.count() != data.count()) {
231  kDebug() << "Serious problem in move sample. plotdata[i] has "
232  << data.count() << " and neworder has " << newOrder.count();
233  } else {
234  QList<double> newPlot;
235  for (int i = 0; i < newOrder.count(); i++) {
236  int newIndex = newOrder[i];
237  newPlot.append(data.at(newIndex));
238  }
239  data = newPlot;
240  }
241  }
242  QList<PlotColor> newPlotColors;
243  for (int i = 0; i < newOrder.count(); i++) {
244  int newIndex = newOrder[i];
245  PlotColor newColor = d->plotColors.at(newIndex);
246  newPlotColors.append(newColor);
247  }
248  d->plotColors = newPlotColors;
249 }
250 
251 void SignalPlotter::setVerticalRange(double min, double max)
252 {
253  d->verticalMin = min;
254  d->verticalMax = max;
255  calculateNiceRange();
256 }
257 
258 QList<PlotColor> &SignalPlotter::plotColors()
259 {
260  return d->plotColors;
261 }
262 
263 void SignalPlotter::removePlot(uint pos)
264 {
265  if (pos >= (uint)d->plotColors.size()) {
266  return;
267  }
268  d->plotColors.removeAt(pos);
269 
270  foreach (QList<double> data, d->plotData) {
271  if ((uint)data.size() >= pos) {
272  data.removeAt(pos);
273  }
274  }
275 }
276 
277 void SignalPlotter::scale(qreal delta)
278 {
279  if (d->scaledBy == delta) {
280  return;
281  }
282  d->scaledBy = delta;
283  d->backgroundPixmap = QPixmap(); // we changed a paint setting, so reset the cache
284  calculateNiceRange();
285 }
286 
287 qreal SignalPlotter::scaledBy() const
288 {
289  return d->scaledBy;
290 }
291 
292 void SignalPlotter::setTitle(const QString &title)
293 {
294  if (d->title == title) {
295  return;
296  }
297  d->title = title;
298  d->backgroundPixmap = QPixmap(); // we changed a paint setting, so reset the cache
299 }
300 
301 QString SignalPlotter::title() const
302 {
303  return d->title;
304 }
305 
306 void SignalPlotter::setUseAutoRange(bool value)
307 {
308  d->useAutoRange = value;
309  calculateNiceRange();
310  // this change will be detected in paint and the image cache regenerated
311 }
312 
313 bool SignalPlotter::useAutoRange() const
314 {
315  return d->useAutoRange;
316 }
317 
318 double SignalPlotter::verticalMinValue() const
319 {
320  return d->verticalMin;
321 }
322 
323 double SignalPlotter::verticalMaxValue() const
324 {
325  return d->verticalMax;
326 }
327 
328 void SignalPlotter::setHorizontalScale(uint scale)
329 {
330  if (scale == d->horizontalScale) {
331  return;
332  }
333 
334  d->horizontalScale = scale;
335  updateDataBuffers();
336  d->backgroundPixmap = QPixmap(); // we changed a paint setting, so reset the cache
337 }
338 
339 uint SignalPlotter::horizontalScale() const
340 {
341  return d->horizontalScale;
342 }
343 
344 void SignalPlotter::setShowVerticalLines(bool value)
345 {
346  if (d->showVerticalLines == value) {
347  return;
348  }
349  d->showVerticalLines = value;
350  d->backgroundPixmap = QPixmap(); // we changed a paint setting, so reset the cache
351 }
352 
353 bool SignalPlotter::showVerticalLines() const
354 {
355  return d->showVerticalLines;
356 }
357 
358 void SignalPlotter::setVerticalLinesColor(const QColor &color)
359 {
360  if (d->verticalLinesColor == color) {
361  return;
362  }
363  d->verticalLinesColor = color;
364  d->backgroundPixmap = QPixmap(); // we changed a paint setting, so reset the cache
365 }
366 
367 QColor SignalPlotter::verticalLinesColor() const
368 {
369  return d->verticalLinesColor;
370 }
371 
372 void SignalPlotter::setVerticalLinesDistance(uint distance)
373 {
374  if (distance == d->verticalLinesDistance) {
375  return;
376  }
377  d->verticalLinesDistance = distance;
378  d->backgroundPixmap = QPixmap(); // we changed a paint setting, so reset the cache
379 }
380 
381 uint SignalPlotter::verticalLinesDistance() const
382 {
383  return d->verticalLinesDistance;
384 }
385 
386 void SignalPlotter::setVerticalLinesScroll(bool value)
387 {
388  if (value == d->verticalLinesScroll) {
389  return;
390  }
391  d->verticalLinesScroll = value;
392  d->backgroundPixmap = QPixmap(); // we changed a paint setting, so reset the cache
393 }
394 
395 bool SignalPlotter::verticalLinesScroll() const
396 {
397  return d->verticalLinesScroll;
398 }
399 
400 void SignalPlotter::setShowHorizontalLines(bool value)
401 {
402  if (value == d->showHorizontalLines) {
403  return;
404  }
405  d->showHorizontalLines = value;
406  d->backgroundPixmap = QPixmap(); // we changed a paint setting, so reset the cache
407 }
408 
409 bool SignalPlotter::showHorizontalLines() const
410 {
411  return d->showHorizontalLines;
412 }
413 
414 void SignalPlotter::setFontColor(const QColor &color)
415 {
416  d->fontColor = color;
417 }
418 
419 QColor SignalPlotter::fontColor() const
420 {
421  return d->fontColor;
422 }
423 
424 void SignalPlotter::setHorizontalLinesColor(const QColor &color)
425 {
426  if (color == d->horizontalLinesColor) {
427  return;
428  }
429  d->horizontalLinesColor = color;
430  d->backgroundPixmap = QPixmap(); // we changed a paint setting, so reset the cache
431 }
432 
433 QColor SignalPlotter::horizontalLinesColor() const
434 {
435  return d->horizontalLinesColor;
436 }
437 
438 void SignalPlotter::setHorizontalLinesCount(uint count)
439 {
440  if (count == d->horizontalLinesCount) {
441  return;
442  }
443  d->horizontalLinesCount = count;
444  d->backgroundPixmap = QPixmap(); // we changed a paint setting, so reset the cache
445  calculateNiceRange();
446 }
447 
448 uint SignalPlotter::horizontalLinesCount() const
449 {
450  return d->horizontalLinesCount;
451 }
452 
453 void SignalPlotter::setShowLabels(bool value)
454 {
455  if (value == d->showLabels) {
456  return;
457  }
458  d->showLabels = value;
459  d->backgroundPixmap = QPixmap(); // we changed a paint setting, so reset the cache
460 }
461 
462 bool SignalPlotter::showLabels() const
463 {
464  return d->showLabels;
465 }
466 
467 void SignalPlotter::setShowTopBar(bool value)
468 {
469  if (d->showTopBar == value) {
470  return;
471  }
472  d->showTopBar = value;
473  d->backgroundPixmap = QPixmap(); // we changed a paint setting, so reset the cache
474 }
475 
476 bool SignalPlotter::showTopBar() const
477 {
478  return d->showTopBar;
479 }
480 
481 void SignalPlotter::setFont(const QFont &font)
482 {
483  d->font = font;
484  d->backgroundPixmap = QPixmap(); // we changed a paint setting, so reset the cache
485 }
486 
487 QFont SignalPlotter::font() const
488 {
489  return d->font;
490 }
491 
492 QString SignalPlotter::svgBackground()
493 {
494  return d->svgFilename;
495 }
496 
497 void SignalPlotter::setSvgBackground(const QString &filename)
498 {
499  if (d->svgFilename == filename) {
500  return;
501  }
502 
503  if (!filename.isEmpty() && filename[0] == '/') {
504  KStandardDirs *kstd = KGlobal::dirs();
505  d->svgFilename = kstd->findResource("data", "ksysguard/" + filename);
506  } else {
507  d->svgFilename = filename;
508  }
509 
510  delete d->svgBackground;
511  d->svgBackground = 0;
512  if (!d->svgFilename.isEmpty()) {
513  d->svgBackground = new Svg(this);
514  d->svgBackground->setImagePath(d->svgFilename);
515  }
516 
517 }
518 
519 void SignalPlotter::setBackgroundColor(const QColor &color)
520 {
521  if (color == d->backgroundColor) {
522  return;
523  }
524  d->backgroundColor = color;
525  d->backgroundPixmap = QPixmap(); // we changed a paint setting, so reset the cache
526 }
527 
528 QColor SignalPlotter::backgroundColor() const
529 {
530  return d->backgroundColor;
531 }
532 
533 void SignalPlotter::setThinFrame(bool set)
534 {
535  if (d->showThinFrame == set) {
536  return;
537  }
538  d->showThinFrame = set;
539  d->backgroundPixmap = QPixmap(); // we changed a paint setting, so reset the cache
540 }
541 
542 bool SignalPlotter::thinFrame() const
543 {
544  return d->showThinFrame;
545 }
546 
547 void SignalPlotter::setStackPlots(bool stack)
548 {
549  d->stackPlots = stack;
550  d->fillPlots = stack;
551 }
552 
553 bool SignalPlotter::stackPlots() const
554 {
555  return d->stackPlots;
556 }
557 
558 void SignalPlotter::updateDataBuffers()
559 {
560  // This is called when the widget has resized
561  //
562  // Determine new number of samples first.
563  // +0.5 to ensure rounding up
564  // +4 for extra data points so there is
565  // 1) no wasted space and
566  // 2) no loss of precision when drawing the first data point.
567  d->samples = static_cast<uint>(((size().width() - 2) /
568  d->horizontalScale) + 4.5);
569 }
570 
571 QPixmap SignalPlotter::getSnapshotImage(uint w, uint height)
572 {
573  uint horizontalStep = (uint)((1.0 * w / size().width()) + 0.5); // get the closest integer horizontal step
574  uint newWidth = (uint) (horizontalStep * size().width());
575  QPixmap image = QPixmap(newWidth, height);
576  QPainter p(&image);
577  drawWidget(&p, newWidth, height, newWidth);
578  p.end();
579  return image;
580 }
581 
582 void SignalPlotter::setGeometry(const QRectF &geometry)
583 {
584  // First update our size, then update the data buffers accordingly.
585  QGraphicsWidget::setGeometry(geometry);
586  updateDataBuffers();
587 }
588 
589 void SignalPlotter::paint(QPainter *painter,
590  const QStyleOptionGraphicsItem *option, QWidget *widget)
591 {
592  Q_UNUSED(option);
593  Q_UNUSED(widget);
594 
595  uint w = (uint) size().width();
596  uint h = (uint) size().height();
597 
598  // Do not do repaints when the widget is not yet setup properly.
599  if (w <= 2) {
600  return;
601  }
602 
603  drawWidget(painter, w, h, d->horizontalScale);
604 }
605 
606 void SignalPlotter::drawWidget(QPainter *p, uint w, uint height, int horizontalScale)
607 {
608  uint h = height; // h will become the height of just the bit we draw the plots in
609  p->setFont(d->font);
610 
611  uint fontheight = p->fontMetrics().height();
612  if (d->verticalMin < d->niceVertMin ||
613  d->verticalMax > d->niceVertMax ||
614  d->verticalMax < (d->niceVertRange * 0.75 + d->niceVertMin) ||
615  d->niceVertRange == 0) {
616  calculateNiceRange();
617  }
618  QPen pen;
619  pen.setWidth(1);
620  pen.setCapStyle(Qt::RoundCap);
621  p->setPen(pen);
622 
623  uint top = p->pen().width() / 2; // The y position of the top of the graph. Basically this is one more than the height of the top bar
624  h-= top;
625 
626  // Check if there's enough room to actually show a top bar.
627  // Must be enough room for a bar at the top, plus horizontal
628  // lines each of a size with room for a scale.
629  bool showTopBar = d->showTopBar && h > (fontheight/*top bar size*/ +5/*smallest reasonable size for a graph*/);
630  if (showTopBar) {
631  top += fontheight; // The top bar has the same height as fontheight. Thus the top of the graph is at fontheight
632  h -= fontheight;
633  }
634  if (d->backgroundPixmap.isNull() ||
635  (uint)d->backgroundPixmap.size().height() != height ||
636  (uint)d->backgroundPixmap.size().width() != w) {
637  // recreate on resize etc
638  d->backgroundPixmap = QPixmap(w, height);
639  d->backgroundPixmap.fill(Qt::transparent);
640  QPainter pCache(&d->backgroundPixmap);
641  pCache.setRenderHint(QPainter::Antialiasing, false);
642  pCache.setFont(d->font);
643 
644  drawBackground(&pCache, w, height);
645 
646  if (d->showThinFrame) {
647  drawThinFrame(&pCache, w, height);
648  // We have a 'frame' in the bottom and right - so subtract them from the view
649  h--;
650  w--;
651  pCache.setClipRect(0, 0, w, height-1);
652  }
653 
654  if (showTopBar) {
655  int separatorX = w / 2;
656  drawTopBarFrame(&pCache, separatorX, top);
657  }
658 
659  // Draw scope-like grid vertical lines if it doesn't move.
660  // If it does move, draw it in the dynamic part of the code.
661  if (!d->verticalLinesScroll && d->showVerticalLines && w > 60) {
662  drawVerticalLines(&pCache, top, w, h);
663  }
664 
665  if (d->showHorizontalLines) {
666  drawHorizontalLines(&pCache, top, w, h);
667  }
668 
669  } else {
670  if (d->showThinFrame) {
671  // We have a 'frame' in the bottom and right - so subtract them from the view
672  h--;
673  w--;
674  }
675  }
676  p->drawPixmap(0, 0, d->backgroundPixmap);
677  p->setRenderHint(QPainter::Antialiasing, true);
678 
679  if (showTopBar) {
680  int separatorX = w / 2;
681  int topBarWidth = w - separatorX -2;
682  drawTopBarContents(p, separatorX, topBarWidth, top -1);
683  }
684 
685  p->setClipRect(0, top, w, h, Qt::IntersectClip);
686  // Draw scope-like grid vertical lines
687  if (d->verticalLinesScroll && d->showVerticalLines && w > 60) {
688  drawVerticalLines(p, top, w, h);
689  }
690 
691  drawPlots(p, top, w, h, horizontalScale);
692 
693  if (d->showLabels && w > 60 && h > (fontheight + 1)) {
694  // if there's room to draw the labels, then draw them!
695  drawAxisText(p, top, h);
696  }
697 }
698 
699 void SignalPlotter::drawBackground(QPainter *p, int w, int h)
700 {
701  if (d->svgBackground) {
702  d->svgBackground->resize(w, h);
703  d->svgBackground->paint(p, 0, 0);
704  } else {
705  p->fillRect(0, 0, w, h, d->backgroundColor);
706  }
707 }
708 
709 void SignalPlotter::drawThinFrame(QPainter *p, int w, int h)
710 {
711  // Draw a line along the bottom and the right side of the
712  // widget to create a 3D like look.
713  p->setPen(d->borderColor);
714  p->drawLine(0, h - 1, w - 1, h - 1);
715  p->drawLine(w - 1, 0, w - 1, h - 1);
716 }
717 
718 void SignalPlotter::calculateNiceRange()
719 {
720  d->niceVertRange = d->verticalMax - d->verticalMin;
721  // If the range is too small we will force it to 1.0 since it
722  // looks a lot nicer.
723  if (d->niceVertRange < 0.000001) {
724  d->niceVertRange = 1.0;
725  }
726 
727  d->niceVertMin = d->verticalMin;
728  if (d->verticalMin != 0.0) {
729  double dim = pow(10, floor(log10(fabs(d->verticalMin)))) / 2;
730  if (d->verticalMin < 0.0) {
731  d->niceVertMin = dim * floor(d->verticalMin / dim);
732  } else {
733  d->niceVertMin = dim * ceil(d->verticalMin / dim);
734  }
735  d->niceVertRange = d->verticalMax - d->niceVertMin;
736  if (d->niceVertRange < 0.000001) {
737  d->niceVertRange = 1.0;
738  }
739  }
740  // Massage the range so that the grid shows some nice values.
741  double step = d->niceVertRange / (d->scaledBy * (d->horizontalLinesCount + 1));
742  int logdim = (int)floor(log10(step));
743  double dim = pow((double)10.0, logdim) / 2;
744  int a = (int)ceil(step / dim);
745  if (logdim >= 0) {
746  d->precision = 0;
747  } else if (a % 2 == 0) {
748  d->precision = -logdim;
749  } else {
750  d->precision = 1 - logdim;
751  }
752  d->niceVertRange = d->scaledBy * dim * a * (d->horizontalLinesCount + 1);
753  d->niceVertMax = d->niceVertMin + d->niceVertRange;
754 }
755 
756 void SignalPlotter::drawTopBarFrame(QPainter *p, int separatorX, int height)
757 {
758  // Draw horizontal bar with current sensor values at top of display.
759  // Remember that it has a height of 'height'. Thus the lowest pixel
760  // it can draw on is height-1 since we count from 0.
761  p->setPen(Qt::NoPen);
762  p->setPen(d->fontColor);
763  p->drawText(0, 1, separatorX, height, Qt::AlignCenter, d->title);
764  p->setPen(d->horizontalLinesColor);
765  p->drawLine(separatorX - 1, 1, separatorX - 1, height - 1);
766 }
767 
768 void SignalPlotter::drawTopBarContents(QPainter *p, int x, int width, int height)
769 {
770  // The height is the height of the contents, so this will be
771  // one pixel less than the height of the topbar
772  double bias = -d->niceVertMin;
773  double scaleFac = width / d->niceVertRange;
774  // The top bar shows the current values of all the plot data.
775  // This iterates through each different plot and plots the newest data for each.
776  if (!d->plotData.isEmpty()) {
777  QList<double> newestData = d->plotData.first();
778  for (int i = newestData.count()-1; i >= 0; --i) {
779  double newest_datapoint = newestData.at(i);
780  int start = x + (int)(bias * scaleFac);
781  int end = x + (int)((bias += newest_datapoint) * scaleFac);
782  int start2 = qMin(start, end);
783  end = qMax(start, end);
784  start = start2;
785 
786  // If the rect is wider than 2 pixels we draw only the last
787  // pixels with the bright color. The rest is painted with
788  // a 50% darker color.
789 
790  p->setPen(Qt::NoPen);
791  QLinearGradient linearGrad(QPointF(start, 1), QPointF(end, 1));
792  linearGrad.setColorAt(0, d->plotColors[i].darkColor);
793  linearGrad.setColorAt(1, d->plotColors[i].color);
794  p->fillRect(start, 1, end - start, height-1, QBrush(linearGrad));
795  }
796  }
797 }
798 
799 void SignalPlotter::drawVerticalLines(QPainter *p, int top, int w, int h)
800 {
801  p->setPen(d->verticalLinesColor);
802  for (int x = d->verticalLinesOffset; x < (w - 2); x += d->verticalLinesDistance) {
803  p->drawLine(w - x, top, w - x, h + top -1);
804  }
805 }
806 
807 void SignalPlotter::drawPlots(QPainter *p, int top, int w, int h, int horizontalScale)
808 {
809  Q_ASSERT(d->niceVertRange != 0);
810 
811  if (d->niceVertRange == 0) {
812  d->niceVertRange = 1;
813  }
814  double scaleFac = (h - 1) / d->niceVertRange;
815 
816  int xPos = 0;
817  QList< QList<double> >::Iterator it = d->plotData.begin();
818 
819  p->setPen(Qt::NoPen);
820  // In autoRange mode we determine the range and plot the values in
821  // one go. This is more efficiently than running through the
822  // buffers twice but we do react on recently discarded samples as
823  // well as new samples one plot too late. So the range is not
824  // correct if the recently discarded samples are larger or smaller
825  // than the current extreme values. But we can probably live with
826  // this.
827 
828  // These values aren't used directly anywhere. Instead we call
829  // calculateNiceRange() which massages these values into a nicer
830  // values. Rounding etc. This means it's safe to change these values
831  // without affecting any other drawings.
832  if (d->useAutoRange) {
833  d->verticalMin = d->verticalMax = 0.0;
834  }
835 
836  // d->bezierCurveOffset is how many points we have at the start.
837  // All the bezier curves are in groups of 3, with the first of the
838  // next group being the last point of the previous group
839 
840  // Example, when d->bezierCurveOffset == 0, and we have data, then just
841  // plot a normal bezier curve. (we will have at least 3 points in this case)
842  // When d->bezierCurveOffset == 1, then we want a bezier curve that uses
843  // the first data point and the second data point. Then the next group
844  // starts from the second data point.
845  //
846  // When d->bezierCurveOffset == 2, then we want a bezier curve that
847  // uses the first, second and third data.
848  for (uint i = 0; it != d->plotData.end() && i < d->samples; ++i) {
849  QPen pen;
850  pen.setWidth(1);
851  pen.setCapStyle(Qt::FlatCap);
852 
853  // We will plot 1 bezier curve for every 3 points, with the 4th point
854  // being the end of one bezier curve and the start of the second.
855  // This does means the bezier curves will not join nicely, but it
856  // should be better than nothing.
857  QList<double> datapoints = *it;
858  QList<double> prev_datapoints = datapoints;
859  QList<double> prev_prev_datapoints = datapoints;
860  QList<double> prev_prev_prev_datapoints = datapoints;
861 
862  if (i == 0 && d->bezierCurveOffset > 0) {
863  // We are plotting an incomplete bezier curve - we don't have
864  // all the data we want. Try to cope.
865  xPos += horizontalScale * d->bezierCurveOffset;
866  if (d->bezierCurveOffset == 1) {
867  prev_datapoints = *it;
868  ++it; // Now we are on the first element of the next group, if it exists
869  if (it != d->plotData.end()) {
870  prev_prev_prev_datapoints = prev_prev_datapoints = *it;
871  } else {
872  prev_prev_prev_datapoints = prev_prev_datapoints = prev_datapoints;
873  }
874  } else {
875  // d->bezierCurveOffset must be 2 now
876  prev_datapoints = *it;
877  Q_ASSERT(it != d->plotData.end());
878  ++it;
879  prev_prev_datapoints = *it;
880  Q_ASSERT(it != d->plotData.end());
881  ++it; // Now we are on the first element of the next group, if it exists
882  if (it != d->plotData.end()) {
883  prev_prev_prev_datapoints = *it;
884  } else {
885  prev_prev_prev_datapoints = prev_prev_datapoints;
886  }
887  }
888  } else {
889  // We have a group of 3 points at least. That's 1 start point and 2 control points.
890  xPos += horizontalScale * 3;
891  it++;
892  if (it != d->plotData.end()) {
893  prev_datapoints = *it;
894  it++;
895  if (it != d->plotData.end()) {
896  prev_prev_datapoints = *it;
897  it++; // We are now on the next set of data points
898  if (it != d->plotData.end()) {
899  // We have this datapoint, so use it for our finish point
900  prev_prev_prev_datapoints = *it;
901  } else {
902  // We don't have the next set, so use our last control
903  // point as our finish point
904  prev_prev_prev_datapoints = prev_prev_datapoints;
905  }
906  } else {
907  prev_prev_prev_datapoints = prev_prev_datapoints = prev_datapoints;
908  }
909  } else {
910  prev_prev_prev_datapoints = prev_prev_datapoints = prev_datapoints = datapoints;
911  }
912  }
913 
914  float x0 = w - xPos + 3.0 * horizontalScale;
915  float x1 = w - xPos + 2.0 * horizontalScale;
916  float x2 = w - xPos + 1.0 * horizontalScale;
917  float x3 = w - xPos;
918  float y0 = h - 1 + top;
919  float y1 = y0;
920  float y2 = y0;
921  float y3 = y0;
922 
923  int offset = 0; // Our line is 2 pixels thick. This means that when we draw the area, we need to offset
924  double max_y = 0;
925  double min_y = 0;
926  for (int j = qMin(datapoints.size(), d->plotColors.size()) - 1; j >=0; --j) {
927  if (d->useAutoRange) {
928  // If we use autorange, then we need to prepare the min and max values for _next_ time we paint.
929  // If we are stacking the plots, then we need to add the maximums together.
930  double current_maxvalue =
931  qMax(datapoints[j],
932  qMax(prev_datapoints[j],
933  qMax(prev_prev_datapoints[j],
934  prev_prev_prev_datapoints[j])));
935  double current_minvalue =
936  qMin<double>(datapoints[j],
937  qMin(prev_datapoints[j],
938  qMin(prev_prev_datapoints[j],
939  prev_prev_prev_datapoints[j])));
940  d->verticalMax = qMax(d->verticalMax, current_maxvalue);
941  d->verticalMin = qMin(d->verticalMin, current_maxvalue);
942  if (d->stackPlots) {
943  max_y += current_maxvalue;
944  min_y += current_minvalue;
945  }
946  }
947 
948  // Draw polygon only if enough data points are available.
949  if (j < prev_prev_prev_datapoints.count() &&
950  j < prev_prev_datapoints.count() &&
951  j < prev_datapoints.count()) {
952 
953  // The height of the whole widget is h+top-> The height of
954  // the area we are plotting in is just h.
955  // The y coordinate system starts from the top, so at the
956  // bottom the y coordinate is h+top.
957  // So to draw a point at value y', we need to put this at h+top-y'
958  float delta_y0;
959  delta_y0 = (datapoints[j] - d->niceVertMin) * scaleFac;
960 
961  float delta_y1;
962  delta_y1 = (prev_datapoints[j] - d->niceVertMin) * scaleFac;
963 
964  float delta_y2;
965  delta_y2 = (prev_prev_datapoints[j] - d->niceVertMin) * scaleFac;
966 
967  float delta_y3;
968  delta_y3 = (prev_prev_prev_datapoints[j] - d->niceVertMin) * scaleFac;
969 
970  QPainterPath path;
971  if (d->stackPlots && offset) {
972  // we don't want the lines to overdraw each other.
973  // This isn't a great solution though :(
974  if (delta_y0 < 3) {
975  delta_y0=3;
976  }
977  if (delta_y1 < 3) {
978  delta_y1=3;
979  }
980  if (delta_y2 < 3) {
981  delta_y2=3;
982  }
983  if (delta_y3 < 3) {
984  delta_y3=3;
985  }
986  }
987  path.moveTo(x0, y0 - delta_y0);
988  path.cubicTo(x1, y1 - delta_y1, x2, y2 - delta_y2, x3, y3 - delta_y3);
989 
990  if (d->fillPlots) {
991  QPainterPath path2(path);
992  QLinearGradient myGradient(0,(h - 1 + top), 0, (h - 1 + top) / 5);
993  Q_ASSERT(d->plotColors.size() >= j);
994  QColor c0(d->plotColors[j].darkColor);
995  QColor c1(d->plotColors[j].color);
996  c0.setAlpha(150);
997  c1.setAlpha(150);
998  myGradient.setColorAt(0, c0);
999  myGradient.setColorAt(1, c1);
1000 
1001  path2.lineTo(x3, y3 - offset);
1002  if (d->stackPlots) {
1003  // offset is set to 1 after the first plot is drawn,
1004  // so we don't trample on top of the 2pt thick line
1005  path2.cubicTo(x2, y2 - offset, x1, y1 - offset, x0, y0 - offset);
1006  } else {
1007  path2.lineTo(x0, y0 - 1);
1008  }
1009  p->setBrush(myGradient);
1010  p->setPen(Qt::NoPen);
1011  p->drawPath(path2);
1012  }
1013  p->setBrush(Qt::NoBrush);
1014  Q_ASSERT(d->plotColors.size() >= j);
1015  pen.setColor(d->plotColors[j].color);
1016  p->setPen(pen);
1017  p->drawPath(path);
1018 
1019  if (d->stackPlots) {
1020  // We can draw the plots stacked on top of each other.
1021  // This means that say plot 0 has the value 2 and plot
1022  // 1 has the value 3, then we plot plot 0 at 2 and plot 1 at 2+3 = 5.
1023  y0 -= delta_y0;
1024  y1 -= delta_y1;
1025  y2 -= delta_y2;
1026  y3 -= delta_y3;
1027  offset = 1; // see the comment further up for int offset;
1028  }
1029  }
1030  if (d->useAutoRange && d->stackPlots) {
1031  d->verticalMax = qMax(max_y, d->verticalMax);
1032  d->verticalMin = qMin(min_y, d->verticalMin);
1033  }
1034  }
1035  }
1036 }
1037 
1038 void SignalPlotter::drawAxisText(QPainter *p, int top, int h)
1039 {
1040  // Draw horizontal lines and values. Lines are always drawn.
1041  // Values are only draw when width is greater than 60.
1042  QString val;
1043 
1044  // top = 0 or font.height depending on whether there's a topbar or not
1045  // h = graphing area.height - i.e. the actual space we have to draw inside
1046  // Note we are drawing from 0,0 as the top left corner. So we have to add on top
1047  // to get to the top of where we are drawing so top+h is the height of the widget.
1048  p->setPen(d->fontColor);
1049  double stepsize = d->niceVertRange / (d->scaledBy * (d->horizontalLinesCount + 1));
1050  int step =
1051  (int)ceil((d->horizontalLinesCount+1) *
1052  (p->fontMetrics().height() + p->fontMetrics().leading() / 2.0) / h);
1053  if (step == 0) {
1054  step = 1;
1055  }
1056  for (int y = d->horizontalLinesCount + 1; y >= 1; y-= step) {
1057  int y_coord =
1058  top + (y * (h - 1)) / (d->horizontalLinesCount + 1); // Make sure it's y*h first to avoid rounding bugs
1059  if (y_coord - p->fontMetrics().ascent() < top) {
1060  // at most, only allow 4 pixels of the text to be covered up
1061  // by the top bar. Otherwise just don't bother to draw it
1062  continue;
1063  }
1064  double value;
1065  if ((uint)y == d->horizontalLinesCount + 1) {
1066  value = d->niceVertMin; // sometimes using the formulas gives us a value very slightly off
1067  } else {
1068  value = d->niceVertMax / d->scaledBy - y * stepsize;
1069  }
1070 
1071  QString number = KGlobal::locale()->formatNumber(value, d->precision);
1072  val = QString("%1 %2").arg(number, d->unit);
1073  p->drawText(6, y_coord - 3, val);
1074  }
1075 }
1076 
1077 void SignalPlotter::drawHorizontalLines(QPainter *p, int top, int w, int h)
1078 {
1079  p->setPen(d->horizontalLinesColor);
1080  for (uint y = 0; y <= d->horizontalLinesCount + 1; y++) {
1081  // note that the y_coord starts from 0. so we draw from pixel number 0 to h-1. Thus the -1 in the y_coord
1082  int y_coord = top + (y * (h - 1)) / (d->horizontalLinesCount + 1); // Make sure it's y*h first to avoid rounding bugs
1083  p->drawLine(0, y_coord, w - 2, y_coord);
1084  }
1085 }
1086 
1087 double SignalPlotter::lastValue(uint i) const
1088 {
1089  if (d->plotData.isEmpty() || d->plotData.first().size() <= (int)i) {
1090  return 0;
1091  }
1092  return d->plotData.first()[i];
1093 }
1094 
1095 QString SignalPlotter::lastValueAsString(uint i) const
1096 {
1097  if (d->plotData.isEmpty()) {
1098  return QString();
1099  }
1100  double value = d->plotData.first()[i] / d->scaledBy; // retrieve the newest value for this plot then scale it correct
1101  QString number = KGlobal::locale()->formatNumber(value, (value >= 100)?0:2);
1102  return QString("%1 %2").arg(number, d->unit);
1103 }
1104 
1105 } // Plasma namespace
1106 
1107 #include "signalplotter.moc"
1108 
Plasma::SignalPlotter::setShowTopBar
void setShowTopBar(bool value)
Whether to show the title etc at the top.
Definition: signalplotter.cpp:467
signalplotter.h
Plasma::PlotColor::darkColor
QColor darkColor
Definition: signalplotter.h:37
Plasma::SignalPlotter::setShowLabels
void setShowLabels(bool value)
Whether to show the vertical axis labels.
Definition: signalplotter.cpp:453
Plasma::SignalPlotter::getSnapshotImage
QPixmap getSnapshotImage(uint width, uint height)
Render the graph to the specified width and height, and return it as an image.
Definition: signalplotter.cpp:571
Plasma::SignalPlotter::setUnit
void setUnit(const QString &unit)
Set the units.
Definition: signalplotter.cpp:164
Plasma::SignalPlotter::drawWidget
void drawWidget(QPainter *p, uint w, uint height, int horizontalScale)
Definition: signalplotter.cpp:606
Plasma::SignalPlotter::showHorizontalLines
bool showHorizontalLines() const
Whether to draw the horizontal grid lines.
Plasma::SignalPlotter::drawHorizontalLines
void drawHorizontalLines(QPainter *p, int top, int w, int h)
Definition: signalplotter.cpp:1077
QWidget
Plasma::SignalPlotter::horizontalScale
uint horizontalScale() const
The number of pixels horizontally between data points.
Plasma::SignalPlotter::drawAxisText
void drawAxisText(QPainter *p, int top, int h)
Definition: signalplotter.cpp:1038
Plasma::SignalPlotter::setUseAutoRange
void setUseAutoRange(bool value)
Set the minimum and maximum values on the vertical axis automatically from the data available...
Definition: signalplotter.cpp:306
Plasma::Theme::TextColor
the text color to be used by items resting on the background
Definition: theme.h:63
Plasma::SignalPlotter::plotColors
QList< PlotColor > & plotColors()
Return the list of plot colors, in the order that the plots were added (or later reordered).
Definition: signalplotter.cpp:258
Plasma::SignalPlotter::SignalPlotter
SignalPlotter(QGraphicsItem *parent=0)
Definition: signalplotter.cpp:116
Plasma::SignalPlotter::addPlot
Q_INVOKABLE void addPlot(const QColor &color)
Add a new line to the graph plotter, with the specified color.
Definition: signalplotter.cpp:169
Plasma::SignalPlotter::drawVerticalLines
void drawVerticalLines(QPainter *p, int top, int w, int h)
Definition: signalplotter.cpp:799
theme.h
Plasma::SignalPlotter::setFont
void setFont(const QFont &font)
The font used for the axis.
Definition: signalplotter.cpp:481
Plasma::SignalPlotter::setThinFrame
void setThinFrame(bool set)
Whether to show a white line on the left and bottom of the widget, for a 3D effect.
Definition: signalplotter.cpp:533
Plasma::SignalPlotter::lastValueAsString
QString lastValueAsString(uint i) const
Return a translated string like: "34 %" or "100 KB" for plot i.
Definition: signalplotter.cpp:1095
Plasma::SignalPlotter::font
QFont font() const
The font used for the axis.
Plasma::SignalPlotter::removePlot
Q_INVOKABLE void removePlot(uint pos)
Removes the plot at the specified index.
Definition: signalplotter.cpp:263
Plasma::SignalPlotter::updateDataBuffers
void updateDataBuffers()
Definition: signalplotter.cpp:558
Plasma::SignalPlotter::setHorizontalScale
void setHorizontalScale(uint scale)
Set the number of pixels horizontally between data points.
Definition: signalplotter.cpp:328
Plasma::SignalPlotter::showTopBar
bool showTopBar() const
Whether to show the title etc at the top.
Plasma::SignalPlotter::setShowHorizontalLines
void setShowHorizontalLines(bool value)
Whether to draw the horizontal grid lines.
Definition: signalplotter.cpp:400
Plasma::SignalPlotter::addSample
Q_INVOKABLE void addSample(const QList< double > &samples)
Add data to the graph, and advance the graph by one time period.
Definition: signalplotter.cpp:182
Plasma::SignalPlotter::setGeometry
virtual void setGeometry(const QRectF &geometry)
Overwritten to be notified of size changes.
Definition: signalplotter.cpp:582
Plasma::SignalPlotter::setVerticalLinesScroll
void setVerticalLinesScroll(bool value)
Whether the vertical lines move with the data.
Definition: signalplotter.cpp:386
Plasma::SignalPlotter::drawBackground
void drawBackground(QPainter *p, int w, int h)
Definition: signalplotter.cpp:699
Plasma::SignalPlotter::setFontColor
void setFontColor(const QColor &color)
The color of the font used for the axis.
Definition: signalplotter.cpp:414
Plasma::SignalPlotter::scaledBy
qreal scaledBy() const
Amount scaled down by.
Definition: signalplotter.cpp:287
Plasma::SignalPlotter::verticalLinesColor
QColor verticalLinesColor() const
The color of the vertical grid lines.
Plasma::SignalPlotter::backgroundColor
QColor backgroundColor() const
The color to set the background.
Plasma::SignalPlotter::verticalMinValue
double verticalMinValue() const
Get the min value of the vertical axis.
Definition: signalplotter.cpp:318
Plasma::SignalPlotter::verticalMaxValue
double verticalMaxValue() const
Get the max value of the vertical axis.
Definition: signalplotter.cpp:323
Plasma::SignalPlotter::drawTopBarContents
void drawTopBarContents(QPainter *p, int x, int width, int height)
Definition: signalplotter.cpp:768
Plasma::SignalPlotter::lastValue
double lastValue(uint i) const
Return the last value that we have for plot i.
Definition: signalplotter.cpp:1087
Plasma::SignalPlotter::verticalLinesScroll
bool verticalLinesScroll() const
Whether the vertical lines move with the data.
Plasma::SignalPlotter::title
QString title() const
Get the title of the graph.
Plasma::SignalPlotter::setVerticalLinesColor
void setVerticalLinesColor(const QColor &color)
The color of the vertical grid lines.
Definition: signalplotter.cpp:358
Plasma::SignalPlotter::setBackgroundColor
void setBackgroundColor(const QColor &color)
The color to set the background.
Definition: signalplotter.cpp:519
Plasma::SignalPlotter::unit
QString unit() const
Return the units used on the vertical axis of the graph.
Plasma::SignalPlotter::svgBackground
QString svgBackground()
The filename of the svg background.
Plasma::SignalPlotter::setStackPlots
void setStackPlots(bool stack)
Whether to stack the plots on top of each other.
Definition: signalplotter.cpp:547
Plasma::Theme
Interface to the Plasma theme.
Definition: theme.h:56
Plasma::SignalPlotter::drawTopBarFrame
void drawTopBarFrame(QPainter *p, int separatorX, int height)
Definition: signalplotter.cpp:756
Plasma::SignalPlotter::horizontalLinesColor
QColor horizontalLinesColor() const
The color of the horizontal grid lines.
Plasma::SignalPlotter::thinFrame
bool thinFrame() const
show a white line on the left and bottom of the widget for a 3D effect
Plasma::SignalPlotter::setVerticalLinesDistance
void setVerticalLinesDistance(uint distance)
The horizontal distance between the vertical grid lines.
Definition: signalplotter.cpp:372
Plasma::Theme::defaultTheme
static Theme * defaultTheme()
Singleton pattern accessor.
Definition: theme.cpp:544
Plasma::SignalPlotter::setHorizontalLinesColor
void setHorizontalLinesColor(const QColor &color)
The color of the horizontal grid lines.
Definition: signalplotter.cpp:424
Plasma::SignalPlotter::drawThinFrame
void drawThinFrame(QPainter *p, int w, int h)
Definition: signalplotter.cpp:709
Plasma::SignalPlotter::stackPlots
bool stackPlots() const
Whether to stack the plots.
Plasma::SignalPlotter::verticalLinesDistance
uint verticalLinesDistance() const
The horizontal distance between the vertical grid lines.
Plasma::SignalPlotter::setShowVerticalLines
void setShowVerticalLines(bool value)
Whether to draw the vertical grid lines.
Definition: signalplotter.cpp:344
Plasma::SignalPlotter::setVerticalRange
void setVerticalRange(double min, double max)
Change the minimum and maximum values drawn on the graph.
Definition: signalplotter.cpp:251
Plasma::SignalPlotter::reorderPlots
Q_INVOKABLE void reorderPlots(const QList< uint > &newOrder)
Reorder the plots into the order given.
Definition: signalplotter.cpp:222
Plasma::Theme::color
Q_INVOKABLE QColor color(ColorRole role) const
Returns the text color to be used by items resting on the background.
Definition: theme.cpp:918
Plasma::SignalPlotter::scale
qreal scale
Definition: signalplotter.h:50
Plasma::SignalPlotter::setSvgBackground
void setSvgBackground(const QString &filename)
The filename of the svg background.
Definition: signalplotter.cpp:497
Plasma::SignalPlotter::showVerticalLines
bool showVerticalLines() const
Whether the vertical grid lines will be drawn.
Plasma::Theme::BackgroundColor
the default background color
Definition: theme.h:66
Plasma::SignalPlotter::calculateNiceRange
void calculateNiceRange()
Definition: signalplotter.cpp:718
Plasma::SignalPlotter::fontColor
QColor fontColor() const
The color of the font used for the axis.
Plasma::SignalPlotter::~SignalPlotter
~SignalPlotter()
Definition: signalplotter.cpp:155
Plasma::SignalPlotter::useAutoRange
bool useAutoRange() const
Whether the vertical axis range is set automatically.
Plasma::SignalPlotter::showLabels
bool showLabels() const
Whether to show the vertical axis labels.
QStyleOptionGraphicsItem
Plasma::PlotColor::color
QColor color
Definition: signalplotter.h:36
Plasma::Svg
A theme aware image-centric SVG class.
Definition: svg.h:56
Plasma::SignalPlotter::drawPlots
void drawPlots(QPainter *p, int top, int w, int h, int horizontalScale)
Definition: signalplotter.cpp:807
Plasma::SignalPlotter::horizontalLinesCount
uint horizontalLinesCount() const
The number of horizontal lines to draw.
Plasma::PlotColor
Definition: signalplotter.h:34
Plasma::SignalPlotter::setHorizontalLinesCount
void setHorizontalLinesCount(uint count)
The number of horizontal lines to draw.
Definition: signalplotter.cpp:438
Plasma::SignalPlotter::setTitle
void setTitle(const QString &title)
Set the title of the graph.
Definition: signalplotter.cpp:292
Plasma::SignalPlotter::paint
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
Definition: signalplotter.cpp:589
svg.h
QGraphicsWidget
This file is part of the KDE documentation.
Documentation copyright © 1996-2014 The KDE developers.
Generated on Tue Oct 14 2014 22:48:34 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

Plasma

Skip menu "Plasma"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

kdelibs API Reference

Skip menu "kdelibs API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  • kjsembed
  •   WTF
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Nepomuk-Core
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal