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