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 Q_EMIT dataChanged(this);
00427 }
00428 }
00429
00430 void UPlotCurve::addValue(float x, float y)
00431 {
00432 if(_items.size() &&
00433 _minMax[0] != _minMax[1] &&
00434 x < _minMax[1])
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 Q_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 Q_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 Q_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 Q_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 Q_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 Q_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
00827
00828
00829
00830
00831
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 Q_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 Q_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 Q_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 Q_EMIT legendItemRemoved(_curve);
01463 }
01464 else if(action == _aMoveUp)
01465 {
01466 Q_EMIT moveUpRequest(this);
01467 }
01468 else if(action == _aMoveDown)
01469 {
01470 Q_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 Q_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 Q_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 Q_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 Q_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 = 0;
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 int penStyle = 0;
02085 bool colorNotUsed = false;
02086 for(int i=0; i<12; ++i)
02087 {
02088 QColor tmp((Qt::GlobalColor)((penStyle+i) % 12 + 7 ));
02089 bool colorAlreadyUsed = false;
02090 for(QList<UPlotCurve*>::const_iterator iter = _curves.constBegin(); iter!=_curves.constEnd() && !colorAlreadyUsed; ++iter)
02091 {
02092 colorAlreadyUsed = (*iter)->pen().color() == tmp;
02093 }
02094 if(!colorAlreadyUsed)
02095 {
02096 colorNotUsed = true;
02097 penStyle+=i;
02098 break;
02099 }
02100 }
02101 if(colorNotUsed)
02102 {
02103 _penStyleCount = penStyle;
02104 }
02105
02106 return QPen((Qt::GlobalColor)(_penStyleCount++ % 12 + 7 ));
02107 }
02108
02109 void UPlot::replot(QPainter * painter)
02110 {
02111 if(_maxVisibleItems>0)
02112 {
02113 UPlotCurve * c = 0;
02114 int maxItem = 0;
02115
02116 for(QList<UPlotCurve *>::iterator i=_curves.begin(); i!=_curves.end(); ++i)
02117 {
02118 if((*i)->isVisible() && ((UPlotCurve *)(*i))->itemsSize() > maxItem)
02119 {
02120 c = *i;
02121 maxItem = c->itemsSize();
02122 }
02123 }
02124 if(c && (maxItem-1)/2+1 > _maxVisibleItems && _axisMaximums[0] < c->getItemData((c->itemsSize()-1) -_maxVisibleItems*2).x())
02125 {
02126 _axisMaximums[0] = c->getItemData((c->itemsSize()-1) -_maxVisibleItems*2).x();
02127 }
02128 }
02129
02130 float axis[4] = {0};
02131 for(int i=0; i<4; ++i)
02132 {
02133 axis[i] = _axisMaximums[i];
02134 }
02135
02136 _verticalAxis->setAxis(axis[2], axis[3]);
02137 _horizontalAxis->setAxis(axis[0], axis[1]);
02138 if(_aGraphicsView->isChecked() && !painter)
02139 {
02140 _verticalAxis->update();
02141 _horizontalAxis->update();
02142 }
02143
02144
02145
02146 QRectF newRect(0,0, _graphicsViewHolder->size().width(), _graphicsViewHolder->size().height());
02147 _view->scene()->setSceneRect(newRect);
02148 float borderHor = (float)_horizontalAxis->border();
02149 float borderVer = (float)_verticalAxis->border();
02150
02151
02152 qDeleteAll(hGridLines);
02153 hGridLines.clear();
02154 qDeleteAll(vGridLines);
02155 vGridLines.clear();
02156 if(_aShowGrid->isChecked())
02157 {
02158
02159 float w = newRect.width()-(borderHor*2);
02160 float h = newRect.height()-(borderVer*2);
02161 float stepH = w / float(_horizontalAxis->count());
02162 float stepV = h / float(_verticalAxis->count());
02163 QPen dashPen(Qt::DashLine);
02164 dashPen.setColor(QColor(255-_bgColor.red(), 255-_bgColor.green(), 255-_bgColor.blue(), 100));
02165 QPen pen(dashPen.color());
02166 for(float i=0.0f; i*stepV <= h+stepV; i+=5.0f)
02167 {
02168
02169 if(!_aGraphicsView->isChecked())
02170 {
02171 if(painter)
02172 {
02173 painter->save();
02174 painter->setPen(pen);
02175 painter->drawLine(0, stepV*i+borderVer+0.5f, borderHor, stepV*i+borderVer+0.5f);
02176
02177 painter->setPen(dashPen);
02178 painter->drawLine(borderHor, stepV*i+borderVer+0.5f, w+borderHor, stepV*i+borderVer+0.5f);
02179
02180 painter->setPen(pen);
02181 painter->drawLine(w+borderHor, stepV*i+borderVer+0.5f, w+borderHor*2, stepV*i+borderVer+0.5f);
02182 painter->restore();
02183 }
02184 }
02185 else
02186 {
02187 hGridLines.append(new QGraphicsLineItem(0, stepV*i+borderVer, borderHor, stepV*i+borderVer, _sceneRoot));
02188 hGridLines.last()->setPen(pen);
02189 hGridLines.append(new QGraphicsLineItem(borderHor, stepV*i+borderVer, w+borderHor, stepV*i+borderVer, _sceneRoot));
02190 hGridLines.last()->setPen(dashPen);
02191 hGridLines.append(new QGraphicsLineItem(w+borderHor, stepV*i+borderVer, w+borderHor*2, stepV*i+borderVer, _sceneRoot));
02192 hGridLines.last()->setPen(pen);
02193 }
02194 }
02195 for(float i=0; i*stepH < w+stepH; i+=5.0f)
02196 {
02197
02198 if(!_aGraphicsView->isChecked())
02199 {
02200 if(painter)
02201 {
02202 painter->save();
02203 painter->setPen(pen);
02204 painter->drawLine(stepH*i+borderHor+0.5f, 0, stepH*i+borderHor+0.5f, borderVer);
02205
02206 painter->setPen(dashPen);
02207 painter->drawLine(stepH*i+borderHor+0.5f, borderVer, stepH*i+borderHor+0.5f, h+borderVer);
02208
02209 painter->setPen(pen);
02210 painter->drawLine(stepH*i+borderHor+0.5f, h+borderVer, stepH*i+borderHor+0.5f, h+borderVer*2);
02211 painter->restore();
02212 }
02213 }
02214 else
02215 {
02216 vGridLines.append(new QGraphicsLineItem(stepH*i+borderHor, 0, stepH*i+borderHor, borderVer, _sceneRoot));
02217 vGridLines.last()->setPen(pen);
02218 vGridLines.append(new QGraphicsLineItem(stepH*i+borderHor, borderVer, stepH*i+borderHor, h+borderVer, _sceneRoot));
02219 vGridLines.last()->setPen(dashPen);
02220 vGridLines.append(new QGraphicsLineItem(stepH*i+borderHor, h+borderVer, stepH*i+borderHor, h+borderVer*2, _sceneRoot));
02221 vGridLines.last()->setPen(pen);
02222 }
02223 }
02224 }
02225
02226
02227 float scaleX = 1;
02228 float scaleY = 1;
02229 float den = 0;
02230 den = axis[1] - axis[0];
02231 if(den != 0)
02232 {
02233 scaleX = (newRect.width()-(borderHor*2)) / den;
02234 }
02235 den = axis[3] - axis[2];
02236 if(den != 0)
02237 {
02238 scaleY = (newRect.height()-(borderVer*2)) / den;
02239 }
02240 for(QList<UPlotCurve *>::iterator i=_curves.begin(); i!=_curves.end(); ++i)
02241 {
02242 if((*i)->isVisible())
02243 {
02244 float xDir = 1.0f;
02245 float yDir = -1.0f;
02246 (*i)->update(scaleX,
02247 scaleY,
02248 xDir<0?axis[1]+borderHor/scaleX:-(axis[0]-borderHor/scaleX),
02249 yDir<0?axis[3]+borderVer/scaleY:-(axis[2]-borderVer/scaleY),
02250 xDir,
02251 yDir,
02252 _aKeepAllData->isChecked()?0:_maxVisibleItems);
02253 if(painter)
02254 {
02255 (*i)->draw(painter, QRect(0,0,_graphicsViewHolder->rect().width(), _graphicsViewHolder->rect().height()));
02256 }
02257 }
02258 }
02259
02260
02261 if(_aShowRefreshRate->isChecked())
02262 {
02263 int refreshRate = qRound(1000.0f/float(_refreshIntervalTime.restart()));
02264 if(refreshRate > 0 && refreshRate < _lowestRefreshRate)
02265 {
02266 _lowestRefreshRate = refreshRate;
02267 }
02268
02269 if(_refreshStartTime.elapsed() > 1000)
02270 {
02271 _refreshRate->setText(QString::number(_lowestRefreshRate));
02272 _lowestRefreshRate = 99;
02273 _refreshStartTime.start();
02274 }
02275 }
02276 }
02277
02278 void UPlot::setFixedXAxis(float x1, float x2)
02279 {
02280 _fixedAxis[0] = true;
02281 _axisMaximums[0] = x1;
02282 _axisMaximums[1] = x2;
02283 }
02284
02285 void UPlot::setFixedYAxis(float y1, float y2)
02286 {
02287 _fixedAxis[1] = true;
02288 _axisMaximums[2] = y1;
02289 _axisMaximums[3] = y2;
02290 }
02291
02292 void UPlot::updateAxis(const UPlotCurve * curve)
02293 {
02294 if(curve && curve->isVisible() && curve->itemsSize() && curve->isMinMaxValid())
02295 {
02296 const QVector<float> & minMax = curve->getMinMax();
02297
02298 if(minMax.size() != 4)
02299 {
02300 ULOGGER_ERROR("minMax size != 4 ?!?");
02301 return;
02302 }
02303 this->updateAxis(minMax[0], minMax[1], minMax[2], minMax[3]);
02304 _aGraphicsView->isChecked()?this->replot(0):this->update();
02305 }
02306 }
02307
02308 bool UPlot::updateAxis(float x1, float x2, float y1, float y2)
02309 {
02310 bool modified = false;
02311 modified = updateAxis(x1,y1);
02312 if(!modified)
02313 {
02314 modified = updateAxis(x2,y2);
02315 }
02316 else
02317 {
02318 updateAxis(x2,y2);
02319 }
02320 return modified;
02321 }
02322
02323 bool UPlot::updateAxis(float x, float y)
02324 {
02325
02326 bool modified = false;
02327 if(!_fixedAxis[0] && (!_axisMaximumsSet[0] || x < _axisMaximums[0]))
02328 {
02329 _axisMaximums[0] = x;
02330 _axisMaximumsSet[0] = true;
02331 modified = true;
02332 }
02333
02334 if(!_fixedAxis[0] && (!_axisMaximumsSet[1] || x > _axisMaximums[1]))
02335 {
02336 _axisMaximums[1] = x;
02337 _axisMaximumsSet[1] = true;
02338 modified = true;
02339 }
02340
02341 if(!_fixedAxis[1] && (!_axisMaximumsSet[2] || y < _axisMaximums[2]))
02342 {
02343 _axisMaximums[2] = y;
02344 _axisMaximumsSet[2] = true;
02345 modified = true;
02346 }
02347
02348 if(!_fixedAxis[1] && (!_axisMaximumsSet[3] || y > _axisMaximums[3]))
02349 {
02350 _axisMaximums[3] = y;
02351 _axisMaximumsSet[3] = true;
02352 modified = true;
02353 }
02354
02355 return modified;
02356 }
02357
02358 void UPlot::updateAxis()
02359 {
02360
02361 for(int i=0; i<4; ++i)
02362 {
02363 if((!_fixedAxis[0] && i<2) || (!_fixedAxis[1] && i>=2))
02364 {
02365 _axisMaximums[i] = 0;
02366 _axisMaximumsSet[i] = false;
02367 }
02368 }
02369
02370 for(int i=0; i<_curves.size(); ++i)
02371 {
02372 if(_curves.at(i)->isVisible() && _curves.at(i)->isMinMaxValid())
02373 {
02374 const QVector<float> & minMax = _curves.at(i)->getMinMax();
02375 this->updateAxis(minMax[0], minMax[1], minMax[2], minMax[3]);
02376 }
02377 }
02378
02379 _aGraphicsView->isChecked()?this->replot(0):this->update();
02380
02381 this->captureScreen();
02382 }
02383
02384 void UPlot::paintEvent(QPaintEvent * event)
02385 {
02386 #if PRINT_DEBUG
02387 UDEBUG("");
02388 #endif
02389 if(!_aGraphicsView->isChecked())
02390 {
02391 QPainter painter(this);
02392 painter.translate(_graphicsViewHolder->pos());
02393 painter.save();
02394 painter.setBrush(_bgColor);
02395 painter.setPen(QPen(Qt::NoPen));
02396 painter.drawRect(_graphicsViewHolder->rect());
02397 painter.restore();
02398
02399 this->replot(&painter);
02400
02401 if(_mouseCurrentPos != _mousePressedPos)
02402 {
02403 painter.save();
02404 int left, top, right, bottom;
02405 left = _mousePressedPos.x() < _mouseCurrentPos.x() ? _mousePressedPos.x()-_graphicsViewHolder->x():_mouseCurrentPos.x()-_graphicsViewHolder->x();
02406 top = _mousePressedPos.y() < _mouseCurrentPos.y() ? _mousePressedPos.y()-1-_graphicsViewHolder->y():_mouseCurrentPos.y()-1-_graphicsViewHolder->y();
02407 right = _mousePressedPos.x() > _mouseCurrentPos.x() ? _mousePressedPos.x()-_graphicsViewHolder->x():_mouseCurrentPos.x()-_graphicsViewHolder->x();
02408 bottom = _mousePressedPos.y() > _mouseCurrentPos.y() ? _mousePressedPos.y()-_graphicsViewHolder->y():_mouseCurrentPos.y()-_graphicsViewHolder->y();
02409 if(left <= 0)
02410 {
02411 left = 1;
02412 }
02413 if(right >= _graphicsViewHolder->width())
02414 {
02415 right = _graphicsViewHolder->width()-1;
02416 }
02417 if(top <= 0)
02418 {
02419 top = 1;
02420 }
02421 if(bottom >= _graphicsViewHolder->height())
02422 {
02423 bottom = _graphicsViewHolder->height()-1;
02424 }
02425 painter.setPen(Qt::NoPen);
02426 painter.setBrush(QBrush(QColor(255-_bgColor.red(),255-_bgColor.green(),255-_bgColor.blue(),100)));
02427 painter.drawRect(0, 0, _graphicsViewHolder->width(), top);
02428 painter.drawRect(0, top, left, bottom-top);
02429 painter.drawRect(right, top, _graphicsViewHolder->width()-right, bottom-top);
02430 painter.drawRect(0, bottom, _graphicsViewHolder->width(), _graphicsViewHolder->height()-bottom);
02431 painter.restore();
02432 }
02433 }
02434 else
02435 {
02436 QWidget::paintEvent(event);
02437 }
02438 }
02439
02440 void UPlot::resizeEvent(QResizeEvent * event)
02441 {
02442 if(_aGraphicsView->isChecked())
02443 {
02444 this->replot(0);
02445 }
02446 QWidget::resizeEvent(event);
02447 }
02448
02449 void UPlot::mousePressEvent(QMouseEvent * event)
02450 {
02451 _mousePressedPos = event->pos();
02452 _mouseCurrentPos = _mousePressedPos;
02453 QWidget::mousePressEvent(event);
02454 }
02455
02456 void UPlot::mouseMoveEvent(QMouseEvent * event)
02457 {
02458 if(!_aGraphicsView->isChecked())
02459 {
02460 if(!(QApplication::mouseButtons() & Qt::LeftButton))
02461 {
02462 _mousePressedPos = _mouseCurrentPos;
02463 }
02464
02465 float x,y;
02466 if(mousePosToValue(event->pos(), x ,y))
02467 {
02468 if(QApplication::mouseButtons() & Qt::LeftButton)
02469 {
02470 _mouseCurrentPos = event->pos();
02471 this->update();
02472 }
02473
02474 int xPos = event->pos().x() - _graphicsViewHolder->pos().x();
02475 int yPos = event->pos().y() - _graphicsViewHolder->pos().y();
02476 if((QApplication::mouseButtons() & Qt::LeftButton) ||
02477 (_aMouseTracking->isChecked() && xPos>=0 && yPos>=0 && xPos<_graphicsViewHolder->width() && yPos<_graphicsViewHolder->height()))
02478 {
02479 QToolTip::showText(event->globalPos(), QString("%1,%2").arg(x).arg(y));
02480 }
02481 else
02482 {
02483 QToolTip::hideText();
02484 }
02485 }
02486 else
02487 {
02488 QToolTip::hideText();
02489 }
02490 }
02491 QWidget::mouseMoveEvent(event);
02492 }
02493
02494 void UPlot::mouseReleaseEvent(QMouseEvent * event)
02495 {
02496 if(_mousePressedPos != _mouseCurrentPos)
02497 {
02498 int left,top,bottom,right;
02499
02500 left = _mousePressedPos.x() < _mouseCurrentPos.x() ? _mousePressedPos.x():_mouseCurrentPos.x();
02501 top = _mousePressedPos.y() < _mouseCurrentPos.y() ? _mousePressedPos.y():_mouseCurrentPos.y();
02502 right = _mousePressedPos.x() > _mouseCurrentPos.x() ? _mousePressedPos.x():_mouseCurrentPos.x();
02503 bottom = _mousePressedPos.y() > _mouseCurrentPos.y() ? _mousePressedPos.y():_mouseCurrentPos.y();
02504
02505 if(right - left > 5 || bottom - top > 5)
02506 {
02507 float axis[4];
02508 if(mousePosToValue(QPoint(left, top), axis[0], axis[3]) && mousePosToValue(QPoint(right, bottom), axis[1], axis[2]))
02509 {
02510 #if PRINT_DEBUG
02511 UDEBUG("resize! new axis = [%f, %f, %f, %f]", axis[0], axis[1], axis[2], axis[3]);
02512 #endif
02513
02514 for(int i=0; i<4; ++i)
02515 {
02516 if((!_fixedAxis[0] && i<2) || (!_fixedAxis[1] && i>=2))
02517 {
02518 _axisMaximums[i] = axis[i];
02519 }
02520 }
02521 _aGraphicsView->isChecked()?this->replot(0):this->update();
02522 }
02523 }
02524 _mousePressedPos = _mouseCurrentPos;
02525 }
02526 QWidget::mouseReleaseEvent(event);
02527 }
02528
02529 void UPlot::mouseDoubleClickEvent(QMouseEvent * event)
02530 {
02531 this->updateAxis();
02532 QWidget::mouseDoubleClickEvent(event);
02533 }
02534
02535 bool UPlot::mousePosToValue(const QPoint & pos, float & x, float & y)
02536 {
02537 int xPos = pos.x() - _graphicsViewHolder->pos().x() - _horizontalAxis->border();
02538 int yPos = pos.y() - _graphicsViewHolder->pos().y() - _verticalAxis->border();
02539 int maxX = _graphicsViewHolder->width() - _horizontalAxis->border()*2;
02540 int maxY = _graphicsViewHolder->height() - _verticalAxis->border()*2;
02541 if(maxX == 0 || maxY == 0)
02542 {
02543 return false;
02544 }
02545
02546 if(xPos < 0)
02547 {
02548 xPos = 0;
02549 }
02550 else if(xPos > maxX)
02551 {
02552 xPos = maxX;
02553 }
02554
02555 if(yPos < 0)
02556 {
02557 yPos = 0;
02558 }
02559 else if(yPos > maxY)
02560 {
02561 yPos = maxY;
02562 }
02563
02564
02565
02566
02567
02568
02569
02570
02571
02572
02573 x = _axisMaximums[0] + float(xPos)*(_axisMaximums[1] - _axisMaximums[0]) / float(maxX);
02574 y = _axisMaximums[2] + float(maxY - yPos)*(_axisMaximums[3] - _axisMaximums[2]) / float(maxY);
02575 return true;
02576 }
02577
02578 void UPlot::contextMenuEvent(QContextMenuEvent * event)
02579 {
02580 QAction * action = _menu->exec(event->globalPos());
02581
02582 if(!action)
02583 {
02584 return;
02585 }
02586 else if(action == _aShowLegend)
02587 {
02588 this->showLegend(_aShowLegend->isChecked());
02589 }
02590 else if(action == _aShowGrid)
02591 {
02592 this->showGrid(_aShowGrid->isChecked());
02593 }
02594 else if(action == _aShowRefreshRate)
02595 {
02596 this->showRefreshRate(_aShowRefreshRate->isChecked());
02597 }
02598 else if(action == _aMouseTracking)
02599 {
02600 this->trackMouse(_aMouseTracking->isChecked());
02601 }
02602 else if(action == _aGraphicsView)
02603 {
02604 this->setGraphicsView(_aGraphicsView->isChecked());
02605 }
02606 else if(action == _aKeepAllData)
02607 {
02608 this->keepAllData(_aKeepAllData->isChecked());
02609 }
02610 else if(action == _aLimit0 ||
02611 action == _aLimit10 ||
02612 action == _aLimit50 ||
02613 action == _aLimit100 ||
02614 action == _aLimit500 ||
02615 action == _aLimit1000 ||
02616 action == _aLimitCustom)
02617 {
02618 this->setMaxVisibleItems(action->text().toInt());
02619 }
02620 else if(action == _aAddVerticalLine || action == _aAddHorizontalLine)
02621 {
02622 bool ok;
02623 QString text = QInputDialog::getText(this, action->text(), tr("New line name :"), QLineEdit::Normal, "", &ok);
02624 while(ok && text.isEmpty())
02625 {
02626 QMessageBox::warning(this, action->text(), tr("The name is not valid or it is already used in this plot."));
02627 text = QInputDialog::getText(this, action->text(), tr("New line name :"), QLineEdit::Normal, "", &ok);
02628 }
02629 if(ok)
02630 {
02631 double min = _axisMaximums[2];
02632 double max = _axisMaximums[3];
02633 QString axis = "Y";
02634 if(action == _aAddVerticalLine)
02635 {
02636 min = _axisMaximums[0];
02637 max = _axisMaximums[1];
02638 axis = "X";
02639 }
02640 double value = QInputDialog::getDouble(this,
02641 action->text(),
02642 tr("%1 value (min=%2, max=%3):").arg(axis).arg(min).arg(max),
02643 (min+max)/2,
02644 -2147483647,
02645 2147483647,
02646 4,
02647 &ok);
02648 if(ok)
02649 {
02650 if(action == _aAddHorizontalLine)
02651 {
02652 this->addThreshold(text, value, Qt::Horizontal);
02653 }
02654 else
02655 {
02656 this->addThreshold(text, value, Qt::Vertical);
02657 }
02658 }
02659 }
02660 }
02661 else if(action == _aChangeTitle)
02662 {
02663 bool ok;
02664 QString text = _title->text();
02665 if(text.isEmpty())
02666 {
02667 text = this->objectName();
02668 }
02669 text = QInputDialog::getText(this, _aChangeTitle->text(), tr("Title :"), QLineEdit::Normal, text, &ok);
02670 if(ok)
02671 {
02672 this->setTitle(text);
02673 }
02674 }
02675 else if(action == _aChangeXLabel)
02676 {
02677 bool ok;
02678 QString text = QInputDialog::getText(this, _aChangeXLabel->text(), tr("X axis label :"), QLineEdit::Normal, _xLabel->text(), &ok);
02679 if(ok)
02680 {
02681 this->setXLabel(text);
02682 }
02683 }
02684 else if(action == _aChangeYLabel)
02685 {
02686 bool ok;
02687 QString text = QInputDialog::getText(this, _aChangeYLabel->text(), tr("Y axis label :"), QLineEdit::Normal, _yLabel->text(), &ok);
02688 if(ok)
02689 {
02690 this->setYLabel(text, _yLabel->orientation());
02691 }
02692 }
02693 else if(action == _aYLabelVertical)
02694 {
02695 this->setYLabel(_yLabel->text(), _aYLabelVertical->isChecked()?Qt::Vertical:Qt::Horizontal);
02696 }
02697 else if(action == _aChangeBackgroundColor)
02698 {
02699 QColor color = QColorDialog::getColor(_bgColor, this);
02700 if(color.isValid())
02701 {
02702 this->setBackgroundColor(color);
02703 }
02704 }
02705 else if(action == _aSaveFigure)
02706 {
02707
02708 QString text;
02709 #ifdef QT_SVG_LIB
02710 text = QFileDialog::getSaveFileName(this, tr("Save figure to ..."), (QDir::homePath() + "/") + this->title() + ".png", "*.png *.xpm *.jpg *.pdf *.svg");
02711 #else
02712 text = QFileDialog::getSaveFileName(this, tr("Save figure to ..."), (QDir::homePath() + "/") + this->title() + ".png", "*.png *.xpm *.jpg *.pdf");
02713 #endif
02714 if(!text.isEmpty())
02715 {
02716 bool flatModified = false;
02717 if(!_legend->isFlat())
02718 {
02719 _legend->setFlat(true);
02720 flatModified = true;
02721 }
02722
02723 QPalette p(palette());
02724
02725 QColor c = p.color(QPalette::Background);
02726 p.setColor(QPalette::Background, Qt::white);
02727 setPalette(p);
02728
02729 #ifdef QT_SVG_LIB
02730 if(QFileInfo(text).suffix().compare("svg") == 0)
02731 {
02732 QSvgGenerator generator;
02733 generator.setFileName(text);
02734 generator.setSize(this->size());
02735 QPainter painter;
02736 painter.begin(&generator);
02737 this->render(&painter);
02738 painter.end();
02739 }
02740 else
02741 {
02742 #endif
02743 if(QFileInfo(text).suffix().compare("pdf") == 0)
02744 {
02745 QPrinter printer;
02746 printer.setOutputFormat(QPrinter::PdfFormat);
02747 printer.setOutputFileName(text);
02748 this->render(&printer);
02749 }
02750 else
02751 {
02752 QPixmap figure = QPixmap::grabWidget(this);
02753 figure.save(text);
02754 }
02755 #ifdef QT_SVG_LIB
02756 }
02757 #endif
02758
02759 p.setColor(QPalette::Background, c);
02760 setPalette(p);
02761
02762 if(flatModified)
02763 {
02764 _legend->setFlat(false);
02765 }
02766 }
02767 }
02768 else if(action == _aAutoScreenCapture)
02769 {
02770 if(_aAutoScreenCapture->isChecked())
02771 {
02772 this->selectScreenCaptureFormat();
02773 }
02774 }
02775 else if(action == _aClearData)
02776 {
02777 this->clearData();
02778 }
02779 else
02780 {
02781 ULOGGER_WARN("Unknown action");
02782 }
02783 }
02784
02785 void UPlot::setWorkingDirectory(const QString & workingDirectory)
02786 {
02787 if(QDir(_workingDirectory).exists())
02788 {
02789 _workingDirectory = workingDirectory;
02790 }
02791 else
02792 {
02793 ULOGGER_ERROR("The directory \"%s\" doesn't exist", workingDirectory.toStdString().c_str());
02794 }
02795 }
02796
02797 void UPlot::captureScreen()
02798 {
02799 if(!_aAutoScreenCapture->isChecked())
02800 {
02801 return;
02802 }
02803 QString targetDir = _workingDirectory + "/ScreensCaptured";
02804 QDir dir;
02805 if(!dir.exists(targetDir))
02806 {
02807 dir.mkdir(targetDir);
02808 }
02809 targetDir += "/";
02810 targetDir += this->title().replace(" ", "_");
02811 if(!dir.exists(targetDir))
02812 {
02813 dir.mkdir(targetDir);
02814 }
02815 targetDir += "/";
02816 QString name = (QDateTime::currentDateTime().toString("yyMMddhhmmsszzz") + ".") + _autoScreenCaptureFormat;
02817 QPixmap figure = QPixmap::grabWidget(this);
02818 figure.save(targetDir + name);
02819 }
02820
02821 void UPlot::selectScreenCaptureFormat()
02822 {
02823 QStringList items;
02824 items << QString("png") << QString("jpg");
02825 bool ok;
02826 QString item = QInputDialog::getItem(this, tr("Select format"), tr("Format:"), items, 0, false, &ok);
02827 if(ok && !item.isEmpty())
02828 {
02829 _autoScreenCaptureFormat = item;
02830 }
02831 this->captureScreen();
02832 }
02833
02834 void UPlot::clearData()
02835 {
02836 for(int i=0; i<_curves.size(); ++i)
02837 {
02838
02839 if(qobject_cast<UPlotCurveThreshold*>(_curves.at(i)) == 0)
02840 {
02841 _curves.at(i)->clear();
02842 }
02843 }
02844 _aGraphicsView->isChecked()?this->replot(0):this->update();
02845 }
02846
02847
02848 UPlotCurveThreshold * UPlot::addThreshold(const QString & name, float value, Qt::Orientation orientation)
02849 {
02850 UPlotCurveThreshold * curve = new UPlotCurveThreshold(name, value, orientation, this);
02851 QPen pen = curve->pen();
02852 pen.setStyle((Qt::PenStyle)(_penStyleCount++ % 4 + 2));
02853 curve->setPen(pen);
02854 if(!this->addCurve(curve))
02855 {
02856 if(curve)
02857 {
02858 delete curve;
02859 }
02860 }
02861 else
02862 {
02863 _aGraphicsView->isChecked()?this->replot(0):this->update();
02864 }
02865 return curve;
02866 }
02867
02868 void UPlot::setTitle(const QString & text)
02869 {
02870 _title->setText(text);
02871 _title->setVisible(!text.isEmpty());
02872 this->update();
02873 if(_aGraphicsView->isChecked())
02874 {
02875 QTimer::singleShot(10, this, SLOT(updateAxis()));
02876 }
02877 }
02878
02879 void UPlot::setXLabel(const QString & text)
02880 {
02881 _xLabel->setText(text);
02882 _xLabel->setVisible(!text.isEmpty());
02883 this->update();
02884 if(_aGraphicsView->isChecked())
02885 {
02886 QTimer::singleShot(10, this, SLOT(updateAxis()));
02887 }
02888 }
02889
02890 void UPlot::setYLabel(const QString & text, Qt::Orientation orientation)
02891 {
02892 _yLabel->setText(text);
02893 _yLabel->setOrientation(orientation);
02894 _yLabel->setVisible(!text.isEmpty());
02895 _aYLabelVertical->setChecked(orientation==Qt::Vertical);
02896 this->update();
02897 if(_aGraphicsView->isChecked())
02898 {
02899 QTimer::singleShot(10, this, SLOT(updateAxis()));
02900 }
02901 }
02902
02903 void UPlot::setBackgroundColor(const QColor & color)
02904 {
02905 if(color.isValid())
02906 {
02907 _bgColor = color;
02908 _view->scene()->setBackgroundBrush(QBrush(_bgColor));
02909 for(QList<UPlotCurve*>::iterator iter=_curves.begin(); iter!=_curves.end(); ++iter)
02910 {
02911 (*iter)->setItemsColor(QColor(255-_bgColor.red(), 255-_bgColor.green(), 255-_bgColor.blue(), _bgColor.alpha()));
02912 }
02913 }
02914 }
02915
02916 void UPlot::addItem(QGraphicsItem * item)
02917 {
02918 item->setParentItem(_sceneRoot);
02919 item->setZValue(1.0f);
02920 }
02921
02922 void UPlot::showLegend(bool shown)
02923 {
02924 _legend->setVisible(shown);
02925 _aShowLegend->setChecked(shown);
02926 this->update();
02927 if(_aGraphicsView->isChecked())
02928 {
02929 QTimer::singleShot(10, this, SLOT(updateAxis()));
02930 }
02931 }
02932
02933 void UPlot::showGrid(bool shown)
02934 {
02935 _aShowGrid->setChecked(shown);
02936 _aGraphicsView->isChecked()?this->replot(0):this->update();
02937 }
02938
02939 void UPlot::showRefreshRate(bool shown)
02940 {
02941 _aShowRefreshRate->setChecked(shown);
02942 _refreshRate->setVisible(shown);
02943 this->update();
02944 if(_aGraphicsView->isChecked())
02945 {
02946 QTimer::singleShot(10, this, SLOT(updateAxis()));
02947 }
02948 }
02949
02950 void UPlot::trackMouse(bool tracking)
02951 {
02952 _aMouseTracking->setChecked(tracking);
02953 this->setMouseTracking(tracking);
02954 }
02955
02956 void UPlot::setGraphicsView(bool on)
02957 {
02958 _aGraphicsView->setChecked(on);
02959 _view->setVisible(on);
02960 _aGraphicsView->isChecked()?this->replot(0):this->update();
02961 _aMouseTracking->setEnabled(!on);
02962 }
02963
02964 void UPlot::keepAllData(bool kept)
02965 {
02966 _aKeepAllData->setChecked(kept);
02967 }
02968
02969 void UPlot::setMaxVisibleItems(int maxVisibleItems)
02970 {
02971 if(maxVisibleItems <= 0)
02972 {
02973 _aLimit0->setChecked(true);
02974 }
02975 else if(maxVisibleItems == 10)
02976 {
02977 _aLimit10->setChecked(true);
02978 }
02979 else if(maxVisibleItems == 50)
02980 {
02981 _aLimit50->setChecked(true);
02982 }
02983 else if(maxVisibleItems == 100)
02984 {
02985 _aLimit100->setChecked(true);
02986 }
02987 else if(maxVisibleItems == 500)
02988 {
02989 _aLimit500->setChecked(true);
02990 }
02991 else if(maxVisibleItems == 1000)
02992 {
02993 _aLimit1000->setChecked(true);
02994 }
02995 else
02996 {
02997 _aLimitCustom->setVisible(true);
02998 _aLimitCustom->setChecked(true);
02999 _aLimitCustom->setText(QString::number(maxVisibleItems));
03000 }
03001 _maxVisibleItems = maxVisibleItems;
03002 updateAxis();
03003 }
03004
03005 QRectF UPlot::sceneRect() const
03006 {
03007 return _view->sceneRect();
03008 }
03009
03010 void UPlot::removeCurves()
03011 {
03012 QList<UPlotCurve*> tmp = _curves;
03013 for(QList<UPlotCurve*>::iterator iter=tmp.begin(); iter!=tmp.end(); ++iter)
03014 {
03015 this->removeCurve(*iter);
03016 }
03017 _curves.clear();
03018 }
03019
03020 void UPlot::removeCurve(const UPlotCurve * curve)
03021 {
03022 QList<UPlotCurve *>::iterator iter = qFind(_curves.begin(), _curves.end(), curve);
03023 #if PRINT_DEBUG
03024 ULOGGER_DEBUG("Plot=\"%s\" removing curve=\"%s\"", this->objectName().toStdString().c_str(), curve?curve->name().toStdString().c_str():"");
03025 #endif
03026 if(iter!=_curves.end())
03027 {
03028 UPlotCurve * c = *iter;
03029 c->detach(this);
03030 _curves.erase(iter);
03031 _legend->remove(c);
03032 if(!qobject_cast<UPlotCurveThreshold*>(c))
03033 {
03034
03035 for(int i=_curves.size()-1; i>=0; --i)
03036 {
03037 if(!qobject_cast<UPlotCurveThreshold*>(_curves.at(i)))
03038 {
03039 connect(_curves.at(i), SIGNAL(dataChanged(const UPlotCurve *)), this, SLOT(updateAxis()));
03040 break;
03041 }
03042 }
03043 }
03044
03045 if(c->parent() == this)
03046 {
03047 delete c;
03048 }
03049
03050 updateAxis();
03051 }
03052 }
03053
03054 void UPlot::showCurve(const UPlotCurve * curve, bool shown)
03055 {
03056 QList<UPlotCurve *>::iterator iter = qFind(_curves.begin(), _curves.end(), curve);
03057 if(iter!=_curves.end())
03058 {
03059 UPlotCurve * value = *iter;
03060 if(value->isVisible() != shown)
03061 {
03062 value->setVisible(shown);
03063 this->updateAxis();
03064 }
03065 }
03066 }
03067
03068 void UPlot::moveCurve(const UPlotCurve * curve, int index)
03069 {
03070
03071 int currentIndex = -1;
03072 UPlotCurve * c = 0;
03073 for(int i=0; i<_curves.size(); ++i)
03074 {
03075 if(_curves.at(i) == curve)
03076 {
03077 c = _curves.at(i);
03078 currentIndex = i;
03079 break;
03080 }
03081 }
03082
03083 if(c && currentIndex != index)
03084 {
03085 _curves.removeAt(currentIndex);
03086 QList<QGraphicsItem *> children = _sceneRoot->childItems();
03087 _curves.insert(index, c);
03088 if(currentIndex > index)
03089 {
03090 children[currentIndex]->stackBefore(children[index]);
03091 }
03092 else
03093 {
03094 if(currentIndex<children.size()-2)
03095 {
03096 if(index < children.size()-1)
03097 {
03098 children[index]->stackBefore(children[currentIndex]);
03099 }
03100 else
03101 {
03102 children[currentIndex]->stackBefore(children[index]);
03103 }
03104 }
03105 if(currentIndex == children.size()-2 && currentIndex < index)
03106 {
03107 children[index]->stackBefore(children[currentIndex]);
03108 }
03109 }
03110 this->update();
03111 }
03112 }