From 0c7abe97557849367a01b0f7ee9cb93a5117703a Mon Sep 17 00:00:00 2001 From: Damien Date: Fri, 12 Aug 2011 15:39:38 +0200 Subject: [PATCH] Modify Aerolab to add interval highlight and zoom + auto offset Fixes #241 Fixes #147 --- src/Aerolab.cpp | 408 +++++++++++++++++++++++++++++++++++++++--- src/Aerolab.h | 58 ++++-- src/AerolabWindow.cpp | 132 +++++++++++++- src/AerolabWindow.h | 11 +- src/MainWindow.cpp | 3 +- 5 files changed, 565 insertions(+), 47 deletions(-) diff --git a/src/Aerolab.cpp b/src/Aerolab.cpp index bed66ce8e..d2ed2ac75 100644 --- a/src/Aerolab.cpp +++ b/src/Aerolab.cpp @@ -17,6 +17,7 @@ */ #include "Aerolab.h" +#include "AerolabWindow.h" #include "MainWindow.h" #include "RideFile.h" #include "RideItem.h" @@ -42,11 +43,193 @@ max(double a, double b) { if (a > b) return a; else return b; } static inline double min(double a, double b) { if (a < b) return a; else return b; } -Aerolab::Aerolab(QWidget *parent): + +/*---------------------------------------------------------------------- + * Interval plotting + *--------------------------------------------------------------------*/ + +class IntervalAerolabData : public QwtData +{ + public: + Aerolab *aerolab; + MainWindow *mainWindow; + IntervalAerolabData + ( + Aerolab *aerolab, + MainWindow *mainWindow + ) : aerolab( aerolab ), mainWindow( mainWindow ) { } + + double x( size_t ) const; + double y( size_t ) const; + size_t size() const; + virtual QwtData *copy() const; + + void init(); + + IntervalItem *intervalNum( int ) const; + + int intervalCount() const; +}; + +/* + * HELPER FUNCTIONS: + * intervalNum - returns a pointer to the nth selected interval + * intervalCount - returns the number of highlighted intervals + */ +// ------------------------------------------------------------------------------------------------------------ +// note this is operating on the children of allIntervals and not the +// intervalWidget (QTreeWidget) -- this is why we do not use the +// selectedItems() member. N starts a one not zero. +// ------------------------------------------------------------------------------------------------------------ +IntervalItem *IntervalAerolabData::intervalNum +( + int number +) const +{ + int highlighted = 0; + const QTreeWidgetItem *allIntervals = mainWindow->allIntervalItems(); + for ( int ii = 0; ii < allIntervals->childCount(); ii++) + + { + IntervalItem *current = (IntervalItem *) allIntervals->child( ii ); + + if ( current == NULL) + { + return NULL; + } + if ( current->isSelected() == true ) + { + ++highlighted; + } + if ( highlighted == number ) + { + return current; + } + } + + return NULL; +} + +// ------------------------------------------------------------------------------------------------------------ +// how many intervals selected? +// ------------------------------------------------------------------------------------------------------------ +int IntervalAerolabData::intervalCount() const +{ + int highlighted = 0; + + if ( mainWindow->allIntervalItems() != NULL ) + { + const QTreeWidgetItem *allIntervals = mainWindow->allIntervalItems(); + for ( int ii = 0; ii < allIntervals->childCount(); ii++) + { + IntervalItem *current = (IntervalItem *) allIntervals->child( ii ); + if ( current != NULL ) + { + if ( current->isSelected() == true ) + { + ++highlighted; + } + } + } + } + return highlighted; +} +/* + * INTERVAL HIGHLIGHTING CURVE + * IntervalAerolabData - implements the qwtdata interface where + * x,y return point co-ordinates and + * size returns the number of points + */ +// The interval curve data is derived from the intervals that have +// been selected in the MainWindow leftlayout for each selected +// interval we return 4 data points; bottomleft, topleft, topright +// and bottom right. +// +// the points correspond to: +// bottom left = interval start, 0 watts +// top left = interval start, maxwatts +// top right = interval stop, maxwatts +// bottom right = interval stop, 0 watts +// +double IntervalAerolabData::x +( + size_t number +) const +{ + // for each interval there are four points, which interval is this for? + // interval numbers start at 1 not ZERO in the utility functions + + double result = 0; + + int interval_no = number ? 1 + number / 4 : 1; + // get the interval + IntervalItem *current = intervalNum( interval_no ); + + if ( current != NULL ) + { + double multiplier = aerolab->useMetricUnits ? 1 : MILES_PER_KM; + // which point are we returning? +//qDebug() << "number = " << number << endl; + switch ( number % 4 ) + { + case 0 : result = aerolab->bydist ? multiplier * current->startKM : current->start/60; // bottom left + break; + case 1 : result = aerolab->bydist ? multiplier * current->startKM : current->start/60; // top left + break; + case 2 : result = aerolab->bydist ? multiplier * current->stopKM : current->stop/60; // bottom right + break; + case 3 : result = aerolab->bydist ? multiplier * current->stopKM : current->stop/60; // top right + break; + } + } + return result; +} +double IntervalAerolabData::y +( + size_t number +) const +{ + // which point are we returning? + double result = 0; + switch ( number % 4 ) + { + case 0 : result = -5000; // bottom left + break; + case 1 : result = 5000; // top left - set to out of bound value + break; + case 2 : result = 5000; // top right - set to out of bound value + break; + case 3 : result = -5000; // bottom right + break; + } + return result; +} + +size_t IntervalAerolabData::size() const +{ + return intervalCount() * 4; +} + +QwtData *IntervalAerolabData::copy() const +{ + return new IntervalAerolabData( aerolab, mainWindow ); +} + + +//********************************************** +//** END IntervalAerolabData ** +//********************************************** + + +Aerolab::Aerolab( + AerolabWindow *parent, + MainWindow *mainWindow +): QwtPlot(parent), + parent(parent), unit(0), rideItem(NULL), - smooth(1), bydist(false) { + smooth(1), bydist(true), autoEoffset(true) { crr = 0.005; cda = 0.500; @@ -69,9 +252,19 @@ Aerolab::Aerolab(QWidget *parent): setAxisScale(xBottom, 0, 60); veCurve = new QwtPlotCurve(tr("V-Elevation")); - altCurve = new QwtPlotCurve(tr("Elevation")); + // get rid of nasty blank space on right of the plot + veCurve->setYAxis( yLeft ); + altCurve->setYAxis( yLeft ); + + intervalHighlighterCurve = new QwtPlotCurve(); + intervalHighlighterCurve->setBaseline(-5000); + intervalHighlighterCurve->setYAxis( yLeft ); + intervalHighlighterCurve->setData( IntervalAerolabData( this, mainWindow ) ); + intervalHighlighterCurve->attach( this ); + this->legend()->remove( intervalHighlighterCurve ); // don't show in legend + grid = new QwtPlotGrid(); grid->enableX(false); grid->attach(this); @@ -79,6 +272,7 @@ Aerolab::Aerolab(QWidget *parent): configChanged(); } + void Aerolab::configChanged() { @@ -93,6 +287,16 @@ Aerolab::configChanged() QPen gridPen(GColor(CPLOTGRID)); gridPen.setStyle(Qt::DotLine); grid->setPen(gridPen); + + QPen ihlPen = QPen( GColor( CINTERVALHIGHLIGHTER ) ); + ihlPen.setWidth(1); + intervalHighlighterCurve->setPen( ihlPen ); + + QColor ihlbrush = QColor(GColor(CINTERVALHIGHLIGHTER)); + ihlbrush.setAlpha(40); + intervalHighlighterCurve->setBrush(ihlbrush); // fill below the line + + this->legend()->remove( intervalHighlighterCurve ); // don't show in legend } void @@ -158,7 +362,7 @@ Aerolab::setData(RideItem *_rideItem, bool new_zoom) { if ( arrayLength == 0 ) e = eoffset; - timeArray[arrayLength] = p1->secs; + timeArray[arrayLength] = p1->secs / 60.0; if ( have_recorded_alt_curve ) altArray[arrayLength] = (useMetricUnits ? p1->alt @@ -173,8 +377,13 @@ Aerolab::setData(RideItem *_rideItem, bool new_zoom) { } double f = 0.0; double a = 0.0; - d += v * dt; - distanceArray[arrayLength] = d/1000; + + // Use km data insteed of formula for file with a stop (gap). + //d += v * dt; + //distanceArray[arrayLength] = d/1000; + + distanceArray[arrayLength] = p1->km; + if( v > small_number ) { @@ -201,14 +410,34 @@ Aerolab::setData(RideItem *_rideItem, bool new_zoom) { veCurve->setVisible(false); altCurve->setVisible(false); } - recalc(new_zoom); + adjustEoffset(); } else { setTitle("no data"); } } +void +Aerolab::adjustEoffset() { + + if (autoEoffset && !altArray.empty()) { + double idx = axisScaleDiv( QwtPlot::xBottom )->lowerBound(); + parent->eoffsetSlider->setEnabled(false); + + if (bydist) { + int v = 100*(altArray.at(rideItem->ride()->distanceIndex(idx))-veArray.at(rideItem->ride()->distanceIndex(idx))); + parent->eoffsetSlider->setValue(intEoffset()+v); + } + else { + int v = 100*(altArray.at(rideItem->ride()->timeIndex(60*idx))-veArray.at(rideItem->ride()->timeIndex(60*idx))); + parent->eoffsetSlider->setValue(intEoffset()+v); + } + } else + parent->eoffsetSlider->setEnabled(true); +} + + struct DataPoint { double time, hr, watts, speed, cad, alt; DataPoint(double t, double h, double w, double s, double c, double a) : @@ -235,8 +464,7 @@ Aerolab::recalc( bool new_zoom ) { return; } - - QVector &xaxis = distanceArray; + QVector &xaxis = (bydist?distanceArray:timeArray); int startingIndex = 0; int totalPoints = arrayLength - startingIndex; @@ -251,9 +479,12 @@ Aerolab::recalc( bool new_zoom ) { } if( new_zoom ) - setAxisScale(xBottom, 0.0, totalRideDistance); + setAxisScale(xBottom, 0.0, (bydist?totalRideDistance:rideTimeSecs)); - setYMax(); + + + setYMax(new_zoom ); + refreshIntervalMarkers(); replot(); } @@ -261,19 +492,75 @@ Aerolab::recalc( bool new_zoom ) { void -Aerolab::setYMax() { +Aerolab::setYMax(bool new_zoom) +{ + if (veCurve->isVisible()) + { - if (veCurve->isVisible()) { - setAxisTitle(yLeft, tr("Elevation")); + if ( useMetricUnits ) + + { + + setAxisTitle( yLeft, "Elevation (m)" ); + + } + + else + + { + + setAxisTitle( yLeft, "Elevation (')" ); + + } + + double minY = 0.0; + double maxY = 0.0; + + //************ + + //if (veCurve->isVisible()) { + // setAxisTitle(yLeft, tr("Elevation")); if ( !altArray.empty() ) { - setAxisScale(yLeft, - min( veCurve->minYValue(), altCurve->minYValue() ) - 10, - 10.0 + max( veCurve->maxYValue(), altCurve->maxYValue() ) ); + // setAxisScale(yLeft, + // min( veCurve->minYValue(), altCurve->minYValue() ) - 10, + // 10.0 + max( veCurve->maxYValue(), altCurve->maxYValue() ) ); + + minY = min( veCurve->minYValue(), altCurve->minYValue() ) - 10; + maxY = 10.0 + max( veCurve->maxYValue(), altCurve->maxYValue() ); + } else { - setAxisScale(yLeft, - veCurve->minYValue() , - 1.05 * veCurve->maxYValue() ); + //setAxisScale(yLeft, + // veCurve->minYValue() , + // 1.05 * veCurve->maxYValue() ); + + if ( new_zoom ) + + { + + minY = veCurve->minYValue(); + + maxY = veCurve->maxYValue(); + + } + + else + + { + + minY = parent->getCanvasTop(); + + maxY = parent->getCanvasBottom(); + + } + + //adjust eooffset + // TODO + + + } + + setAxisScale( yLeft, minY, maxY ); setAxisLabelRotation(yLeft,270); setAxisLabelAlignment(yLeft,Qt::AlignVCenter); } @@ -292,12 +579,18 @@ Aerolab::setXTitle() { setAxisTitle(xBottom, tr("Time (minutes)")); } +void +Aerolab::setAutoEoffset(int value) +{ + autoEoffset = value; + adjustEoffset(); +} void -Aerolab::setByDistance() { - bydist = true; +Aerolab::setByDistance(int value) { + bydist = value; setXTitle(); - recalc(false); + recalc(true); } @@ -388,3 +681,72 @@ Aerolab::setIntEoffset( eoffset = (double) value / 100.0; recalc(false); } + + + + + + + + + + +void Aerolab::pointHover (QwtPlotCurve *curve, int index) +{ + if ( index >= 0 && curve != intervalHighlighterCurve ) + { + double x_value = curve->x( index ); + double y_value = curve->y( index ); + // output the tooltip + + QString text = QString( "%1 %2 %3 %4 %5" ) + . arg( this->axisTitle( curve->xAxis() ).text() ) + . arg( x_value, 0, 'f', 3 ) + . arg( "\n" ) + . arg( this->axisTitle( curve->yAxis() ).text() ) + . arg( y_value, 0, 'f', 3 ); + + // set that text up + tooltip->setText( text ); + } + else + { + // no point + tooltip->setText( "" ); + } +} + +void Aerolab::refreshIntervalMarkers() +{ + foreach( QwtPlotMarker *mrk, d_mrk ) + { + mrk->detach(); + delete mrk; + } + d_mrk.clear(); + + QRegExp wkoAuto("^(Peak *[0-9]*(s|min)|Entire workout|Find #[0-9]*) *\\([^)]*\\)$"); + if ( rideItem->ride() ) + { + foreach(const RideFileInterval &interval, rideItem->ride()->intervals()) { + // skip WKO autogenerated peak intervals + if (wkoAuto.exactMatch(interval.name)) + continue; + QwtPlotMarker *mrk = new QwtPlotMarker; + d_mrk.append(mrk); + mrk->attach(this); + mrk->setLineStyle(QwtPlotMarker::VLine); + mrk->setLabelAlignment(Qt::AlignRight | Qt::AlignTop); + mrk->setLinePen(QPen(GColor(CPLOTMARKER), 0, Qt::DashDotLine)); + QwtText text(interval.name); + text.setFont(QFont("Helvetica", 10, QFont::Bold)); + text.setColor(GColor(CPLOTMARKER)); + if (!bydist) + mrk->setValue(interval.start / 60.0, 0.0); + else + mrk->setValue((useMetricUnits ? 1 : MILES_PER_KM) * + rideItem->ride()->timeToDistance(interval.start), 0.0); + mrk->setLabel(text); + } + } +} diff --git a/src/Aerolab.h b/src/Aerolab.h index ebf293ee3..bdefe24b0 100644 --- a/src/Aerolab.h +++ b/src/Aerolab.h @@ -22,6 +22,7 @@ #include #include #include +#include "LTMWindow.h" // for tooltip/canvaspicker // forward references class RideItem; @@ -31,32 +32,56 @@ class QwtPlotGrid; class QwtPlotMarker; class AerolabWindow; class MainWindow; +class IntervalAerolabData; +class LTMToolTip; +class LTMCanvasPicker; + class Aerolab : public QwtPlot { Q_OBJECT public: - Aerolab(QWidget *parent); + Aerolab( AerolabWindow *, MainWindow * ); bool byDistance() const { return bydist; } bool useMetricUnits; // whether metric units are used (or imperial) void setData(RideItem *_rideItem, bool new_zoom); + void refreshIntervalMarkers(); + + private: + AerolabWindow *parent; + + LTMToolTip *tooltip; + LTMCanvasPicker *_canvasPicker; // allow point selection/hover + + void adjustEoffset(); + public slots: - void setByDistance(); + + void setAutoEoffset(int value); + void setByDistance(int value); void configChanged(); + void pointHover( QwtPlotCurve *, int ); + signals: protected: friend class ::AerolabWindow; + friend class ::IntervalAerolabData; + + QVariant unit; QwtPlotGrid *grid; + QVector d_mrk; // One curve to plot in the Course Profile: QwtPlotCurve *veCurve; // virtual elevation curve QwtPlotCurve *altCurve; // recorded elevation curve, if available + QwtPlotCurve *intervalHighlighterCurve; // highlight selected intervals on the Plot + RideItem *rideItem; QVector hrArray; @@ -72,6 +97,7 @@ class Aerolab : public QwtPlot { int smooth; bool bydist; + bool autoEoffset; int arrayLength; int iCrr; int iCda; @@ -85,7 +111,7 @@ class Aerolab : public QwtPlot { double slope(double, double, double, double, double, double, double); void recalc(bool); - void setYMax(); + void setYMax(bool); void setXTitle(); void setIntCrr(int); void setIntCda(int); @@ -93,18 +119,20 @@ class Aerolab : public QwtPlot { void setIntEta(int); void setIntEoffset(int); void setIntTotalMass(int); - double getCrr() const { return (double)crr; }; - double getCda() const { return (double)cda; }; - double getTotalMass() const { return (double)totalMass; }; - double getRho() const { return (double)rho; }; - double getEta() const { return (double)eta; }; - double getEoffset() const { return (double)eoffset; }; - int intCrr() const { return (int)( crr * 1000000 ); }; - int intCda() const { return (int)( cda * 100000); }; - int intTotalMass() const { return (int)( totalMass * 100); }; - int intRho() const { return (int)( rho * 10000); }; - int intEta() const { return (int)( eta * 10000); }; - int intEoffset() const { return (int)( eoffset * 100); }; + double getCrr() const { return (double)crr; } + double getCda() const { return (double)cda; } + double getTotalMass() const { return (double)totalMass; } + double getRho() const { return (double)rho; } + double getEta() const { return (double)eta; } + double getEoffset() const { return (double)eoffset; } + int intCrr() const { return (int)( crr * 1000000 ); } + int intCda() const { return (int)( cda * 10000); } + int intTotalMass() const { return (int)( totalMass * 100); } + int intRho() const { return (int)( rho * 10000); } + int intEta() const { return (int)( eta * 10000); } + int intEoffset() const { return (int)( eoffset * 100); } + + }; #endif // _GC_Aerolab_h diff --git a/src/AerolabWindow.cpp b/src/AerolabWindow.cpp index eab916275..8ebf1d423 100644 --- a/src/AerolabWindow.cpp +++ b/src/AerolabWindow.cpp @@ -33,7 +33,7 @@ AerolabWindow::AerolabWindow(MainWindow *mainWindow) : QHBoxLayout *cLayout = new QHBoxLayout; // Plot: - aerolab = new Aerolab(this); + aerolab = new Aerolab(this, mainWindow); // Left controls layout: QVBoxLayout *leftControls = new QVBoxLayout; @@ -63,11 +63,14 @@ AerolabWindow::AerolabWindow(MainWindow *mainWindow) : QHBoxLayout *cdaLayout = new QHBoxLayout; QLabel *cdaLabel = new QLabel(tr("CdA"), this); cdaLabel->setFixedWidth(labelWidth1); - cdaQLCDNumber = new QLCDNumber(7); + cdaLineEdit = new QLineEdit(); + cdaLineEdit->setFixedWidth(50); + cdaLineEdit->setText(QString("%1").arg(aerolab->getCda()) ); + /*cdaQLCDNumber = new QLCDNumber(7); cdaQLCDNumber->setMode(QLCDNumber::Dec); cdaQLCDNumber->setSmallDecimalPoint(false); cdaQLCDNumber->setSegmentStyle(QLCDNumber::Flat); - cdaQLCDNumber->display(QString("%1").arg(aerolab->getCda()) ); + cdaQLCDNumber->display(QString("%1").arg(aerolab->getCda()) );*/ cdaSlider = new QSlider(Qt::Horizontal); cdaSlider->setTickPosition(QSlider::TicksBelow); cdaSlider->setTickInterval(100); @@ -75,7 +78,8 @@ AerolabWindow::AerolabWindow(MainWindow *mainWindow) : cdaSlider->setMaximum(6000); cdaSlider->setValue(aerolab->intCda()); cdaLayout->addWidget( cdaLabel ); - cdaLayout->addWidget( cdaQLCDNumber ); + //cdaLayout->addWidget( cdaQLCDNumber ); + cdaLayout->addWidget( cdaLineEdit ); cdaLayout->addWidget( cdaSlider ); // Eta: @@ -157,16 +161,28 @@ AerolabWindow::AerolabWindow(MainWindow *mainWindow) : eoffsetSlider->setTickPosition(QSlider::TicksBelow); eoffsetSlider->setTickInterval(1000); eoffsetSlider->setMinimum(-30000); - eoffsetSlider->setMaximum(30000); + eoffsetSlider->setMaximum(100000); eoffsetSlider->setValue(aerolab->intEoffset()); eoffsetLayout->addWidget( eoffsetLabel ); eoffsetLayout->addWidget( eoffsetQLCDNumber ); eoffsetLayout->addWidget( eoffsetSlider ); + QCheckBox *eoffsetAuto = new QCheckBox(tr("eoffset auto"), this); + eoffsetAuto->setCheckState(Qt::Checked); + eoffsetLayout->addWidget(eoffsetAuto); + + QHBoxLayout *smoothLayout = new QHBoxLayout; + QComboBox *comboDistance = new QComboBox(); + comboDistance->addItem(tr("X Axis Shows Time")); + comboDistance->addItem(tr("X Axis Shows Distance")); + comboDistance->setCurrentIndex(1); + smoothLayout->addWidget(comboDistance); + // Add to leftControls: rightControls->addLayout( mLayout ); rightControls->addLayout( rhoLayout ); rightControls->addLayout( eoffsetLayout ); + rightControls->addLayout( smoothLayout ); // Assemble controls layout: @@ -180,26 +196,67 @@ AerolabWindow::AerolabWindow(MainWindow *mainWindow) : | QwtPicker::CornerToCorner); allZoomer->setTrackerMode(QwtPicker::AlwaysOff); allZoomer->setEnabled(true); + allZoomer->setMousePattern( QwtEventPattern::MouseSelect2, Qt::RightButton, Qt::ControlModifier ); + allZoomer->setMousePattern( QwtEventPattern::MouseSelect3, Qt::RightButton ); // SIGNALs to SLOTs: connect(mainWindow, SIGNAL(rideSelected()), this, SLOT(rideSelected())); connect(crrSlider, SIGNAL(valueChanged(int)),this, SLOT(setCrrFromSlider())); connect(cdaSlider, SIGNAL(valueChanged(int)), this, SLOT(setCdaFromSlider())); + connect(cdaLineEdit, SIGNAL(textChanged(const QString)), this, SLOT(setCdaFromText(const QString))); connect(mSlider, SIGNAL(valueChanged(int)),this, SLOT(setTotalMassFromSlider())); connect(rhoSlider, SIGNAL(valueChanged(int)), this, SLOT(setRhoFromSlider())); connect(etaSlider, SIGNAL(valueChanged(int)), this, SLOT(setEtaFromSlider())); connect(eoffsetSlider, SIGNAL(valueChanged(int)), this, SLOT(setEoffsetFromSlider())); + connect(eoffsetAuto, SIGNAL(stateChanged(int)), this, SLOT(setAutoEoffset(int))); + connect(comboDistance, SIGNAL(currentIndexChanged(int)), this, SLOT(setByDistance(int))); connect(mainWindow, SIGNAL(configChanged()), aerolab, SLOT(configChanged())); connect(mainWindow, SIGNAL(configChanged()), this, SLOT(configChanged())); + connect(mainWindow, SIGNAL( intervalSelected() ), this, SLOT(intervalSelected())); + connect(allZoomer, SIGNAL( zoomed(const QwtDoubleRect) ), this, SLOT(zoomChanged())); + // Build the tab layout: vLayout->addWidget(aerolab); vLayout->addLayout(cLayout); setLayout(vLayout); + + // tooltip on hover over point + //************************************ + aerolab->tooltip = new LTMToolTip( QwtPlot::xBottom, + QwtPlot::yLeft, + QwtPicker::PointSelection, + QwtPicker::VLineRubberBand, + QwtPicker::AlwaysOn, + aerolab->canvas(), + "" + ); + aerolab->tooltip->setSelectionFlags( QwtPicker::PointSelection | QwtPicker::RectSelection | QwtPicker::DragSelection); + aerolab->tooltip->setRubberBand( QwtPicker::VLineRubberBand ); + aerolab->tooltip->setMousePattern( QwtEventPattern::MouseSelect1, Qt::LeftButton, Qt::ShiftModifier ); + aerolab->tooltip->setTrackerPen( QColor( Qt::black ) ); + QColor inv( Qt::white ); + inv.setAlpha( 0 ); + aerolab->tooltip->setRubberBandPen( inv ); + aerolab->tooltip->setEnabled( true ); + aerolab->_canvasPicker = new LTMCanvasPicker( aerolab ); + + connect( aerolab->_canvasPicker, SIGNAL( pointHover( QwtPlotCurve*, int ) ), + aerolab, SLOT ( pointHover( QwtPlotCurve*, int ) ) ); + + configChanged(); // pickup colors etc } +void +AerolabWindow::zoomChanged() +{ + RideItem *ride = mainWindow->rideItem(); + aerolab->setData(ride, false); +} + + void AerolabWindow::configChanged() { @@ -217,7 +274,10 @@ AerolabWindow::rideSelected() { if (!ride) return; + + aerolab->setData(ride, true); + allZoomer->setZoomBase(); } @@ -232,12 +292,25 @@ AerolabWindow::setCrrFromSlider() { } } +void +AerolabWindow::setCdaFromText(const QString text) { + int value = 10000 * text.toDouble(); + if (aerolab->intCda() != value) { + aerolab->setIntCda(value); + //cdaQLCDNumber->display(QString("%1").arg(aerolab->getCda())); + cdaSlider->setValue(aerolab->intCda()); + RideItem *ride = mainWindow->rideItem(); + aerolab->setData(ride, false); + } +} + void AerolabWindow::setCdaFromSlider() { if (aerolab->intCda() != cdaSlider->value()) { aerolab->setIntCda(cdaSlider->value()); - cdaQLCDNumber->display(QString("%1").arg(aerolab->getCda())); + //cdaQLCDNumber->display(QString("%1").arg(aerolab->getCda())); + cdaLineEdit->setText(QString("%1").arg(aerolab->getCda()) ); RideItem *ride = mainWindow->rideItem(); aerolab->setData(ride, false); } @@ -287,6 +360,23 @@ AerolabWindow::setEoffsetFromSlider() { } } +void +AerolabWindow::setAutoEoffset(int value) +{ + aerolab->setAutoEoffset(value); +} + +void +AerolabWindow::setByDistance(int value) +{ + aerolab->setByDistance(value); + // refresh + RideItem *ride = mainWindow->rideItem(); + aerolab->setData(ride, false); +} + + + void AerolabWindow::zoomInterval(IntervalItem *which) { @@ -302,5 +392,35 @@ AerolabWindow::zoomInterval(IntervalItem *which) { rect.setTop(aerolab->veCurve->maxYValue()*1.1); rect.setBottom(aerolab->veCurve->minYValue()-10); allZoomer->zoom(rect); + + aerolab->recalc(false); } +void AerolabWindow::intervalSelected() +{ + if ( mainWindow->activeTab() != this ) + { + return; + } + + RideItem *ride = mainWindow->rideItem(); + if ( !ride ) + { + return; + } + + // set the elevation data + aerolab->setData( ride, true ); +} + +double AerolabWindow::getCanvasTop() const +{ + const QwtDoubleRect &canvasRect = allZoomer->zoomRect(); + return canvasRect.top(); +} + +double AerolabWindow::getCanvasBottom() const +{ + const QwtDoubleRect &canvasRect = allZoomer->zoomRect(); + return canvasRect.bottom(); +} diff --git a/src/AerolabWindow.h b/src/AerolabWindow.h index 94cf28392..8cc492fa2 100644 --- a/src/AerolabWindow.h +++ b/src/AerolabWindow.h @@ -38,18 +38,25 @@ class AerolabWindow : public QWidget { AerolabWindow(MainWindow *mainWindow); void setData(RideItem *ride); void zoomInterval(IntervalItem *); // zoom into a specified interval + double getCanvasTop() const; + double getCanvasBottom() const; + QSlider *eoffsetSlider; public slots: void setCrrFromSlider(); void setCdaFromSlider(); + void setCdaFromText(const QString text); void setTotalMassFromSlider(); void setRhoFromSlider(); void setEtaFromSlider(); void setEoffsetFromSlider(); + void setAutoEoffset(int value); + void setByDistance(int value); void rideSelected(); + void zoomChanged(); void configChanged(); - + void intervalSelected(); protected slots: @@ -74,7 +81,7 @@ class AerolabWindow : public QWidget { QSlider *etaSlider; QLineEdit *etaLineEdit; QLCDNumber *etaQLCDNumber; - QSlider *eoffsetSlider; + QLineEdit *eoffsetLineEdit; QLCDNumber *eoffsetQLCDNumber; diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index e83aabe49..2a7c4111b 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -1004,7 +1004,7 @@ MainWindow::showContextMenuPopup(const QPoint &pos) connect(actFrontInt, SIGNAL(triggered(void)), this, SLOT(frontInterval(void))); connect(actBackInt, SIGNAL(triggered(void)), this, SLOT(backInterval(void))); - if (tabWidget->currentWidget() == allPlotWindow) + if (tabWidget->currentWidget() == allPlotWindow || tabWidget->currentWidget() == aerolabWindow) menu.addAction(actZoomInt); menu.addAction(actRenameInt); menu.addAction(actDeleteInt); @@ -1070,6 +1070,7 @@ void MainWindow::zoomInterval() { // zoom into this interval on allPlot allPlotWindow->zoomInterval(activeInterval); + aerolabWindow->zoomInterval(activeInterval); } void