UPlot.cpp
Go to the documentation of this file.
1 /*
2 * utilite is a cross-platform library with
3 * useful utilities for fast and small developing.
4 * Copyright (C) 2010 Mathieu Labbe
5 *
6 * utilite is free library: you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * utilite is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19 
20 #include "rtabmap/utilite/UPlot.h"
22 #include "rtabmap/utilite/UMath.h"
23 
24 #include <QGraphicsScene>
25 #include <QGraphicsView>
26 #include <QGraphicsItem>
27 #include <QGraphicsRectItem>
28 #include <QHBoxLayout>
29 #include <QFormLayout>
30 #include <QtGui/QResizeEvent>
31 #include <QtGui/QMouseEvent>
32 #include <QtCore/QTime>
33 #include <QtCore/QTimer>
34 #include <QtCore/QFileInfo>
35 #include <QPushButton>
36 #include <QToolButton>
37 #include <QLabel>
38 #include <QMenu>
39 #include <QStyle>
40 #include <QInputDialog>
41 #include <QMessageBox>
42 #include <QFileDialog>
43 #include <QtGui/QClipboard>
44 #include <QApplication>
45 #include <QPrinter>
46 #include <QColorDialog>
47 #include <QToolTip>
48 #ifdef QT_SVG_LIB
49 #include <QtSvg/QSvgGenerator>
50 #endif
51 #include <cmath>
52 #include <limits>
53 
54 #define PRINT_DEBUG 0
55 
56 UPlotItem::UPlotItem(qreal dataX, qreal dataY, qreal width) :
57  QGraphicsEllipseItem(0, 0, width, width, 0),
58  _previousItem(0),
59  _nextItem(0),
60  _text(0),
61  _textBackground(0)
62 {
63  this->init(dataX, dataY);
64 }
65 
66 UPlotItem::UPlotItem(const QPointF & data, qreal width) :
67  QGraphicsEllipseItem(0, 0, width, width, 0),
68  _previousItem(0),
69  _nextItem(0),
70  _text(0),
72 {
73  this->init(data.x(), data.y());
74 }
75 
76 void UPlotItem::init(qreal dataX, qreal dataY)
77 {
78  _data.setX(dataX);
79  _data.setY(dataY);
80  this->setAcceptHoverEvents(true);
81  this->setFlag(QGraphicsItem::ItemIsFocusable, true);
82 }
83 
85 {
87  {
90  }
91  else if(_previousItem)
92  {
94  }
95  else if(_nextItem)
96  {
98  }
99 }
100 
101 void UPlotItem::setData(const QPointF & data)
102 {
103  _data = data;
104 }
105 
107 {
108  if(_nextItem != nextItem)
109  {
111  if(nextItem)
112  {
113  nextItem->setPreviousItem(this);
114  }
115  }
116 }
117 
119 {
120  if(_previousItem != previousItem)
121  {
123  if(previousItem)
124  {
125  previousItem->setNextItem(this);
126  }
127  }
128 }
129 
131 {
132  if(!_textBackground)
133  {
134  _textBackground = new QGraphicsRectItem(this);
135  _textBackground->setBrush(QBrush(QColor(255, 255, 255, 200)));
136  _textBackground->setPen(Qt::NoPen);
137  _textBackground->setZValue(this->zValue()+1);
138  _textBackground->setVisible(false);
139 
140  _text = new QGraphicsTextItem(_textBackground);
141  }
142 
143  if(this->parentItem() && this->parentItem() != _textBackground->parentItem())
144  {
145  _textBackground->setParentItem(this->parentItem());
146  _textBackground->setZValue(this->zValue()+1);
147  }
148 
149  if(this->scene() && shown)
150  {
151  _textBackground->setVisible(true);
152  _text->setPlainText(QString("(%1,%2)").arg(_data.x()).arg(_data.y()));
153 
154  this->setPen(QPen(this->pen().color(), 2));
155 
156  QRectF rect = this->scene()->sceneRect();
157  QPointF p = this->pos();
158  QRectF br = _text->boundingRect();
159  _textBackground->setRect(QRectF(0,0,br.width(), br.height()));
160 
161  // Make sure the text is always in the scene
162  if(p.x() - br.width() < 0)
163  {
164  p.setX(0);
165  }
166  else if(p.x() > rect.width())
167  {
168  p.setX(rect.width() - br.width());
169  }
170  else
171  {
172  p.setX(p.x() - br.width());
173  }
174 
175  if(p.y() - br.height() < 0)
176  {
177  p.setY(0);
178  }
179  else
180  {
181  p.setY(p.y() - br.height());
182  }
183 
184  _textBackground->setPos(p);
185  }
186  else
187  {
188  this->setPen(QPen(this->pen().color(), 1));
189  _textBackground->setVisible(false);
190  }
191 }
192 
193 void UPlotItem::hoverEnterEvent(QGraphicsSceneHoverEvent * event)
194 {
195  this->showDescription(true);
196  QGraphicsEllipseItem::hoverEnterEvent(event);
197 }
198 
199 void UPlotItem::hoverLeaveEvent(QGraphicsSceneHoverEvent * event)
200 {
201  if(!this->hasFocus())
202  {
203  this->showDescription(false);
204  }
205  QGraphicsEllipseItem::hoverLeaveEvent(event);
206 }
207 
208 void UPlotItem::focusInEvent(QFocusEvent * event)
209 {
210  this->showDescription(true);
211  QGraphicsEllipseItem::focusInEvent(event);
212 }
213 
214 void UPlotItem::focusOutEvent(QFocusEvent * event)
215 {
216  this->showDescription(false);
217  QGraphicsEllipseItem::focusOutEvent(event);
218 }
219 
220 void UPlotItem::keyReleaseEvent(QKeyEvent * keyEvent)
221 {
222  //Get the next/previous visible item
223  if(keyEvent->key() == Qt::Key_Right)
224  {
225  UPlotItem * next = _nextItem;
226  while(next && !next->isVisible())
227  {
228  next = next->nextItem();
229  }
230  if(next && next->isVisible())
231  {
232  this->clearFocus();
233  next->setFocus();
234  }
235  }
236  else if(keyEvent->key() == Qt::Key_Left)
237  {
238  UPlotItem * previous = _previousItem;
239  while(previous && !previous->isVisible())
240  {
241  previous = previous->previousItem();
242  }
243  if(previous && previous->isVisible())
244  {
245  this->clearFocus();
246  previous->setFocus();
247  }
248  }
249  QGraphicsEllipseItem::keyReleaseEvent(keyEvent);
250 }
251 
252 
253 
254 
255 
256 UPlotCurve::UPlotCurve(const QString & name, QObject * parent) :
257  QObject(parent),
258  _plot(0),
259  _name(name),
260  _xIncrement(1),
261  _xStart(0),
262  _visible(true),
263  _valuesShown(false),
264  _itemsColor(0,0,0,150)
265 {
266  _rootItem = new QGraphicsRectItem();
267 }
268 
269 UPlotCurve::UPlotCurve(const QString & name, QVector<UPlotItem *> data, QObject * parent) :
270  QObject(parent),
271  _plot(0),
272  _name(name),
273  _xIncrement(1),
274  _xStart(0),
275  _visible(true),
276  _valuesShown(false),
277  _itemsColor(0,0,0,150)
278 {
279  _rootItem = new QGraphicsRectItem();
280  this->setData(data);
281 }
282 
283 UPlotCurve::UPlotCurve(const QString & name, const QVector<qreal> & x, const QVector<qreal> & y, QObject * parent) :
284  QObject(parent),
285  _plot(0),
286  _name(name),
287  _xIncrement(1),
288  _xStart(0),
289  _visible(true),
291  _itemsColor(0,0,0,150)
292 {
293  _rootItem = new QGraphicsRectItem();
294  this->setData(x, y);
295 }
296 
298 {
299  if(_plot)
300  {
301  _plot->removeCurve(this);
302  }
303 #if PRINT_DEBUG
304  ULOGGER_DEBUG("%s", this->name().toStdString().c_str());
305 #endif
306  this->clear();
307  delete _rootItem;
308 }
309 
311 {
312  if(!plot || plot == _plot)
313  {
314  return;
315  }
316  if(_plot)
317  {
318  _plot->removeCurve(this);
319  }
320  _plot = plot;
322 }
323 
325 {
326 #if PRINT_DEBUG
327  ULOGGER_DEBUG("curve=\"%s\" from plot=\"%s\"", this->objectName().toStdString().c_str(), plot?plot->objectName().toStdString().c_str():"");
328 #endif
329  if(plot && _plot == plot)
330  {
331  _plot = 0;
332  if(_rootItem->scene())
333  {
334  _rootItem->scene()->removeItem(_rootItem);
335  }
336  }
337 }
338 
340 {
341  qreal x,y;
342  const UPlotItem * item;
343  if(!_items.size())
344  {
345  _minMax = QVector<qreal>();
346  }
347  else
348  {
349  _minMax = QVector<qreal>(4);
350  }
351  for(int i=0; i<_items.size(); ++i)
352  {
353  item = qgraphicsitem_cast<const UPlotItem *>(_items.at(i));
354  if(item)
355  {
356  x = item->data().x();
357  y = item->data().y();
358  if(i==0)
359  {
360  _minMax[0] = x;
361  _minMax[1] = x;
362  _minMax[2] = y;
363  _minMax[3] = y;
364  }
365  else
366  {
367  if(x<_minMax[0]) _minMax[0] = x;
368  if(x>_minMax[1]) _minMax[1] = x;
369  if(y<_minMax[2]) _minMax[2] = y;
370  if(y>_minMax[3]) _minMax[3] = y;
371  }
372  }
373  }
374 }
375 
377 {
378  // add item
379  if(data)
380  {
381  qreal x = data->data().x();
382  qreal y = data->data().y();
383 
384  if(_minMax.size() != 4)
385  {
386  _minMax = QVector<qreal>(4);
387  }
388  if(_items.size())
389  {
390  data->setPreviousItem((UPlotItem *)_items.last());
391  QGraphicsLineItem * line = new QGraphicsLineItem(_rootItem);
392  line->setPen(_pen);
393  line->setVisible(false);
394  _items.append(line);
395  //Update min/max
396  if(x<_minMax[0]) _minMax[0] = x;
397  if(x>_minMax[1]) _minMax[1] = x;
398  if(y<_minMax[2]) _minMax[2] = y;
399  if(y>_minMax[3]) _minMax[3] = y;
400  }
401  else
402  {
403  _minMax[0] = x;
404  _minMax[1] = x;
405  _minMax[2] = y;
406  _minMax[3] = y;
407  }
408  data->setParentItem(_rootItem);
409  data->setZValue(1);
410  _items.append(data);
411  data->setVisible(false);
412  QPen pen = data->pen();
413  pen.setColor(_itemsColor);
414  data->setPen(pen);
415  }
416  else
417  {
418  ULOGGER_ERROR("Data is null ?!?");
419  }
420 }
421 
423 {
424  // add item
425  if(data)
426  {
427  this->_addValue(data);
428  Q_EMIT dataChanged(this);
429  }
430 }
431 
432 void UPlotCurve::addValue(qreal x, qreal y)
433 {
434  if(_items.size() &&
435  _minMax[0] != _minMax[1] &&
436  x < _minMax[1])
437  {
438  UWARN("New value (%f) added to curve \"%s\" is smaller "
439  "than the last added (%f). Clearing the curve.",
440  x, this->name().toStdString().c_str(), ((UPlotItem*)_items.back())->data().x());
441  this->clear();
442  }
443 
444  qreal width = 2; // TODO warn : hard coded value!
445  this->addValue(new UPlotItem(x,y,width));
446 }
447 
448 void UPlotCurve::addValue(qreal y)
449 {
450  qreal x = 0;
451  if(_items.size())
452  {
453  UPlotItem * lastItem = (UPlotItem *)_items.last();
454  x = lastItem->data().x() + _xIncrement;
455  }
456  else
457  {
458  x = _xStart;
459  }
460  this->addValue(x,y);
461 }
462 
463 void UPlotCurve::addValue(const QString & value)
464 {
465  bool ok;
466  qreal v = value.toDouble(&ok);
467  if(ok)
468  {
469  this->addValue(v);
470  }
471  else
472  {
473  ULOGGER_ERROR("Value not valid, must be a number, received %s", value.toStdString().c_str());
474  }
475 }
476 
477 void UPlotCurve::addValues(QVector<UPlotItem *> & data)
478 {
479  for(int i=0; i<data.size(); ++i)
480  {
481  this->_addValue(data.at(i));
482  }
483  Q_EMIT dataChanged(this);
484 }
485 
486 void UPlotCurve::addValues(const QVector<qreal> & xs, const QVector<qreal> & ys)
487 {
488  qreal width = 2; // TODO warn : hard coded value!
489  for(int i=0; i<xs.size() && i<ys.size(); ++i)
490  {
491  this->_addValue(new UPlotItem(xs.at(i),ys.at(i),width));
492  }
493  Q_EMIT dataChanged(this);
494 }
495 
496 void UPlotCurve::addValues(const QVector<qreal> & ys)
497 {
498  qreal x = 0;
499  qreal width = 2; // TODO warn : hard coded value!
500  for(int i=0; i<ys.size(); ++i)
501  {
502  if(_items.size())
503  {
504  UPlotItem * lastItem = (UPlotItem *)_items.last();
505  x = lastItem->data().x() + _xIncrement;
506  }
507  else
508  {
509  x = _xStart;
510  }
511  this->_addValue(new UPlotItem(x,ys.at(i),width));
512  }
513  Q_EMIT dataChanged(this);
514 }
515 
516 void UPlotCurve::addValues(const QVector<int> & ys)
517 {
518  qreal x = 0;
519  qreal width = 2; // TODO warn : hard coded value!
520  for(int i=0; i<ys.size(); ++i)
521  {
522  if(_items.size())
523  {
524  UPlotItem * lastItem = (UPlotItem *)_items.last();
525  x = lastItem->data().x() + _xIncrement;
526  }
527  else
528  {
529  x = _xStart;
530  }
531  this->_addValue(new UPlotItem(x,ys.at(i),width));
532  }
533  Q_EMIT dataChanged(this);
534 }
535 
536 void UPlotCurve::addValues(const std::vector<int> & ys)
537 {
538  qreal x = 0;
539  qreal width = 2; // TODO warn : hard coded value!
540  for(unsigned int i=0; i<ys.size(); ++i)
541  {
542  if(_items.size())
543  {
544  UPlotItem * lastItem = (UPlotItem *)_items.last();
545  x = lastItem->data().x() + _xIncrement;
546  }
547  else
548  {
549  x = _xStart;
550  }
551  this->_addValue(new UPlotItem(x,ys.at(i),width));
552  }
553  Q_EMIT dataChanged(this);
554 }
555 
556 void UPlotCurve::addValues(const std::vector<qreal> & ys)
557 {
558  qreal x = 0;
559  qreal width = 2; // TODO warn : hard coded value!
560  for(unsigned int i=0; i<ys.size(); ++i)
561  {
562  if(_items.size())
563  {
564  UPlotItem * lastItem = (UPlotItem *)_items.last();
565  x = lastItem->data().x() + _xIncrement;
566  }
567  else
568  {
569  x = _xStart;
570  }
571  this->_addValue(new UPlotItem(x,ys.at(i),width));
572  }
573  Q_EMIT dataChanged(this);
574 }
575 
577 {
578  if(index >= 0 && index < _items.size())
579  {
580  if(index!=0)
581  {
582  index-=1;
583  delete _items.takeAt(index); // the line
584  }
585  else if(_items.size()>1)
586  {
587  delete _items.takeAt(index+1); // the line
588  }
589  UPlotItem * item = (UPlotItem *)_items.takeAt(index); // the plot item
590  //Update min/max
591  if(_minMax.size() == 4)
592  {
593  if(item->data().x() == _minMax[0] || item->data().x() == _minMax[1] ||
594  item->data().y() == _minMax[2] || item->data().y() == _minMax[3])
595  {
596  if(_items.size())
597  {
598  UPlotItem * tmp = (UPlotItem *)_items.at(0);
599  qreal x = tmp->data().x();
600  qreal y = tmp->data().y();
601  _minMax[0]=x;
602  _minMax[1]=x;
603  _minMax[2]=y;
604  _minMax[3]=y;
605  for(int i = 2; i<_items.size(); i+=2)
606  {
607  tmp = (UPlotItem*)_items.at(i);
608  x = tmp->data().x();
609  y = tmp->data().y();
610  if(x<_minMax[0]) _minMax[0] = x;
611  if(x>_minMax[1]) _minMax[1] = x;
612  if(y<_minMax[2]) _minMax[2] = y;
613  if(y>_minMax[3]) _minMax[3] = y;
614  }
615  }
616  else
617  {
618  _minMax = QVector<qreal>();
619  }
620  }
621  }
622  delete item;
623  }
624 
625  return index;
626 }
627 
628 void UPlotCurve::removeItem(UPlotItem * item) // ownership is transfered to the caller
629 {
630  for(int i=0; i<_items.size(); ++i)
631  {
632  if(_items.at(i) == item)
633  {
634  if(i!=0)
635  {
636  i-=1;
637  delete _items[i];
638  _items.removeAt(i);
639  }
640  else if(_items.size()>1)
641  {
642  delete _items[i+1];
643  _items.removeAt(i+1);
644  }
645  item->scene()->removeItem(item);
646  _items.removeAt(i);
647  break;
648  }
649  }
650 }
651 
653 {
654 #if PRINT_DEBUG
655  ULOGGER_DEBUG("%s", this->name().toStdString().c_str());
656 #endif
657  qDeleteAll(_rootItem->childItems());
658  _items.clear();
659 }
660 
661 void UPlotCurve::setPen(const QPen & pen)
662 {
663  _pen = pen;
664  for(int i=1; i<_items.size(); i+=2)
665  {
666  ((QGraphicsLineItem*) _items.at(i))->setPen(_pen);
667  }
668 }
669 
670 void UPlotCurve::setBrush(const QBrush & brush)
671 {
672  _brush = brush;
673  ULOGGER_WARN("Not used...");
674 }
675 
676 void UPlotCurve::setItemsColor(const QColor & color)
677 {
678  if(color.isValid())
679  {
680  _itemsColor.setRgb(color.red(), color.green(), color.blue(), _itemsColor.alpha());
681  for(int i=0; i<_items.size(); i+=2)
682  {
683  QPen pen = ((UPlotItem*) _items.at(i))->pen();
684  pen.setColor(_itemsColor);
685  ((UPlotItem*) _items.at(i))->setPen(pen);
686  }
687  }
688 }
689 
690 void UPlotCurve::update(qreal scaleX, qreal scaleY, qreal offsetX, qreal offsetY, qreal xDir, qreal yDir, int maxItemsKept)
691 {
692  //ULOGGER_DEBUG("scaleX=%f, scaleY=%f, offsetX=%f, offsetY=%f, xDir=%d, yDir=%d, _plot->scene()->width()=%f, _plot->scene()->height=%f", scaleX, scaleY, offsetX, offsetY, xDir, yDir,_plot->scene()->width(),_plot->scene()->height());
693  //make sure direction values are 1 or -1
694  xDir<0?xDir=-1:xDir=1;
695  yDir<0?yDir=-1:yDir=1;
696 
697  bool hide = false;
698  int j=0;
699  for(int i=_items.size()-1; i>=0; --i)
700  {
701  if(i%2 == 0)
702  {
703  UPlotItem * item = (UPlotItem *)_items.at(i);
704  if(hide)
705  {
706  if(maxItemsKept == 0 || j <= maxItemsKept)
707  {
708  // if not visible, stop looping... all other items are normally already hidden
709  if(!item->isVisible())
710  {
711  break;
712  }
713  item->setVisible(false);
714  }
715  else
716  {
717  //remove the item with his line
718  i = this->removeItem(i);
719  }
720  }
721  else
722  {
723  QPointF newPos(((xDir*item->data().x()+offsetX)*scaleX-item->rect().width()/2.0f),
724  ((yDir*item->data().y()+offsetY)*scaleY-item->rect().width()/2.0f));
725  if(!item->isVisible())
726  {
727  item->setVisible(true);
728  }
729  item->setPos(newPos);
730  }
731  ++j;
732  }
733  else
734  {
735  if(hide)
736  {
737  _items.at(i)->setVisible(false);
738  }
739  else
740  {
741  UPlotItem * from = (UPlotItem *)_items.at(i-1);
742  UPlotItem * to = (UPlotItem *)_items.at(i+1);
743  QGraphicsLineItem * lineItem = (QGraphicsLineItem *)_items.at(i);
744  lineItem->setLine((xDir*from->data().x()+offsetX)*scaleX,
745  (yDir*from->data().y()+offsetY)*scaleY,
746  (xDir*to->data().x()+offsetX)*scaleX,
747  (yDir*to->data().y()+offsetY)*scaleY);
748  if(!lineItem->isVisible())
749  {
750  lineItem->setVisible(true);
751  }
752  //Don't update not visible items
753  // (Detect also if the curve goes forward or backward)
754  QLineF line = lineItem->line();
755  if((line.x1() <= line.x2() && line.x2() < 0-((line.x2() - line.x1()))) ||
756  (line.x1() > line.x2() && line.x2() > lineItem->scene()->sceneRect().width() + ((line.x1() - line.x2()))))
757  {
758  hide = true;
759  }
760 
761  }
762  }
763  }
764 
765 }
766 
767 void UPlotCurve::draw(QPainter * painter, const QRect & limits)
768 {
769  if(painter)
770  {
771  for(int i=_items.size()-1; i>=0 && _items.at(i)->isVisible(); i-=2)
772  {
773  //plotItem
774  const UPlotItem * item = (const UPlotItem *)_items.at(i);
775  int x = (int)item->x();
776  if(x<0)
777  {
778  break;
779  }
780 
781  // draw line in first
782  if(i-1>=0)
783  {
784  //lineItem
785  const QGraphicsLineItem * lineItem = (const QGraphicsLineItem *)_items.at(i-1);
786  QLine line = lineItem->line().toLine();
787  if(limits.contains(line.p1()) || limits.contains(line.p2()))
788  {
789  QPointF intersection;
790  QLineF::IntersectType type;
791  type = lineItem->line().intersect(QLineF(limits.topLeft(), limits.bottomLeft()), &intersection);
792  if(type == QLineF::BoundedIntersection)
793  {
794  !limits.contains(line.p1())?line.setP1(intersection.toPoint()):line.setP2(intersection.toPoint());
795  }
796  else
797  {
798  type = lineItem->line().intersect(QLineF(limits.topLeft(), limits.topRight()), &intersection);
799  if(type == QLineF::BoundedIntersection)
800  {
801  !limits.contains(line.p1())?line.setP1(intersection.toPoint()):line.setP2(intersection.toPoint());
802  }
803  else
804  {
805  type = lineItem->line().intersect(QLineF(limits.bottomLeft(), limits.bottomRight()), &intersection);
806  if(type == QLineF::BoundedIntersection)
807  {
808  !limits.contains(line.p1())?line.setP1(intersection.toPoint()):line.setP2(intersection.toPoint());
809  }
810  else
811  {
812  type = lineItem->line().intersect(QLineF(limits.topRight(), limits.bottomRight()), &intersection);
813  if(type == QLineF::BoundedIntersection)
814  {
815  !limits.contains(line.p1())?line.setP1(intersection.toPoint()):line.setP2(intersection.toPoint());
816  }
817  }
818  }
819  }
820  painter->save();
821  painter->setPen(this->pen());
822  painter->setBrush(this->brush());
823  painter->drawLine(line);
824  painter->restore();
825  }
826  }
827 
828  /*if(limits.contains(item->pos().toPoint()) && limits.contains((item->pos() + QPointF(item->rect().width(), item->rect().height())).toPoint()))
829  {
830  painter->save();
831  painter->setPen(QPen(_itemsColor));
832  painter->drawEllipse(item->pos()+QPointF(item->rect().width()/2, item->rect().height()/2), (int)item->rect().width()/2, (int)item->rect().height()/2);
833  painter->restore();
834  }*/
835  }
836  }
837 }
838 
840 {
841  return _items.size();
842 }
843 
844 QPointF UPlotCurve::getItemData(int index)
845 {
846  QPointF data;
847  //make sure the index point to a PlotItem {PlotItem, line, PlotItem, line...}
848  if(index>=0 && index < _items.size() && index % 2 == 0 )
849  {
850  data = ((UPlotItem*)_items.at(index))->data();
851  }
852  else
853  {
854  ULOGGER_ERROR("Wrong index, not pointing on a PlotItem");
855  }
856  return data;
857 }
858 
859 void UPlotCurve::setVisible(bool visible)
860 {
861  _visible = visible;
862  for(int i=0; i<_items.size(); ++i)
863  {
864  _items.at(i)->setVisible(visible);
865  }
866 }
867 
868 void UPlotCurve::setXIncrement(qreal increment)
869 {
870  _xIncrement = increment;
871 }
872 
873 void UPlotCurve::setXStart(qreal val)
874 {
875  _xStart = val;
876 }
877 
878 void UPlotCurve::setData(QVector<UPlotItem*> & data)
879 {
880  this->clear();
881  for(int i = 0; i<data.size(); ++i)
882  {
883  this->addValue(data[i]);
884  }
885 }
886 
887 void UPlotCurve::setData(const QVector<qreal> & x, const QVector<qreal> & y)
888 {
889  if(x.size() == y.size())
890  {
891  //match the size of the current data
892  int margin = int((_items.size()+1)/2) - x.size();
893  while(margin < 0)
894  {
895  UPlotItem * newItem = new UPlotItem(0, 0, 2);
896  this->_addValue(newItem);
897  ++margin;
898  }
899  while(margin > 0)
900  {
901  this->removeItem(0);
902  --margin;
903  }
904 
905  // update values
906  int index = 0;
907  QVector<qreal>::const_iterator i=x.begin();
908  QVector<qreal>::const_iterator j=y.begin();
909  for(; i!=x.end() && j!=y.end(); ++i, ++j, index+=2)
910  {
911  ((UPlotItem*)_items[index])->setData(QPointF(*i, *j));
912  }
913 
914  //reset minMax, this will force the plot to update the axes
915  this->updateMinMax();
916  Q_EMIT dataChanged(this);
917  }
918  else if(y.size()>0 && x.size()==0)
919  {
920  this->setData(y);
921  }
922  else
923  {
924  ULOGGER_ERROR("Data vectors have not the same size.");
925  }
926 }
927 
928 void UPlotCurve::setData(const std::vector<qreal> & x, const std::vector<qreal> & y)
929 {
930  if(x.size() == y.size())
931  {
932  //match the size of the current data
933  int margin = int((_items.size()+1)/2) - int(x.size());
934  while(margin < 0)
935  {
936  UPlotItem * newItem = new UPlotItem(0, 0, 2);
937  this->_addValue(newItem);
938  ++margin;
939  }
940  while(margin > 0)
941  {
942  this->removeItem(0);
943  --margin;
944  }
945 
946  // update values
947  int index = 0;
948  std::vector<qreal>::const_iterator i=x.begin();
949  std::vector<qreal>::const_iterator j=y.begin();
950  for(; i!=x.end() && j!=y.end(); ++i, ++j, index+=2)
951  {
952  ((UPlotItem*)_items[index])->setData(QPointF(*i, *j));
953  }
954 
955  //reset minMax, this will force the plot to update the axes
956  this->updateMinMax();
957  Q_EMIT dataChanged(this);
958  }
959  else if(y.size()>0 && x.size()==0)
960  {
961  this->setData(y);
962  }
963  else
964  {
965  ULOGGER_ERROR("Data vectors have not the same size.");
966  }
967 }
968 
969 void UPlotCurve::setData(const QVector<qreal> & y)
970 {
971  this->setData(y.toStdVector());
972 }
973 
974 void UPlotCurve::setData(const std::vector<qreal> & y)
975 {
976  //match the size of the current data
977  int margin = int((_items.size()+1)/2) - int(y.size());
978  while(margin < 0)
979  {
980  UPlotItem * newItem = new UPlotItem(0, 0, 2);
981  this->_addValue(newItem);
982  ++margin;
983  }
984  while(margin > 0)
985  {
986  this->removeItem(0);
987  --margin;
988  }
989 
990  // update values
991  int index = 0;
992  qreal x = 0;
993  std::vector<qreal>::const_iterator j=y.begin();
994  for(; j!=y.end(); ++j, index+=2)
995  {
996  ((UPlotItem*)_items[index])->setData(QPointF(x++, *j));
997  }
998 
999  //reset minMax, this will force the plot to update the axes
1000  this->updateMinMax();
1001  Q_EMIT dataChanged(this);
1002 }
1003 
1004 void UPlotCurve::getData(QVector<qreal> & x, QVector<qreal> & y) const
1005 {
1006  x.clear();
1007  y.clear();
1008  if(_items.size())
1009  {
1010  x.resize((_items.size()-1)/2+1);
1011  y.resize(x.size());
1012  int j=0;
1013  for(int i=0; i<_items.size(); i+=2)
1014  {
1015  x[j] = ((UPlotItem*)_items.at(i))->data().x();
1016  y[j++] = ((UPlotItem*)_items.at(i))->data().y();
1017  }
1018  }
1019 }
1020 
1021 void UPlotCurve::getData(QMap<qreal,qreal> & data) const
1022 {
1023  data.clear();
1024  if(_items.size())
1025  {
1026  for(int i=0; i<_items.size(); i+=2)
1027  {
1028  data.insert(((UPlotItem*)_items.at(i))->data().x(), ((UPlotItem*)_items.at(i))->data().y());
1029  }
1030  }
1031 }
1032 
1033 
1034 
1035 
1036 
1037 UPlotCurveThreshold::UPlotCurveThreshold(const QString & name, qreal thesholdValue, Qt::Orientation orientation, QObject * parent) :
1038  UPlotCurve(name, parent),
1039  _orientation(orientation)
1040 {
1041  if(_orientation == Qt::Horizontal)
1042  {
1043  this->addValue(0, thesholdValue);
1044  this->addValue(1, thesholdValue);
1045  }
1046  else
1047  {
1048  this->addValue(thesholdValue, 0);
1049  this->addValue(thesholdValue, 1);
1050  }
1051 }
1052 
1054 {
1055 
1056 }
1057 
1059 {
1060 #if PRINT_DEBUG
1061  ULOGGER_DEBUG("%f", threshold);
1062 #endif
1063  if(_items.size() == 3)
1064  {
1065  UPlotItem * item = 0;
1066  if(_orientation == Qt::Horizontal)
1067  {
1068  item = (UPlotItem*)_items.at(0);
1069  item->setData(QPointF(item->data().x(), threshold));
1070  item = (UPlotItem*)_items.at(2);
1071  item->setData(QPointF(item->data().x(), threshold));
1072  }
1073  else
1074  {
1075  item = (UPlotItem*)_items.at(0);
1076  item->setData(QPointF(threshold, item->data().y()));
1077  item = (UPlotItem*)_items.at(2);
1078  item->setData(QPointF(threshold, item->data().y()));
1079  }
1080  }
1081  else
1082  {
1083  ULOGGER_ERROR("A threshold must has only 3 items (1 PlotItem + 1 QGraphicsLineItem + 1 PlotItem)");
1084  }
1085 }
1086 
1088 {
1089  if(_orientation != orientation)
1090  {
1092  if(_items.size() == 3)
1093  {
1094  UPlotItem * item = 0;
1095  item = (UPlotItem*)_items.at(0);
1096  item->setData(QPointF(item->data().y(), item->data().x()));
1097  item = (UPlotItem*)_items.at(2);
1098  item->setData(QPointF(item->data().y(), item->data().x()));
1099  }
1100  else
1101  {
1102  ULOGGER_ERROR("A threshold must has only 3 items (1 PlotItem + 1 QGraphicsLineItem + 1 PlotItem)");
1103  }
1104  }
1105 }
1106 
1107 void UPlotCurveThreshold::update(qreal scaleX, qreal scaleY, qreal offsetX, qreal offsetY, qreal xDir, qreal yDir, int maxItemsKept)
1108 {
1109  if(_items.size() == 3)
1110  {
1111  if(_plot)
1112  {
1113  UPlotItem * item = 0;
1114  if(_orientation == Qt::Horizontal)
1115  {
1116  //(xDir*item->data().x()+offsetX)*scaleX
1117  item = (UPlotItem*)_items.at(0);
1118  item->setData(QPointF(-(offsetX-item->rect().width()/scaleX)/xDir, item->data().y()));
1119  item = (UPlotItem*)_items.at(2);
1120  item->setData(QPointF( (_plot->sceneRect().width()/scaleX-(offsetX+item->rect().width()/scaleX))/xDir, item->data().y()));
1121  }
1122  else
1123  {
1124  item = (UPlotItem*)_items.at(0);
1125  item->setData(QPointF(item->data().x(), -(offsetY-item->rect().height()/scaleY)/yDir));
1126  item = (UPlotItem*)_items.at(2);
1127  item->setData(QPointF(item->data().x(), (_plot->sceneRect().height()/scaleY-(offsetY+item->rect().height()/scaleY))/yDir));
1128  }
1129  this->updateMinMax();
1130  }
1131  }
1132  else
1133  {
1134  ULOGGER_ERROR("A threshold must has only 3 items (1 PlotItem + 1 QGraphicsLineItem + 1 PlotItem)");
1135  }
1136  UPlotCurve::update(scaleX, scaleY, offsetX, offsetY, xDir, yDir, maxItemsKept);
1137 }
1138 
1139 
1140 
1141 
1142 
1143 
1144 
1145 UPlotAxis::UPlotAxis(Qt::Orientation orientation, qreal min, qreal max, QWidget * parent) :
1146  QWidget(parent),
1147  _orientation(orientation),
1148  _min(0),
1149  _max(0),
1150  _count(0),
1151  _step(0),
1152  _reversed(false),
1153  _gradMaxDigits(4),
1154  _border(0)
1155 {
1156  if(_orientation == Qt::Vertical)
1157  {
1158  _reversed = true; // default bottom->up
1159  }
1160 #ifdef _WIN32
1161  this->setMinimumSize(15, 25);
1162 #else
1163  this->setMinimumSize(15, 25);
1164 #endif
1165  this->setAxis(min, max); // this initialize all attributes
1166 }
1167 
1169 {
1170 #if PRINT_DEBUG
1171  ULOGGER_DEBUG("");
1172 #endif
1173 }
1174 
1175 // Vertical :bottom->up, horizontal :right->left
1176 void UPlotAxis::setReversed(bool reversed)
1177 {
1178  if(_reversed != reversed)
1179  {
1180  qreal min = _min;
1181  _min = _max;
1182  _max = min;
1183  }
1184  _reversed = reversed;
1185 }
1186 
1187 void UPlotAxis::setAxis(qreal & min, qreal & max)
1188 {
1189  int borderMin = 0;
1190  int borderMax = 0;
1191  if(_orientation == Qt::Vertical)
1192  {
1193  borderMin = borderMax = this->fontMetrics().height()/2;
1194  }
1195  else
1196  {
1197  borderMin = this->fontMetrics().width(QString::number(_min,'g',_gradMaxDigits))/2;
1198  borderMax = this->fontMetrics().width(QString::number(_max,'g',_gradMaxDigits))/2;
1199  }
1200  int border = borderMin>borderMax?borderMin:borderMax;
1201  int borderDelta;
1202  int length;
1203  if(_orientation == Qt::Vertical)
1204  {
1205  length = (this->height()-border*2);
1206  }
1207  else
1208  {
1209  length = (this->width()-border*2);
1210  }
1211 
1212  if(length <= 70)
1213  {
1214  _count = 5;
1215  }
1216  else if(length <= 175)
1217  {
1218  _count = 10;
1219  }
1220  else if(length <= 350)
1221  {
1222  _count = 20;
1223  }
1224  else if(length <= 700)
1225  {
1226  _count = 40;
1227  }
1228  else if(length <= 1000)
1229  {
1230  _count = 60;
1231  }
1232  else if(length <= 1300)
1233  {
1234  _count = 80;
1235  }
1236  else
1237  {
1238  _count = 100;
1239  }
1240 
1241  // Rounding min and max
1242  if(min != max)
1243  {
1244  qreal mul = 1;
1245  qreal rangef = max - min;
1246  int countStep = _count/5;
1247  qreal val;
1248  for(int i=0; i<6; ++i)
1249  {
1250  val = (rangef/qreal(countStep)) * mul;
1251  if( val >= 1.0f && val < 10.0f)
1252  {
1253  break;
1254  }
1255  else if(val<1)
1256  {
1257  mul *= 10.0f;
1258  }
1259  else
1260  {
1261  mul /= 10.0f;
1262  }
1263  }
1264  //ULOGGER_DEBUG("min=%f, max=%f", min, max);
1265  int minR = min*mul-0.9;
1266  int maxR = max*mul+0.9;
1267  min = qreal(minR)/mul;
1268  max = qreal(maxR)/mul;
1269  //ULOGGER_DEBUG("mul=%f, minR=%d, maxR=%d,countStep=%d", mul, minR, maxR, countStep);
1270  }
1271 
1272  _min = min;
1273  _max = max;
1274 
1275  if(_reversed)
1276  {
1277  _min = _max;
1278  _max = min;
1279  }
1280 
1281  if(_orientation == Qt::Vertical)
1282  {
1283  _step = length/_count;
1284  borderDelta = length - (_step*_count);
1285  }
1286  else
1287  {
1288  _step = length/_count;
1289  borderDelta = length - (_step*_count);
1290  }
1291 
1292  if(borderDelta%2 != 0)
1293  {
1294  borderDelta+=1;
1295  }
1296 
1297  _border = border + borderDelta/2;
1298 
1299  //Resize estimation
1300  if(_orientation == Qt::Vertical)
1301  {
1302  int minWidth = 0;
1303  for (int i = 0; i <= _count; i+=5)
1304  {
1305  QString n(QString::number(_min + (i/5)*((_max-_min)/(_count/5)),'g',_gradMaxDigits));
1306  if(this->fontMetrics().width(n) > minWidth)
1307  {
1308  minWidth = this->fontMetrics().width(n);
1309  }
1310  }
1311  this->setMinimumWidth(15+minWidth);
1312  }
1313 }
1314 
1315 void UPlotAxis::paintEvent(QPaintEvent * event)
1316 {
1317  QPainter painter(this);
1318  if(_orientation == Qt::Vertical)
1319  {
1320  painter.translate(0, _border);
1321  for (int i = 0; i <= _count; ++i)
1322  {
1323  if(i%5 == 0)
1324  {
1325  painter.drawLine(this->width(), 0, this->width()-10, 0);
1326  QLabel n(QString::number(_min + (i/5)*((_max-_min)/(_count/5)),'g',_gradMaxDigits));
1327  painter.drawText(this->width()-(12+n.sizeHint().width()), n.sizeHint().height()/2-2, n.text());
1328  }
1329  else
1330  {
1331  painter.drawLine(this->width(), 0, this->width()-5, 0);
1332  }
1333  painter.translate(0, _step);
1334  }
1335  }
1336  else
1337  {
1338  painter.translate(_border, 0);
1339  for (int i = 0; i <= _count; ++i)
1340  {
1341  if(i%5 == 0)
1342  {
1343  painter.drawLine(0, 0, 0, 10);
1344  QLabel n(QString::number(_min + (i/5)*((_max-_min)/(_count/5)),'g',_gradMaxDigits));
1345  painter.drawText(-(n.sizeHint().width()/2)+1, 22, n.text());
1346  }
1347  else
1348  {
1349  painter.drawLine(0, 0, 0, 5);
1350  }
1351  painter.translate(_step, 0);
1352  }
1353  }
1354 }
1355 
1356 
1357 
1358 
1359 UPlotLegendItem::UPlotLegendItem(UPlotCurve * curve, QWidget * parent) :
1360  QPushButton(parent),
1361  _curve(curve)
1362 {
1363  QString nameSpaced = curve->name();
1364  nameSpaced.replace('_', ' ');
1365  this->setText(nameSpaced);
1366 
1367  this->setIcon(QIcon(this->createSymbol(curve->pen(), curve->brush())));
1368  this->setIconSize(QSize(25,20));
1369 
1370  _aChangeText = new QAction(tr("Change text..."), this);
1371  _aResetText = new QAction(tr("Reset text..."), this);
1372  _aChangeColor = new QAction(tr("Change color..."), this);
1373  _aCopyToClipboard = new QAction(tr("Copy curve data to clipboard"), this);
1374  _aShowStdDevMeanMax = new QAction(tr("Show %1, %2, max").arg(QChar(0xbc, 0x03)).arg(QChar(0xc3, 0x03)), this);
1375  _aShowStdDevMeanMax->setCheckable(true);
1376  _aMoveUp = new QAction(tr("Move up"), this);
1377  _aMoveDown = new QAction(tr("Move down"), this);
1378  _aRemoveCurve = new QAction(tr("Remove this curve"), this);
1379  _menu = new QMenu(tr("Curve"), this);
1380  _menu->addAction(_aChangeText);
1381  _menu->addAction(_aResetText);
1382  _menu->addAction(_aChangeColor);
1383  _menu->addAction(_aCopyToClipboard);
1384  _menu->addAction(_aShowStdDevMeanMax);
1385  _menu->addSeparator();
1386  _menu->addAction(_aMoveUp);
1387  _menu->addAction(_aMoveDown);
1388  _menu->addSeparator();
1389  _menu->addAction(_aRemoveCurve);
1390 }
1391 
1393 {
1394 
1395 }
1396 void UPlotLegendItem::contextMenuEvent(QContextMenuEvent * event)
1397 {
1398  QAction * action = _menu->exec(event->globalPos());
1399  if(action == _aChangeText)
1400  {
1401  bool ok;
1402  QString text = QInputDialog::getText(this, _aChangeText->text(), tr("Name :"), QLineEdit::Normal, this->text(), &ok);
1403  if(ok && !text.isEmpty())
1404  {
1405  this->setText(text);
1406  }
1407  }
1408  else if(action == _aResetText)
1409  {
1410  if(_curve)
1411  {
1412  this->setText(_curve->name());
1413  }
1414  }
1415  else if(action == _aChangeColor)
1416  {
1417  if(_curve)
1418  {
1419  QPen pen = _curve->pen();
1420  QColor color = QColorDialog::getColor(pen.color(), this);
1421  if(color.isValid())
1422  {
1423  pen.setColor(color);
1424  _curve->setPen(pen);
1425  this->setIcon(QIcon(this->createSymbol(_curve->pen(), _curve->brush())));
1426  }
1427  }
1428  }
1429  else if (action == _aCopyToClipboard)
1430  {
1431  if(_curve)
1432  {
1433  QVector<qreal> x;
1434  QVector<qreal> y;
1435  _curve->getData(x, y);
1436  QString text;
1437  text.append("x");
1438  text.append('\t');
1439  text.append(_curve->name());
1440  text.append('\n');
1441  for(int i=0; i<x.size(); ++i)
1442  {
1443  text.append(QString::number(x[i]));
1444  text.append('\t');
1445  text.append(QString::number(y[i]));
1446  if(i+1<x.size())
1447  {
1448  text.append('\n');
1449  }
1450  }
1451  QClipboard * clipboard = QApplication::clipboard();
1452  clipboard->setText(text);
1453  }
1454  }
1455  else if(action == _aShowStdDevMeanMax)
1456  {
1457  showStdDevMeanMax(_aShowStdDevMeanMax->isChecked());
1458  }
1459  else if(action == _aRemoveCurve)
1460  {
1461  Q_EMIT legendItemRemoved(_curve);
1462  }
1463  else if(action == _aMoveUp)
1464  {
1465  Q_EMIT moveUpRequest(this);
1466  }
1467  else if(action == _aMoveDown)
1468  {
1469  Q_EMIT moveDownRequest(this);
1470  }
1471 }
1472 
1474 {
1475  _aShowStdDevMeanMax->setChecked(shown);
1476  if(shown)
1477  {
1478  connect(_curve, SIGNAL(dataChanged(const UPlotCurve *)), this, SLOT(updateStdDevMeanMax()));
1480  }
1481  else
1482  {
1483  disconnect(_curve, SIGNAL(dataChanged(const UPlotCurve *)), this, SLOT(updateStdDevMeanMax()));
1484  QString nameSpaced = _curve->name();
1485  nameSpaced.replace('_', ' ');
1486  this->setText(nameSpaced);
1487  }
1488 }
1489 
1490 QPixmap UPlotLegendItem::createSymbol(const QPen & pen, const QBrush & brush)
1491 {
1492  QPixmap pixmap(50, 50);
1493  pixmap.fill(Qt::transparent);
1494  QPainter painter(&pixmap);
1495  QPen p = pen;
1496  p.setWidthF(4.0);
1497  painter.setPen(p);
1498  painter.drawLine(0.0, 25.0, 50.0, 25.0);
1499  return pixmap;
1500 }
1501 
1503 {
1504  QVector<qreal> x, y;
1505  _curve->getData(x, y);
1506  qreal mean = uMean(y.data(), y.size());
1507  qreal stdDev = std::sqrt(uVariance(y.data(), y.size(), mean));
1508  qreal max = uMax(y.data(), y.size());
1509  QString nameSpaced = _curve->name();
1510  nameSpaced.replace('_', ' ');
1511  nameSpaced += QString("\n(%1=%2, %3=%4, max=%5, n=%6)").arg(QChar(0xbc, 0x03)).arg(QString::number(mean, 'f', 3)).arg(QChar(0xc3, 0x03)).arg(QString::number(stdDev, 'f', 3)).arg(QString::number(max, 'f', 3)).arg(y.size());
1512  this->setText(nameSpaced);
1513 }
1514 
1515 
1516 
1517 
1518 
1519 
1520 UPlotLegend::UPlotLegend(QWidget * parent) :
1521  QWidget(parent),
1522  _flat(true)
1523 {
1524  //menu
1525  _aUseFlatButtons = new QAction(tr("Use flat buttons"), this);
1526  _aUseFlatButtons->setCheckable(true);
1527  _aUseFlatButtons->setChecked(_flat);
1528  _aCopyAllCurvesToClipboard = new QAction(tr("Copy all curve data to clipboard"), this);
1529  _aShowAllStdDevMeanMax = new QAction(tr("Show all %1, %2, max").arg(QChar(0xbc, 0x03)).arg(QChar(0xc3, 0x03)), this);
1530  _aShowAllStdDevMeanMax->setCheckable(true);
1531  _aShowAllStdDevMeanMax->setChecked(false);
1532  _menu = new QMenu(tr("Legend"), this);
1533  _menu->addAction(_aUseFlatButtons);
1534  _menu->addAction(_aShowAllStdDevMeanMax);
1535  _menu->addAction(_aCopyAllCurvesToClipboard);
1536 
1537  _scrollArea = new QScrollArea(this);
1538  _scrollArea->setWidgetResizable( true );
1539  _scrollArea->setFrameShape(QFrame::NoFrame);
1540 
1541  this->setLayout(new QVBoxLayout());
1542  this->layout()->setContentsMargins(0,0,0,0);
1543  this->layout()->addWidget(_scrollArea);
1544 
1545  QWidget * _scrollAreaWidgetContent = new QWidget();
1546  _scrollArea->setWidget( _scrollAreaWidgetContent );
1547 
1548  _contentLayout = new QVBoxLayout();
1549  _scrollAreaWidgetContent->setLayout(_contentLayout);
1550  _contentLayout->setContentsMargins(0,0,0,0);
1551  ((QVBoxLayout*)_contentLayout)->addStretch(0);
1552  _contentLayout->setSpacing(0);
1553 }
1554 
1556 {
1557 #if PRINT_DEBUG
1558  ULOGGER_DEBUG("");
1559 #endif
1560 }
1561 
1563 {
1564  if(_flat != on)
1565  {
1566  _flat = on;
1567  QList<UPlotLegendItem*> items = this->findChildren<UPlotLegendItem*>();
1568  for(int i=0; i<items.size(); ++i)
1569  {
1570  items.at(i)->setFlat(_flat);
1571  items.at(i)->setChecked(!items.at(i)->isChecked());
1572  }
1573  _aUseFlatButtons->setChecked(_flat);
1574  }
1575 }
1576 
1578 {
1579  if(curve)
1580  {
1581  UPlotLegendItem * legendItem = new UPlotLegendItem(curve, this);
1582  legendItem->setAutoDefault(false);
1583  legendItem->setFlat(_flat);
1584  legendItem->setCheckable(true);
1585  legendItem->setChecked(false);
1586  connect(legendItem, SIGNAL(toggled(bool)), this, SLOT(redirectToggled(bool)));
1587  connect(legendItem, SIGNAL(legendItemRemoved(const UPlotCurve *)), this, SLOT(removeLegendItem(const UPlotCurve *)));
1588  connect(legendItem, SIGNAL(moveUpRequest(UPlotLegendItem *)), this, SLOT(moveUp(UPlotLegendItem *)));
1589  connect(legendItem, SIGNAL(moveDownRequest(UPlotLegendItem *)), this, SLOT(moveDown(UPlotLegendItem *)));
1590 
1591  // layout
1592  QHBoxLayout * hLayout = new QHBoxLayout();
1593  hLayout->addWidget(legendItem);
1594  hLayout->addStretch(0);
1595  hLayout->setMargin(0);
1596 
1597  // add to the legend
1598  ((QVBoxLayout*)_contentLayout)->insertLayout(_contentLayout->count()-1, hLayout);
1599 
1600  _scrollArea->setMinimumWidth(std::min(480, _scrollArea->widget()->sizeHint().width()+QApplication::style()->pixelMetric(QStyle::PM_ScrollBarExtent)));
1601  }
1602 }
1603 
1604 bool UPlotLegend::remove(const UPlotCurve * curve)
1605 {
1606  QList<UPlotLegendItem *> items = this->findChildren<UPlotLegendItem*>();
1607  for(int i=0; i<items.size(); ++i)
1608  {
1609  if(items.at(i)->curve() == curve)
1610  {
1611  delete items.at(i);
1612  _scrollArea->setMinimumWidth(std::min(480, _scrollArea->widget()->sizeHint().width()+QApplication::style()->pixelMetric(QStyle::PM_ScrollBarExtent)));
1613  return true;
1614  }
1615  }
1616  return false;
1617 }
1618 
1620 {
1621  if(this->remove(curve))
1622  {
1623  Q_EMIT legendItemRemoved(curve);
1624  }
1625 }
1626 
1628 {
1629  int index = -1;
1630  QLayoutItem * layoutItem = 0;
1631  for(int i=0; i<_contentLayout->count(); ++i)
1632  {
1633  if(_contentLayout->itemAt(i)->layout() &&
1634  _contentLayout->itemAt(i)->layout()->indexOf(item) != -1)
1635  {
1636  layoutItem = _contentLayout->itemAt(i);
1637  index = i;
1638  break;
1639  }
1640  }
1641  if(index > 0 && layoutItem)
1642  {
1643  _contentLayout->removeItem(layoutItem);
1644  QHBoxLayout * hLayout = new QHBoxLayout();
1645  hLayout->addWidget(layoutItem->layout()->itemAt(0)->widget());
1646  hLayout->addStretch(0);
1647  hLayout->setMargin(0);
1648  ((QVBoxLayout*)_contentLayout)->insertLayout(index-1, hLayout);
1649  delete layoutItem;
1650  Q_EMIT legendItemMoved(item->curve(), index-1);
1651  }
1652 }
1653 
1655 {
1656  int index = -1;
1657  QLayoutItem * layoutItem = 0;
1658  for(int i=0; i<_contentLayout->count(); ++i)
1659  {
1660  if(_contentLayout->itemAt(i)->layout() &&
1661  _contentLayout->itemAt(i)->layout()->indexOf(item) != -1)
1662  {
1663  layoutItem = _contentLayout->itemAt(i);
1664  index = i;
1665  break;
1666  }
1667  }
1668  if(index < _contentLayout->count()-2 && layoutItem)
1669  {
1670  _contentLayout->removeItem(layoutItem);
1671  QHBoxLayout * hLayout = new QHBoxLayout();
1672  hLayout->addWidget(layoutItem->layout()->itemAt(0)->widget());
1673  hLayout->addStretch(0);
1674  hLayout->setMargin(0);
1675  ((QVBoxLayout*)_contentLayout)->insertLayout(index+1, hLayout);
1676  delete layoutItem;
1677  Q_EMIT legendItemMoved(item->curve(), index+1);
1678  }
1679 }
1680 
1682 {
1683  QList<UPlotLegendItem *> items = this->findChildren<UPlotLegendItem*>();
1684  if(items.size())
1685  {
1686  // create common x-axis
1687  QMap<qreal, qreal> xAxisMap;
1688  for(int i=0; i<items.size(); ++i)
1689  {
1690  QMap<qreal, qreal> data;
1691  items.at(i)->curve()->getData(data);
1692  for(QMap<qreal, qreal>::iterator iter=data.begin(); iter!=data.end(); ++iter)
1693  {
1694  xAxisMap.insert(iter.key(), iter.value());
1695  }
1696  }
1697  QList<qreal> xAxis = xAxisMap.uniqueKeys();
1698 
1699  QVector<QVector<qreal> > axes;
1700  for(int i=0; i<items.size(); ++i)
1701  {
1702  QMap<qreal, qreal> data;
1703  items.at(i)->curve()->getData(data);
1704 
1705  QVector<qreal> y(xAxis.size(), std::numeric_limits<qreal>::quiet_NaN());
1706  // just to make sure that we have the same number of data on each curve, set NAN for unknowns
1707  int j=0;
1708  for(QList<qreal>::iterator iter=xAxis.begin(); iter!=xAxis.end(); ++iter)
1709  {
1710  if(data.contains(*iter))
1711  {
1712  y[j] = data.value(*iter);
1713  }
1714  ++j;
1715  }
1716  axes.push_back(y);
1717  }
1718  if(!xAxis.empty())
1719  {
1720  axes.push_front(xAxis.toVector());
1721  QString text;
1722  text.append('x');
1723  text.append('\t');
1724  for(int i=0; i<items.size(); ++i)
1725  {
1726  text.append(items.at(i)->curve()->name());
1727  if(i+1<axes.size())
1728  {
1729  text.append('\t');
1730  }
1731  }
1732  text.append('\n');
1733  for(int i=0; i<axes[0].size(); ++i)
1734  {
1735  for(int j=0; j<axes.size(); ++j)
1736  {
1737  if(uIsNan(axes[j][i]))
1738  {
1739  text.append("NaN"); // NaN is interpreted by default as NaN in MatLab/Octave
1740  }
1741  else
1742  {
1743  text.append(QString::number(axes[j][i], 'f'));
1744  }
1745  if(j+1<axes.size())
1746  {
1747  text.append('\t');
1748  }
1749  }
1750  if(i+1<axes[0].size())
1751  {
1752  text.append("\n");
1753  }
1754  }
1755  return text;
1756  }
1757  }
1758  return "";
1759 }
1760 
1761 void UPlotLegend::contextMenuEvent(QContextMenuEvent * event)
1762 {
1763  QAction * action = _menu->exec(event->globalPos());
1764  if(action == _aUseFlatButtons)
1765  {
1766  this->setFlat(_aUseFlatButtons->isChecked());
1767  }
1768  else if(action == _aCopyAllCurvesToClipboard)
1769  {
1770  QString data = getAllCurveDataAsText();
1771  if(!data.isEmpty())
1772  {
1773  QClipboard * clipboard = QApplication::clipboard();
1774  clipboard->setText(data);
1775  }
1776  }
1777  else if(action == _aShowAllStdDevMeanMax)
1778  {
1779  QList<UPlotLegendItem *> items = this->findChildren<UPlotLegendItem*>();
1780  for(int i=0; i<items.size(); ++i)
1781  {
1782  items.at(i)->showStdDevMeanMax(_aShowAllStdDevMeanMax->isChecked());
1783  }
1784  }
1785 }
1786 
1788 {
1789  if(sender())
1790  {
1791  UPlotLegendItem * item = qobject_cast<UPlotLegendItem*>(sender());
1792  if(item)
1793  {
1794  Q_EMIT legendItemToggled(item->curve(), _flat?!toggled:toggled);
1795  }
1796  }
1797 }
1798 
1799 
1800 
1801 
1802 
1803 
1804 
1805 UOrientableLabel::UOrientableLabel(const QString & text, Qt::Orientation orientation, QWidget * parent) :
1806  QLabel(text, parent),
1807  _orientation(orientation)
1808 {
1809 }
1810 
1812 {
1813 }
1814 
1816 {
1817  QSize size = QLabel::sizeHint();
1818  if (_orientation == Qt::Vertical)
1819  size.transpose();
1820  return size;
1821 
1822 }
1823 
1825 {
1826  QSize size = QLabel::minimumSizeHint();
1827  if (_orientation == Qt::Vertical)
1828  size.transpose();
1829  return size;
1830 }
1831 
1833 {
1835  switch(orientation)
1836  {
1837  case Qt::Horizontal:
1838  setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
1839  break;
1840 
1841  case Qt::Vertical:
1842  setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum);
1843  break;
1844  }
1845 }
1846 
1847 void UOrientableLabel::paintEvent(QPaintEvent* event)
1848 {
1849  QPainter p(this);
1850  QRect r = rect();
1851  switch (_orientation)
1852  {
1853  case Qt::Horizontal:
1854  break;
1855  case Qt::Vertical:
1856  p.rotate(-90);
1857  p.translate(-height(), 0);
1858  QSize size = r.size();
1859  size.transpose();
1860  r.setSize(size);
1861  break;
1862  }
1863  p.drawText(r, this->alignment() | (this->wordWrap()?Qt::TextWordWrap:0), this->text());
1864 }
1865 
1866 
1867 
1868 
1869 
1870 
1871 
1872 
1873 
1874 
1875 
1876 
1877 
1878 UPlot::UPlot(QWidget *parent) :
1879  QWidget(parent),
1880  _legend(0),
1881  _view(0),
1882  _sceneRoot(0),
1883  _graphicsViewHolder(0),
1884  _verticalAxis(0),
1885  _horizontalAxis(0),
1886  _penStyleCount(0),
1887  _maxVisibleItems(-1),
1888  _title(0),
1889  _xLabel(0),
1890  _yLabel(0),
1891  _refreshRate(0),
1892  _workingDirectory(QDir::homePath()),
1893  _lowestRefreshRate(99),
1894  _autoScreenCaptureFormat("png"),
1895  _bgColor(Qt::white),
1896  _menu(0),
1897  _aShowLegend(0),
1898  _aShowGrid(0),
1899  _aKeepAllData(0),
1900  _aLimit0(0),
1901  _aLimit10(0),
1902  _aLimit50(0),
1903  _aLimit100(0),
1904  _aLimit500(0),
1905  _aLimit1000(0),
1906  _aLimitCustom(0),
1907  _aAddVerticalLine(0),
1908  _aAddHorizontalLine(0),
1909  _aChangeTitle(0),
1910  _aChangeXLabel(0),
1911  _aChangeYLabel(0),
1912  _aChangeBackgroundColor(0),
1913  _aYLabelVertical(0),
1914  _aShowRefreshRate(0),
1915  _aMouseTracking(0),
1916  _aSaveFigure(0),
1917  _aAutoScreenCapture(0),
1918  _aClearData(0),
1919  _aGraphicsView(0)
1920 {
1921  this->setupUi();
1922  this->createActions();
1923  this->createMenus();
1924 
1925  // This will update actions
1926  this->showLegend(true);
1927  this->setGraphicsView(false);
1928  this->setMaxVisibleItems(0);
1929  this->showGrid(false);
1930  this->showRefreshRate(false);
1931  this->keepAllData(true);
1932 
1933  for(int i=0; i<4; ++i)
1934  {
1935  _axisMaximums[i] = 0;
1936  _axisMaximumsSet[i] = false;
1937  if(i<2)
1938  {
1939  _fixedAxis[i] = false;
1940  }
1941  }
1942 
1943  _mouseCurrentPos = _mousePressedPos; // for zooming
1944 
1945  _refreshIntervalTime.start();
1946  _refreshStartTime.start();
1947 }
1948 
1950 {
1951  _aAutoScreenCapture->setChecked(false);
1952 #if PRINT_DEBUG
1953  ULOGGER_DEBUG("%s", this->title().toStdString().c_str());
1954 #endif
1955  this->removeCurves();
1956 }
1957 
1959 {
1960  _legend = new UPlotLegend(this);
1961  _view = new QGraphicsView(this);
1962  _view->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
1963  _view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
1964  _view->setScene(new QGraphicsScene(0,0,0,0,this));
1965  _view->setStyleSheet( "QGraphicsView { border-style: none; }" );
1966  _sceneRoot = _view->scene()->addText("");
1967  _sceneRoot->setTransform(QTransform::fromTranslate(0, 0), true);
1968  _graphicsViewHolder = new QWidget(this);
1969  _graphicsViewHolder->setMinimumSize(100,100);
1970  _graphicsViewHolder->setMouseTracking(true);
1971  _verticalAxis = new UPlotAxis(Qt::Vertical, 0, 1, this);
1972  _horizontalAxis = new UPlotAxis(Qt::Horizontal, 0, 1, this);
1973  _title = new QLabel("");
1974  _xLabel = new QLabel("");
1975  _refreshRate = new QLabel("");
1976  _yLabel = new UOrientableLabel("");
1977  _yLabel->setOrientation(Qt::Vertical);
1978  _title->setAlignment(Qt::AlignCenter);
1979  _xLabel->setAlignment(Qt::AlignCenter);
1980  _yLabel->setAlignment(Qt::AlignCenter);
1981  _refreshRate->setAlignment(Qt::AlignCenter);
1982  _title->setWordWrap(true);
1983  _xLabel->setWordWrap(true);
1984  _yLabel->setWordWrap(true);
1985  _title->setVisible(false);
1986  _xLabel->setVisible(false);
1987  _yLabel->setVisible(false);
1988  _refreshRate->setVisible(false);
1989 
1990  //layouts
1991  QVBoxLayout * vLayout = new QVBoxLayout(_graphicsViewHolder);
1992  vLayout->setContentsMargins(0,0,0,0);
1993  vLayout->addWidget(_view);
1994 
1995  QGridLayout * grid = new QGridLayout(this);
1996  grid->setContentsMargins(0,0,0,0);
1997  grid->addWidget(_title, 0, 2);
1998  grid->addWidget(_yLabel, 1, 0);
1999  grid->addWidget(_verticalAxis, 1, 1);
2000  grid->addWidget(_refreshRate, 2, 1);
2001  grid->addWidget(_graphicsViewHolder, 1, 2);
2002  grid->setColumnStretch(2, 1);
2003  grid->setRowStretch(1, 1);
2004  grid->addWidget(_horizontalAxis, 2, 2);
2005  grid->addWidget(_xLabel, 3, 2);
2006  grid->addWidget(_legend, 1, 3);
2007 
2008  connect(_legend, SIGNAL(legendItemToggled(const UPlotCurve *, bool)), this, SLOT(showCurve(const UPlotCurve *, bool)));
2009  connect(_legend, SIGNAL(legendItemRemoved(const UPlotCurve *)), this, SLOT(removeCurve(const UPlotCurve *)));
2010  connect(_legend, SIGNAL(legendItemMoved(const UPlotCurve *, int)), this, SLOT(moveCurve(const UPlotCurve *, int)));
2011 }
2012 
2014 {
2015  _aShowLegend = new QAction(tr("Show legend"), this);
2016  _aShowLegend->setCheckable(true);
2017  _aShowGrid = new QAction(tr("Show grid"), this);
2018  _aShowGrid->setCheckable(true);
2019  _aShowRefreshRate = new QAction(tr("Show refresh rate"), this);
2020  _aShowRefreshRate->setCheckable(true);
2021  _aMouseTracking = new QAction(tr("Mouse tracking"), this);
2022  _aMouseTracking->setCheckable(true);
2023  _aGraphicsView = new QAction(tr("Graphics view"), this);
2024  _aGraphicsView->setCheckable(true);
2025  _aKeepAllData = new QAction(tr("Keep all data"), this);
2026  _aKeepAllData->setCheckable(true);
2027  _aLimit0 = new QAction(tr("No maximum items shown"), this);
2028  _aLimit10 = new QAction(tr("10"), this);
2029  _aLimit50 = new QAction(tr("50"), this);
2030  _aLimit100 = new QAction(tr("100"), this);
2031  _aLimit500 = new QAction(tr("500"), this);
2032  _aLimit1000 = new QAction(tr("1000"), this);
2033  _aLimitCustom = new QAction(tr(""), this);
2034  _aLimit0->setCheckable(true);
2035  _aLimit10->setCheckable(true);
2036  _aLimit50->setCheckable(true);
2037  _aLimit100->setCheckable(true);
2038  _aLimit500->setCheckable(true);
2039  _aLimit1000->setCheckable(true);
2040  _aLimitCustom->setCheckable(true);
2041  _aLimitCustom->setVisible(false);
2042  _aAddVerticalLine = new QAction(tr("Vertical line..."), this);
2043  _aAddHorizontalLine = new QAction(tr("Horizontal line..."), this);
2044  _aChangeTitle = new QAction(tr("Change title"), this);
2045  _aChangeXLabel = new QAction(tr("Change X label..."), this);
2046  _aChangeYLabel = new QAction(tr("Change Y label..."), this);
2047  _aChangeBackgroundColor = new QAction(tr("Change bg color..."), this);
2048  _aYLabelVertical = new QAction(tr("Vertical orientation"), this);
2049  _aYLabelVertical->setCheckable(true);
2050  _aYLabelVertical->setChecked(true);
2051  _aSaveFigure = new QAction(tr("Save figure..."), this);
2052  _aAutoScreenCapture = new QAction(tr("Auto screen capture..."), this);
2053  _aAutoScreenCapture->setCheckable(true);
2054  _aClearData = new QAction(tr("Clear data"), this);
2055 
2056  QActionGroup * grpLimit = new QActionGroup(this);
2057  grpLimit->addAction(_aLimit0);
2058  grpLimit->addAction(_aLimit10);
2059  grpLimit->addAction(_aLimit50);
2060  grpLimit->addAction(_aLimit100);
2061  grpLimit->addAction(_aLimit500);
2062  grpLimit->addAction(_aLimit1000);
2063  grpLimit->addAction(_aLimitCustom);
2064  _aLimit0->setChecked(true);
2065 }
2066 
2068 {
2069  _menu = new QMenu(tr("Plot"), this);
2070  _menu->addAction(_aShowLegend);
2071  _menu->addAction(_aShowGrid);
2072  _menu->addAction(_aShowRefreshRate);
2073  _menu->addAction(_aMouseTracking);
2074  _menu->addAction(_aGraphicsView);
2075  _menu->addAction(_aKeepAllData);
2076  _menu->addSeparator()->setStatusTip(tr("Maximum items shown"));
2077  _menu->addAction(_aLimit0);
2078  _menu->addAction(_aLimit10);
2079  _menu->addAction(_aLimit50);
2080  _menu->addAction(_aLimit100);
2081  _menu->addAction(_aLimit500);
2082  _menu->addAction(_aLimit1000);
2083  _menu->addAction(_aLimitCustom);
2084  _menu->addSeparator();
2085  QMenu * addLineMenu = _menu->addMenu(tr("Add line"));
2086  addLineMenu->addAction(_aAddHorizontalLine);
2087  addLineMenu->addAction(_aAddVerticalLine);
2088  _menu->addSeparator();
2089  _menu->addAction(_aChangeTitle);
2090  _menu->addAction(_aChangeXLabel);
2091  QMenu * yLabelMenu = _menu->addMenu(tr("Y label"));
2092  yLabelMenu->addAction(_aChangeYLabel);
2093  yLabelMenu->addAction(_aYLabelVertical);
2094  _menu->addAction(_aChangeBackgroundColor);
2095  _menu->addAction(_aSaveFigure);
2096  _menu->addAction(_aAutoScreenCapture);
2097  _menu->addSeparator();
2098  _menu->addAction(_aClearData);
2099 
2100 }
2101 
2102 UPlotCurve * UPlot::addCurve(const QString & curveName, const QColor & color)
2103 {
2104  // add curve
2105  UPlotCurve * curve = new UPlotCurve(curveName, this);
2106  if(color.isValid())
2107  {
2108  curve->setPen(color);
2109  }
2110  else
2111  {
2112  curve->setPen(this->getRandomPenColored());
2113  }
2114  this->addCurve(curve);
2115  return curve;
2116 }
2117 
2118 bool UPlot::addCurve(UPlotCurve * curve, bool ownershipTransferred)
2119 {
2120  if(curve)
2121  {
2122 #if PRINT_DEBUG
2123  ULOGGER_DEBUG("Adding curve \"%s\" to plot \"%s\"...", curve->name().toStdString().c_str(), this->title().toStdString().c_str());
2124 #endif
2125  // only last curve can trigger an update, so disable previous connections
2126  if(!qobject_cast<UPlotCurveThreshold*>(curve))
2127  {
2128  for(int i=_curves.size()-1; i>=0; --i)
2129  {
2130  if(!qobject_cast<UPlotCurveThreshold*>(_curves.at(i)))
2131  {
2132  disconnect(_curves.at(i), SIGNAL(dataChanged(const UPlotCurve *)), this, SLOT(updateAxis()));
2133  break;
2134  }
2135  }
2136  }
2137 
2138  // add curve
2139  _curves.append(curve);
2140  curve->attach(this);
2141  curve->setItemsColor(QColor(255-_bgColor.red(), 255-_bgColor.green(), 255-_bgColor.red(), _bgColor.alpha()));
2142  if(ownershipTransferred)
2143  {
2144  curve->setParent(this);
2145  }
2146  this->updateAxis(curve);
2147  curve->setXStart(_axisMaximums[1]);
2148 
2149  connect(curve, SIGNAL(dataChanged(const UPlotCurve *)), this, SLOT(updateAxis()));
2150 
2151  _legend->addItem(curve);
2152 
2153 #if PRINT_DEBUG
2154  ULOGGER_DEBUG("Curve \"%s\" added to plot \"%s\"", curve->name().toStdString().c_str(), this->title().toStdString().c_str());
2155 #endif
2156 
2157  return true;
2158  }
2159  else
2160  {
2161  ULOGGER_ERROR("The curve is null!");
2162  }
2163  return false;
2164 }
2165 
2166 QStringList UPlot::curveNames()
2167 {
2168  QStringList names;
2169  for(QList<UPlotCurve*>::iterator iter = _curves.begin(); iter!=_curves.end(); ++iter)
2170  {
2171  if(*iter)
2172  {
2173  names.append((*iter)->name());
2174  }
2175  }
2176  return names;
2177 }
2178 
2179 bool UPlot::contains(const QString & curveName)
2180 {
2181  for(QList<UPlotCurve*>::iterator iter = _curves.begin(); iter!=_curves.end(); ++iter)
2182  {
2183  if(*iter && (*iter)->name().compare(curveName) == 0)
2184  {
2185  return true;
2186  }
2187  }
2188  return false;
2189 }
2190 
2192 {
2193  int penStyle = 0;
2194  bool colorNotUsed = false;
2195  for(int i=0; i<12; ++i)
2196  {
2197  QColor tmp((Qt::GlobalColor)((penStyle+i) % 12 + 7 ));
2198  bool colorAlreadyUsed = false;
2199  for(QList<UPlotCurve*>::const_iterator iter = _curves.constBegin(); iter!=_curves.constEnd() && !colorAlreadyUsed; ++iter)
2200  {
2201  colorAlreadyUsed = (*iter)->pen().color() == tmp;
2202  }
2203  if(!colorAlreadyUsed)
2204  {
2205  colorNotUsed = true;
2206  penStyle+=i;
2207  break;
2208  }
2209  }
2210  if(colorNotUsed)
2211  {
2212  _penStyleCount = penStyle;
2213  }
2214 
2215  return QPen((Qt::GlobalColor)(_penStyleCount++ % 12 + 7 ));
2216 }
2217 
2218 void UPlot::replot(QPainter * painter)
2219 {
2220  if(_maxVisibleItems>0)
2221  {
2222  UPlotCurve * c = 0;
2223  int maxItem = 0;
2224  // find the curve with the most items
2225  for(QList<UPlotCurve *>::iterator i=_curves.begin(); i!=_curves.end(); ++i)
2226  {
2227  if((*i)->isVisible() && ((UPlotCurve *)(*i))->itemsSize() > maxItem)
2228  {
2229  c = *i;
2230  maxItem = c->itemsSize();
2231  }
2232  }
2233  if(c && (maxItem-1)/2+1 > _maxVisibleItems && _axisMaximums[0] < c->getItemData((c->itemsSize()-1) -_maxVisibleItems*2).x())
2234  {
2235  _axisMaximums[0] = c->getItemData((c->itemsSize()-1) -_maxVisibleItems*2).x();
2236  }
2237  }
2238 
2239  qreal axis[4] = {0};
2240  for(int i=0; i<4; ++i)
2241  {
2242  axis[i] = _axisMaximums[i];
2243  }
2244 
2245  _verticalAxis->setAxis(axis[2], axis[3]);
2246  _horizontalAxis->setAxis(axis[0], axis[1]);
2247  if(_aGraphicsView->isChecked() && !painter)
2248  {
2249  _verticalAxis->update();
2250  _horizontalAxis->update();
2251  }
2252 
2253  //ULOGGER_DEBUG("x1=%f, x2=%f, y1=%f, y2=%f", _axisMaximums[0], _axisMaximums[1], _axisMaximums[2], _axisMaximums[3]);
2254 
2255  QRectF newRect(0,0, _graphicsViewHolder->size().width(), _graphicsViewHolder->size().height());
2256  _view->scene()->setSceneRect(newRect);
2257  qreal borderHor = (qreal)_horizontalAxis->border();
2258  qreal borderVer = (qreal)_verticalAxis->border();
2259 
2260  //grid
2261  qDeleteAll(hGridLines);
2262  hGridLines.clear();
2263  qDeleteAll(vGridLines);
2264  vGridLines.clear();
2265  if(_aShowGrid->isChecked())
2266  {
2267  // TODO make a PlotGrid class ?
2268  qreal w = newRect.width()-(borderHor*2);
2269  qreal h = newRect.height()-(borderVer*2);
2270  qreal stepH = w / qreal(_horizontalAxis->count());
2271  qreal stepV = h / qreal(_verticalAxis->count());
2272  QPen dashPen(Qt::DashLine);
2273  dashPen.setColor(QColor(255-_bgColor.red(), 255-_bgColor.green(), 255-_bgColor.blue(), 100));
2274  QPen pen(dashPen.color());
2275  for(qreal i=0.0f; i*stepV <= h+stepV; i+=5.0f)
2276  {
2277  //horizontal lines
2278  if(!_aGraphicsView->isChecked())
2279  {
2280  if(painter)
2281  {
2282  painter->save();
2283  painter->setPen(pen);
2284  painter->drawLine(0, stepV*i+borderVer+0.5f, borderHor, stepV*i+borderVer+0.5f);
2285 
2286  painter->setPen(dashPen);
2287  painter->drawLine(borderHor, stepV*i+borderVer+0.5f, w+borderHor, stepV*i+borderVer+0.5f);
2288 
2289  painter->setPen(pen);
2290  painter->drawLine(w+borderHor, stepV*i+borderVer+0.5f, w+borderHor*2, stepV*i+borderVer+0.5f);
2291  painter->restore();
2292  }
2293  }
2294  else
2295  {
2296  hGridLines.append(new QGraphicsLineItem(0, stepV*i+borderVer, borderHor, stepV*i+borderVer, _sceneRoot));
2297  hGridLines.last()->setPen(pen);
2298  hGridLines.append(new QGraphicsLineItem(borderHor, stepV*i+borderVer, w+borderHor, stepV*i+borderVer, _sceneRoot));
2299  hGridLines.last()->setPen(dashPen);
2300  hGridLines.append(new QGraphicsLineItem(w+borderHor, stepV*i+borderVer, w+borderHor*2, stepV*i+borderVer, _sceneRoot));
2301  hGridLines.last()->setPen(pen);
2302  }
2303  }
2304  for(qreal i=0; i*stepH < w+stepH; i+=5.0f)
2305  {
2306  //vertical lines
2307  if(!_aGraphicsView->isChecked())
2308  {
2309  if(painter)
2310  {
2311  painter->save();
2312  painter->setPen(pen);
2313  painter->drawLine(stepH*i+borderHor+0.5f, 0, stepH*i+borderHor+0.5f, borderVer);
2314 
2315  painter->setPen(dashPen);
2316  painter->drawLine(stepH*i+borderHor+0.5f, borderVer, stepH*i+borderHor+0.5f, h+borderVer);
2317 
2318  painter->setPen(pen);
2319  painter->drawLine(stepH*i+borderHor+0.5f, h+borderVer, stepH*i+borderHor+0.5f, h+borderVer*2);
2320  painter->restore();
2321  }
2322  }
2323  else
2324  {
2325  vGridLines.append(new QGraphicsLineItem(stepH*i+borderHor, 0, stepH*i+borderHor, borderVer, _sceneRoot));
2326  vGridLines.last()->setPen(pen);
2327  vGridLines.append(new QGraphicsLineItem(stepH*i+borderHor, borderVer, stepH*i+borderHor, h+borderVer, _sceneRoot));
2328  vGridLines.last()->setPen(dashPen);
2329  vGridLines.append(new QGraphicsLineItem(stepH*i+borderHor, h+borderVer, stepH*i+borderHor, h+borderVer*2, _sceneRoot));
2330  vGridLines.last()->setPen(pen);
2331  }
2332  }
2333  }
2334 
2335  // curves
2336  qreal scaleX = 1;
2337  qreal scaleY = 1;
2338  qreal den = 0;
2339  den = axis[1] - axis[0];
2340  if(den != 0)
2341  {
2342  scaleX = (newRect.width()-(borderHor*2)) / den;
2343  }
2344  den = axis[3] - axis[2];
2345  if(den != 0)
2346  {
2347  scaleY = (newRect.height()-(borderVer*2)) / den;
2348  }
2349  for(QList<UPlotCurve *>::iterator i=_curves.begin(); i!=_curves.end(); ++i)
2350  {
2351  if((*i)->isVisible())
2352  {
2353  qreal xDir = 1.0f;
2354  qreal yDir = -1.0f;
2355  (*i)->update(scaleX,
2356  scaleY,
2357  xDir<0?axis[1]+borderHor/scaleX:-(axis[0]-borderHor/scaleX),
2358  yDir<0?axis[3]+borderVer/scaleY:-(axis[2]-borderVer/scaleY),
2359  xDir,
2360  yDir,
2361  _aKeepAllData->isChecked()?0:_maxVisibleItems);
2362  if(painter)
2363  {
2364  (*i)->draw(painter, QRect(0,0,_graphicsViewHolder->rect().width(), _graphicsViewHolder->rect().height()));
2365  }
2366  }
2367  }
2368 
2369  // Update refresh rate
2370  if(_aShowRefreshRate->isChecked())
2371  {
2372  int refreshRate = qRound(1000.0f/qreal(_refreshIntervalTime.restart()));
2373  if(refreshRate > 0 && refreshRate < _lowestRefreshRate)
2374  {
2375  _lowestRefreshRate = refreshRate;
2376  }
2377  // Refresh the label only after each 1000 ms
2378  if(_refreshStartTime.elapsed() > 1000)
2379  {
2380  _refreshRate->setText(QString::number(_lowestRefreshRate));
2381  _lowestRefreshRate = 99;
2382  _refreshStartTime.start();
2383  }
2384  }
2385 }
2386 
2387 void UPlot::setFixedXAxis(qreal x1, qreal x2)
2388 {
2389  _fixedAxis[0] = true;
2390  _axisMaximums[0] = x1;
2391  _axisMaximums[1] = x2;
2392 }
2393 
2394 void UPlot::setFixedYAxis(qreal y1, qreal y2)
2395 {
2396  _fixedAxis[1] = true;
2397  _axisMaximums[2] = y1;
2398  _axisMaximums[3] = y2;
2399 }
2400 
2401 void UPlot::updateAxis(const UPlotCurve * curve)
2402 {
2403  if(curve && curve->isVisible() && curve->itemsSize() && curve->isMinMaxValid())
2404  {
2405  const QVector<qreal> & minMax = curve->getMinMax();
2406  //ULOGGER_DEBUG("x1=%f, x2=%f, y1=%f, y2=%f", minMax[0], minMax[1], minMax[2], minMax[3]);
2407  if(minMax.size() != 4)
2408  {
2409  ULOGGER_ERROR("minMax size != 4 ?!?");
2410  return;
2411  }
2412  this->updateAxis(minMax[0], minMax[1], minMax[2], minMax[3]);
2413  _aGraphicsView->isChecked()?this->replot(0):this->update();
2414  }
2415 }
2416 
2417 bool UPlot::updateAxis(qreal x1, qreal x2, qreal y1, qreal y2)
2418 {
2419  bool modified = false;
2420  modified = updateAxis(x1,y1);
2421  if(!modified)
2422  {
2423  modified = updateAxis(x2,y2);
2424  }
2425  else
2426  {
2427  updateAxis(x2,y2);
2428  }
2429  return modified;
2430 }
2431 
2432 bool UPlot::updateAxis(qreal x, qreal y)
2433 {
2434  //ULOGGER_DEBUG("x=%f, y=%f", x,y);
2435  bool modified = false;
2436  if(!_fixedAxis[0] && (!_axisMaximumsSet[0] || x < _axisMaximums[0]))
2437  {
2438  _axisMaximums[0] = x;
2439  _axisMaximumsSet[0] = true;
2440  modified = true;
2441  }
2442 
2443  if(!_fixedAxis[0] && (!_axisMaximumsSet[1] || x > _axisMaximums[1]))
2444  {
2445  _axisMaximums[1] = x;
2446  _axisMaximumsSet[1] = true;
2447  modified = true;
2448  }
2449 
2450  if(!_fixedAxis[1] && (!_axisMaximumsSet[2] || y < _axisMaximums[2]))
2451  {
2452  _axisMaximums[2] = y;
2453  _axisMaximumsSet[2] = true;
2454  modified = true;
2455  }
2456 
2457  if(!_fixedAxis[1] && (!_axisMaximumsSet[3] || y > _axisMaximums[3]))
2458  {
2459  _axisMaximums[3] = y;
2460  _axisMaximumsSet[3] = true;
2461  modified = true;
2462  }
2463 
2464  return modified;
2465 }
2466 
2468 {
2469  //Reset the axis
2470  for(int i=0; i<4; ++i)
2471  {
2472  if((!_fixedAxis[0] && i<2) || (!_fixedAxis[1] && i>=2))
2473  {
2474  _axisMaximums[i] = 0;
2475  _axisMaximumsSet[i] = false;
2476  }
2477  }
2478 
2479  for(int i=0; i<_curves.size(); ++i)
2480  {
2481  if(_curves.at(i)->isVisible() && _curves.at(i)->isMinMaxValid())
2482  {
2483  const QVector<qreal> & minMax = _curves.at(i)->getMinMax();
2484  this->updateAxis(minMax[0], minMax[1], minMax[2], minMax[3]);
2485  }
2486  }
2487 
2488  _aGraphicsView->isChecked()?this->replot(0):this->update();
2489 
2490  this->captureScreen();
2491 }
2492 
2493 void UPlot::paintEvent(QPaintEvent * event)
2494 {
2495 #if PRINT_DEBUG
2496  UDEBUG("");
2497 #endif
2498  if(!_aGraphicsView->isChecked())
2499  {
2500  QPainter painter(this);
2501  painter.translate(_graphicsViewHolder->pos());
2502  painter.save();
2503  painter.setBrush(_bgColor);
2504  painter.setPen(QPen(Qt::NoPen));
2505  painter.drawRect(_graphicsViewHolder->rect());
2506  painter.restore();
2507 
2508  this->replot(&painter);
2509 
2511  {
2512  painter.save();
2513  int left, top, right, bottom;
2518  if(left <= 0)
2519  {
2520  left = 1;
2521  }
2522  if(right >= _graphicsViewHolder->width())
2523  {
2524  right = _graphicsViewHolder->width()-1;
2525  }
2526  if(top <= 0)
2527  {
2528  top = 1;
2529  }
2530  if(bottom >= _graphicsViewHolder->height())
2531  {
2532  bottom = _graphicsViewHolder->height()-1;
2533  }
2534  painter.setPen(Qt::NoPen);
2535  painter.setBrush(QBrush(QColor(255-_bgColor.red(),255-_bgColor.green(),255-_bgColor.blue(),100)));
2536  painter.drawRect(0, 0, _graphicsViewHolder->width(), top);
2537  painter.drawRect(0, top, left, bottom-top);
2538  painter.drawRect(right, top, _graphicsViewHolder->width()-right, bottom-top);
2539  painter.drawRect(0, bottom, _graphicsViewHolder->width(), _graphicsViewHolder->height()-bottom);
2540  painter.restore();
2541  }
2542  }
2543  else
2544  {
2545  QWidget::paintEvent(event);
2546  }
2547 }
2548 
2549 void UPlot::resizeEvent(QResizeEvent * event)
2550 {
2551  if(_aGraphicsView->isChecked())
2552  {
2553  this->replot(0);
2554  }
2555  QWidget::resizeEvent(event);
2556 }
2557 
2558 void UPlot::mousePressEvent(QMouseEvent * event)
2559 {
2560  _mousePressedPos = event->pos();
2562  QWidget::mousePressEvent(event);
2563 }
2564 
2565 void UPlot::mouseMoveEvent(QMouseEvent * event)
2566 {
2567  if(!_aGraphicsView->isChecked())
2568  {
2569  if(!(QApplication::mouseButtons() & Qt::LeftButton))
2570  {
2572  }
2573 
2574  qreal x,y;
2575  if(mousePosToValue(event->pos(), x ,y))
2576  {
2577  if(QApplication::mouseButtons() & Qt::LeftButton)
2578  {
2579  _mouseCurrentPos = event->pos();
2580  this->update();
2581  }
2582 
2583  int xPos = event->pos().x() - _graphicsViewHolder->pos().x();
2584  int yPos = event->pos().y() - _graphicsViewHolder->pos().y();
2585  if((QApplication::mouseButtons() & Qt::LeftButton) ||
2586  (_aMouseTracking->isChecked() && xPos>=0 && yPos>=0 && xPos<_graphicsViewHolder->width() && yPos<_graphicsViewHolder->height()))
2587  {
2588  QToolTip::showText(event->globalPos(), QString("%1,%2").arg(x).arg(y));
2589  }
2590  else
2591  {
2592  QToolTip::hideText();
2593  }
2594  }
2595  else
2596  {
2597  QToolTip::hideText();
2598  }
2599  }
2600  QWidget::mouseMoveEvent(event);
2601 }
2602 
2603 void UPlot::mouseReleaseEvent(QMouseEvent * event)
2604 {
2606  {
2607  int left,top,bottom,right;
2608 
2613 
2614  if(right - left > 5 || bottom - top > 5)
2615  {
2616  qreal axis[4];
2617  if(mousePosToValue(QPoint(left, top), axis[0], axis[3]) && mousePosToValue(QPoint(right, bottom), axis[1], axis[2]))
2618  {
2619 #if PRINT_DEBUG
2620  UDEBUG("resize! new axis = [%f, %f, %f, %f]", axis[0], axis[1], axis[2], axis[3]);
2621 #endif
2622  //update axis (only if not fixed)
2623  for(int i=0; i<4; ++i)
2624  {
2625  if((!_fixedAxis[0] && i<2) || (!_fixedAxis[1] && i>=2))
2626  {
2627  _axisMaximums[i] = axis[i];
2628  }
2629  }
2630  _aGraphicsView->isChecked()?this->replot(0):this->update();
2631  }
2632  }
2634  }
2635  QWidget::mouseReleaseEvent(event);
2636 }
2637 
2638 void UPlot::mouseDoubleClickEvent(QMouseEvent * event)
2639 {
2640  this->updateAxis();
2641  QWidget::mouseDoubleClickEvent(event);
2642 }
2643 
2644 bool UPlot::mousePosToValue(const QPoint & pos, qreal & x, qreal & y)
2645 {
2646  int xPos = pos.x() - _graphicsViewHolder->pos().x() - _horizontalAxis->border();
2647  int yPos = pos.y() - _graphicsViewHolder->pos().y() - _verticalAxis->border();
2648  int maxX = _graphicsViewHolder->width() - _horizontalAxis->border()*2;
2649  int maxY = _graphicsViewHolder->height() - _verticalAxis->border()*2;
2650  if(maxX == 0 || maxY == 0)
2651  {
2652  return false;
2653  }
2654 
2655  if(xPos < 0)
2656  {
2657  xPos = 0;
2658  }
2659  else if(xPos > maxX)
2660  {
2661  xPos = maxX;
2662  }
2663 
2664  if(yPos < 0)
2665  {
2666  yPos = 0;
2667  }
2668  else if(yPos > maxY)
2669  {
2670  yPos = maxY;
2671  }
2672 
2673  //UDEBUG("IN");
2674  //UDEBUG("x1=%f, x2=%f, y1=%f, y2=%f", _axisMaximums[0], _axisMaximums[1], _axisMaximums[2], _axisMaximums[3]);
2675  //UDEBUG("border hor=%f ver=%f", (qreal)_horizontalAxis->border(), (qreal)_verticalAxis->border());
2676  //UDEBUG("rect = %d,%d %d,%d", _graphicsViewHolder->pos().x(), _graphicsViewHolder->pos().y(), _graphicsViewHolder->width(), _graphicsViewHolder->height());
2677  //UDEBUG("%d,%d", event->pos().x(), event->pos().y());
2678  //UDEBUG("x/y %d,%d", x, y);
2679  //UDEBUG("max %d,%d", maxX, maxY);
2680 
2681  //UDEBUG("map %f,%f", x, y);
2682  x = _axisMaximums[0] + qreal(xPos)*(_axisMaximums[1] - _axisMaximums[0]) / qreal(maxX);
2683  y = _axisMaximums[2] + qreal(maxY - yPos)*(_axisMaximums[3] - _axisMaximums[2]) / qreal(maxY);
2684  return true;
2685 }
2686 
2687 void UPlot::contextMenuEvent(QContextMenuEvent * event)
2688 {
2689  QAction * action = _menu->exec(event->globalPos());
2690 
2691  if(!action)
2692  {
2693  return;
2694  }
2695  else if(action == _aShowLegend)
2696  {
2697  this->showLegend(_aShowLegend->isChecked());
2698  }
2699  else if(action == _aShowGrid)
2700  {
2701  this->showGrid(_aShowGrid->isChecked());
2702  }
2703  else if(action == _aShowRefreshRate)
2704  {
2705  this->showRefreshRate(_aShowRefreshRate->isChecked());
2706  }
2707  else if(action == _aMouseTracking)
2708  {
2709  this->trackMouse(_aMouseTracking->isChecked());
2710  }
2711  else if(action == _aGraphicsView)
2712  {
2713  this->setGraphicsView(_aGraphicsView->isChecked());
2714  }
2715  else if(action == _aKeepAllData)
2716  {
2717  this->keepAllData(_aKeepAllData->isChecked());
2718  }
2719  else if(action == _aLimit0 ||
2720  action == _aLimit10 ||
2721  action == _aLimit50 ||
2722  action == _aLimit100 ||
2723  action == _aLimit500 ||
2724  action == _aLimit1000 ||
2725  action == _aLimitCustom)
2726  {
2727  this->setMaxVisibleItems(action->text().toInt());
2728  }
2729  else if(action == _aAddVerticalLine || action == _aAddHorizontalLine)
2730  {
2731  bool ok;
2732  QString text = QInputDialog::getText(this, action->text(), tr("New line name :"), QLineEdit::Normal, "", &ok);
2733  while(ok && text.isEmpty())
2734  {
2735  QMessageBox::warning(this, action->text(), tr("The name is not valid or it is already used in this plot."));
2736  text = QInputDialog::getText(this, action->text(), tr("New line name :"), QLineEdit::Normal, "", &ok);
2737  }
2738  if(ok)
2739  {
2740  double min = _axisMaximums[2];
2741  double max = _axisMaximums[3];
2742  QString axis = "Y";
2743  if(action == _aAddVerticalLine)
2744  {
2745  min = _axisMaximums[0];
2746  max = _axisMaximums[1];
2747  axis = "X";
2748  }
2749  double value = QInputDialog::getDouble(this,
2750  action->text(),
2751  tr("%1 value (min=%2, max=%3):").arg(axis).arg(min).arg(max),
2752  (min+max)/2,
2753  -2147483647,
2754  2147483647,
2755  4,
2756  &ok);
2757  if(ok)
2758  {
2759  if(action == _aAddHorizontalLine)
2760  {
2761  this->addThreshold(text, value, Qt::Horizontal);
2762  }
2763  else
2764  {
2765  this->addThreshold(text, value, Qt::Vertical);
2766  }
2767  }
2768  }
2769  }
2770  else if(action == _aChangeTitle)
2771  {
2772  bool ok;
2773  QString text = _title->text();
2774  if(text.isEmpty())
2775  {
2776  text = this->objectName();
2777  }
2778  text = QInputDialog::getText(this, _aChangeTitle->text(), tr("Title :"), QLineEdit::Normal, text, &ok);
2779  if(ok)
2780  {
2781  this->setTitle(text);
2782  }
2783  }
2784  else if(action == _aChangeXLabel)
2785  {
2786  bool ok;
2787  QString text = QInputDialog::getText(this, _aChangeXLabel->text(), tr("X axis label :"), QLineEdit::Normal, _xLabel->text(), &ok);
2788  if(ok)
2789  {
2790  this->setXLabel(text);
2791  }
2792  }
2793  else if(action == _aChangeYLabel)
2794  {
2795  bool ok;
2796  QString text = QInputDialog::getText(this, _aChangeYLabel->text(), tr("Y axis label :"), QLineEdit::Normal, _yLabel->text(), &ok);
2797  if(ok)
2798  {
2799  this->setYLabel(text, _yLabel->orientation());
2800  }
2801  }
2802  else if(action == _aYLabelVertical)
2803  {
2804  this->setYLabel(_yLabel->text(), _aYLabelVertical->isChecked()?Qt::Vertical:Qt::Horizontal);
2805  }
2806  else if(action == _aChangeBackgroundColor)
2807  {
2808  QColor color = QColorDialog::getColor(_bgColor, this);
2809  if(color.isValid())
2810  {
2811  this->setBackgroundColor(color);
2812  }
2813  }
2814  else if(action == _aSaveFigure)
2815  {
2816 
2817  QString text;
2818 #ifdef QT_SVG_LIB
2819  text = QFileDialog::getSaveFileName(this, tr("Save figure to ..."), (QDir::homePath() + "/") + this->title() + ".png", "*.png *.xpm *.jpg *.pdf *.svg");
2820 #else
2821  text = QFileDialog::getSaveFileName(this, tr("Save figure to ..."), (QDir::homePath() + "/") + this->title() + ".png", "*.png *.xpm *.jpg *.pdf");
2822 #endif
2823  if(!text.isEmpty())
2824  {
2825  bool flatModified = false;
2826  if(!_legend->isFlat())
2827  {
2828  _legend->setFlat(true);
2829  flatModified = true;
2830  }
2831 
2832  QPalette p(palette());
2833  // Set background color to white
2834  QColor c = p.color(QPalette::Background);
2835  p.setColor(QPalette::Background, Qt::white);
2836  setPalette(p);
2837 
2838 #ifdef QT_SVG_LIB
2839  if(QFileInfo(text).suffix().compare("svg") == 0)
2840  {
2841  QSvgGenerator generator;
2842  generator.setFileName(text);
2843  generator.setSize(this->size());
2844  QPainter painter;
2845  painter.begin(&generator);
2846  this->render(&painter);
2847  painter.end();
2848  }
2849  else
2850  {
2851 #endif
2852  if(QFileInfo(text).suffix().compare("pdf") == 0)
2853  {
2854  QPrinter printer;
2855  printer.setOutputFormat(QPrinter::PdfFormat);
2856  printer.setOutputFileName(text);
2857  this->render(&printer);
2858  }
2859  else
2860  {
2861  QPixmap figure = QPixmap::grabWidget(this);
2862  figure.save(text);
2863  }
2864 #ifdef QT_SVG_LIB
2865  }
2866 #endif
2867  // revert background color
2868  p.setColor(QPalette::Background, c);
2869  setPalette(p);
2870 
2871  if(flatModified)
2872  {
2873  _legend->setFlat(false);
2874  }
2875  }
2876  }
2877  else if(action == _aAutoScreenCapture)
2878  {
2879  if(_aAutoScreenCapture->isChecked())
2880  {
2881  this->selectScreenCaptureFormat();
2882  }
2883  }
2884  else if(action == _aClearData)
2885  {
2886  this->clearData();
2887  }
2888  else
2889  {
2890  ULOGGER_WARN("Unknown action");
2891  }
2892 }
2893 
2894 void UPlot::setWorkingDirectory(const QString & workingDirectory)
2895 {
2896  if(QDir(_workingDirectory).exists())
2897  {
2898  _workingDirectory = workingDirectory;
2899  }
2900  else
2901  {
2902  ULOGGER_ERROR("The directory \"%s\" doesn't exist", workingDirectory.toStdString().c_str());
2903  }
2904 }
2905 
2907 {
2908  if(!_aAutoScreenCapture->isChecked())
2909  {
2910  return;
2911  }
2912  QString targetDir = _workingDirectory + "/ScreensCaptured";
2913  QDir dir;
2914  if(!dir.exists(targetDir))
2915  {
2916  dir.mkdir(targetDir);
2917  }
2918  targetDir += "/";
2919  targetDir += this->title().replace(" ", "_");
2920  if(!dir.exists(targetDir))
2921  {
2922  dir.mkdir(targetDir);
2923  }
2924  targetDir += "/";
2925  QString name = (QDateTime::currentDateTime().toString("yyMMddhhmmsszzz") + ".") + _autoScreenCaptureFormat;
2926  QPixmap figure = QPixmap::grabWidget(this);
2927  figure.save(targetDir + name);
2928 }
2929 
2931 {
2932  QStringList items;
2933  items << QString("png") << QString("jpg");
2934  bool ok;
2935  QString item = QInputDialog::getItem(this, tr("Select format"), tr("Format:"), items, 0, false, &ok);
2936  if(ok && !item.isEmpty())
2937  {
2938  _autoScreenCaptureFormat = item;
2939  }
2940  this->captureScreen();
2941 }
2942 
2944 {
2945  for(int i=0; i<_curves.size(); ++i)
2946  {
2947  // Don't clear threshold curves
2948  if(qobject_cast<UPlotCurveThreshold*>(_curves.at(i)) == 0)
2949  {
2950  _curves.at(i)->clear();
2951  }
2952  }
2953  _aGraphicsView->isChecked()?this->replot(0):this->update();
2954 }
2955 
2956 void UPlot::frameData(bool xAxis, bool yAxis)
2957 {
2958  if(!xAxis && !yAxis)
2959  {
2960  return;
2961  }
2962  qreal minX = std::numeric_limits<qreal>::max();
2963  qreal minY = std::numeric_limits<qreal>::max();
2964  for(int i=0; i<_curves.size(); ++i)
2965  {
2966  if(qobject_cast<UPlotCurveThreshold*>(_curves.at(i)) == 0)
2967  {
2968  const QVector<qreal> & minMax = _curves.at(i)->getMinMax();
2969  if(minMax.size() == 4)
2970  {
2971  if(minMax[0] < minX)
2972  {
2973  minX = minMax[0];
2974  }
2975  if(minMax[2] < minY)
2976  {
2977  minY = minMax[2];
2978  }
2979  }
2980  }
2981  }
2982  if(minX != std::numeric_limits<qreal>::max())
2983  {
2984  for(int i=0; i<_curves.size(); ++i)
2985  {
2986  if(qobject_cast<UPlotCurveThreshold*>(_curves.at(i)) == 0)
2987  {
2988  QVector<qreal> x;
2989  QVector<qreal> y;
2990  _curves.at(i)->getData(x,y);
2991  for(int j=0; j<x.size(); ++j)
2992  {
2993  if(xAxis)
2994  {
2995  x[j]-=minX;
2996  }
2997  if(yAxis)
2998  {
2999  y[j]-=minY;
3000  }
3001  }
3002  _curves.at(i)->setData(x,y);
3003  }
3004  }
3005  }
3006  _aGraphicsView->isChecked()?this->replot(0):this->update();
3007 }
3008 
3009 // for convenience...
3010 UPlotCurveThreshold * UPlot::addThreshold(const QString & name, qreal value, Qt::Orientation orientation)
3011 {
3012  UPlotCurveThreshold * curve = new UPlotCurveThreshold(name, value, orientation, this);
3013  QPen pen = curve->pen();
3014  pen.setStyle((Qt::PenStyle)(_penStyleCount++ % 4 + 2));
3015  curve->setPen(pen);
3016  if(!this->addCurve(curve))
3017  {
3018  if(curve)
3019  {
3020  delete curve;
3021  }
3022  }
3023  else
3024  {
3025  _aGraphicsView->isChecked()?this->replot(0):this->update();
3026  }
3027  return curve;
3028 }
3029 
3030 void UPlot::setTitle(const QString & text)
3031 {
3032  _title->setText(text);
3033  _title->setVisible(!text.isEmpty());
3034  this->update();
3035  if(_aGraphicsView->isChecked())
3036  {
3037  QTimer::singleShot(10, this, SLOT(updateAxis()));
3038  }
3039 }
3040 
3041 void UPlot::setXLabel(const QString & text)
3042 {
3043  _xLabel->setText(text);
3044  _xLabel->setVisible(!text.isEmpty());
3045  this->update();
3046  if(_aGraphicsView->isChecked())
3047  {
3048  QTimer::singleShot(10, this, SLOT(updateAxis()));
3049  }
3050 }
3051 
3052 void UPlot::setYLabel(const QString & text, Qt::Orientation orientation)
3053 {
3054  _yLabel->setText(text);
3055  _yLabel->setOrientation(orientation);
3056  _yLabel->setVisible(!text.isEmpty());
3057  _aYLabelVertical->setChecked(orientation==Qt::Vertical);
3058  this->update();
3059  if(_aGraphicsView->isChecked())
3060  {
3061  QTimer::singleShot(10, this, SLOT(updateAxis()));
3062  }
3063 }
3064 
3065 void UPlot::setBackgroundColor(const QColor & color)
3066 {
3067  if(color.isValid())
3068  {
3069  _bgColor = color;
3070  _view->scene()->setBackgroundBrush(QBrush(_bgColor));
3071  for(QList<UPlotCurve*>::iterator iter=_curves.begin(); iter!=_curves.end(); ++iter)
3072  {
3073  (*iter)->setItemsColor(QColor(255-_bgColor.red(), 255-_bgColor.green(), 255-_bgColor.blue(), _bgColor.alpha()));
3074  }
3075  }
3076 }
3077 
3078 void UPlot::addItem(QGraphicsItem * item)
3079 {
3080  item->setParentItem(_sceneRoot);
3081  item->setZValue(1.0f);
3082 }
3083 
3084 void UPlot::showLegend(bool shown)
3085 {
3086  _legend->setVisible(shown);
3087  _aShowLegend->setChecked(shown);
3088  this->update();
3089  if(_aGraphicsView->isChecked())
3090  {
3091  QTimer::singleShot(10, this, SLOT(updateAxis()));
3092  }
3093 }
3094 
3095 void UPlot::showGrid(bool shown)
3096 {
3097  _aShowGrid->setChecked(shown);
3098  _aGraphicsView->isChecked()?this->replot(0):this->update();
3099 }
3100 
3101 void UPlot::showRefreshRate(bool shown)
3102 {
3103  _aShowRefreshRate->setChecked(shown);
3104  _refreshRate->setVisible(shown);
3105  this->update();
3106  if(_aGraphicsView->isChecked())
3107  {
3108  QTimer::singleShot(10, this, SLOT(updateAxis()));
3109  }
3110 }
3111 
3112 void UPlot::trackMouse(bool tracking)
3113 {
3114  _aMouseTracking->setChecked(tracking);
3115  this->setMouseTracking(tracking);
3116 }
3117 
3119 {
3120  _aGraphicsView->setChecked(on);
3121  _view->setVisible(on);
3122  _aGraphicsView->isChecked()?this->replot(0):this->update();
3123  _aMouseTracking->setEnabled(!on);
3124 }
3125 
3126 void UPlot::keepAllData(bool kept)
3127 {
3128  _aKeepAllData->setChecked(kept);
3129 }
3130 
3131 void UPlot::setMaxVisibleItems(int maxVisibleItems)
3132 {
3133  if(maxVisibleItems <= 0)
3134  {
3135  _aLimit0->setChecked(true);
3136  }
3137  else if(maxVisibleItems == 10)
3138  {
3139  _aLimit10->setChecked(true);
3140  }
3141  else if(maxVisibleItems == 50)
3142  {
3143  _aLimit50->setChecked(true);
3144  }
3145  else if(maxVisibleItems == 100)
3146  {
3147  _aLimit100->setChecked(true);
3148  }
3149  else if(maxVisibleItems == 500)
3150  {
3151  _aLimit500->setChecked(true);
3152  }
3153  else if(maxVisibleItems == 1000)
3154  {
3155  _aLimit1000->setChecked(true);
3156  }
3157  else
3158  {
3159  _aLimitCustom->setVisible(true);
3160  _aLimitCustom->setChecked(true);
3161  _aLimitCustom->setText(QString::number(maxVisibleItems));
3162  }
3163  _maxVisibleItems = maxVisibleItems;
3164  updateAxis();
3165 }
3166 
3167 QRectF UPlot::sceneRect() const
3168 {
3169  return _view->sceneRect();
3170 }
3171 
3173 {
3174  QList<UPlotCurve*> tmp = _curves;
3175  for(QList<UPlotCurve*>::iterator iter=tmp.begin(); iter!=tmp.end(); ++iter)
3176  {
3177  this->removeCurve(*iter);
3178  }
3179  _curves.clear();
3180 }
3181 
3182 void UPlot::removeCurve(const UPlotCurve * curve)
3183 {
3184  QList<UPlotCurve *>::iterator iter = qFind(_curves.begin(), _curves.end(), curve);
3185 #if PRINT_DEBUG
3186  ULOGGER_DEBUG("Plot=\"%s\" removing curve=\"%s\"", this->objectName().toStdString().c_str(), curve?curve->name().toStdString().c_str():"");
3187 #endif
3188  if(iter!=_curves.end())
3189  {
3190  UPlotCurve * c = *iter;
3191  c->detach(this);
3192  _curves.erase(iter);
3193  _legend->remove(c);
3194  if(!qobject_cast<UPlotCurveThreshold*>(c))
3195  {
3196  // transfer update connection to next curve
3197  for(int i=_curves.size()-1; i>=0; --i)
3198  {
3199  if(!qobject_cast<UPlotCurveThreshold*>(_curves.at(i)))
3200  {
3201  connect(_curves.at(i), SIGNAL(dataChanged(const UPlotCurve *)), this, SLOT(updateAxis()));
3202  break;
3203  }
3204  }
3205  }
3206 
3207  if(c->parent() == this)
3208  {
3209  delete c;
3210  }
3211  // Update axis
3212  updateAxis();
3213  }
3214 }
3215 
3216 void UPlot::showCurve(const UPlotCurve * curve, bool shown)
3217 {
3218  QList<UPlotCurve *>::iterator iter = qFind(_curves.begin(), _curves.end(), curve);
3219  if(iter!=_curves.end())
3220  {
3221  UPlotCurve * value = *iter;
3222  if(value->isVisible() != shown)
3223  {
3224  value->setVisible(shown);
3225  this->updateAxis();
3226  }
3227  }
3228 }
3229 
3230 void UPlot::moveCurve(const UPlotCurve * curve, int index)
3231 {
3232  // this will change the print order
3233  int currentIndex = -1;
3234  UPlotCurve * c = 0;
3235  for(int i=0; i<_curves.size(); ++i)
3236  {
3237  if(_curves.at(i) == curve)
3238  {
3239  c = _curves.at(i);
3240  currentIndex = i;
3241  break;
3242  }
3243  }
3244 
3245  if(c && currentIndex != index)
3246  {
3247  _curves.removeAt(currentIndex);
3248  QList<QGraphicsItem *> children = _sceneRoot->childItems();
3249  _curves.insert(index, c);
3250  if(currentIndex > index)
3251  {
3252  children[currentIndex]->stackBefore(children[index]);
3253  }
3254  else
3255  {
3256  if(currentIndex<children.size()-2)
3257  {
3258  if(index < children.size()-1)
3259  {
3260  children[index]->stackBefore(children[currentIndex]);
3261  }
3262  else
3263  {
3264  children[currentIndex]->stackBefore(children[index]);
3265  }
3266  }
3267  if(currentIndex == children.size()-2 && currentIndex < index)
3268  {
3269  children[index]->stackBefore(children[currentIndex]);
3270  }
3271  }
3272  this->update();
3273  }
3274 }
3275 
3277 {
3278  if(_legend)
3279  {
3280  return _legend->getAllCurveDataAsText();
3281  }
3282  return "";
3283 }
QString _autoScreenCaptureFormat
Definition: UPlot.h:608
void setXStart(qreal val)
Definition: UPlot.cpp:873
virtual ~UPlotCurve()
Definition: UPlot.cpp:297
QPointF getItemData(int index)
Definition: UPlot.cpp:844
QString getAllCurveDataAsText() const
Definition: UPlot.cpp:3276
T uVariance(const T *v, unsigned int size, T meanV)
Definition: UMath.h:491
QGraphicsTextItem * _text
Definition: UPlot.h:83
virtual void contextMenuEvent(QContextMenuEvent *event)
Definition: UPlot.cpp:1396
UPlot * _plot
Definition: UPlot.h:240
void detach(UPlot *plot)
Definition: UPlot.cpp:324
void setOrientation(Qt::Orientation orientation)
Definition: UPlot.cpp:1087
void redirectToggled(bool)
Definition: UPlot.cpp:1787
QAction * _aChangeYLabel
Definition: UPlot.h:628
UPlotCurveThreshold * addThreshold(const QString &name, qreal value, Qt::Orientation orientation=Qt::Horizontal)
Definition: UPlot.cpp:3010
QGraphicsItem * _sceneRoot
Definition: UPlot.h:588
UPlotAxis * _verticalAxis
Definition: UPlot.h:593
virtual void update(qreal scaleX, qreal scaleY, qreal offsetX, qreal offsetY, qreal xDir, qreal yDir, int maxItemsKept)
Definition: UPlot.cpp:690
QList< UPlotCurve * > _curves
Definition: UPlot.h:599
T uMean(const T *v, unsigned int size)
Definition: UMath.h:401
QRectF sceneRect() const
Definition: UPlot.cpp:3167
virtual ~UPlotCurveThreshold()
Definition: UPlot.cpp:1053
void showGrid(bool shown)
Definition: UPlot.cpp:3095
QPen _pen
Definition: UPlot.h:247
GLM_FUNC_DECL genType min(genType const &x, genType const &y)
void setFixedXAxis(qreal x1, qreal x2)
Definition: UPlot.cpp:2387
virtual ~UPlotLegend()
Definition: UPlot.cpp:1555
virtual void contextMenuEvent(QContextMenuEvent *event)
Definition: UPlot.cpp:2687
UPlotCurveThreshold(const QString &name, qreal thesholdValue, Qt::Orientation orientation=Qt::Horizontal, QObject *parent=0)
Definition: UPlot.cpp:1037
QAction * _aKeepAllData
Definition: UPlot.h:616
f
QAction * _aLimit500
Definition: UPlot.h:621
x
const QBrush & brush() const
Definition: UPlot.h:118
QLabel * _refreshRate
Definition: UPlot.h:603
int removeItem(int index)
Definition: UPlot.cpp:576
void moveDownRequest(UPlotLegendItem *)
bool _flat
Definition: UPlot.h:420
virtual void hoverEnterEvent(QGraphicsSceneHoverEvent *event)
Definition: UPlot.cpp:193
GLM_FUNC_DECL vecType< T, P > sqrt(vecType< T, P > const &x)
QColor _bgColor
Definition: UPlot.h:611
void setBrush(const QBrush &brush)
Definition: UPlot.cpp:670
QAction * _aLimit100
Definition: UPlot.h:620
QAction * _aGraphicsView
Definition: UPlot.h:636
QGraphicsRectItem * _textBackground
Definition: UPlot.h:84
qreal _axisMaximums[4]
Definition: UPlot.h:590
QLabel * _xLabel
Definition: UPlot.h:601
GLM_FUNC_DECL detail::tvec3< T, P > axis(detail::tquat< T, P > const &x)
int itemsSize() const
Definition: UPlot.cpp:839
void updateStdDevMeanMax()
Definition: UPlot.cpp:1502
qreal _xIncrement
Definition: UPlot.h:249
void updateMinMax()
Definition: UPlot.cpp:339
QAction * _aAddVerticalLine
Definition: UPlot.h:624
data
int border() const
Definition: UPlot.h:313
UPlotItem * _nextItem
Definition: UPlot.h:82
bool _fixedAxis[2]
Definition: UPlot.h:592
qreal _max
Definition: UPlot.h:333
virtual void mouseReleaseEvent(QMouseEvent *event)
Definition: UPlot.cpp:2603
UPlotItem * _previousItem
Definition: UPlot.h:81
QAction * _aClearData
Definition: UPlot.h:635
const UPlotCurve * curve() const
Definition: UPlot.h:355
QAction * _aShowStdDevMeanMax
Definition: UPlot.h:377
virtual ~UOrientableLabel()
Definition: UPlot.cpp:1811
virtual void contextMenuEvent(QContextMenuEvent *event)
Definition: UPlot.cpp:1761
virtual bool isMinMaxValid() const
Definition: UPlot.h:237
Basic mathematics functions.
bool isFlat() const
Definition: UPlot.h:398
void setThreshold(qreal threshold)
Definition: UPlot.cpp:1058
void showRefreshRate(bool shown)
Definition: UPlot.cpp:3101
QAction * _aMouseTracking
Definition: UPlot.h:632
UOrientableLabel * _yLabel
Definition: UPlot.h:602
void addValue(UPlotItem *data)
Definition: UPlot.cpp:422
QWidget * _graphicsViewHolder
Definition: UPlot.h:589
QStringList curveNames()
Definition: UPlot.cpp:2166
void moveCurve(const UPlotCurve *, int index)
Definition: UPlot.cpp:3230
Qt::Orientation _orientation
Definition: UPlot.h:331
static void countStep(sqlite3_context *context, int argc, sqlite3_value **argv)
Definition: sqlite3.c:91146
QTime _refreshIntervalTime
Definition: UPlot.h:605
QAction * _aChangeBackgroundColor
Definition: UPlot.h:629
virtual void mouseDoubleClickEvent(QMouseEvent *event)
Definition: UPlot.cpp:2638
UPlotCurve * _curve
Definition: UPlot.h:371
void createMenus()
Definition: UPlot.cpp:2067
QAction * _aShowGrid
Definition: UPlot.h:615
void setPen(const QPen &pen)
Definition: UPlot.cpp:661
void setupUi()
Definition: UPlot.cpp:1958
void setData(QVector< UPlotItem *> &data)
Definition: UPlot.cpp:878
Qt::Orientation orientation() const
Definition: UPlot.h:446
void removeCurves()
Definition: UPlot.cpp:3172
void init(qreal dataX, qreal dataY)
Definition: UPlot.cpp:76
void showStdDevMeanMax(bool shown)
Definition: UPlot.cpp:1473
QString _workingDirectory
Definition: UPlot.h:604
QAction * _aLimitCustom
Definition: UPlot.h:623
virtual void mousePressEvent(QMouseEvent *event)
Definition: UPlot.cpp:2558
Definition: UPlot.h:489
bool _visible
Definition: UPlot.h:251
QAction * _aCopyAllCurvesToClipboard
Definition: UPlot.h:423
void legendItemMoved(const UPlotCurve *curve, int)
void getData(QVector< qreal > &x, QVector< qreal > &y) const
Definition: UPlot.cpp:1004
QAction * _aLimit10
Definition: UPlot.h:618
QPen getRandomPenColored()
Definition: UPlot.cpp:2191
UPlotAxis * _horizontalAxis
Definition: UPlot.h:594
int _count
Definition: UPlot.h:334
QString getAllCurveDataAsText() const
Definition: UPlot.cpp:1681
virtual void showDescription(bool shown)
Definition: UPlot.cpp:130
UPlot(QWidget *parent=0)
Definition: UPlot.cpp:1878
bool remove(const UPlotCurve *curve)
Definition: UPlot.cpp:1604
void trackMouse(bool tracking)
Definition: UPlot.cpp:3112
void removeLegendItem(const UPlotCurve *curve)
Definition: UPlot.cpp:1619
virtual void paintEvent(QPaintEvent *event)
Definition: UPlot.cpp:1315
#define true
Definition: ConvertUTF.c:57
friend class UPlotCurve
Definition: UPlot.h:572
QAction * _aRemoveCurve
Definition: UPlot.h:378
QSize sizeHint() const
Definition: UPlot.cpp:1815
void setVisible(bool visible)
Definition: UPlot.cpp:859
qreal _xStart
Definition: UPlot.h:250
#define ULOGGER_DEBUG(...)
Definition: ULogger.h:53
Qt::Orientation _orientation
Definition: UPlot.h:456
QMenu * _menu
Definition: UPlot.h:372
QAction * _aChangeText
Definition: UPlot.h:373
void setOrientation(Qt::Orientation orientation)
Definition: UPlot.cpp:1832
UPlotCurve * addCurve(const QString &curveName, const QColor &color=QColor())
Definition: UPlot.cpp:2102
string name
const QVector< qreal > & getMinMax() const
Definition: UPlot.h:234
QString name() const
Definition: UPlot.h:135
QScrollArea * _scrollArea
Definition: UPlot.h:426
QAction * _aShowRefreshRate
Definition: UPlot.h:631
QAction * _aLimit1000
Definition: UPlot.h:622
void clearData()
Definition: UPlot.cpp:2943
void removeCurve(const UPlotCurve *curve)
Definition: UPlot.cpp:3182
UPlotItem(qreal dataX, qreal dataY, qreal width=2)
Definition: UPlot.cpp:56
bool _valuesShown
Definition: UPlot.h:252
void setGraphicsView(bool on)
Definition: UPlot.cpp:3118
void setFixedYAxis(qreal y1, qreal y2)
Definition: UPlot.cpp:2394
QAction * _aAddHorizontalLine
Definition: UPlot.h:625
void addItem(UPlotCurve *curve)
Definition: UPlot.cpp:1577
QPixmap createSymbol(const QPen &pen, const QBrush &brush)
Definition: UPlot.cpp:1490
const QPen & pen() const
Definition: UPlot.h:114
virtual void mouseMoveEvent(QMouseEvent *event)
Definition: UPlot.cpp:2565
QMenu * _menu
Definition: UPlot.h:421
QGraphicsView * _view
Definition: UPlot.h:587
void _addValue(UPlotItem *data)
Definition: UPlot.cpp:376
QPoint _mouseCurrentPos
Definition: UPlot.h:610
QColor _itemsColor
Definition: UPlot.h:255
bool mousePosToValue(const QPoint &pos, qreal &x, qreal &y)
Definition: UPlot.cpp:2644
QAction * _aChangeColor
Definition: UPlot.h:375
void attach(UPlot *plot)
Definition: UPlot.cpp:310
void legendItemRemoved(const UPlotCurve *)
int _maxVisibleItems
Definition: UPlot.h:596
virtual ~UPlotLegendItem()
Definition: UPlot.cpp:1392
QAction * _aShowAllStdDevMeanMax
Definition: UPlot.h:424
UPlotLegend(QWidget *parent=0)
Definition: UPlot.cpp:1520
QSize minimumSizeHint() const
Definition: UPlot.cpp:1824
virtual void keyReleaseEvent(QKeyEvent *keyEvent)
Definition: UPlot.cpp:220
int count() const
Definition: UPlot.h:321
QList< QGraphicsItem * > _items
Definition: UPlot.h:239
virtual void resizeEvent(QResizeEvent *event)
Definition: UPlot.cpp:2549
void moveDown(UPlotLegendItem *item)
Definition: UPlot.cpp:1654
void setAxis(qreal &min, qreal &max)
Definition: UPlot.cpp:1187
QMenu * _menu
Definition: UPlot.h:613
QAction * _aYLabelVertical
Definition: UPlot.h:630
virtual ~UPlotItem()
Definition: UPlot.cpp:84
virtual ~UPlot()
Definition: UPlot.cpp:1949
T uMax(const T *v, unsigned int size, unsigned int &index)
Definition: UMath.h:94
void setFlat(bool on)
Definition: UPlot.cpp:1562
#define false
Definition: ConvertUTF.c:56
QGraphicsRectItem * _rootItem
Definition: UPlot.h:254
virtual ~UPlotAxis()
Definition: UPlot.cpp:1168
bool contains(const QString &curveName)
Definition: UPlot.cpp:2179
void setItemsColor(const QColor &color)
Definition: UPlot.cpp:676
QPoint _mousePressedPos
Definition: UPlot.h:609
UOrientableLabel(const QString &text, Qt::Orientation orientation=Qt::Horizontal, QWidget *parent=0)
Definition: UPlot.cpp:1805
void keepAllData(bool kept)
Definition: UPlot.cpp:3126
void setXLabel(const QString &text)
Definition: UPlot.cpp:3041
QList< QGraphicsLineItem * > vGridLines
Definition: UPlot.h:598
QAction * _aCopyToClipboard
Definition: UPlot.h:376
int _step
Definition: UPlot.h:335
virtual void update(qreal scaleX, qreal scaleY, qreal offsetX, qreal offsetY, qreal xDir, qreal yDir, int maxItemsKept)
Definition: UPlot.cpp:1107
QAction * _aAutoScreenCapture
Definition: UPlot.h:634
qreal _min
Definition: UPlot.h:332
void updateAxis()
Definition: UPlot.cpp:2467
QAction * _aChangeXLabel
Definition: UPlot.h:627
#define UDEBUG(...)
GLM_FUNC_DECL genType max(genType const &x, genType const &y)
void selectScreenCaptureFormat()
Definition: UPlot.cpp:2930
int _penStyleCount
Definition: UPlot.h:595
void setTitle(const QString &text)
Definition: UPlot.cpp:3030
int _gradMaxDigits
Definition: UPlot.h:337
bool isVisible() const
Definition: UPlot.h:141
virtual void paintEvent(QPaintEvent *event)
Definition: UPlot.cpp:2493
UPlotLegend * _legend
Definition: UPlot.h:586
QAction * _aLimit0
Definition: UPlot.h:617
virtual void clear()
Definition: UPlot.cpp:652
QLabel * _title
Definition: UPlot.h:600
QAction * _aMoveUp
Definition: UPlot.h:379
void createActions()
Definition: UPlot.cpp:2013
QAction * _aSaveFigure
Definition: UPlot.h:633
virtual void focusOutEvent(QFocusEvent *event)
Definition: UPlot.cpp:214
#define ULOGGER_WARN(...)
Definition: ULogger.h:55
QString _name
Definition: UPlot.h:246
ULogger class and convenient macros.
void legendItemRemoved(const UPlotCurve *curve)
void moveUpRequest(UPlotLegendItem *)
#define UWARN(...)
UPlotItem * nextItem() const
Definition: UPlot.h:64
UPlotItem * previousItem() const
Definition: UPlot.h:65
void setData(const QPointF &data)
Definition: UPlot.cpp:101
void setMaxVisibleItems(int maxVisibleItems)
Definition: UPlot.cpp:3131
QAction * _aChangeTitle
Definition: UPlot.h:626
const QPointF & data() const
Definition: UPlot.h:66
QTime _refreshStartTime
Definition: UPlot.h:607
void setBackgroundColor(const QColor &color)
Definition: UPlot.cpp:3065
void draw(QPainter *painter, const QRect &limits)
Definition: UPlot.cpp:767
virtual void focusInEvent(QFocusEvent *event)
Definition: UPlot.cpp:208
bool uIsNan(const T &value)
Definition: UMath.h:42
bool _axisMaximumsSet[4]
Definition: UPlot.h:591
QBrush _brush
Definition: UPlot.h:248
QAction * _aMoveDown
Definition: UPlot.h:380
void addItem(QGraphicsItem *item)
Definition: UPlot.cpp:3078
QAction * _aUseFlatButtons
Definition: UPlot.h:422
virtual void hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
Definition: UPlot.cpp:199
void replot(QPainter *painter)
Definition: UPlot.cpp:2218
virtual void paintEvent(QPaintEvent *event)
Definition: UPlot.cpp:1847
int _border
Definition: UPlot.h:338
QVector< qreal > _minMax
Definition: UPlot.h:253
void showLegend(bool shown)
Definition: UPlot.cpp:3084
void dataChanged(const UPlotCurve *)
GLM_FUNC_DECL genType::value_type length(genType const &x)
bool _reversed
Definition: UPlot.h:336
UPlotCurve(const QString &name, QObject *parent=0)
Definition: UPlot.cpp:256
#define ULOGGER_ERROR(...)
Definition: ULogger.h:56
int _lowestRefreshRate
Definition: UPlot.h:606
QAction * _aShowLegend
Definition: UPlot.h:614
QAction * _aResetText
Definition: UPlot.h:374
void setYLabel(const QString &text, Qt::Orientation orientation=Qt::Vertical)
Definition: UPlot.cpp:3052
void showCurve(const UPlotCurve *curve, bool shown)
Definition: UPlot.cpp:3216
void setReversed(bool reversed)
Definition: UPlot.cpp:1176
QPointF _data
Definition: UPlot.h:80
UPlotLegendItem(UPlotCurve *curve, QWidget *parent=0)
Definition: UPlot.cpp:1359
void setNextItem(UPlotItem *nextItem)
Definition: UPlot.cpp:106
QList< QGraphicsLineItem * > hGridLines
Definition: UPlot.h:597
void addValues(QVector< UPlotItem *> &data)
Definition: UPlot.cpp:477
UPlotAxis(Qt::Orientation orientation=Qt::Horizontal, qreal min=0, qreal max=1, QWidget *parent=0)
Definition: UPlot.cpp:1145
Qt::Orientation _orientation
Definition: UPlot.h:289
QAction * _aLimit50
Definition: UPlot.h:619
void captureScreen()
Definition: UPlot.cpp:2906
QString title() const
Definition: UPlot.h:519
void setWorkingDirectory(const QString &workingDirectory)
Definition: UPlot.cpp:2894
GLM_FUNC_DECL detail::tmat4x4< T, P > orientation(detail::tvec3< T, P > const &Normal, detail::tvec3< T, P > const &Up)
QLayout * _contentLayout
Definition: UPlot.h:425
void legendItemToggled(const UPlotCurve *curve, bool toggled)
void setXIncrement(qreal increment)
Definition: UPlot.cpp:868
void setPreviousItem(UPlotItem *previousItem)
Definition: UPlot.cpp:118
void moveUp(UPlotLegendItem *item)
Definition: UPlot.cpp:1627
void frameData(bool xAxis=true, bool yAxis=false)
Definition: UPlot.cpp:2956


rtabmap
Author(s): Mathieu Labbe
autogenerated on Mon Jan 23 2023 03:38:58