UPlot.cpp
Go to the documentation of this file.
00001 /*
00002 *  utilite is a cross-platform library with
00003 *  useful utilities for fast and small developing.
00004 *  Copyright (C) 2010  Mathieu Labbe
00005 *
00006 *  utilite is free library: you can redistribute it and/or modify
00007 *  it under the terms of the GNU Lesser General Public License as published by
00008 *  the Free Software Foundation, either version 3 of the License, or
00009 *  (at your option) any later version.
00010 *
00011 *  utilite is distributed in the hope that it will be useful,
00012 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014 *  GNU Lesser General Public License for more details.
00015 *
00016 *  You should have received a copy of the GNU Lesser General Public License
00017 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
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                 // Make sure the text is always in the scene
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         //Get the next/previous visible item
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         // add item
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                         //Update min/max
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         // add item
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; // TODO warn : hard coded value!
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; // TODO warn : hard coded value!
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; // TODO warn : hard coded value!
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; // TODO warn : hard coded value!
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; // TODO warn : hard coded value!
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; // TODO warn : hard coded value!
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); // the line
00571                 }
00572                 else if(_items.size()>1)
00573                 {
00574                         delete _items.takeAt(index+1); // the line
00575                 }
00576                 UPlotItem * item = (UPlotItem *)_items.takeAt(index); // the plot item
00577                 //Update min/max
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) // ownership is transfered to the caller
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         //ULOGGER_DEBUG("scaleX=%f, scaleY=%f, offsetX=%f, offsetY=%f, xDir=%d, yDir=%d, _plot->scene()->width()=%f, _plot->scene()->height=%f", scaleX, scaleY, offsetX, offsetY, xDir, yDir,_plot->scene()->width(),_plot->scene()->height());
00680         //make sure direction values are 1 or -1
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                                         // if not visible, stop looping... all other items are normally already hidden
00696                                         if(!item->isVisible())
00697                                         {
00698                                                 break;
00699                                         }
00700                                         item->setVisible(false);
00701                                 }
00702                                 else
00703                                 {
00704                                         //remove the item with his line
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                                 //Don't update not visible items
00740                                 // (Detect also if the curve goes forward or backward)
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                         //plotItem
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                         // draw line in first
00769                         if(i-1>=0)
00770                         {
00771                                 //lineItem
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         //make sure the index point to a PlotItem {PlotItem, line, PlotItem, line...}
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                 //match the size of the current data
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                 // update values
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                 //reset minMax, this will force the plot to update the axes
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                 //match the size of the current data
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                 // update values
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                 //reset minMax, this will force the plot to update the axes
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         //match the size of the current data
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         // update values
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         //reset minMax, this will force the plot to update the axes
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                                 //(xDir*item->data().x()+offsetX)*scaleX
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; // default bottom->up
01130         }
01131 #ifdef _WIN32
01132         this->setMinimumSize(15, 25);
01133 #else
01134         this->setMinimumSize(15, 25);
01135 #endif
01136         this->setAxis(min, max); // this initialize all attributes
01137 }
01138 
01139 UPlotAxis::~UPlotAxis()
01140 {
01141 #if PRINT_DEBUG
01142         ULOGGER_DEBUG("");
01143 #endif
01144 }
01145 
01146 // Vertical :bottom->up, horizontal :right->left
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         // Rounding min and max
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                 //ULOGGER_DEBUG("min=%f, max=%f", min, max);
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                 //ULOGGER_DEBUG("mul=%f, minR=%d, maxR=%d,countStep=%d", mul, minR, maxR, countStep);
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         //Resize estimation
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         //menu
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                 // layout
01534                 QHBoxLayout * hLayout = new QHBoxLayout();
01535                 hLayout->addWidget(legendItem);
01536                 hLayout->addStretch(0);
01537                 hLayout->setMargin(0);
01538 
01539                 // add to the legend
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         // This will update actions
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; // for zooming
01749 
01750         _refreshIntervalTime.start();
01751         _lowestRefreshRate = 99;
01752         _refreshStartTime.start();
01753 
01754         _penStyleCount = rand() % 10 + 1; // rand 1->10
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         //layouts
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         // add curve
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                 // only last curve can trigger an update, so disable previous connections
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                 // add curve
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                 // find the curve with the most items
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         //ULOGGER_DEBUG("x1=%f, x2=%f, y1=%f, y2=%f", _axisMaximums[0], _axisMaximums[1], _axisMaximums[2], _axisMaximums[3]);
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         //grid
02048         qDeleteAll(hGridLines);
02049         hGridLines.clear();
02050         qDeleteAll(vGridLines);
02051         vGridLines.clear();
02052         if(_aShowGrid->isChecked())
02053         {
02054                 // TODO make a PlotGrid class ?
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                         //horizontal lines
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                         //vertical lines
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         // curves
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         // Update refresh rate
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                 // Refresh the label only after each 1000 ms
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                 //ULOGGER_DEBUG("x1=%f, x2=%f, y1=%f, y2=%f", minMax[0], minMax[1], minMax[2], minMax[3]);
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         //ULOGGER_DEBUG("x=%f, y=%f", x,y);
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         //Reset the axis
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                                 //update axis (only if not fixed)
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         //UDEBUG("IN");
02461         //UDEBUG("x1=%f, x2=%f, y1=%f, y2=%f", _axisMaximums[0], _axisMaximums[1], _axisMaximums[2], _axisMaximums[3]);
02462         //UDEBUG("border hor=%f ver=%f", (float)_horizontalAxis->border(), (float)_verticalAxis->border());
02463         //UDEBUG("rect = %d,%d %d,%d", _graphicsViewHolder->pos().x(), _graphicsViewHolder->pos().y(), _graphicsViewHolder->width(), _graphicsViewHolder->height());
02464         //UDEBUG("%d,%d", event->pos().x(), event->pos().y());
02465         //UDEBUG("x/y %d,%d", x, y);
02466         //UDEBUG("max %d,%d", maxX, maxY);
02467 
02468         //UDEBUG("map %f,%f", x, y);
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                         // Set background color to white
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                         // revert background color
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                 // Don't clear threshold curves
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 // for convenience...
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                         // transfer update connection to next curve
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                 // Update axis
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         // this will change the print order
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 }


rtabmap
Author(s): Mathieu Labbe
autogenerated on Fri Aug 28 2015 12:51:42