// %flair:license{ // This file is part of the Flair framework distributed under the // CECILL-C License, Version 1.0. // %flair:license} #include "Scope.h" #include "Scrollbar.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #define WHEEL_DIVIDOR 30 Scope::Scope(QString title,float ymin,float ymax,float view_size_s,unsigned int refresh_rate_ms,unsigned int history_size): QwtPlot() { this->ymin=ymin; this->ymax=ymax; this->history_size=history_size; this->view_size_s=view_size_s; orig_view_size_s=view_size_s; //scroll bar scrollbar=new ScrollBar(Qt::Horizontal,canvas()); connect(scrollbar,SIGNAL(valueChanged(Qt::Orientation,float,float)),this,SLOT(scrollBarMoved(Qt::Orientation,float,float))); scrolling=true; //minimum size; sinon widget trop grand setMinimumHeight(10); setMinimumWidth(1); alignScales();//is it necessary? // Initialize data elapsed_time_s=0; // Assign a title setTitle(title); // Axis setAxisTitle(QwtPlot::xBottom, "Time (s)"); setAxisScale(QwtPlot::xBottom,0, view_size_s); setAxisTitle(QwtPlot::yLeft, "Values"); setAxisScale(QwtPlot::yLeft, ymin, ymax); // grid QwtPlotGrid *grid = new QwtPlotGrid; grid->setPen(QPen(Qt::black, 0, Qt::DotLine)); grid->attach(this); //zoomer QwtPlotMagnifier * zoomer = new QwtPlotMagnifier(canvas()); zoomer->setWheelModifiers( Qt::ControlModifier ); zoomer->setMouseButton(Qt::NoButton); zoomer->setAxisEnabled(xBottom,0); //scroller QwtPlotPanner *scroller =new QwtPlotPanner(canvas()); scroller->setAxisEnabled(xBottom,0); //legend QwtLegend* new_legend=new QwtLegend(); new_legend->setDefaultItemMode(QwtLegendData::Checkable); insertLegend(new_legend, QwtPlot::BottomLegend); connect( new_legend, SIGNAL( checked( const QVariant &, bool, int ) ), SLOT( legendChecked( const QVariant &, bool ) ) ); QTimer *timer = new QTimer(this); connect(timer, SIGNAL(timeout()), this, SLOT(replot())); timer->start(refresh_rate_ms); } Scope::~Scope() { for(int i=0;idata_x); free(curves.at(i)->data_y); delete curves.at(i)->plot; free(curves.at(i)); } } void Scope::resetXView(void) { //setAxisScale(QwtPlot::xBottom,0, orig_view_size_s); changeViewSize(orig_view_size_s); } void Scope::resetYView(void) { setAxisScale(QwtPlot::yLeft, ymin, ymax); } bool Scope::eventFilter(QObject *o, QEvent *e) { switch(e->type()) { case QEvent::Resize: { const int fw = ((QwtPlotCanvas *)canvas())->frameWidth(); QRect rect; rect.setSize(((QResizeEvent *)e)->size()); rect.setRect(rect.x() + fw, rect.y() + fw, rect.width() - 2 * fw, rect.height() - 2 * fw); scrollbar->setGeometry(0, 0, rect.width(), 10); return true; } case QEvent::Wheel: { //ctrl+wheel is already handled for y zoom if(!(QApplication::keyboardModifiers() & Qt::ControlModifier)) { QWheelEvent *wheelevent = static_cast (e); if(view_size_s+wheelevent->delta()/WHEEL_DIVIDOR>0) changeViewSize(view_size_s+wheelevent->delta()/WHEEL_DIVIDOR); } return true; } default: break; } return QwtPlot::eventFilter(o, e); } void Scope::changeViewSize(float new_view_size_s) { view_size_s=new_view_size_s; if(scrolling==false) { //4 cas: on utilise le temps au milieu de la vue actuelle //le temps total est plus petit que le view_size_s, on affiche tout: if(elapsed_time_selapsed_time_s) { min=elapsed_time_s-view_size_s; max=elapsed_time_s; } scrollbar->moveSlider(min,max);//move slider coupe le signal, on fait aussi le scrollbar scrollBarMoved(Qt::Horizontal,min,max); } } } void Scope::legendChecked( const QVariant &itemInfo, bool on ) { QwtPlotItem *plotItem=infoToItem(itemInfo); if(plotItem) showCurve( plotItem, on ); } void Scope::showCurve(QwtPlotItem *item, bool on) { item->setVisible(on); QwtLegend *lgd=qobject_cast(legend()); QList legendWidgets=lgd->legendWidgets(itemToInfo(item)); if(legendWidgets.size()==1) { QwtLegendLabel *legendLabel=qobject_cast(legendWidgets[0]); if(legendLabel) legendLabel->setChecked( on ); } } int Scope::addCurve(QPen pen,QString legend) { Curve* curve=(Curve*)malloc(sizeof(Curve)); curve->data_x=(double*)calloc(history_size,sizeof(double)); curve->data_y=(double*)calloc(history_size,sizeof(double)); curve->index=0; curve->min_index=0; curve->max_index=0; // Insert new curve curve->plot=new QwtPlotCurve(legend); curve->plot->attach(this); curve->plot->setPen(pen); curves.append(curve); showCurve(curve->plot, true); return curves.count()-1; } void Scope::updateCurve(Curve* curve) { if(scrolling==true) { curve->plot->setRawSamples(&curve->data_x[curve->min_index], &curve->data_y[curve->min_index], curve->max_index-curve->min_index); } if(curve->index==history_size) { //printf("a revoir qd on arrive a la fin, il faudrait faire un realloc pour rien perdre\n"); //attention le setrawdata s'attend a ce que l'adresse change pas, ce qui n'est pas le cas avec lerealloc //il faudra refaire un setrawdata ici curve->index=0; curve->min_index=0; scrolling=true; } //determine les index pour la visualisation if(scrolling==true) { curve->max_index=curve->index; computeMinIndex(curve,elapsed_time_s-view_size_s); } scrollbar->setBase(0,elapsed_time_s); if(scrolling==true) { scrollbar->moveSlider(elapsed_time_s-view_size_s,elapsed_time_s); if(elapsed_time_smoveSlider(min_scroll,max_scroll); } } void Scope::alignScales(void) { // The code below shows how to align the scales to // the canvas frame, but is also a good example demonstrating // why the spreaded API needs polishing. /* plot->canvas()->setFrameStyle(QFrame::Box | QFrame::Plain ); plot->canvas()->setLineWidth(1); */ for(int i = 0;isetMargin(0); QwtScaleDraw *scaleDraw=(QwtScaleDraw *)axisScaleDraw(i); if(scaleDraw) scaleDraw->enableComponent(QwtAbstractScaleDraw::Backbone, false); } } void Scope::scrollBarMoved(Qt::Orientation o, float min, float max) { min_scroll=min; max_scroll=max; if(max==scrollbar->maxBaseValue()) { scrolling=true; } else { scrolling=false; setAxisScale(QwtPlot::xBottom,min,max); //determine les index pour la visualisation for(int i=0;iplot->setRawSamples(&curves.at(i)->data_x[curves.at(i)->min_index], &curves.at(i)->data_y[curves.at(i)->min_index], curves.at(i)->max_index-curves.at(i)->min_index); } } } //TODO: faire une dichotomie void Scope::computeMinIndex(Curve* curve,float displayed_min_time) { if(curve->data_x[curve->index]>displayed_min_time) { if(curve->data_x[curve->min_index]data_x[curve->min_index]min_index!=curve->index) curve->min_index++; } else { while(curve->data_x[curve->min_index]>displayed_min_time && curve->min_index!=0) curve->min_index--; } } } void Scope::computeMaxIndex(Curve* curve,float displayed_max_time) { if(curve->data_x[curve->max_index]data_x[curve->max_index]max_index!=curve->index) curve->max_index++; } else { while(curve->data_x[curve->max_index]>displayed_max_time) curve->max_index--; } }