00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "rtabmap/utilite/UPlot.h"
00021 #include "rtabmap/utilite/ULogger.h"
00022 #include "rtabmap/utilite/UMath.h"
00023
00024 #include <QGraphicsScene>
00025 #include <QGraphicsView>
00026 #include <QGraphicsItem>
00027 #include <QGraphicsRectItem>
00028 #include <QHBoxLayout>
00029 #include <QFormLayout>
00030 #include <QtGui/QResizeEvent>
00031 #include <QtGui/QMouseEvent>
00032 #include <QtCore/QTime>
00033 #include <QtCore/QTimer>
00034 #include <QtCore/QFileInfo>
00035 #include <QPushButton>
00036 #include <QToolButton>
00037 #include <QLabel>
00038 #include <QMenu>
00039 #include <QInputDialog>
00040 #include <QMessageBox>
00041 #include <QFileDialog>
00042 #include <QtGui/QClipboard>
00043 #include <QApplication>
00044 #include <QPrinter>
00045 #include <QColorDialog>
00046 #include <QToolTip>
00047 #ifdef QT_SVG_LIB
00048 #include <QtSvg/QSvgGenerator>
00049 #endif
00050 #include <cmath>
00051
00052 #define PRINT_DEBUG 0
00053
00054 UPlotItem::UPlotItem(qreal dataX, qreal dataY, qreal width) :
00055 QGraphicsEllipseItem(0, 0, width, width, 0),
00056 _previousItem(0),
00057 _nextItem(0),
00058 _text(0),
00059 _textBackground(0)
00060 {
00061 this->init(dataX, dataY);
00062 }
00063
00064 UPlotItem::UPlotItem(const QPointF & data, qreal width) :
00065 QGraphicsEllipseItem(0, 0, width, width, 0),
00066 _previousItem(0),
00067 _nextItem(0),
00068 _text(0),
00069 _textBackground(0)
00070 {
00071 this->init(data.x(), data.y());
00072 }
00073
00074 void UPlotItem::init(qreal dataX, qreal dataY)
00075 {
00076 _data.setX(dataX);
00077 _data.setY(dataY);
00078 this->setAcceptHoverEvents(true);
00079 this->setFlag(QGraphicsItem::ItemIsFocusable, true);
00080 }
00081
00082 UPlotItem::~UPlotItem()
00083 {
00084 if(_previousItem && _nextItem)
00085 {
00086 _previousItem->setNextItem(_nextItem);
00087 _nextItem->setPreviousItem(_previousItem);
00088 }
00089 else if(_previousItem)
00090 {
00091 _previousItem->setNextItem(0);
00092 }
00093 else if(_nextItem)
00094 {
00095 _nextItem->setPreviousItem(0);
00096 }
00097 }
00098
00099 void UPlotItem::setData(const QPointF & data)
00100 {
00101 _data = data;
00102 }
00103
00104 void UPlotItem::setNextItem(UPlotItem * nextItem)
00105 {
00106 if(_nextItem != nextItem)
00107 {
00108 _nextItem = nextItem;
00109 if(nextItem)
00110 {
00111 nextItem->setPreviousItem(this);
00112 }
00113 }
00114 }
00115
00116 void UPlotItem::setPreviousItem(UPlotItem * previousItem)
00117 {
00118 if(_previousItem != previousItem)
00119 {
00120 _previousItem = previousItem;
00121 if(previousItem)
00122 {
00123 previousItem->setNextItem(this);
00124 }
00125 }
00126 }
00127
00128 void UPlotItem::showDescription(bool shown)
00129 {
00130 if(!_textBackground)
00131 {
00132 _textBackground = new QGraphicsRectItem(this);
00133 _textBackground->setBrush(QBrush(QColor(255, 255, 255, 200)));
00134 _textBackground->setPen(Qt::NoPen);
00135 _textBackground->setZValue(this->zValue()+1);
00136 _textBackground->setVisible(false);
00137
00138 _text = new QGraphicsTextItem(_textBackground);
00139 }
00140
00141 if(this->parentItem() && this->parentItem() != _textBackground->parentItem())
00142 {
00143 _textBackground->setParentItem(this->parentItem());
00144 _textBackground->setZValue(this->zValue()+1);
00145 }
00146
00147 if(this->scene() && shown)
00148 {
00149 _textBackground->setVisible(true);
00150 _text->setPlainText(QString("(%1,%2)").arg(_data.x()).arg(_data.y()));
00151
00152 this->setPen(QPen(this->pen().color(), 2));
00153
00154 QRectF rect = this->scene()->sceneRect();
00155 QPointF p = this->pos();
00156 QRectF br = _text->boundingRect();
00157 _textBackground->setRect(QRectF(0,0,br.width(), br.height()));
00158
00159
00160 if(p.x() - br.width() < 0)
00161 {
00162 p.setX(0);
00163 }
00164 else if(p.x() > rect.width())
00165 {
00166 p.setX(rect.width() - br.width());
00167 }
00168 else
00169 {
00170 p.setX(p.x() - br.width());
00171 }
00172
00173 if(p.y() - br.height() < 0)
00174 {
00175 p.setY(0);
00176 }
00177 else
00178 {
00179 p.setY(p.y() - br.height());
00180 }
00181
00182 _textBackground->setPos(p);
00183 }
00184 else
00185 {
00186 this->setPen(QPen(this->pen().color(), 1));
00187 _textBackground->setVisible(false);
00188 }
00189 }
00190
00191 void UPlotItem::hoverEnterEvent(QGraphicsSceneHoverEvent * event)
00192 {
00193 this->showDescription(true);
00194 QGraphicsEllipseItem::hoverEnterEvent(event);
00195 }
00196
00197 void UPlotItem::hoverLeaveEvent(QGraphicsSceneHoverEvent * event)
00198 {
00199 if(!this->hasFocus())
00200 {
00201 this->showDescription(false);
00202 }
00203 QGraphicsEllipseItem::hoverLeaveEvent(event);
00204 }
00205
00206 void UPlotItem::focusInEvent(QFocusEvent * event)
00207 {
00208 this->showDescription(true);
00209 QGraphicsEllipseItem::focusInEvent(event);
00210 }
00211
00212 void UPlotItem::focusOutEvent(QFocusEvent * event)
00213 {
00214 this->showDescription(false);
00215 QGraphicsEllipseItem::focusOutEvent(event);
00216 }
00217
00218 void UPlotItem::keyReleaseEvent(QKeyEvent * keyEvent)
00219 {
00220
00221 if(keyEvent->key() == Qt::Key_Right)
00222 {
00223 UPlotItem * next = _nextItem;
00224 while(next && !next->isVisible())
00225 {
00226 next = next->nextItem();
00227 }
00228 if(next && next->isVisible())
00229 {
00230 this->clearFocus();
00231 next->setFocus();
00232 }
00233 }
00234 else if(keyEvent->key() == Qt::Key_Left)
00235 {
00236 UPlotItem * previous = _previousItem;
00237 while(previous && !previous->isVisible())
00238 {
00239 previous = previous->previousItem();
00240 }
00241 if(previous && previous->isVisible())
00242 {
00243 this->clearFocus();
00244 previous->setFocus();
00245 }
00246 }
00247 QGraphicsEllipseItem::keyReleaseEvent(keyEvent);
00248 }
00249
00250
00251
00252
00253
00254 UPlotCurve::UPlotCurve(const QString & name, QObject * parent) :
00255 QObject(parent),
00256 _plot(0),
00257 _name(name),
00258 _xIncrement(1),
00259 _xStart(0),
00260 _visible(true),
00261 _valuesShown(false),
00262 _itemsColor(0,0,0,150)
00263 {
00264 _rootItem = new QGraphicsRectItem();
00265 }
00266
00267 UPlotCurve::UPlotCurve(const QString & name, QVector<UPlotItem *> data, QObject * parent) :
00268 QObject(parent),
00269 _plot(0),
00270 _name(name),
00271 _xIncrement(1),
00272 _xStart(0),
00273 _visible(true),
00274 _valuesShown(false),
00275 _itemsColor(0,0,0,150)
00276 {
00277 _rootItem = new QGraphicsRectItem();
00278 this->setData(data);
00279 }
00280
00281 UPlotCurve::UPlotCurve(const QString & name, const QVector<float> & x, const QVector<float> & y, QObject * parent) :
00282 QObject(parent),
00283 _plot(0),
00284 _name(name),
00285 _xIncrement(1),
00286 _xStart(0),
00287 _visible(true),
00288 _valuesShown(false),
00289 _itemsColor(0,0,0,150)
00290 {
00291 _rootItem = new QGraphicsRectItem();
00292 this->setData(x, y);
00293 }
00294
00295 UPlotCurve::~UPlotCurve()
00296 {
00297 if(_plot)
00298 {
00299 _plot->removeCurve(this);
00300 }
00301 #if PRINT_DEBUG
00302 ULOGGER_DEBUG("%s", this->name().toStdString().c_str());
00303 #endif
00304 this->clear();
00305 delete _rootItem;
00306 }
00307
00308 void UPlotCurve::attach(UPlot * plot)
00309 {
00310 if(!plot || plot == _plot)
00311 {
00312 return;
00313 }
00314 if(_plot)
00315 {
00316 _plot->removeCurve(this);
00317 }
00318 _plot = plot;
00319 _plot->addItem(_rootItem);
00320 }
00321
00322 void UPlotCurve::detach(UPlot * plot)
00323 {
00324 #if PRINT_DEBUG
00325 ULOGGER_DEBUG("curve=\"%s\" from plot=\"%s\"", this->objectName().toStdString().c_str(), plot?plot->objectName().toStdString().c_str():"");
00326 #endif
00327 if(plot && _plot == plot)
00328 {
00329 _plot = 0;
00330 if(_rootItem->scene())
00331 {
00332 _rootItem->scene()->removeItem(_rootItem);
00333 }
00334 }
00335 }
00336
00337 void UPlotCurve::updateMinMax()
00338 {
00339 float x,y;
00340 const UPlotItem * item;
00341 if(!_items.size())
00342 {
00343 _minMax = QVector<float>();
00344 }
00345 else
00346 {
00347 _minMax = QVector<float>(4);
00348 }
00349 for(int i=0; i<_items.size(); ++i)
00350 {
00351 item = qgraphicsitem_cast<const UPlotItem *>(_items.at(i));
00352 if(item)
00353 {
00354 x = item->data().x();
00355 y = item->data().y();
00356 if(i==0)
00357 {
00358 _minMax[0] = x;
00359 _minMax[1] = x;
00360 _minMax[2] = y;
00361 _minMax[3] = y;
00362 }
00363 else
00364 {
00365 if(x<_minMax[0]) _minMax[0] = x;
00366 if(x>_minMax[1]) _minMax[1] = x;
00367 if(y<_minMax[2]) _minMax[2] = y;
00368 if(y>_minMax[3]) _minMax[3] = y;
00369 }
00370 }
00371 }
00372 }
00373
00374 void UPlotCurve::_addValue(UPlotItem * data)
00375 {
00376
00377 if(data)
00378 {
00379 float x = data->data().x();
00380 float y = data->data().y();
00381
00382 if(_minMax.size() != 4)
00383 {
00384 _minMax = QVector<float>(4);
00385 }
00386 if(_items.size())
00387 {
00388 data->setPreviousItem((UPlotItem *)_items.last());
00389 QGraphicsLineItem * line = new QGraphicsLineItem(_rootItem);
00390 line->setPen(_pen);
00391 line->setVisible(false);
00392 _items.append(line);
00393
00394 if(x<_minMax[0]) _minMax[0] = x;
00395 if(x>_minMax[1]) _minMax[1] = x;
00396 if(y<_minMax[2]) _minMax[2] = y;
00397 if(y>_minMax[3]) _minMax[3] = y;
00398 }
00399 else
00400 {
00401 _minMax[0] = x;
00402 _minMax[1] = x;
00403 _minMax[2] = y;
00404 _minMax[3] = y;
00405 }
00406 data->setParentItem(_rootItem);
00407 data->setZValue(1);
00408 _items.append(data);
00409 data->setVisible(false);
00410 QPen pen = data->pen();
00411 pen.setColor(_itemsColor);
00412 data->setPen(pen);
00413 }
00414 else
00415 {
00416 ULOGGER_ERROR("Data is null ?!?");
00417 }
00418 }
00419
00420 void UPlotCurve::addValue(UPlotItem * data)
00421 {
00422
00423 if(data)
00424 {
00425 this->_addValue(data);
00426 emit dataChanged(this);
00427 }
00428 }
00429
00430 void UPlotCurve::addValue(float x, float y)
00431 {
00432 if(_items.size() &&
00433 dynamic_cast<UPlotItem*>(_items.back()) &&
00434 x < ((UPlotItem*)_items.back())->data().x())
00435 {
00436 UWARN("New value (%f) added to curve \"%s\" is smaller "
00437 "than the last added (%f). Clearing the curve.",
00438 x, this->name().toStdString().c_str(), ((UPlotItem*)_items.back())->data().x());
00439 this->clear();
00440 }
00441
00442 float width = 2;
00443 this->addValue(new UPlotItem(x,y,width));
00444 }
00445
00446 void UPlotCurve::addValue(float y)
00447 {
00448 float x = 0;
00449 if(_items.size())
00450 {
00451 UPlotItem * lastItem = (UPlotItem *)_items.last();
00452 x = lastItem->data().x() + _xIncrement;
00453 }
00454 else
00455 {
00456 x = _xStart;
00457 }
00458 this->addValue(x,y);
00459 }
00460
00461 void UPlotCurve::addValue(const QString & value)
00462 {
00463 bool ok;
00464 float v = value.toFloat(&ok);
00465 if(ok)
00466 {
00467 this->addValue(v);
00468 }
00469 else
00470 {
00471 ULOGGER_ERROR("Value not valid, must be a number, received %s", value.toStdString().c_str());
00472 }
00473 }
00474
00475 void UPlotCurve::addValues(QVector<UPlotItem *> & data)
00476 {
00477 for(int i=0; i<data.size(); ++i)
00478 {
00479 this->_addValue(data.at(i));
00480 }
00481 emit dataChanged(this);
00482 }
00483
00484 void UPlotCurve::addValues(const QVector<float> & xs, const QVector<float> & ys)
00485 {
00486 float width = 2;
00487 for(int i=0; i<xs.size() && i<ys.size(); ++i)
00488 {
00489 this->_addValue(new UPlotItem(xs.at(i),ys.at(i),width));
00490 }
00491 emit dataChanged(this);
00492 }
00493
00494 void UPlotCurve::addValues(const QVector<float> & ys)
00495 {
00496 float x = 0;
00497 float width = 2;
00498 for(int i=0; i<ys.size(); ++i)
00499 {
00500 if(_items.size())
00501 {
00502 UPlotItem * lastItem = (UPlotItem *)_items.last();
00503 x = lastItem->data().x() + _xIncrement;
00504 }
00505 else
00506 {
00507 x = _xStart;
00508 }
00509 this->_addValue(new UPlotItem(x,ys.at(i),width));
00510 }
00511 emit dataChanged(this);
00512 }
00513
00514 void UPlotCurve::addValues(const QVector<int> & ys)
00515 {
00516 float x = 0;
00517 float width = 2;
00518 for(int i=0; i<ys.size(); ++i)
00519 {
00520 if(_items.size())
00521 {
00522 UPlotItem * lastItem = (UPlotItem *)_items.last();
00523 x = lastItem->data().x() + _xIncrement;
00524 }
00525 else
00526 {
00527 x = _xStart;
00528 }
00529 this->_addValue(new UPlotItem(x,ys.at(i),width));
00530 }
00531 emit dataChanged(this);
00532 }
00533
00534 void UPlotCurve::addValues(const std::vector<int> & ys)
00535 {
00536 float x = 0;
00537 float width = 2;
00538 for(unsigned int i=0; i<ys.size(); ++i)
00539 {
00540 if(_items.size())
00541 {
00542 UPlotItem * lastItem = (UPlotItem *)_items.last();
00543 x = lastItem->data().x() + _xIncrement;
00544 }
00545 else
00546 {
00547 x = _xStart;
00548 }
00549 this->_addValue(new UPlotItem(x,ys.at(i),width));
00550 }
00551 emit dataChanged(this);
00552 }
00553
00554 void UPlotCurve::addValues(const std::vector<float> & ys)
00555 {
00556 float x = 0;
00557 float width = 2;
00558 for(unsigned int i=0; i<ys.size(); ++i)
00559 {
00560 if(_items.size())
00561 {
00562 UPlotItem * lastItem = (UPlotItem *)_items.last();
00563 x = lastItem->data().x() + _xIncrement;
00564 }
00565 else
00566 {
00567 x = _xStart;
00568 }
00569 this->_addValue(new UPlotItem(x,ys.at(i),width));
00570 }
00571 emit dataChanged(this);
00572 }
00573
00574 int UPlotCurve::removeItem(int index)
00575 {
00576 if(index >= 0 && index < _items.size())
00577 {
00578 if(index!=0)
00579 {
00580 index-=1;
00581 delete _items.takeAt(index);
00582 }
00583 else if(_items.size()>1)
00584 {
00585 delete _items.takeAt(index+1);
00586 }
00587 UPlotItem * item = (UPlotItem *)_items.takeAt(index);
00588
00589 if(_minMax.size() == 4)
00590 {
00591 if(item->data().x() == _minMax[0] || item->data().x() == _minMax[1] ||
00592 item->data().y() == _minMax[2] || item->data().y() == _minMax[3])
00593 {
00594 if(_items.size())
00595 {
00596 UPlotItem * tmp = (UPlotItem *)_items.at(0);
00597 float x = tmp->data().x();
00598 float y = tmp->data().y();
00599 _minMax[0]=x;
00600 _minMax[1]=x;
00601 _minMax[2]=y;
00602 _minMax[3]=y;
00603 for(int i = 2; i<_items.size(); i+=2)
00604 {
00605 tmp = (UPlotItem*)_items.at(i);
00606 x = tmp->data().x();
00607 y = tmp->data().y();
00608 if(x<_minMax[0]) _minMax[0] = x;
00609 if(x>_minMax[1]) _minMax[1] = x;
00610 if(y<_minMax[2]) _minMax[2] = y;
00611 if(y>_minMax[3]) _minMax[3] = y;
00612 }
00613 }
00614 else
00615 {
00616 _minMax = QVector<float>();
00617 }
00618 }
00619 }
00620 delete item;
00621 }
00622
00623 return index;
00624 }
00625
00626 void UPlotCurve::removeItem(UPlotItem * item)
00627 {
00628 for(int i=0; i<_items.size(); ++i)
00629 {
00630 if(_items.at(i) == item)
00631 {
00632 if(i!=0)
00633 {
00634 i-=1;
00635 delete _items[i];
00636 _items.removeAt(i);
00637 }
00638 else if(_items.size()>1)
00639 {
00640 delete _items[i+1];
00641 _items.removeAt(i+1);
00642 }
00643 item->scene()->removeItem(item);
00644 _items.removeAt(i);
00645 break;
00646 }
00647 }
00648 }
00649
00650 void UPlotCurve::clear()
00651 {
00652 #if PRINT_DEBUG
00653 ULOGGER_DEBUG("%s", this->name().toStdString().c_str());
00654 #endif
00655 qDeleteAll(_rootItem->childItems());
00656 _items.clear();
00657 }
00658
00659 void UPlotCurve::setPen(const QPen & pen)
00660 {
00661 _pen = pen;
00662 for(int i=1; i<_items.size(); i+=2)
00663 {
00664 ((QGraphicsLineItem*) _items.at(i))->setPen(_pen);
00665 }
00666 }
00667
00668 void UPlotCurve::setBrush(const QBrush & brush)
00669 {
00670 _brush = brush;
00671 ULOGGER_WARN("Not used...");
00672 }
00673
00674 void UPlotCurve::setItemsColor(const QColor & color)
00675 {
00676 if(color.isValid())
00677 {
00678 _itemsColor.setRgb(color.red(), color.green(), color.blue(), _itemsColor.alpha());
00679 for(int i=0; i<_items.size(); i+=2)
00680 {
00681 QPen pen = ((UPlotItem*) _items.at(i))->pen();
00682 pen.setColor(_itemsColor);
00683 ((UPlotItem*) _items.at(i))->setPen(pen);
00684 }
00685 }
00686 }
00687
00688 void UPlotCurve::update(float scaleX, float scaleY, float offsetX, float offsetY, float xDir, float yDir, int maxItemsKept)
00689 {
00690
00691
00692 xDir<0?xDir=-1:xDir=1;
00693 yDir<0?yDir=-1:yDir=1;
00694
00695 bool hide = false;
00696 int j=0;
00697 for(int i=_items.size()-1; i>=0; --i)
00698 {
00699 if(i%2 == 0)
00700 {
00701 UPlotItem * item = (UPlotItem *)_items.at(i);
00702 if(hide)
00703 {
00704 if(maxItemsKept == 0 || j <= maxItemsKept)
00705 {
00706
00707 if(!item->isVisible())
00708 {
00709 break;
00710 }
00711 item->setVisible(false);
00712 }
00713 else
00714 {
00715
00716 i = this->removeItem(i);
00717 }
00718 }
00719 else
00720 {
00721 QPointF newPos(((xDir*item->data().x()+offsetX)*scaleX-item->rect().width()/2.0f),
00722 ((yDir*item->data().y()+offsetY)*scaleY-item->rect().width()/2.0f));
00723 if(!item->isVisible())
00724 {
00725 item->setVisible(true);
00726 }
00727 item->setPos(newPos);
00728 }
00729 ++j;
00730 }
00731 else
00732 {
00733 if(hide)
00734 {
00735 _items.at(i)->setVisible(false);
00736 }
00737 else
00738 {
00739 UPlotItem * from = (UPlotItem *)_items.at(i-1);
00740 UPlotItem * to = (UPlotItem *)_items.at(i+1);
00741 QGraphicsLineItem * lineItem = (QGraphicsLineItem *)_items.at(i);
00742 lineItem->setLine((xDir*from->data().x()+offsetX)*scaleX,
00743 (yDir*from->data().y()+offsetY)*scaleY,
00744 (xDir*to->data().x()+offsetX)*scaleX,
00745 (yDir*to->data().y()+offsetY)*scaleY);
00746 if(!lineItem->isVisible())
00747 {
00748 lineItem->setVisible(true);
00749 }
00750
00751
00752 QLineF line = lineItem->line();
00753 if((line.x1() <= line.x2() && line.x2() < 0-((line.x2() - line.x1()))) ||
00754 (line.x1() > line.x2() && line.x2() > lineItem->scene()->sceneRect().width() + ((line.x1() - line.x2()))))
00755 {
00756 hide = true;
00757 }
00758
00759 }
00760 }
00761 }
00762
00763 }
00764
00765 void UPlotCurve::draw(QPainter * painter, const QRect & limits)
00766 {
00767 if(painter)
00768 {
00769 for(int i=_items.size()-1; i>=0 && _items.at(i)->isVisible(); i-=2)
00770 {
00771
00772 const UPlotItem * item = (const UPlotItem *)_items.at(i);
00773 int x = (int)item->x();
00774 if(x<0)
00775 {
00776 break;
00777 }
00778
00779
00780 if(i-1>=0)
00781 {
00782
00783 const QGraphicsLineItem * lineItem = (const QGraphicsLineItem *)_items.at(i-1);
00784 QLine line = lineItem->line().toLine();
00785 if(limits.contains(line.p1()) || limits.contains(line.p2()))
00786 {
00787 QPointF intersection;
00788 QLineF::IntersectType type;
00789 type = lineItem->line().intersect(QLineF(limits.topLeft(), limits.bottomLeft()), &intersection);
00790 if(type == QLineF::BoundedIntersection)
00791 {
00792 !limits.contains(line.p1())?line.setP1(intersection.toPoint()):line.setP2(intersection.toPoint());
00793 }
00794 else
00795 {
00796 type = lineItem->line().intersect(QLineF(limits.topLeft(), limits.topRight()), &intersection);
00797 if(type == QLineF::BoundedIntersection)
00798 {
00799 !limits.contains(line.p1())?line.setP1(intersection.toPoint()):line.setP2(intersection.toPoint());
00800 }
00801 else
00802 {
00803 type = lineItem->line().intersect(QLineF(limits.bottomLeft(), limits.bottomRight()), &intersection);
00804 if(type == QLineF::BoundedIntersection)
00805 {
00806 !limits.contains(line.p1())?line.setP1(intersection.toPoint()):line.setP2(intersection.toPoint());
00807 }
00808 else
00809 {
00810 type = lineItem->line().intersect(QLineF(limits.topRight(), limits.bottomRight()), &intersection);
00811 if(type == QLineF::BoundedIntersection)
00812 {
00813 !limits.contains(line.p1())?line.setP1(intersection.toPoint()):line.setP2(intersection.toPoint());
00814 }
00815 }
00816 }
00817 }
00818 painter->save();
00819 painter->setPen(this->pen());
00820 painter->setBrush(this->brush());
00821 painter->drawLine(line);
00822 painter->restore();
00823 }
00824 }
00825
00826 if(limits.contains(item->pos().toPoint()) && limits.contains((item->pos() + QPointF(item->rect().width(), item->rect().height())).toPoint()))
00827 {
00828 painter->save();
00829 painter->setPen(QPen(_itemsColor));
00830 painter->drawEllipse(item->pos()+QPointF(item->rect().width()/2, item->rect().height()/2), (int)item->rect().width()/2, (int)item->rect().height()/2);
00831 painter->restore();
00832 }
00833 }
00834 }
00835 }
00836
00837 int UPlotCurve::itemsSize() const
00838 {
00839 return _items.size();
00840 }
00841
00842 QPointF UPlotCurve::getItemData(int index)
00843 {
00844 QPointF data;
00845
00846 if(index>=0 && index < _items.size() && index % 2 == 0 )
00847 {
00848 data = ((UPlotItem*)_items.at(index))->data();
00849 }
00850 else
00851 {
00852 ULOGGER_ERROR("Wrong index, not pointing on a PlotItem");
00853 }
00854 return data;
00855 }
00856
00857 void UPlotCurve::setVisible(bool visible)
00858 {
00859 _visible = visible;
00860 for(int i=0; i<_items.size(); ++i)
00861 {
00862 _items.at(i)->setVisible(visible);
00863 }
00864 }
00865
00866 void UPlotCurve::setXIncrement(float increment)
00867 {
00868 _xIncrement = increment;
00869 }
00870
00871 void UPlotCurve::setXStart(float val)
00872 {
00873 _xStart = val;
00874 }
00875
00876 void UPlotCurve::setData(QVector<UPlotItem*> & data)
00877 {
00878 this->clear();
00879 for(int i = 0; i<data.size(); ++i)
00880 {
00881 this->addValue(data[i]);
00882 }
00883 }
00884
00885 void UPlotCurve::setData(const QVector<float> & x, const QVector<float> & y)
00886 {
00887 if(x.size() == y.size())
00888 {
00889
00890 int margin = int((_items.size()+1)/2) - x.size();
00891 while(margin < 0)
00892 {
00893 UPlotItem * newItem = new UPlotItem(0, 0, 2);
00894 this->_addValue(newItem);
00895 ++margin;
00896 }
00897 while(margin > 0)
00898 {
00899 this->removeItem(0);
00900 --margin;
00901 }
00902
00903
00904 int index = 0;
00905 QVector<float>::const_iterator i=x.begin();
00906 QVector<float>::const_iterator j=y.begin();
00907 for(; i!=x.end() && j!=y.end(); ++i, ++j, index+=2)
00908 {
00909 ((UPlotItem*)_items[index])->setData(QPointF(*i, *j));
00910 }
00911
00912
00913 this->updateMinMax();
00914 emit dataChanged(this);
00915 }
00916 else if(y.size()>0 && x.size()==0)
00917 {
00918 this->setData(y);
00919 }
00920 else
00921 {
00922 ULOGGER_ERROR("Data vectors have not the same size.");
00923 }
00924 }
00925
00926 void UPlotCurve::setData(const std::vector<float> & x, const std::vector<float> & y)
00927 {
00928 if(x.size() == y.size())
00929 {
00930
00931 int margin = int((_items.size()+1)/2) - int(x.size());
00932 while(margin < 0)
00933 {
00934 UPlotItem * newItem = new UPlotItem(0, 0, 2);
00935 this->_addValue(newItem);
00936 ++margin;
00937 }
00938 while(margin > 0)
00939 {
00940 this->removeItem(0);
00941 --margin;
00942 }
00943
00944
00945 int index = 0;
00946 std::vector<float>::const_iterator i=x.begin();
00947 std::vector<float>::const_iterator j=y.begin();
00948 for(; i!=x.end() && j!=y.end(); ++i, ++j, index+=2)
00949 {
00950 ((UPlotItem*)_items[index])->setData(QPointF(*i, *j));
00951 }
00952
00953
00954 this->updateMinMax();
00955 emit dataChanged(this);
00956 }
00957 else if(y.size()>0 && x.size()==0)
00958 {
00959 this->setData(y);
00960 }
00961 else
00962 {
00963 ULOGGER_ERROR("Data vectors have not the same size.");
00964 }
00965 }
00966
00967 void UPlotCurve::setData(const QVector<float> & y)
00968 {
00969 this->setData(y.toStdVector());
00970 }
00971
00972 void UPlotCurve::setData(const std::vector<float> & y)
00973 {
00974
00975 int margin = int((_items.size()+1)/2) - int(y.size());
00976 while(margin < 0)
00977 {
00978 UPlotItem * newItem = new UPlotItem(0, 0, 2);
00979 this->_addValue(newItem);
00980 ++margin;
00981 }
00982 while(margin > 0)
00983 {
00984 this->removeItem(0);
00985 --margin;
00986 }
00987
00988
00989 int index = 0;
00990 float x = 0;
00991 std::vector<float>::const_iterator j=y.begin();
00992 for(; j!=y.end(); ++j, index+=2)
00993 {
00994 ((UPlotItem*)_items[index])->setData(QPointF(x++, *j));
00995 }
00996
00997
00998 this->updateMinMax();
00999 emit dataChanged(this);
01000 }
01001
01002 void UPlotCurve::getData(QVector<float> & x, QVector<float> & y) const
01003 {
01004 x.clear();
01005 y.clear();
01006 if(_items.size())
01007 {
01008 x.resize((_items.size()-1)/2+1);
01009 y.resize(x.size());
01010 int j=0;
01011 for(int i=0; i<_items.size(); i+=2)
01012 {
01013 x[j] = ((UPlotItem*)_items.at(i))->data().x();
01014 y[j++] = ((UPlotItem*)_items.at(i))->data().y();
01015 }
01016 }
01017 }
01018
01019 void UPlotCurve::getData(QMap<float,float> & data) const
01020 {
01021 data.clear();
01022 if(_items.size())
01023 {
01024 for(int i=0; i<_items.size(); i+=2)
01025 {
01026 data.insert(((UPlotItem*)_items.at(i))->data().x(), ((UPlotItem*)_items.at(i))->data().y());
01027 }
01028 }
01029 }
01030
01031
01032
01033
01034
01035 UPlotCurveThreshold::UPlotCurveThreshold(const QString & name, float thesholdValue, Qt::Orientation orientation, QObject * parent) :
01036 UPlotCurve(name, parent),
01037 _orientation(orientation)
01038 {
01039 if(_orientation == Qt::Horizontal)
01040 {
01041 this->addValue(0, thesholdValue);
01042 this->addValue(1, thesholdValue);
01043 }
01044 else
01045 {
01046 this->addValue(thesholdValue, 0);
01047 this->addValue(thesholdValue, 1);
01048 }
01049 }
01050
01051 UPlotCurveThreshold::~UPlotCurveThreshold()
01052 {
01053
01054 }
01055
01056 void UPlotCurveThreshold::setThreshold(float threshold)
01057 {
01058 #if PRINT_DEBUG
01059 ULOGGER_DEBUG("%f", threshold);
01060 #endif
01061 if(_items.size() == 3)
01062 {
01063 UPlotItem * item = 0;
01064 if(_orientation == Qt::Horizontal)
01065 {
01066 item = (UPlotItem*)_items.at(0);
01067 item->setData(QPointF(item->data().x(), threshold));
01068 item = (UPlotItem*)_items.at(2);
01069 item->setData(QPointF(item->data().x(), threshold));
01070 }
01071 else
01072 {
01073 item = (UPlotItem*)_items.at(0);
01074 item->setData(QPointF(threshold, item->data().y()));
01075 item = (UPlotItem*)_items.at(2);
01076 item->setData(QPointF(threshold, item->data().y()));
01077 }
01078 }
01079 else
01080 {
01081 ULOGGER_ERROR("A threshold must has only 3 items (1 PlotItem + 1 QGraphicsLineItem + 1 PlotItem)");
01082 }
01083 }
01084
01085 void UPlotCurveThreshold::setOrientation(Qt::Orientation orientation)
01086 {
01087 if(_orientation != orientation)
01088 {
01089 _orientation = orientation;
01090 if(_items.size() == 3)
01091 {
01092 UPlotItem * item = 0;
01093 item = (UPlotItem*)_items.at(0);
01094 item->setData(QPointF(item->data().y(), item->data().x()));
01095 item = (UPlotItem*)_items.at(2);
01096 item->setData(QPointF(item->data().y(), item->data().x()));
01097 }
01098 else
01099 {
01100 ULOGGER_ERROR("A threshold must has only 3 items (1 PlotItem + 1 QGraphicsLineItem + 1 PlotItem)");
01101 }
01102 }
01103 }
01104
01105 void UPlotCurveThreshold::update(float scaleX, float scaleY, float offsetX, float offsetY, float xDir, float yDir, int maxItemsKept)
01106 {
01107 if(_items.size() == 3)
01108 {
01109 if(_plot)
01110 {
01111 UPlotItem * item = 0;
01112 if(_orientation == Qt::Horizontal)
01113 {
01114
01115 item = (UPlotItem*)_items.at(0);
01116 item->setData(QPointF(-(offsetX-item->rect().width()/scaleX)/xDir, item->data().y()));
01117 item = (UPlotItem*)_items.at(2);
01118 item->setData(QPointF( (_plot->sceneRect().width()/scaleX-(offsetX+item->rect().width()/scaleX))/xDir, item->data().y()));
01119 }
01120 else
01121 {
01122 item = (UPlotItem*)_items.at(0);
01123 item->setData(QPointF(item->data().x(), -(offsetY-item->rect().height()/scaleY)/yDir));
01124 item = (UPlotItem*)_items.at(2);
01125 item->setData(QPointF(item->data().x(), (_plot->sceneRect().height()/scaleY-(offsetY+item->rect().height()/scaleY))/yDir));
01126 }
01127 this->updateMinMax();
01128 }
01129 }
01130 else
01131 {
01132 ULOGGER_ERROR("A threshold must has only 3 items (1 PlotItem + 1 QGraphicsLineItem + 1 PlotItem)");
01133 }
01134 UPlotCurve::update(scaleX, scaleY, offsetX, offsetY, xDir, yDir, maxItemsKept);
01135 }
01136
01137
01138
01139
01140
01141
01142
01143 UPlotAxis::UPlotAxis(Qt::Orientation orientation, float min, float max, QWidget * parent) :
01144 QWidget(parent),
01145 _orientation(orientation),
01146 _reversed(false),
01147 _gradMaxDigits(4),
01148 _border(0)
01149 {
01150 if(_orientation == Qt::Vertical)
01151 {
01152 _reversed = true;
01153 }
01154 #ifdef _WIN32
01155 this->setMinimumSize(15, 25);
01156 #else
01157 this->setMinimumSize(15, 25);
01158 #endif
01159 this->setAxis(min, max);
01160 }
01161
01162 UPlotAxis::~UPlotAxis()
01163 {
01164 #if PRINT_DEBUG
01165 ULOGGER_DEBUG("");
01166 #endif
01167 }
01168
01169
01170 void UPlotAxis::setReversed(bool reversed)
01171 {
01172 if(_reversed != reversed)
01173 {
01174 float min = _min;
01175 _min = _max;
01176 _max = min;
01177 }
01178 _reversed = reversed;
01179 }
01180
01181 void UPlotAxis::setAxis(float & min, float & max)
01182 {
01183 int borderMin = 0;
01184 int borderMax = 0;
01185 if(_orientation == Qt::Vertical)
01186 {
01187 borderMin = borderMax = this->fontMetrics().height()/2;
01188 }
01189 else
01190 {
01191 borderMin = this->fontMetrics().width(QString::number(_min,'g',_gradMaxDigits))/2;
01192 borderMax = this->fontMetrics().width(QString::number(_max,'g',_gradMaxDigits))/2;
01193 }
01194 int border = borderMin>borderMax?borderMin:borderMax;
01195 int borderDelta;
01196 int length;
01197 if(_orientation == Qt::Vertical)
01198 {
01199 length = (this->height()-border*2);
01200 }
01201 else
01202 {
01203 length = (this->width()-border*2);
01204 }
01205
01206 if(length <= 70)
01207 {
01208 _count = 5;
01209 }
01210 else if(length <= 175)
01211 {
01212 _count = 10;
01213 }
01214 else if(length <= 350)
01215 {
01216 _count = 20;
01217 }
01218 else if(length <= 700)
01219 {
01220 _count = 40;
01221 }
01222 else if(length <= 1000)
01223 {
01224 _count = 60;
01225 }
01226 else if(length <= 1300)
01227 {
01228 _count = 80;
01229 }
01230 else
01231 {
01232 _count = 100;
01233 }
01234
01235
01236 if(min != max)
01237 {
01238 float mul = 1;
01239 float rangef = max - min;
01240 int countStep = _count/5;
01241 float val;
01242 for(int i=0; i<6; ++i)
01243 {
01244 val = (rangef/float(countStep)) * mul;
01245 if( val >= 1.0f && val < 10.0f)
01246 {
01247 break;
01248 }
01249 else if(val<1)
01250 {
01251 mul *= 10.0f;
01252 }
01253 else
01254 {
01255 mul /= 10.0f;
01256 }
01257 }
01258
01259 int minR = min*mul-0.9;
01260 int maxR = max*mul+0.9;
01261 min = float(minR)/mul;
01262 max = float(maxR)/mul;
01263
01264 }
01265
01266 _min = min;
01267 _max = max;
01268
01269 if(_reversed)
01270 {
01271 _min = _max;
01272 _max = min;
01273 }
01274
01275 if(_orientation == Qt::Vertical)
01276 {
01277 _step = length/_count;
01278 borderDelta = length - (_step*_count);
01279 }
01280 else
01281 {
01282 _step = length/_count;
01283 borderDelta = length - (_step*_count);
01284 }
01285
01286 if(borderDelta%2 != 0)
01287 {
01288 borderDelta+=1;
01289 }
01290
01291 _border = border + borderDelta/2;
01292
01293
01294 if(_orientation == Qt::Vertical)
01295 {
01296 int minWidth = 0;
01297 for (int i = 0; i <= _count; i+=5)
01298 {
01299 QString n(QString::number(_min + (i/5)*((_max-_min)/(_count/5)),'g',_gradMaxDigits));
01300 if(this->fontMetrics().width(n) > minWidth)
01301 {
01302 minWidth = this->fontMetrics().width(n);
01303 }
01304 }
01305 this->setMinimumWidth(15+minWidth);
01306 }
01307 }
01308
01309 void UPlotAxis::paintEvent(QPaintEvent * event)
01310 {
01311 QPainter painter(this);
01312 if(_orientation == Qt::Vertical)
01313 {
01314 painter.translate(0, _border);
01315 for (int i = 0; i <= _count; ++i)
01316 {
01317 if(i%5 == 0)
01318 {
01319 painter.drawLine(this->width(), 0, this->width()-10, 0);
01320 QLabel n(QString::number(_min + (i/5)*((_max-_min)/(_count/5)),'g',_gradMaxDigits));
01321 painter.drawText(this->width()-(12+n.sizeHint().width()), n.sizeHint().height()/2-2, n.text());
01322 }
01323 else
01324 {
01325 painter.drawLine(this->width(), 0, this->width()-5, 0);
01326 }
01327 painter.translate(0, _step);
01328 }
01329 }
01330 else
01331 {
01332 painter.translate(_border, 0);
01333 for (int i = 0; i <= _count; ++i)
01334 {
01335 if(i%5 == 0)
01336 {
01337 painter.drawLine(0, 0, 0, 10);
01338 QLabel n(QString::number(_min + (i/5)*((_max-_min)/(_count/5)),'g',_gradMaxDigits));
01339 painter.drawText(-(n.sizeHint().width()/2)+1, 22, n.text());
01340 }
01341 else
01342 {
01343 painter.drawLine(0, 0, 0, 5);
01344 }
01345 painter.translate(_step, 0);
01346 }
01347 }
01348 }
01349
01350
01351
01352
01353 UPlotLegendItem::UPlotLegendItem(UPlotCurve * curve, QWidget * parent) :
01354 QPushButton(parent),
01355 _curve(curve)
01356 {
01357 QString nameSpaced = curve->name();
01358 nameSpaced.replace('_', ' ');
01359 this->setText(nameSpaced);
01360
01361 this->setIcon(QIcon(this->createSymbol(curve->pen(), curve->brush())));
01362 this->setIconSize(QSize(25,20));
01363
01364 _aChangeText = new QAction(tr("Change text..."), this);
01365 _aResetText = new QAction(tr("Reset text..."), this);
01366 _aChangeColor = new QAction(tr("Change color..."), this);
01367 _aCopyToClipboard = new QAction(tr("Copy curve data to clipboard"), this);
01368 _aShowStdDev = new QAction(tr("Show std deviation"), this);
01369 _aShowStdDev->setCheckable(true);
01370 _aMoveUp = new QAction(tr("Move up"), this);
01371 _aMoveDown = new QAction(tr("Move down"), this);
01372 _aRemoveCurve = new QAction(tr("Remove this curve"), this);
01373 _menu = new QMenu(tr("Curve"), this);
01374 _menu->addAction(_aChangeText);
01375 _menu->addAction(_aResetText);
01376 _menu->addAction(_aChangeColor);
01377 _menu->addAction(_aCopyToClipboard);
01378 _menu->addAction(_aShowStdDev);
01379 _menu->addSeparator();
01380 _menu->addAction(_aMoveUp);
01381 _menu->addAction(_aMoveDown);
01382 _menu->addSeparator();
01383 _menu->addAction(_aRemoveCurve);
01384 }
01385
01386 UPlotLegendItem::~UPlotLegendItem()
01387 {
01388
01389 }
01390 void UPlotLegendItem::contextMenuEvent(QContextMenuEvent * event)
01391 {
01392 QAction * action = _menu->exec(event->globalPos());
01393 if(action == _aChangeText)
01394 {
01395 bool ok;
01396 QString text = QInputDialog::getText(this, _aChangeText->text(), tr("Name :"), QLineEdit::Normal, this->text(), &ok);
01397 if(ok && !text.isEmpty())
01398 {
01399 this->setText(text);
01400 }
01401 }
01402 else if(action == _aResetText)
01403 {
01404 if(_curve)
01405 {
01406 this->setText(_curve->name());
01407 }
01408 }
01409 else if(action == _aChangeColor)
01410 {
01411 if(_curve)
01412 {
01413 QPen pen = _curve->pen();
01414 QColor color = QColorDialog::getColor(pen.color(), this);
01415 if(color.isValid())
01416 {
01417 pen.setColor(color);
01418 _curve->setPen(pen);
01419 this->setIcon(QIcon(this->createSymbol(_curve->pen(), _curve->brush())));
01420 }
01421 }
01422 }
01423 else if (action == _aCopyToClipboard)
01424 {
01425 if(_curve)
01426 {
01427 QVector<float> x;
01428 QVector<float> y;
01429 _curve->getData(x, y);
01430 QString textX;
01431 QString textY;
01432 for(int i=0; i<x.size(); ++i)
01433 {
01434 textX.append(QString::number(x[i]));
01435 textY.append(QString::number(y[i]));
01436 if(i+1<x.size())
01437 {
01438 textX.append(' ');
01439 textY.append(' ');
01440 }
01441 }
01442 QClipboard * clipboard = QApplication::clipboard();
01443 clipboard->setText((textX+"\n")+textY);
01444 }
01445 }
01446 else if(action == _aShowStdDev)
01447 {
01448 if(_aShowStdDev->isChecked())
01449 {
01450 connect(_curve, SIGNAL(dataChanged(const UPlotCurve *)), this, SLOT(updateStdDev()));
01451 }
01452 else
01453 {
01454 disconnect(_curve, SIGNAL(dataChanged(const UPlotCurve *)), this, SLOT(updateStdDev()));
01455 QString nameSpaced = _curve->name();
01456 nameSpaced.replace('_', ' ');
01457 this->setText(nameSpaced);
01458 }
01459 }
01460 else if(action == _aRemoveCurve)
01461 {
01462 emit legendItemRemoved(_curve);
01463 }
01464 else if(action == _aMoveUp)
01465 {
01466 emit moveUpRequest(this);
01467 }
01468 else if(action == _aMoveDown)
01469 {
01470 emit moveDownRequest(this);
01471 }
01472 }
01473
01474 QPixmap UPlotLegendItem::createSymbol(const QPen & pen, const QBrush & brush)
01475 {
01476 QPixmap pixmap(50, 50);
01477 pixmap.fill(Qt::transparent);
01478 QPainter painter(&pixmap);
01479 QPen p = pen;
01480 p.setWidthF(4.0);
01481 painter.setPen(p);
01482 painter.drawLine(0.0, 25.0, 50.0, 25.0);
01483 return pixmap;
01484 }
01485
01486 void UPlotLegendItem::updateStdDev()
01487 {
01488 QVector<float> x, y;
01489 _curve->getData(x, y);
01490 float stdDev = std::sqrt(uVariance(y.data(), y.size()));
01491 QString nameSpaced = _curve->name();
01492 nameSpaced.replace('_', ' ');
01493 nameSpaced += QString(" (%1=%2)").arg(QChar(0xc3, 0x03)).arg(stdDev);
01494 this->setText(nameSpaced);
01495 }
01496
01497
01498
01499
01500
01501
01502 UPlotLegend::UPlotLegend(QWidget * parent) :
01503 QWidget(parent),
01504 _flat(true)
01505 {
01506
01507 _aUseFlatButtons = new QAction(tr("Use flat buttons"), this);
01508 _aUseFlatButtons->setCheckable(true);
01509 _aUseFlatButtons->setChecked(_flat);
01510 _aCopyAllCurveToClipboard = new QAction(tr("Copy all curve data to clipboard"), this);
01511 _menu = new QMenu(tr("Legend"), this);
01512 _menu->addAction(_aUseFlatButtons);
01513 _menu->addAction(_aCopyAllCurveToClipboard);
01514
01515 QVBoxLayout * vLayout = new QVBoxLayout(this);
01516 vLayout->setContentsMargins(0,0,0,0);
01517 this->setLayout(vLayout);
01518 vLayout->addStretch(0);
01519 vLayout->setSpacing(0);
01520 }
01521
01522 UPlotLegend::~UPlotLegend()
01523 {
01524 #if PRINT_DEBUG
01525 ULOGGER_DEBUG("");
01526 #endif
01527 }
01528
01529 void UPlotLegend::setFlat(bool on)
01530 {
01531 if(_flat != on)
01532 {
01533 _flat = on;
01534 QList<UPlotLegendItem*> items = this->findChildren<UPlotLegendItem*>();
01535 for(int i=0; i<items.size(); ++i)
01536 {
01537 items.at(i)->setFlat(_flat);
01538 items.at(i)->setChecked(!items.at(i)->isChecked());
01539 }
01540 _aUseFlatButtons->setChecked(_flat);
01541 }
01542 }
01543
01544 void UPlotLegend::addItem(UPlotCurve * curve)
01545 {
01546 if(curve)
01547 {
01548 UPlotLegendItem * legendItem = new UPlotLegendItem(curve, this);
01549 legendItem->setAutoDefault(false);
01550 legendItem->setFlat(_flat);
01551 legendItem->setCheckable(true);
01552 legendItem->setChecked(false);
01553 connect(legendItem, SIGNAL(toggled(bool)), this, SLOT(redirectToggled(bool)));
01554 connect(legendItem, SIGNAL(legendItemRemoved(const UPlotCurve *)), this, SLOT(removeLegendItem(const UPlotCurve *)));
01555 connect(legendItem, SIGNAL(moveUpRequest(UPlotLegendItem *)), this, SLOT(moveUp(UPlotLegendItem *)));
01556 connect(legendItem, SIGNAL(moveDownRequest(UPlotLegendItem *)), this, SLOT(moveDown(UPlotLegendItem *)));
01557
01558
01559 QHBoxLayout * hLayout = new QHBoxLayout();
01560 hLayout->addWidget(legendItem);
01561 hLayout->addStretch(0);
01562 hLayout->setMargin(0);
01563
01564
01565 ((QVBoxLayout*)this->layout())->insertLayout(this->layout()->count()-1, hLayout);
01566 }
01567 }
01568
01569 bool UPlotLegend::remove(const UPlotCurve * curve)
01570 {
01571 QList<UPlotLegendItem *> items = this->findChildren<UPlotLegendItem*>();
01572 for(int i=0; i<items.size(); ++i)
01573 {
01574 if(items.at(i)->curve() == curve)
01575 {
01576 delete items.at(i);
01577 return true;
01578 }
01579 }
01580 return false;
01581 }
01582
01583 void UPlotLegend::removeLegendItem(const UPlotCurve * curve)
01584 {
01585 if(this->remove(curve))
01586 {
01587 emit legendItemRemoved(curve);
01588 }
01589 }
01590
01591 void UPlotLegend::moveUp(UPlotLegendItem * item)
01592 {
01593 int index = -1;
01594 QLayoutItem * layoutItem = 0;
01595 for(int i=0; i<this->layout()->count(); ++i)
01596 {
01597 if(this->layout()->itemAt(i)->layout() &&
01598 this->layout()->itemAt(i)->layout()->indexOf(item) != -1)
01599 {
01600 layoutItem = this->layout()->itemAt(i);
01601 index = i;
01602 break;
01603 }
01604 }
01605 if(index > 0 && layoutItem)
01606 {
01607 this->layout()->removeItem(layoutItem);
01608 QHBoxLayout * hLayout = new QHBoxLayout();
01609 hLayout->addWidget(layoutItem->layout()->itemAt(0)->widget());
01610 hLayout->addStretch(0);
01611 hLayout->setMargin(0);
01612 ((QVBoxLayout*)this->layout())->insertLayout(index-1, hLayout);
01613 delete layoutItem;
01614 emit legendItemMoved(item->curve(), index-1);
01615 }
01616 }
01617
01618 void UPlotLegend::moveDown(UPlotLegendItem * item)
01619 {
01620 int index = -1;
01621 QLayoutItem * layoutItem = 0;
01622 for(int i=0; i<this->layout()->count(); ++i)
01623 {
01624 if(this->layout()->itemAt(i)->layout() &&
01625 this->layout()->itemAt(i)->layout()->indexOf(item) != -1)
01626 {
01627 layoutItem = this->layout()->itemAt(i);
01628 index = i;
01629 break;
01630 }
01631 }
01632 if(index < this->layout()->count()-2 && layoutItem)
01633 {
01634 this->layout()->removeItem(layoutItem);
01635 QHBoxLayout * hLayout = new QHBoxLayout();
01636 hLayout->addWidget(layoutItem->layout()->itemAt(0)->widget());
01637 hLayout->addStretch(0);
01638 hLayout->setMargin(0);
01639 ((QVBoxLayout*)this->layout())->insertLayout(index+1, hLayout);
01640 delete layoutItem;
01641 emit legendItemMoved(item->curve(), index+1);
01642 }
01643 }
01644
01645 void UPlotLegend::contextMenuEvent(QContextMenuEvent * event)
01646 {
01647 QAction * action = _menu->exec(event->globalPos());
01648 if(action == _aUseFlatButtons)
01649 {
01650 this->setFlat(_aUseFlatButtons->isChecked());
01651 }
01652 else if(action == _aCopyAllCurveToClipboard)
01653 {
01654 QList<UPlotLegendItem *> items = this->findChildren<UPlotLegendItem*>();
01655 if(items.size())
01656 {
01657 QMap<float,float> firstData;
01658 QVector<QVector<float> > axes;
01659 for(int i=0; i<items.size(); ++i)
01660 {
01661 QMap<float, float> data;
01662 items.at(i)->curve()->getData(data);
01663
01664 if(i==0)
01665 {
01666 firstData = data;
01667 }
01668 else
01669 {
01670 QVector<float> y(firstData.size(), 0.0f);
01671
01672 int j=0;
01673 for(QMap<float,float>::iterator iter=firstData.begin(); iter!=firstData.end(); ++iter)
01674 {
01675 if(data.contains(iter.key()))
01676 {
01677 y[j] = data.value(iter.key());
01678 }
01679 ++j;
01680 }
01681 axes.push_back(y);
01682 }
01683 }
01684 if(firstData.size())
01685 {
01686 axes.push_front(firstData.values().toVector());
01687 axes.push_front(firstData.keys().toVector());
01688 QString text;
01689 for(int i=0; i<axes.size(); ++i)
01690 {
01691 for(int j=0; j<axes[i].size(); ++j)
01692 {
01693 text.append(QString::number(axes[i][j]));
01694 if(j+1<axes[i].size())
01695 {
01696 text.append(' ');
01697 }
01698 }
01699 if(i+1<axes.size())
01700 {
01701 text.append("\n");
01702 }
01703 }
01704 QClipboard * clipboard = QApplication::clipboard();
01705 clipboard->setText(text);
01706 }
01707 }
01708 }
01709 }
01710
01711 void UPlotLegend::redirectToggled(bool toggled)
01712 {
01713 if(sender())
01714 {
01715 UPlotLegendItem * item = qobject_cast<UPlotLegendItem*>(sender());
01716 if(item)
01717 {
01718 emit legendItemToggled(item->curve(), _flat?!toggled:toggled);
01719 }
01720 }
01721 }
01722
01723
01724
01725
01726
01727
01728
01729 UOrientableLabel::UOrientableLabel(const QString & text, Qt::Orientation orientation, QWidget * parent) :
01730 QLabel(text, parent),
01731 _orientation(orientation)
01732 {
01733 }
01734
01735 UOrientableLabel::~UOrientableLabel()
01736 {
01737 }
01738
01739 QSize UOrientableLabel::sizeHint() const
01740 {
01741 QSize size = QLabel::sizeHint();
01742 if (_orientation == Qt::Vertical)
01743 size.transpose();
01744 return size;
01745
01746 }
01747
01748 QSize UOrientableLabel::minimumSizeHint() const
01749 {
01750 QSize size = QLabel::minimumSizeHint();
01751 if (_orientation == Qt::Vertical)
01752 size.transpose();
01753 return size;
01754 }
01755
01756 void UOrientableLabel::setOrientation(Qt::Orientation orientation)
01757 {
01758 _orientation = orientation;
01759 switch(orientation)
01760 {
01761 case Qt::Horizontal:
01762 setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
01763 break;
01764
01765 case Qt::Vertical:
01766 setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum);
01767 break;
01768 }
01769 }
01770
01771 void UOrientableLabel::paintEvent(QPaintEvent* event)
01772 {
01773 QPainter p(this);
01774 QRect r = rect();
01775 switch (_orientation)
01776 {
01777 case Qt::Horizontal:
01778 break;
01779 case Qt::Vertical:
01780 p.rotate(-90);
01781 p.translate(-height(), 0);
01782 QSize size = r.size();
01783 size.transpose();
01784 r.setSize(size);
01785 break;
01786 }
01787 p.drawText(r, this->alignment() | (this->wordWrap()?Qt::TextWordWrap:0), this->text());
01788 }
01789
01790
01791
01792
01793
01794
01795
01796
01797
01798
01799
01800
01801
01802 UPlot::UPlot(QWidget *parent) :
01803 QWidget(parent),
01804 _maxVisibleItems(-1),
01805 _autoScreenCaptureFormat("png"),
01806 _bgColor(Qt::white)
01807 {
01808 this->setupUi();
01809 this->createActions();
01810 this->createMenus();
01811
01812
01813 this->showLegend(true);
01814 this->setGraphicsView(false);
01815 this->setMaxVisibleItems(0);
01816 this->showGrid(false);
01817 this->showRefreshRate(false);
01818 this->keepAllData(false);
01819
01820 for(int i=0; i<4; ++i)
01821 {
01822 _axisMaximums[i] = 0;
01823 _axisMaximumsSet[i] = false;
01824 if(i<2)
01825 {
01826 _fixedAxis[i] = false;
01827 }
01828 }
01829
01830 _mouseCurrentPos = _mousePressedPos;
01831
01832 _refreshIntervalTime.start();
01833 _lowestRefreshRate = 99;
01834 _refreshStartTime.start();
01835
01836 _penStyleCount = rand() % 10 + 1;
01837 _workingDirectory = QDir::homePath();
01838 }
01839
01840 UPlot::~UPlot()
01841 {
01842 _aAutoScreenCapture->setChecked(false);
01843 #if PRINT_DEBUG
01844 ULOGGER_DEBUG("%s", this->title().toStdString().c_str());
01845 #endif
01846 this->removeCurves();
01847 }
01848
01849 void UPlot::setupUi()
01850 {
01851 _legend = new UPlotLegend(this);
01852 _view = new QGraphicsView(this);
01853 _view->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
01854 _view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
01855 _view->setScene(new QGraphicsScene(0,0,0,0,this));
01856 _view->setStyleSheet( "QGraphicsView { border-style: none; }" );
01857 _sceneRoot = _view->scene()->addText("");
01858 _sceneRoot->setTransform(QTransform::fromTranslate(0, 0), true);
01859 _graphicsViewHolder = new QWidget(this);
01860 _graphicsViewHolder->setMinimumSize(100,100);
01861 _graphicsViewHolder->setMouseTracking(true);
01862 _verticalAxis = new UPlotAxis(Qt::Vertical, 0, 1, this);
01863 _horizontalAxis = new UPlotAxis(Qt::Horizontal, 0, 1, this);
01864 _title = new QLabel("");
01865 _xLabel = new QLabel("");
01866 _refreshRate = new QLabel("");
01867 _yLabel = new UOrientableLabel("");
01868 _yLabel->setOrientation(Qt::Vertical);
01869 _title->setAlignment(Qt::AlignCenter);
01870 _xLabel->setAlignment(Qt::AlignCenter);
01871 _yLabel->setAlignment(Qt::AlignCenter);
01872 _refreshRate->setAlignment(Qt::AlignCenter);
01873 _title->setWordWrap(true);
01874 _xLabel->setWordWrap(true);
01875 _yLabel->setWordWrap(true);
01876 _title->setVisible(false);
01877 _xLabel->setVisible(false);
01878 _yLabel->setVisible(false);
01879 _refreshRate->setVisible(false);
01880
01881
01882 QVBoxLayout * vLayout = new QVBoxLayout(_graphicsViewHolder);
01883 vLayout->setContentsMargins(0,0,0,0);
01884 vLayout->addWidget(_view);
01885
01886 QGridLayout * grid = new QGridLayout(this);
01887 grid->setContentsMargins(0,0,0,0);
01888 grid->addWidget(_title, 0, 2);
01889 grid->addWidget(_yLabel, 1, 0);
01890 grid->addWidget(_verticalAxis, 1, 1);
01891 grid->addWidget(_refreshRate, 2, 1);
01892 grid->addWidget(_graphicsViewHolder, 1, 2);
01893 grid->setColumnStretch(2, 1);
01894 grid->setRowStretch(1, 1);
01895 grid->addWidget(_horizontalAxis, 2, 2);
01896 grid->addWidget(_xLabel, 3, 2);
01897 grid->addWidget(_legend, 1, 3);
01898
01899 connect(_legend, SIGNAL(legendItemToggled(const UPlotCurve *, bool)), this, SLOT(showCurve(const UPlotCurve *, bool)));
01900 connect(_legend, SIGNAL(legendItemRemoved(const UPlotCurve *)), this, SLOT(removeCurve(const UPlotCurve *)));
01901 connect(_legend, SIGNAL(legendItemMoved(const UPlotCurve *, int)), this, SLOT(moveCurve(const UPlotCurve *, int)));
01902 }
01903
01904 void UPlot::createActions()
01905 {
01906 _aShowLegend = new QAction(tr("Show legend"), this);
01907 _aShowLegend->setCheckable(true);
01908 _aShowGrid = new QAction(tr("Show grid"), this);
01909 _aShowGrid->setCheckable(true);
01910 _aShowRefreshRate = new QAction(tr("Show refresh rate"), this);
01911 _aShowRefreshRate->setCheckable(true);
01912 _aMouseTracking = new QAction(tr("Mouse tracking"), this);
01913 _aMouseTracking->setCheckable(true);
01914 _aGraphicsView = new QAction(tr("Graphics view"), this);
01915 _aGraphicsView->setCheckable(true);
01916 _aKeepAllData = new QAction(tr("Keep all data"), this);
01917 _aKeepAllData->setCheckable(true);
01918 _aLimit0 = new QAction(tr("No maximum items shown"), this);
01919 _aLimit10 = new QAction(tr("10"), this);
01920 _aLimit50 = new QAction(tr("50"), this);
01921 _aLimit100 = new QAction(tr("100"), this);
01922 _aLimit500 = new QAction(tr("500"), this);
01923 _aLimit1000 = new QAction(tr("1000"), this);
01924 _aLimitCustom = new QAction(tr(""), this);
01925 _aLimit0->setCheckable(true);
01926 _aLimit10->setCheckable(true);
01927 _aLimit50->setCheckable(true);
01928 _aLimit100->setCheckable(true);
01929 _aLimit500->setCheckable(true);
01930 _aLimit1000->setCheckable(true);
01931 _aLimitCustom->setCheckable(true);
01932 _aLimitCustom->setVisible(false);
01933 _aAddVerticalLine = new QAction(tr("Vertical line..."), this);
01934 _aAddHorizontalLine = new QAction(tr("Horizontal line..."), this);
01935 _aChangeTitle = new QAction(tr("Change title"), this);
01936 _aChangeXLabel = new QAction(tr("Change X label..."), this);
01937 _aChangeYLabel = new QAction(tr("Change Y label..."), this);
01938 _aChangeBackgroundColor = new QAction(tr("Change bg color..."), this);
01939 _aYLabelVertical = new QAction(tr("Vertical orientation"), this);
01940 _aYLabelVertical->setCheckable(true);
01941 _aYLabelVertical->setChecked(true);
01942 _aSaveFigure = new QAction(tr("Save figure..."), this);
01943 _aAutoScreenCapture = new QAction(tr("Auto screen capture..."), this);
01944 _aAutoScreenCapture->setCheckable(true);
01945 _aClearData = new QAction(tr("Clear data"), this);
01946
01947 QActionGroup * grpLimit = new QActionGroup(this);
01948 grpLimit->addAction(_aLimit0);
01949 grpLimit->addAction(_aLimit10);
01950 grpLimit->addAction(_aLimit50);
01951 grpLimit->addAction(_aLimit100);
01952 grpLimit->addAction(_aLimit500);
01953 grpLimit->addAction(_aLimit1000);
01954 grpLimit->addAction(_aLimitCustom);
01955 _aLimit0->setChecked(true);
01956 }
01957
01958 void UPlot::createMenus()
01959 {
01960 _menu = new QMenu(tr("Plot"), this);
01961 _menu->addAction(_aShowLegend);
01962 _menu->addAction(_aShowGrid);
01963 _menu->addAction(_aShowRefreshRate);
01964 _menu->addAction(_aMouseTracking);
01965 _menu->addAction(_aGraphicsView);
01966 _menu->addAction(_aKeepAllData);
01967 _menu->addSeparator()->setStatusTip(tr("Maximum items shown"));
01968 _menu->addAction(_aLimit0);
01969 _menu->addAction(_aLimit10);
01970 _menu->addAction(_aLimit50);
01971 _menu->addAction(_aLimit100);
01972 _menu->addAction(_aLimit500);
01973 _menu->addAction(_aLimit1000);
01974 _menu->addAction(_aLimitCustom);
01975 _menu->addSeparator();
01976 QMenu * addLineMenu = _menu->addMenu(tr("Add line"));
01977 addLineMenu->addAction(_aAddHorizontalLine);
01978 addLineMenu->addAction(_aAddVerticalLine);
01979 _menu->addSeparator();
01980 _menu->addAction(_aChangeTitle);
01981 _menu->addAction(_aChangeXLabel);
01982 QMenu * yLabelMenu = _menu->addMenu(tr("Y label"));
01983 yLabelMenu->addAction(_aChangeYLabel);
01984 yLabelMenu->addAction(_aYLabelVertical);
01985 _menu->addAction(_aChangeBackgroundColor);
01986 _menu->addAction(_aSaveFigure);
01987 _menu->addAction(_aAutoScreenCapture);
01988 _menu->addSeparator();
01989 _menu->addAction(_aClearData);
01990
01991 }
01992
01993 UPlotCurve * UPlot::addCurve(const QString & curveName, const QColor & color)
01994 {
01995
01996 UPlotCurve * curve = new UPlotCurve(curveName, this);
01997 if(color.isValid())
01998 {
01999 curve->setPen(color);
02000 }
02001 else
02002 {
02003 curve->setPen(this->getRandomPenColored());
02004 }
02005 this->addCurve(curve);
02006 return curve;
02007 }
02008
02009 bool UPlot::addCurve(UPlotCurve * curve, bool ownershipTransferred)
02010 {
02011 if(curve)
02012 {
02013 #if PRINT_DEBUG
02014 ULOGGER_DEBUG("Adding curve \"%s\" to plot \"%s\"...", curve->name().toStdString().c_str(), this->title().toStdString().c_str());
02015 #endif
02016
02017 if(!qobject_cast<UPlotCurveThreshold*>(curve))
02018 {
02019 for(int i=_curves.size()-1; i>=0; --i)
02020 {
02021 if(!qobject_cast<UPlotCurveThreshold*>(_curves.at(i)))
02022 {
02023 disconnect(_curves.at(i), SIGNAL(dataChanged(const UPlotCurve *)), this, SLOT(updateAxis()));
02024 break;
02025 }
02026 }
02027 }
02028
02029
02030 _curves.append(curve);
02031 curve->attach(this);
02032 curve->setItemsColor(QColor(255-_bgColor.red(), 255-_bgColor.green(), 255-_bgColor.red(), _bgColor.alpha()));
02033 if(ownershipTransferred)
02034 {
02035 curve->setParent(this);
02036 }
02037 this->updateAxis(curve);
02038 curve->setXStart(_axisMaximums[1]);
02039
02040 connect(curve, SIGNAL(dataChanged(const UPlotCurve *)), this, SLOT(updateAxis()));
02041
02042 _legend->addItem(curve);
02043
02044 #if PRINT_DEBUG
02045 ULOGGER_DEBUG("Curve \"%s\" added to plot \"%s\"", curve->name().toStdString().c_str(), this->title().toStdString().c_str());
02046 #endif
02047
02048 return true;
02049 }
02050 else
02051 {
02052 ULOGGER_ERROR("The curve is null!");
02053 }
02054 return false;
02055 }
02056
02057 QStringList UPlot::curveNames()
02058 {
02059 QStringList names;
02060 for(QList<UPlotCurve*>::iterator iter = _curves.begin(); iter!=_curves.end(); ++iter)
02061 {
02062 if(*iter)
02063 {
02064 names.append((*iter)->name());
02065 }
02066 }
02067 return names;
02068 }
02069
02070 bool UPlot::contains(const QString & curveName)
02071 {
02072 for(QList<UPlotCurve*>::iterator iter = _curves.begin(); iter!=_curves.end(); ++iter)
02073 {
02074 if(*iter && (*iter)->name().compare(curveName) == 0)
02075 {
02076 return true;
02077 }
02078 }
02079 return false;
02080 }
02081
02082 QPen UPlot::getRandomPenColored()
02083 {
02084 return QPen((Qt::GlobalColor)(_penStyleCount++ % 12 + 7 ));
02085 }
02086
02087 void UPlot::replot(QPainter * painter)
02088 {
02089 if(_maxVisibleItems>0)
02090 {
02091 UPlotCurve * c = 0;
02092 int maxItem = 0;
02093
02094 for(QList<UPlotCurve *>::iterator i=_curves.begin(); i!=_curves.end(); ++i)
02095 {
02096 if((*i)->isVisible() && ((UPlotCurve *)(*i))->itemsSize() > maxItem)
02097 {
02098 c = *i;
02099 maxItem = c->itemsSize();
02100 }
02101 }
02102 if(c && (maxItem-1)/2+1 > _maxVisibleItems && _axisMaximums[0] < c->getItemData((c->itemsSize()-1) -_maxVisibleItems*2).x())
02103 {
02104 _axisMaximums[0] = c->getItemData((c->itemsSize()-1) -_maxVisibleItems*2).x();
02105 }
02106 }
02107
02108 float axis[4] = {0};
02109 for(int i=0; i<4; ++i)
02110 {
02111 axis[i] = _axisMaximums[i];
02112 }
02113
02114 _verticalAxis->setAxis(axis[2], axis[3]);
02115 _horizontalAxis->setAxis(axis[0], axis[1]);
02116 if(_aGraphicsView->isChecked() && !painter)
02117 {
02118 _verticalAxis->update();
02119 _horizontalAxis->update();
02120 }
02121
02122
02123
02124 QRectF newRect(0,0, _graphicsViewHolder->size().width(), _graphicsViewHolder->size().height());
02125 _view->scene()->setSceneRect(newRect);
02126 float borderHor = (float)_horizontalAxis->border();
02127 float borderVer = (float)_verticalAxis->border();
02128
02129
02130 qDeleteAll(hGridLines);
02131 hGridLines.clear();
02132 qDeleteAll(vGridLines);
02133 vGridLines.clear();
02134 if(_aShowGrid->isChecked())
02135 {
02136
02137 float w = newRect.width()-(borderHor*2);
02138 float h = newRect.height()-(borderVer*2);
02139 float stepH = w / float(_horizontalAxis->count());
02140 float stepV = h / float(_verticalAxis->count());
02141 QPen dashPen(Qt::DashLine);
02142 dashPen.setColor(QColor(255-_bgColor.red(), 255-_bgColor.green(), 255-_bgColor.blue(), 100));
02143 QPen pen(dashPen.color());
02144 for(float i=0.0f; i*stepV <= h+stepV; i+=5.0f)
02145 {
02146
02147 if(!_aGraphicsView->isChecked())
02148 {
02149 if(painter)
02150 {
02151 painter->save();
02152 painter->setPen(pen);
02153 painter->drawLine(0, stepV*i+borderVer+0.5f, borderHor, stepV*i+borderVer+0.5f);
02154
02155 painter->setPen(dashPen);
02156 painter->drawLine(borderHor, stepV*i+borderVer+0.5f, w+borderHor, stepV*i+borderVer+0.5f);
02157
02158 painter->setPen(pen);
02159 painter->drawLine(w+borderHor, stepV*i+borderVer+0.5f, w+borderHor*2, stepV*i+borderVer+0.5f);
02160 painter->restore();
02161 }
02162 }
02163 else
02164 {
02165 hGridLines.append(new QGraphicsLineItem(0, stepV*i+borderVer, borderHor, stepV*i+borderVer, _sceneRoot));
02166 hGridLines.last()->setPen(pen);
02167 hGridLines.append(new QGraphicsLineItem(borderHor, stepV*i+borderVer, w+borderHor, stepV*i+borderVer, _sceneRoot));
02168 hGridLines.last()->setPen(dashPen);
02169 hGridLines.append(new QGraphicsLineItem(w+borderHor, stepV*i+borderVer, w+borderHor*2, stepV*i+borderVer, _sceneRoot));
02170 hGridLines.last()->setPen(pen);
02171 }
02172 }
02173 for(float i=0; i*stepH < w+stepH; i+=5.0f)
02174 {
02175
02176 if(!_aGraphicsView->isChecked())
02177 {
02178 if(painter)
02179 {
02180 painter->save();
02181 painter->setPen(pen);
02182 painter->drawLine(stepH*i+borderHor+0.5f, 0, stepH*i+borderHor+0.5f, borderVer);
02183
02184 painter->setPen(dashPen);
02185 painter->drawLine(stepH*i+borderHor+0.5f, borderVer, stepH*i+borderHor+0.5f, h+borderVer);
02186
02187 painter->setPen(pen);
02188 painter->drawLine(stepH*i+borderHor+0.5f, h+borderVer, stepH*i+borderHor+0.5f, h+borderVer*2);
02189 painter->restore();
02190 }
02191 }
02192 else
02193 {
02194 vGridLines.append(new QGraphicsLineItem(stepH*i+borderHor, 0, stepH*i+borderHor, borderVer, _sceneRoot));
02195 vGridLines.last()->setPen(pen);
02196 vGridLines.append(new QGraphicsLineItem(stepH*i+borderHor, borderVer, stepH*i+borderHor, h+borderVer, _sceneRoot));
02197 vGridLines.last()->setPen(dashPen);
02198 vGridLines.append(new QGraphicsLineItem(stepH*i+borderHor, h+borderVer, stepH*i+borderHor, h+borderVer*2, _sceneRoot));
02199 vGridLines.last()->setPen(pen);
02200 }
02201 }
02202 }
02203
02204
02205 float scaleX = 1;
02206 float scaleY = 1;
02207 float den = 0;
02208 den = axis[1] - axis[0];
02209 if(den != 0)
02210 {
02211 scaleX = (newRect.width()-(borderHor*2)) / den;
02212 }
02213 den = axis[3] - axis[2];
02214 if(den != 0)
02215 {
02216 scaleY = (newRect.height()-(borderVer*2)) / den;
02217 }
02218 for(QList<UPlotCurve *>::iterator i=_curves.begin(); i!=_curves.end(); ++i)
02219 {
02220 if((*i)->isVisible())
02221 {
02222 float xDir = 1.0f;
02223 float yDir = -1.0f;
02224 (*i)->update(scaleX,
02225 scaleY,
02226 xDir<0?axis[1]+borderHor/scaleX:-(axis[0]-borderHor/scaleX),
02227 yDir<0?axis[3]+borderVer/scaleY:-(axis[2]-borderVer/scaleY),
02228 xDir,
02229 yDir,
02230 _aKeepAllData->isChecked()?0:_maxVisibleItems);
02231 if(painter)
02232 {
02233 (*i)->draw(painter, QRect(0,0,_graphicsViewHolder->rect().width(), _graphicsViewHolder->rect().height()));
02234 }
02235 }
02236 }
02237
02238
02239 if(_aShowRefreshRate->isChecked())
02240 {
02241 int refreshRate = qRound(1000.0f/float(_refreshIntervalTime.restart()));
02242 if(refreshRate > 0 && refreshRate < _lowestRefreshRate)
02243 {
02244 _lowestRefreshRate = refreshRate;
02245 }
02246
02247 if(_refreshStartTime.elapsed() > 1000)
02248 {
02249 _refreshRate->setText(QString::number(_lowestRefreshRate));
02250 _lowestRefreshRate = 99;
02251 _refreshStartTime.start();
02252 }
02253 }
02254 }
02255
02256 void UPlot::setFixedXAxis(float x1, float x2)
02257 {
02258 _fixedAxis[0] = true;
02259 _axisMaximums[0] = x1;
02260 _axisMaximums[1] = x2;
02261 }
02262
02263 void UPlot::setFixedYAxis(float y1, float y2)
02264 {
02265 _fixedAxis[1] = true;
02266 _axisMaximums[2] = y1;
02267 _axisMaximums[3] = y2;
02268 }
02269
02270 void UPlot::updateAxis(const UPlotCurve * curve)
02271 {
02272 if(curve && curve->isVisible() && curve->itemsSize() && curve->isMinMaxValid())
02273 {
02274 const QVector<float> & minMax = curve->getMinMax();
02275
02276 if(minMax.size() != 4)
02277 {
02278 ULOGGER_ERROR("minMax size != 4 ?!?");
02279 return;
02280 }
02281 this->updateAxis(minMax[0], minMax[1], minMax[2], minMax[3]);
02282 _aGraphicsView->isChecked()?this->replot(0):this->update();
02283 }
02284 }
02285
02286 bool UPlot::updateAxis(float x1, float x2, float y1, float y2)
02287 {
02288 bool modified = false;
02289 modified = updateAxis(x1,y1);
02290 if(!modified)
02291 {
02292 modified = updateAxis(x2,y2);
02293 }
02294 else
02295 {
02296 updateAxis(x2,y2);
02297 }
02298 return modified;
02299 }
02300
02301 bool UPlot::updateAxis(float x, float y)
02302 {
02303
02304 bool modified = false;
02305 if(!_fixedAxis[0] && (!_axisMaximumsSet[0] || x < _axisMaximums[0]))
02306 {
02307 _axisMaximums[0] = x;
02308 _axisMaximumsSet[0] = true;
02309 modified = true;
02310 }
02311
02312 if(!_fixedAxis[0] && (!_axisMaximumsSet[1] || x > _axisMaximums[1]))
02313 {
02314 _axisMaximums[1] = x;
02315 _axisMaximumsSet[1] = true;
02316 modified = true;
02317 }
02318
02319 if(!_fixedAxis[1] && (!_axisMaximumsSet[2] || y < _axisMaximums[2]))
02320 {
02321 _axisMaximums[2] = y;
02322 _axisMaximumsSet[2] = true;
02323 modified = true;
02324 }
02325
02326 if(!_fixedAxis[1] && (!_axisMaximumsSet[3] || y > _axisMaximums[3]))
02327 {
02328 _axisMaximums[3] = y;
02329 _axisMaximumsSet[3] = true;
02330 modified = true;
02331 }
02332
02333 return modified;
02334 }
02335
02336 void UPlot::updateAxis()
02337 {
02338
02339 for(int i=0; i<4; ++i)
02340 {
02341 if((!_fixedAxis[0] && i<2) || (!_fixedAxis[1] && i>=2))
02342 {
02343 _axisMaximums[i] = 0;
02344 _axisMaximumsSet[i] = false;
02345 }
02346 }
02347
02348 for(int i=0; i<_curves.size(); ++i)
02349 {
02350 if(_curves.at(i)->isVisible() && _curves.at(i)->isMinMaxValid())
02351 {
02352 const QVector<float> & minMax = _curves.at(i)->getMinMax();
02353 this->updateAxis(minMax[0], minMax[1], minMax[2], minMax[3]);
02354 }
02355 }
02356
02357 _aGraphicsView->isChecked()?this->replot(0):this->update();
02358
02359 this->captureScreen();
02360 }
02361
02362 void UPlot::paintEvent(QPaintEvent * event)
02363 {
02364 #if PRINT_DEBUG
02365 UDEBUG("");
02366 #endif
02367 if(!_aGraphicsView->isChecked())
02368 {
02369 QPainter painter(this);
02370 painter.translate(_graphicsViewHolder->pos());
02371 painter.save();
02372 painter.setBrush(_bgColor);
02373 painter.setPen(QPen(Qt::NoPen));
02374 painter.drawRect(_graphicsViewHolder->rect());
02375 painter.restore();
02376
02377 this->replot(&painter);
02378
02379 if(_mouseCurrentPos != _mousePressedPos)
02380 {
02381 painter.save();
02382 int left, top, right, bottom;
02383 left = _mousePressedPos.x() < _mouseCurrentPos.x() ? _mousePressedPos.x()-_graphicsViewHolder->x():_mouseCurrentPos.x()-_graphicsViewHolder->x();
02384 top = _mousePressedPos.y() < _mouseCurrentPos.y() ? _mousePressedPos.y()-1-_graphicsViewHolder->y():_mouseCurrentPos.y()-1-_graphicsViewHolder->y();
02385 right = _mousePressedPos.x() > _mouseCurrentPos.x() ? _mousePressedPos.x()-_graphicsViewHolder->x():_mouseCurrentPos.x()-_graphicsViewHolder->x();
02386 bottom = _mousePressedPos.y() > _mouseCurrentPos.y() ? _mousePressedPos.y()-_graphicsViewHolder->y():_mouseCurrentPos.y()-_graphicsViewHolder->y();
02387 if(left <= 0)
02388 {
02389 left = 1;
02390 }
02391 if(right >= _graphicsViewHolder->width())
02392 {
02393 right = _graphicsViewHolder->width()-1;
02394 }
02395 if(top <= 0)
02396 {
02397 top = 1;
02398 }
02399 if(bottom >= _graphicsViewHolder->height())
02400 {
02401 bottom = _graphicsViewHolder->height()-1;
02402 }
02403 painter.setPen(Qt::NoPen);
02404 painter.setBrush(QBrush(QColor(255-_bgColor.red(),255-_bgColor.green(),255-_bgColor.blue(),100)));
02405 painter.drawRect(0, 0, _graphicsViewHolder->width(), top);
02406 painter.drawRect(0, top, left, bottom-top);
02407 painter.drawRect(right, top, _graphicsViewHolder->width()-right, bottom-top);
02408 painter.drawRect(0, bottom, _graphicsViewHolder->width(), _graphicsViewHolder->height()-bottom);
02409 painter.restore();
02410 }
02411 }
02412 else
02413 {
02414 QWidget::paintEvent(event);
02415 }
02416 }
02417
02418 void UPlot::resizeEvent(QResizeEvent * event)
02419 {
02420 if(_aGraphicsView->isChecked())
02421 {
02422 this->replot(0);
02423 }
02424 QWidget::resizeEvent(event);
02425 }
02426
02427 void UPlot::mousePressEvent(QMouseEvent * event)
02428 {
02429 _mousePressedPos = event->pos();
02430 _mouseCurrentPos = _mousePressedPos;
02431 QWidget::mousePressEvent(event);
02432 }
02433
02434 void UPlot::mouseMoveEvent(QMouseEvent * event)
02435 {
02436 if(!_aGraphicsView->isChecked())
02437 {
02438 if(!(QApplication::mouseButtons() & Qt::LeftButton))
02439 {
02440 _mousePressedPos = _mouseCurrentPos;
02441 }
02442
02443 float x,y;
02444 if(mousePosToValue(event->pos(), x ,y))
02445 {
02446 if(QApplication::mouseButtons() & Qt::LeftButton)
02447 {
02448 _mouseCurrentPos = event->pos();
02449 this->update();
02450 }
02451
02452 int xPos = event->pos().x() - _graphicsViewHolder->pos().x();
02453 int yPos = event->pos().y() - _graphicsViewHolder->pos().y();
02454 if((QApplication::mouseButtons() & Qt::LeftButton) ||
02455 (_aMouseTracking->isChecked() && xPos>=0 && yPos>=0 && xPos<_graphicsViewHolder->width() && yPos<_graphicsViewHolder->height()))
02456 {
02457 QToolTip::showText(event->globalPos(), QString("%1,%2").arg(x).arg(y));
02458 }
02459 else
02460 {
02461 QToolTip::hideText();
02462 }
02463 }
02464 else
02465 {
02466 QToolTip::hideText();
02467 }
02468 }
02469 QWidget::mouseMoveEvent(event);
02470 }
02471
02472 void UPlot::mouseReleaseEvent(QMouseEvent * event)
02473 {
02474 if(_mousePressedPos != _mouseCurrentPos)
02475 {
02476 int left,top,bottom,right;
02477
02478 left = _mousePressedPos.x() < _mouseCurrentPos.x() ? _mousePressedPos.x():_mouseCurrentPos.x();
02479 top = _mousePressedPos.y() < _mouseCurrentPos.y() ? _mousePressedPos.y():_mouseCurrentPos.y();
02480 right = _mousePressedPos.x() > _mouseCurrentPos.x() ? _mousePressedPos.x():_mouseCurrentPos.x();
02481 bottom = _mousePressedPos.y() > _mouseCurrentPos.y() ? _mousePressedPos.y():_mouseCurrentPos.y();
02482
02483 if(right - left > 5 || bottom - top > 5)
02484 {
02485 float axis[4];
02486 if(mousePosToValue(QPoint(left, top), axis[0], axis[3]) && mousePosToValue(QPoint(right, bottom), axis[1], axis[2]))
02487 {
02488 #if PRINT_DEBUG
02489 UDEBUG("resize! new axis = [%f, %f, %f, %f]", axis[0], axis[1], axis[2], axis[3]);
02490 #endif
02491
02492 for(int i=0; i<4; ++i)
02493 {
02494 if((!_fixedAxis[0] && i<2) || (!_fixedAxis[1] && i>=2))
02495 {
02496 _axisMaximums[i] = axis[i];
02497 }
02498 }
02499 _aGraphicsView->isChecked()?this->replot(0):this->update();
02500 }
02501 }
02502 _mousePressedPos = _mouseCurrentPos;
02503 }
02504 QWidget::mouseReleaseEvent(event);
02505 }
02506
02507 void UPlot::mouseDoubleClickEvent(QMouseEvent * event)
02508 {
02509 this->updateAxis();
02510 QWidget::mouseDoubleClickEvent(event);
02511 }
02512
02513 bool UPlot::mousePosToValue(const QPoint & pos, float & x, float & y)
02514 {
02515 int xPos = pos.x() - _graphicsViewHolder->pos().x() - _horizontalAxis->border();
02516 int yPos = pos.y() - _graphicsViewHolder->pos().y() - _verticalAxis->border();
02517 int maxX = _graphicsViewHolder->width() - _horizontalAxis->border()*2;
02518 int maxY = _graphicsViewHolder->height() - _verticalAxis->border()*2;
02519 if(maxX == 0 || maxY == 0)
02520 {
02521 return false;
02522 }
02523
02524 if(xPos < 0)
02525 {
02526 xPos = 0;
02527 }
02528 else if(xPos > maxX)
02529 {
02530 xPos = maxX;
02531 }
02532
02533 if(yPos < 0)
02534 {
02535 yPos = 0;
02536 }
02537 else if(yPos > maxY)
02538 {
02539 yPos = maxY;
02540 }
02541
02542
02543
02544
02545
02546
02547
02548
02549
02550
02551 x = _axisMaximums[0] + float(xPos)*(_axisMaximums[1] - _axisMaximums[0]) / float(maxX);
02552 y = _axisMaximums[2] + float(maxY - yPos)*(_axisMaximums[3] - _axisMaximums[2]) / float(maxY);
02553 return true;
02554 }
02555
02556 void UPlot::contextMenuEvent(QContextMenuEvent * event)
02557 {
02558 QAction * action = _menu->exec(event->globalPos());
02559
02560 if(!action)
02561 {
02562 return;
02563 }
02564 else if(action == _aShowLegend)
02565 {
02566 this->showLegend(_aShowLegend->isChecked());
02567 }
02568 else if(action == _aShowGrid)
02569 {
02570 this->showGrid(_aShowGrid->isChecked());
02571 }
02572 else if(action == _aShowRefreshRate)
02573 {
02574 this->showRefreshRate(_aShowRefreshRate->isChecked());
02575 }
02576 else if(action == _aMouseTracking)
02577 {
02578 this->trackMouse(_aMouseTracking->isChecked());
02579 }
02580 else if(action == _aGraphicsView)
02581 {
02582 this->setGraphicsView(_aGraphicsView->isChecked());
02583 }
02584 else if(action == _aKeepAllData)
02585 {
02586 this->keepAllData(_aKeepAllData->isChecked());
02587 }
02588 else if(action == _aLimit0 ||
02589 action == _aLimit10 ||
02590 action == _aLimit50 ||
02591 action == _aLimit100 ||
02592 action == _aLimit500 ||
02593 action == _aLimit1000 ||
02594 action == _aLimitCustom)
02595 {
02596 this->setMaxVisibleItems(action->text().toInt());
02597 }
02598 else if(action == _aAddVerticalLine || action == _aAddHorizontalLine)
02599 {
02600 bool ok;
02601 QString text = QInputDialog::getText(this, action->text(), tr("New line name :"), QLineEdit::Normal, "", &ok);
02602 while(ok && text.isEmpty())
02603 {
02604 QMessageBox::warning(this, action->text(), tr("The name is not valid or it is already used in this plot."));
02605 text = QInputDialog::getText(this, action->text(), tr("New line name :"), QLineEdit::Normal, "", &ok);
02606 }
02607 if(ok)
02608 {
02609 double min = _axisMaximums[2];
02610 double max = _axisMaximums[3];
02611 QString axis = "Y";
02612 if(action == _aAddVerticalLine)
02613 {
02614 min = _axisMaximums[0];
02615 max = _axisMaximums[1];
02616 axis = "X";
02617 }
02618 double value = QInputDialog::getDouble(this,
02619 action->text(),
02620 tr("%1 value (min=%2, max=%3):").arg(axis).arg(min).arg(max),
02621 (min+max)/2,
02622 -2147483647,
02623 2147483647,
02624 4,
02625 &ok);
02626 if(ok)
02627 {
02628 if(action == _aAddHorizontalLine)
02629 {
02630 this->addThreshold(text, value, Qt::Horizontal);
02631 }
02632 else
02633 {
02634 this->addThreshold(text, value, Qt::Vertical);
02635 }
02636 }
02637 }
02638 }
02639 else if(action == _aChangeTitle)
02640 {
02641 bool ok;
02642 QString text = _title->text();
02643 if(text.isEmpty())
02644 {
02645 text = this->objectName();
02646 }
02647 text = QInputDialog::getText(this, _aChangeTitle->text(), tr("Title :"), QLineEdit::Normal, text, &ok);
02648 if(ok)
02649 {
02650 this->setTitle(text);
02651 }
02652 }
02653 else if(action == _aChangeXLabel)
02654 {
02655 bool ok;
02656 QString text = QInputDialog::getText(this, _aChangeXLabel->text(), tr("X axis label :"), QLineEdit::Normal, _xLabel->text(), &ok);
02657 if(ok)
02658 {
02659 this->setXLabel(text);
02660 }
02661 }
02662 else if(action == _aChangeYLabel)
02663 {
02664 bool ok;
02665 QString text = QInputDialog::getText(this, _aChangeYLabel->text(), tr("Y axis label :"), QLineEdit::Normal, _yLabel->text(), &ok);
02666 if(ok)
02667 {
02668 this->setYLabel(text, _yLabel->orientation());
02669 }
02670 }
02671 else if(action == _aYLabelVertical)
02672 {
02673 this->setYLabel(_yLabel->text(), _aYLabelVertical->isChecked()?Qt::Vertical:Qt::Horizontal);
02674 }
02675 else if(action == _aChangeBackgroundColor)
02676 {
02677 QColor color = QColorDialog::getColor(_bgColor, this);
02678 if(color.isValid())
02679 {
02680 this->setBackgroundColor(color);
02681 }
02682 }
02683 else if(action == _aSaveFigure)
02684 {
02685
02686 QString text;
02687 #ifdef QT_SVG_LIB
02688 text = QFileDialog::getSaveFileName(this, tr("Save figure to ..."), (QDir::homePath() + "/") + this->title() + ".png", "*.png *.xpm *.jpg *.pdf *.svg");
02689 #else
02690 text = QFileDialog::getSaveFileName(this, tr("Save figure to ..."), (QDir::homePath() + "/") + this->title() + ".png", "*.png *.xpm *.jpg *.pdf");
02691 #endif
02692 if(!text.isEmpty())
02693 {
02694 bool flatModified = false;
02695 if(!_legend->isFlat())
02696 {
02697 _legend->setFlat(true);
02698 flatModified = true;
02699 }
02700
02701 QPalette p(palette());
02702
02703 QColor c = p.color(QPalette::Background);
02704 p.setColor(QPalette::Background, Qt::white);
02705 setPalette(p);
02706
02707 #ifdef QT_SVG_LIB
02708 if(QFileInfo(text).suffix().compare("svg") == 0)
02709 {
02710 QSvgGenerator generator;
02711 generator.setFileName(text);
02712 generator.setSize(this->size());
02713 QPainter painter;
02714 painter.begin(&generator);
02715 this->render(&painter);
02716 painter.end();
02717 }
02718 else
02719 {
02720 #endif
02721 if(QFileInfo(text).suffix().compare("pdf") == 0)
02722 {
02723 QPrinter printer;
02724 printer.setOutputFormat(QPrinter::PdfFormat);
02725 printer.setOutputFileName(text);
02726 this->render(&printer);
02727 }
02728 else
02729 {
02730 QPixmap figure = QPixmap::grabWidget(this);
02731 figure.save(text);
02732 }
02733 #ifdef QT_SVG_LIB
02734 }
02735 #endif
02736
02737 p.setColor(QPalette::Background, c);
02738 setPalette(p);
02739
02740 if(flatModified)
02741 {
02742 _legend->setFlat(false);
02743 }
02744 }
02745 }
02746 else if(action == _aAutoScreenCapture)
02747 {
02748 if(_aAutoScreenCapture->isChecked())
02749 {
02750 this->selectScreenCaptureFormat();
02751 }
02752 }
02753 else if(action == _aClearData)
02754 {
02755 this->clearData();
02756 }
02757 else
02758 {
02759 ULOGGER_WARN("Unknown action");
02760 }
02761 }
02762
02763 void UPlot::setWorkingDirectory(const QString & workingDirectory)
02764 {
02765 if(QDir(_workingDirectory).exists())
02766 {
02767 _workingDirectory = workingDirectory;
02768 }
02769 else
02770 {
02771 ULOGGER_ERROR("The directory \"%s\" doesn't exist", workingDirectory.toStdString().c_str());
02772 }
02773 }
02774
02775 void UPlot::captureScreen()
02776 {
02777 if(!_aAutoScreenCapture->isChecked())
02778 {
02779 return;
02780 }
02781 QString targetDir = _workingDirectory + "/ScreensCaptured";
02782 QDir dir;
02783 if(!dir.exists(targetDir))
02784 {
02785 dir.mkdir(targetDir);
02786 }
02787 targetDir += "/";
02788 targetDir += this->title().replace(" ", "_");
02789 if(!dir.exists(targetDir))
02790 {
02791 dir.mkdir(targetDir);
02792 }
02793 targetDir += "/";
02794 QString name = (QDateTime::currentDateTime().toString("yyMMddhhmmsszzz") + ".") + _autoScreenCaptureFormat;
02795 QPixmap figure = QPixmap::grabWidget(this);
02796 figure.save(targetDir + name);
02797 }
02798
02799 void UPlot::selectScreenCaptureFormat()
02800 {
02801 QStringList items;
02802 items << QString("png") << QString("jpg");
02803 bool ok;
02804 QString item = QInputDialog::getItem(this, tr("Select format"), tr("Format:"), items, 0, false, &ok);
02805 if(ok && !item.isEmpty())
02806 {
02807 _autoScreenCaptureFormat = item;
02808 }
02809 this->captureScreen();
02810 }
02811
02812 void UPlot::clearData()
02813 {
02814 for(int i=0; i<_curves.size(); ++i)
02815 {
02816
02817 if(qobject_cast<UPlotCurveThreshold*>(_curves.at(i)) == 0)
02818 {
02819 _curves.at(i)->clear();
02820 }
02821 }
02822 _aGraphicsView->isChecked()?this->replot(0):this->update();
02823 }
02824
02825
02826 UPlotCurveThreshold * UPlot::addThreshold(const QString & name, float value, Qt::Orientation orientation)
02827 {
02828 UPlotCurveThreshold * curve = new UPlotCurveThreshold(name, value, orientation, this);
02829 QPen pen = curve->pen();
02830 pen.setStyle((Qt::PenStyle)(_penStyleCount++ % 4 + 2));
02831 curve->setPen(pen);
02832 if(!this->addCurve(curve))
02833 {
02834 if(curve)
02835 {
02836 delete curve;
02837 }
02838 }
02839 else
02840 {
02841 _aGraphicsView->isChecked()?this->replot(0):this->update();
02842 }
02843 return curve;
02844 }
02845
02846 void UPlot::setTitle(const QString & text)
02847 {
02848 _title->setText(text);
02849 _title->setVisible(!text.isEmpty());
02850 this->update();
02851 if(_aGraphicsView->isChecked())
02852 {
02853 QTimer::singleShot(10, this, SLOT(updateAxis()));
02854 }
02855 }
02856
02857 void UPlot::setXLabel(const QString & text)
02858 {
02859 _xLabel->setText(text);
02860 _xLabel->setVisible(!text.isEmpty());
02861 this->update();
02862 if(_aGraphicsView->isChecked())
02863 {
02864 QTimer::singleShot(10, this, SLOT(updateAxis()));
02865 }
02866 }
02867
02868 void UPlot::setYLabel(const QString & text, Qt::Orientation orientation)
02869 {
02870 _yLabel->setText(text);
02871 _yLabel->setOrientation(orientation);
02872 _yLabel->setVisible(!text.isEmpty());
02873 _aYLabelVertical->setChecked(orientation==Qt::Vertical);
02874 this->update();
02875 if(_aGraphicsView->isChecked())
02876 {
02877 QTimer::singleShot(10, this, SLOT(updateAxis()));
02878 }
02879 }
02880
02881 void UPlot::setBackgroundColor(const QColor & color)
02882 {
02883 if(color.isValid())
02884 {
02885 _bgColor = color;
02886 _view->scene()->setBackgroundBrush(QBrush(_bgColor));
02887 for(QList<UPlotCurve*>::iterator iter=_curves.begin(); iter!=_curves.end(); ++iter)
02888 {
02889 (*iter)->setItemsColor(QColor(255-_bgColor.red(), 255-_bgColor.green(), 255-_bgColor.blue(), _bgColor.alpha()));
02890 }
02891 }
02892 }
02893
02894 void UPlot::addItem(QGraphicsItem * item)
02895 {
02896 item->setParentItem(_sceneRoot);
02897 item->setZValue(1.0f);
02898 }
02899
02900 void UPlot::showLegend(bool shown)
02901 {
02902 _legend->setVisible(shown);
02903 _aShowLegend->setChecked(shown);
02904 this->update();
02905 if(_aGraphicsView->isChecked())
02906 {
02907 QTimer::singleShot(10, this, SLOT(updateAxis()));
02908 }
02909 }
02910
02911 void UPlot::showGrid(bool shown)
02912 {
02913 _aShowGrid->setChecked(shown);
02914 _aGraphicsView->isChecked()?this->replot(0):this->update();
02915 }
02916
02917 void UPlot::showRefreshRate(bool shown)
02918 {
02919 _aShowRefreshRate->setChecked(shown);
02920 _refreshRate->setVisible(shown);
02921 this->update();
02922 if(_aGraphicsView->isChecked())
02923 {
02924 QTimer::singleShot(10, this, SLOT(updateAxis()));
02925 }
02926 }
02927
02928 void UPlot::trackMouse(bool tracking)
02929 {
02930 _aMouseTracking->setChecked(tracking);
02931 this->setMouseTracking(tracking);
02932 }
02933
02934 void UPlot::setGraphicsView(bool on)
02935 {
02936 _aGraphicsView->setChecked(on);
02937 _view->setVisible(on);
02938 _aGraphicsView->isChecked()?this->replot(0):this->update();
02939 _aMouseTracking->setEnabled(!on);
02940 }
02941
02942 void UPlot::keepAllData(bool kept)
02943 {
02944 _aKeepAllData->setChecked(kept);
02945 }
02946
02947 void UPlot::setMaxVisibleItems(int maxVisibleItems)
02948 {
02949 if(maxVisibleItems <= 0)
02950 {
02951 _aLimit0->setChecked(true);
02952 }
02953 else if(maxVisibleItems == 10)
02954 {
02955 _aLimit10->setChecked(true);
02956 }
02957 else if(maxVisibleItems == 50)
02958 {
02959 _aLimit50->setChecked(true);
02960 }
02961 else if(maxVisibleItems == 100)
02962 {
02963 _aLimit100->setChecked(true);
02964 }
02965 else if(maxVisibleItems == 500)
02966 {
02967 _aLimit500->setChecked(true);
02968 }
02969 else if(maxVisibleItems == 1000)
02970 {
02971 _aLimit1000->setChecked(true);
02972 }
02973 else
02974 {
02975 _aLimitCustom->setVisible(true);
02976 _aLimitCustom->setChecked(true);
02977 _aLimitCustom->setText(QString::number(maxVisibleItems));
02978 }
02979 _maxVisibleItems = maxVisibleItems;
02980 updateAxis();
02981 }
02982
02983 QRectF UPlot::sceneRect() const
02984 {
02985 return _view->sceneRect();
02986 }
02987
02988 void UPlot::removeCurves()
02989 {
02990 QList<UPlotCurve*> tmp = _curves;
02991 for(QList<UPlotCurve*>::iterator iter=tmp.begin(); iter!=tmp.end(); ++iter)
02992 {
02993 this->removeCurve(*iter);
02994 }
02995 _curves.clear();
02996 }
02997
02998 void UPlot::removeCurve(const UPlotCurve * curve)
02999 {
03000 QList<UPlotCurve *>::iterator iter = qFind(_curves.begin(), _curves.end(), curve);
03001 #if PRINT_DEBUG
03002 ULOGGER_DEBUG("Plot=\"%s\" removing curve=\"%s\"", this->objectName().toStdString().c_str(), curve?curve->name().toStdString().c_str():"");
03003 #endif
03004 if(iter!=_curves.end())
03005 {
03006 UPlotCurve * c = *iter;
03007 c->detach(this);
03008 _curves.erase(iter);
03009 _legend->remove(c);
03010 if(!qobject_cast<UPlotCurveThreshold*>(c))
03011 {
03012
03013 for(int i=_curves.size()-1; i>=0; --i)
03014 {
03015 if(!qobject_cast<UPlotCurveThreshold*>(_curves.at(i)))
03016 {
03017 connect(_curves.at(i), SIGNAL(dataChanged(const UPlotCurve *)), this, SLOT(updateAxis()));
03018 break;
03019 }
03020 }
03021 }
03022
03023 if(c->parent() == this)
03024 {
03025 delete c;
03026 }
03027
03028 updateAxis();
03029 }
03030 }
03031
03032 void UPlot::showCurve(const UPlotCurve * curve, bool shown)
03033 {
03034 QList<UPlotCurve *>::iterator iter = qFind(_curves.begin(), _curves.end(), curve);
03035 if(iter!=_curves.end())
03036 {
03037 UPlotCurve * value = *iter;
03038 if(value->isVisible() != shown)
03039 {
03040 value->setVisible(shown);
03041 this->updateAxis();
03042 }
03043 }
03044 }
03045
03046 void UPlot::moveCurve(const UPlotCurve * curve, int index)
03047 {
03048
03049 int currentIndex = -1;
03050 UPlotCurve * c = 0;
03051 for(int i=0; i<_curves.size(); ++i)
03052 {
03053 if(_curves.at(i) == curve)
03054 {
03055 c = _curves.at(i);
03056 currentIndex = i;
03057 break;
03058 }
03059 }
03060
03061 if(c && currentIndex != index)
03062 {
03063 _curves.removeAt(currentIndex);
03064 QList<QGraphicsItem *> children = _sceneRoot->childItems();
03065 _curves.insert(index, c);
03066 if(currentIndex > index)
03067 {
03068 children[currentIndex]->stackBefore(children[index]);
03069 }
03070 else
03071 {
03072 if(currentIndex<children.size()-2)
03073 {
03074 if(index < children.size()-1)
03075 {
03076 children[index]->stackBefore(children[currentIndex]);
03077 }
03078 else
03079 {
03080 children[currentIndex]->stackBefore(children[index]);
03081 }
03082 }
03083 if(currentIndex == children.size()-2 && currentIndex < index)
03084 {
03085 children[index]->stackBefore(children[currentIndex]);
03086 }
03087 }
03088 this->update();
03089 }
03090 }