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


rtabmap
Author(s): Mathieu Labbe
autogenerated on Wed Jun 5 2019 22:43:40