mirror of
https://github.com/GoldenCheetah/GoldenCheetah.git
synced 2026-02-14 16:39:57 +00:00
.. check for NULL. .. this is odd, some behaviour upstream has changed and needs to be investigated as this bug is too significant to have only just been found.
3947 lines
131 KiB
C++
3947 lines
131 KiB
C++
/*
|
|
* Copyright (c) 2009 Sean C. Rhea (srhea@srhea.net)
|
|
* Copyright (c) 2014 Mark Liversedge (liversedge@gmail.com)
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License as published by the Free
|
|
* Software Foundation; either version 2 of the License, or (at your option)
|
|
* any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
* more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program; if not, write to the Free Software Foundation, Inc., 51
|
|
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
|
|
#include "Context.h"
|
|
#include "Context.h"
|
|
#include "Athlete.h"
|
|
#include "TabView.h"
|
|
#include "AllPlotInterval.h"
|
|
#include "AllPlotWindow.h"
|
|
#include "AllPlot.h"
|
|
#include "RideFile.h"
|
|
#include "RideItem.h"
|
|
#include "IntervalItem.h"
|
|
#include "IntervalTreeView.h"
|
|
#include "TimeUtils.h"
|
|
#include "Settings.h"
|
|
#include "Units.h" // for MILES_PER_KM
|
|
#include "Colors.h" // for MILES_PER_KM
|
|
#include <qwt_plot_layout.h>
|
|
#include <qwt_plot_canvas.h>
|
|
#include <qwt_plot_panner.h>
|
|
#include <qwt_plot_zoomer.h>
|
|
#include <qwt_plot_picker.h>
|
|
#include <qwt_plot_marker.h>
|
|
#include <qwt_scale_widget.h>
|
|
#include <qwt_arrow_button.h>
|
|
#include <qwt_plot_curve.h>
|
|
#include <qwt_plot_grid.h>
|
|
#include <qwt_text.h>
|
|
#include <qwt_legend.h>
|
|
#include <qwt_series_data.h>
|
|
|
|
// span slider specials
|
|
#include <qxtspanslider.h>
|
|
#include <QStyleFactory>
|
|
#include <QStyle>
|
|
#include <QScrollBar>
|
|
|
|
// tooltip
|
|
#include "LTMWindow.h"
|
|
|
|
// help
|
|
#include "HelpWhatsThis.h"
|
|
|
|
// overlay helper
|
|
#include "GcOverlayWidget.h"
|
|
#include "IntervalSummaryWindow.h"
|
|
|
|
static const int stackZoomWidth[8] = { 5, 10, 15, 20, 30, 45, 60, 120 };
|
|
|
|
AllPlotWindow::AllPlotWindow(Context *context) :
|
|
GcChartWindow(context), current(NULL), context(context), active(false), stale(true), setupStack(false), setupSeriesStack(false), compareStale(true), firstShow(true)
|
|
{
|
|
// basic setup
|
|
setContentsMargins(0,0,0,0);
|
|
QWidget *c = new QWidget;
|
|
HelpWhatsThis *helpConfig = new HelpWhatsThis(c);
|
|
c->setWhatsThis(helpConfig->getWhatsThisText(HelpWhatsThis::ChartRides_Performance));
|
|
setControls(c);
|
|
QVBoxLayout *clv = new QVBoxLayout(c);
|
|
|
|
// all the controls
|
|
QFormLayout *mainControls = new QFormLayout; // basic stuff at top; power, slider etc
|
|
|
|
// aside from basic settings, other stuff is now
|
|
// in a tab widget as we have so many data series !
|
|
QTabWidget *st = new QTabWidget(this);
|
|
clv->addWidget(st);
|
|
|
|
// gui controls
|
|
QWidget *basic = new QWidget(this); // show stack etc
|
|
QVBoxLayout *basicControls = new QVBoxLayout(basic);
|
|
basicControls->addLayout(mainControls);
|
|
QFormLayout *guiControls = new QFormLayout; // show stack etc BUT ALSO ACCEL etc
|
|
basicControls->addLayout(guiControls);
|
|
basicControls->addStretch();
|
|
st->addTab(basic, tr("Basic"));
|
|
|
|
HelpWhatsThis *basicHelp = new HelpWhatsThis(basic);
|
|
basic->setWhatsThis(basicHelp->getWhatsThisText(HelpWhatsThis::ChartRides_Performance_Config_Basic));
|
|
|
|
// data series
|
|
QWidget *series = new QWidget(this); // data series selection
|
|
QHBoxLayout *seriesControls = new QHBoxLayout(series);
|
|
QFormLayout *seriesLeft = new QFormLayout(); // ride side series
|
|
QFormLayout *seriesRight = new QFormLayout(); // ride side series
|
|
seriesControls->setSpacing(2);
|
|
seriesLeft->setSpacing(2);
|
|
seriesRight->setSpacing(2);
|
|
seriesControls->addLayout(seriesLeft);
|
|
seriesControls->addLayout(seriesRight); // ack I swapped them around !
|
|
st->addTab(series, tr("Curves"));
|
|
|
|
HelpWhatsThis *seriesHelp = new HelpWhatsThis(series);
|
|
series->setWhatsThis(seriesHelp->getWhatsThisText(HelpWhatsThis::ChartRides_Performance_Config_Series));
|
|
|
|
// user data widget
|
|
custom = new QWidget(this);
|
|
st->addTab(custom, tr("User Data"));
|
|
custom->setContentsMargins(20,20,20,20);
|
|
//HelpWhatsThis *curvesHelp = new HelpWhatsThis(custom);
|
|
//custom->setWhatsThis(curvesHelp->getWhatsThisText(HelpWhatsThis::ChartTrends_MetricTrends_Config_Curves));
|
|
QVBoxLayout *customLayout = new QVBoxLayout(custom);
|
|
customLayout->setContentsMargins(0,0,0,0);
|
|
customLayout->setSpacing(5);
|
|
|
|
// custom table
|
|
customTable = new QTableWidget(this);
|
|
#ifdef Q_OS_MAX
|
|
customTable->setAttribute(Qt::WA_MacShowFocusRect, 0);
|
|
#endif
|
|
customTable->setColumnCount(2);
|
|
customTable->horizontalHeader()->setStretchLastSection(true);
|
|
QStringList headings;
|
|
headings << tr("Name");
|
|
headings << tr("Formula");
|
|
customTable->setHorizontalHeaderLabels(headings);
|
|
customTable->setSortingEnabled(false);
|
|
customTable->verticalHeader()->hide();
|
|
customTable->setShowGrid(false);
|
|
customTable->setSelectionMode(QAbstractItemView::SingleSelection);
|
|
customTable->setSelectionBehavior(QAbstractItemView::SelectRows);
|
|
customLayout->addWidget(customTable);
|
|
connect(customTable, SIGNAL(cellDoubleClicked(int, int)), this, SLOT(doubleClicked(int, int)));
|
|
|
|
// custom buttons
|
|
editCustomButton = new QPushButton(tr("Edit"));
|
|
connect(editCustomButton, SIGNAL(clicked()), this, SLOT(editUserData()));
|
|
|
|
addCustomButton = new QPushButton("+");
|
|
connect(addCustomButton, SIGNAL(clicked()), this, SLOT(addUserData()));
|
|
|
|
deleteCustomButton = new QPushButton("-");
|
|
connect(deleteCustomButton, SIGNAL(clicked()), this, SLOT(deleteUserData()));
|
|
|
|
#ifndef Q_OS_MAC
|
|
upCustomButton = new QToolButton(this);
|
|
downCustomButton = new QToolButton(this);
|
|
upCustomButton->setArrowType(Qt::UpArrow);
|
|
downCustomButton->setArrowType(Qt::DownArrow);
|
|
upCustomButton->setFixedSize(20,20);
|
|
downCustomButton->setFixedSize(20,20);
|
|
addCustomButton->setFixedSize(20,20);
|
|
deleteCustomButton->setFixedSize(20,20);
|
|
#else
|
|
upCustomButton = new QPushButton(tr("Up"));
|
|
downCustomButton = new QPushButton(tr("Down"));
|
|
#endif
|
|
connect(upCustomButton, SIGNAL(clicked()), this, SLOT(moveUserDataUp()));
|
|
connect(downCustomButton, SIGNAL(clicked()), this, SLOT(moveUserDataDown()));
|
|
|
|
|
|
QHBoxLayout *customButtons = new QHBoxLayout;
|
|
customButtons->setSpacing(2);
|
|
customButtons->addWidget(upCustomButton);
|
|
customButtons->addWidget(downCustomButton);
|
|
customButtons->addStretch();
|
|
customButtons->addWidget(editCustomButton);
|
|
customButtons->addStretch();
|
|
customButtons->addWidget(addCustomButton);
|
|
customButtons->addWidget(deleteCustomButton);
|
|
customLayout->addLayout(customButtons);
|
|
|
|
// Main layout
|
|
//QGridLayout *mainLayout = new QGridLayout();
|
|
//mainLayout->setContentsMargins(2,2,2,2);
|
|
|
|
//
|
|
// reveal controls widget
|
|
//
|
|
|
|
// reveal controls
|
|
rSmooth = new QLabel(tr("Smooth"));
|
|
rSmoothEdit = new QLineEdit();
|
|
rSmoothEdit->setFixedWidth(30);
|
|
rSmoothSlider = new QSlider(Qt::Horizontal);
|
|
rSmoothSlider->setTickPosition(QSlider::TicksBelow);
|
|
rSmoothSlider->setTickInterval(10);
|
|
rSmoothSlider->setMinimum(1);
|
|
rSmoothSlider->setMaximum(100);
|
|
rStack = new QCheckBox(tr("Stacked"));
|
|
rBySeries = new QCheckBox(tr("by series"));
|
|
rFull = new QCheckBox(tr("Fullplot"));
|
|
rHelp = new QCheckBox(tr("Overlay"));
|
|
|
|
// layout reveal controls
|
|
QHBoxLayout *r = new QHBoxLayout;
|
|
r->setContentsMargins(0,0,0,0);
|
|
r->addStretch();
|
|
r->addWidget(rSmooth);
|
|
r->addWidget(rSmoothEdit);
|
|
r->addWidget(rSmoothSlider);
|
|
QVBoxLayout *v = new QVBoxLayout;
|
|
QHBoxLayout *s = new QHBoxLayout;
|
|
QHBoxLayout *t = new QHBoxLayout;
|
|
s->addWidget(rStack);
|
|
s->addWidget(rBySeries);
|
|
v->addLayout(s);
|
|
t->addWidget(rFull);
|
|
t->addWidget(rHelp);
|
|
v->addLayout(t);
|
|
r->addSpacing(20);
|
|
r->addLayout(v);
|
|
r->addStretch();
|
|
setRevealLayout(r);
|
|
//revealControls->setLayout(r);
|
|
|
|
// hide them initially
|
|
//revealControls->hide();
|
|
|
|
// setup the controls
|
|
QLabel *showLabel = new QLabel(tr("View"), c);
|
|
|
|
showStack = new QCheckBox(tr("Stack"), this);
|
|
showStack->setCheckState(Qt::Unchecked);
|
|
guiControls->addRow(showLabel, showStack);
|
|
|
|
showBySeries = new QCheckBox(tr("By Series"), this);
|
|
showBySeries->setCheckState(Qt::Unchecked);
|
|
guiControls->addRow(new QLabel("", this), showBySeries);
|
|
guiControls->addRow(new QLabel("", this), new QLabel("",this)); // spacer
|
|
|
|
stackWidth = 20;
|
|
stackZoomSlider = new QSlider(Qt::Horizontal,this);
|
|
stackZoomSlider->setMinimum(0);
|
|
stackZoomSlider->setMaximum(7);
|
|
stackZoomSlider->setTickInterval(1);
|
|
stackZoomSlider->setValue(3);
|
|
guiControls->addRow(new QLabel(tr("Stack Zoom")), stackZoomSlider);
|
|
|
|
showFull = new QCheckBox(tr("Full plot"), this);
|
|
showFull->setCheckState(Qt::Checked);
|
|
guiControls->addRow(new QLabel(""), showFull);
|
|
|
|
showInterval = new QCheckBox(tr("Interval Navigator"), this);
|
|
showInterval->setCheckState(Qt::Checked);
|
|
guiControls->addRow(new QLabel(""), showInterval);
|
|
|
|
showHover = new QCheckBox(tr("Hover intervals"), this);
|
|
showHover->setCheckState(Qt::Checked);
|
|
guiControls->addRow(new QLabel(""), showHover);
|
|
|
|
showHelp = new QCheckBox(tr("Overlay"), this);
|
|
showHelp->setCheckState(Qt::Unchecked);
|
|
guiControls->addRow(new QLabel(""), showHelp);
|
|
|
|
paintBrush = new QCheckBox(tr("Fill Curves"), this);
|
|
paintBrush->setCheckState(Qt::Unchecked);
|
|
guiControls->addRow(new QLabel(""), paintBrush);
|
|
|
|
showGrid = new QCheckBox(tr("Grid"), this);
|
|
showGrid->setCheckState(Qt::Checked);
|
|
guiControls->addRow(new QLabel(""), showGrid);
|
|
guiControls->addRow(new QLabel(""), new QLabel(""));
|
|
|
|
showAccel = new QCheckBox(tr("Acceleration"), this);
|
|
showAccel->setCheckState(Qt::Checked);
|
|
seriesRight->addRow(new QLabel(tr("Delta Series")), showAccel);
|
|
showPowerD = new QCheckBox(QString(tr("Power %1").arg(deltaChar)), this);
|
|
showPowerD->setCheckState(Qt::Unchecked);
|
|
seriesRight->addRow(new QLabel(""), showPowerD);
|
|
showCadD = new QCheckBox(QString(tr("Cadence %1").arg(deltaChar)), this);
|
|
showCadD->setCheckState(Qt::Unchecked);
|
|
seriesRight->addRow(new QLabel(""), showCadD);
|
|
showTorqueD = new QCheckBox(QString(tr("Torque %1").arg(deltaChar)), this);
|
|
showTorqueD->setCheckState(Qt::Unchecked);
|
|
seriesRight->addRow(new QLabel(""), showTorqueD);
|
|
showHrD = new QCheckBox(QString(tr("Heartrate %1").arg(deltaChar)), this);
|
|
showHrD->setCheckState(Qt::Unchecked);
|
|
seriesRight->addRow(new QLabel(""), showHrD);
|
|
|
|
seriesRight->addRow(new QLabel(""), new QLabel(""));
|
|
|
|
showBalance = new QCheckBox(tr("Balance"), this);
|
|
showBalance->setCheckState(Qt::Checked);
|
|
seriesRight->addRow(new QLabel(tr("Left/Right")), showBalance);
|
|
|
|
showTE = new QCheckBox(tr("Torque Effectiveness"));
|
|
showTE->setCheckState(Qt::Unchecked);
|
|
seriesRight->addRow(new QLabel(""), showTE);
|
|
|
|
showPS = new QCheckBox(tr("Smoothness"), this);
|
|
showPS->setCheckState(Qt::Unchecked);
|
|
seriesRight->addRow(new QLabel(""), showPS);
|
|
|
|
showPCO = new QCheckBox(tr("Pedal Center Offset"), this);
|
|
showPCO->setCheckState(Qt::Unchecked);
|
|
seriesRight->addRow(new QLabel(""), showPCO);
|
|
|
|
showDC = new QCheckBox(tr("Power Phase"), this);
|
|
showDC->setCheckState(Qt::Unchecked);
|
|
seriesRight->addRow(new QLabel(""), showDC);
|
|
|
|
showPPP = new QCheckBox(tr("Peak Power Phase"), this);
|
|
showPPP->setCheckState(Qt::Unchecked);
|
|
seriesRight->addRow(new QLabel(""), showPPP);
|
|
|
|
// running !
|
|
seriesRight->addRow(new QLabel(""), new QLabel(""));
|
|
|
|
showRV = new QCheckBox(tr("Vertical Oscillation"), this);
|
|
showRV->setCheckState(Qt::Checked);
|
|
seriesRight->addRow(new QLabel(tr("Running")), showRV);
|
|
|
|
showRGCT = new QCheckBox(tr("Ground Contact Time"), this);
|
|
showRGCT->setCheckState(Qt::Checked);
|
|
seriesRight->addRow(new QLabel(""), showRGCT);
|
|
|
|
showRCad = new QCheckBox(tr("Cadence"), this);
|
|
showRCad->setCheckState(Qt::Checked);
|
|
seriesRight->addRow(new QLabel(""), showRCad);
|
|
|
|
seriesRight->addRow(new QLabel(""), new QLabel(""));
|
|
|
|
showSmO2 = new QCheckBox(tr("SmO2"), this);
|
|
showSmO2->setCheckState(Qt::Checked);
|
|
seriesRight->addRow(new QLabel(tr("Moxy")), showSmO2);
|
|
|
|
showtHb = new QCheckBox(tr("tHb"), this);
|
|
showtHb->setCheckState(Qt::Checked);
|
|
seriesRight->addRow(new QLabel(""), showtHb);
|
|
|
|
showO2Hb = new QCheckBox(tr("O2Hb"), this);
|
|
showO2Hb->setCheckState(Qt::Checked);
|
|
seriesRight->addRow(new QLabel(""), showO2Hb);
|
|
|
|
showHHb = new QCheckBox(tr("HHb"), this);
|
|
showHHb->setCheckState(Qt::Checked);
|
|
seriesRight->addRow(new QLabel(""), showHHb);
|
|
|
|
// "standard"
|
|
showHr = new QCheckBox(tr("Heart Rate"), this);
|
|
showHr->setCheckState(Qt::Checked);
|
|
seriesLeft->addRow(new QLabel(tr("Data series")), showHr);
|
|
|
|
showTcore = new QCheckBox(tr("Core Temperature"), this);
|
|
showTcore->setCheckState(Qt::Unchecked); // don't show unless user insists
|
|
seriesLeft->addRow(new QLabel(tr("")), showTcore);
|
|
|
|
showSpeed = new QCheckBox(tr("Speed"), this);
|
|
showSpeed->setCheckState(Qt::Checked);
|
|
seriesLeft->addRow(new QLabel(""), showSpeed);
|
|
|
|
showCad = new QCheckBox(tr("Cadence"), this);
|
|
showCad->setCheckState(Qt::Checked);
|
|
seriesLeft->addRow(new QLabel(""), showCad);
|
|
|
|
showAlt = new QCheckBox(tr("Altitude"), this);
|
|
showAlt->setCheckState(Qt::Checked);
|
|
seriesLeft->addRow(new QLabel(""), showAlt);
|
|
|
|
showTemp = new QCheckBox(tr("Temperature"), this);
|
|
showTemp->setCheckState(Qt::Checked);
|
|
seriesLeft->addRow(new QLabel(""), showTemp);
|
|
|
|
showWind = new QCheckBox(tr("Headwind"), this);
|
|
showWind->setCheckState(Qt::Checked);
|
|
seriesLeft->addRow(new QLabel(""), showWind);
|
|
|
|
showTorque = new QCheckBox(tr("Torque"), this);
|
|
showTorque->setCheckState(Qt::Checked);
|
|
seriesLeft->addRow(new QLabel(""), showTorque);
|
|
|
|
showGear = new QCheckBox(tr("Gear Ratio"), this);
|
|
showGear->setCheckState(Qt::Checked);
|
|
seriesLeft->addRow(new QLabel(""), showGear);
|
|
|
|
showSlope = new QCheckBox(tr("Slope"), this);
|
|
showSlope->setCheckState(Qt::Checked);
|
|
seriesLeft->addRow(new QLabel(""), showSlope);
|
|
|
|
seriesLeft->addRow(new QLabel(""), new QLabel(""));
|
|
|
|
showAltSlope = new QComboBox(this);
|
|
showAltSlope->addItem(tr("No Alt/Slope"));
|
|
showAltSlope->addItem(tr("0.1km|mi - 1min"));
|
|
showAltSlope->addItem(tr("0.5km|mi - 5min"));
|
|
showAltSlope->addItem(tr("1.0km|mi - 10min"));
|
|
seriesLeft->addRow(new QLabel(tr("Alt/Slope")), showAltSlope);
|
|
showAltSlope->setCurrentIndex(0);
|
|
|
|
seriesLeft->addRow(new QLabel(""), new QLabel(""));
|
|
|
|
showANTISS = new QCheckBox(tr("Anaerobic TISS"), this);
|
|
showANTISS->setCheckState(Qt::Unchecked);
|
|
seriesLeft->addRow(new QLabel(tr("Metrics")), showANTISS);
|
|
|
|
showATISS = new QCheckBox(tr("Aerobic TISS"), this);
|
|
showATISS->setCheckState(Qt::Unchecked);
|
|
seriesLeft->addRow(new QLabel(""), showATISS);
|
|
|
|
showNP = new QCheckBox(tr("Normalized Power"), this);
|
|
showNP->setCheckState(Qt::Unchecked);
|
|
seriesLeft->addRow(new QLabel(""), showNP);
|
|
|
|
showXP = new QCheckBox(tr("Skiba xPower"), this);
|
|
showXP->setCheckState(Qt::Unchecked);
|
|
seriesLeft->addRow(new QLabel(""), showXP);
|
|
|
|
showAP = new QCheckBox(tr("Altitude Power"), this);
|
|
showAP->setCheckState(Qt::Unchecked);
|
|
seriesLeft->addRow(new QLabel(""), showAP);
|
|
|
|
showW = new QCheckBox(tr("W' balance"), this);
|
|
showW->setCheckState(Qt::Unchecked);
|
|
seriesLeft->addRow(new QLabel(""), showW);
|
|
|
|
showPower = new QComboBox(this);
|
|
showPower->addItem(tr("Power + shade"));
|
|
showPower->addItem(tr("Power - shade"));
|
|
showPower->addItem(tr("No Power"));
|
|
mainControls->addRow(new QLabel(tr("Shading")), showPower);
|
|
showPower->setCurrentIndex(0);
|
|
|
|
comboDistance = new QComboBox(this);
|
|
comboDistance->addItem(tr("Time"));
|
|
comboDistance->addItem(tr("Distance"));
|
|
mainControls->addRow(new QLabel(tr("X Axis")), comboDistance);
|
|
|
|
QLabel *smoothLabel = new QLabel(tr("Smooth"), this);
|
|
smoothLineEdit = new QLineEdit(this);
|
|
smoothLineEdit->setFixedWidth(40);
|
|
|
|
smoothSlider = new QSlider(Qt::Horizontal, this);
|
|
smoothSlider->setTickPosition(QSlider::TicksBelow);
|
|
smoothSlider->setTickInterval(10);
|
|
smoothSlider->setMinimum(1);
|
|
smoothSlider->setMaximum(600);
|
|
smoothLineEdit->setValidator(new QIntValidator(smoothSlider->minimum(),
|
|
smoothSlider->maximum(),
|
|
smoothLineEdit));
|
|
QHBoxLayout *smoothLayout = new QHBoxLayout;
|
|
smoothLayout->addWidget(smoothLineEdit);
|
|
smoothLayout->addWidget(smoothSlider);
|
|
mainControls->addRow(smoothLabel, smoothLayout);
|
|
|
|
QPalette palette;
|
|
palette.setBrush(QPalette::Background, QBrush(GColor(CRIDEPLOTBACKGROUND)));
|
|
|
|
allPlot = new AllPlot(this, this, context);
|
|
allPlot->setContentsMargins(0,0,0,0);
|
|
allPlot->enableAxis(QwtPlot::xBottom, true);
|
|
allPlot->setAxisVisible(QwtPlot::xBottom, true);
|
|
//allPlot->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
|
//allPlot->axisWidget(QwtPlot::yLeft)->installEventFilter(this);
|
|
|
|
allStack = new QStackedWidget(this);
|
|
allStack->addWidget(allPlot);
|
|
allStack->setCurrentIndex(0);
|
|
|
|
HelpWhatsThis *help = new HelpWhatsThis(allPlot);
|
|
allPlot->setWhatsThis(help->getWhatsThisText(HelpWhatsThis::ChartRides_Performance));
|
|
|
|
// sort out default values
|
|
smoothSlider->setValue(allPlot->smooth);
|
|
smoothLineEdit->setText(QString("%1").arg(allPlot->smooth));
|
|
rSmoothSlider->setValue(allPlot->smooth);
|
|
rSmoothEdit->setText(QString("%1").arg(allPlot->smooth));
|
|
|
|
allZoomer = new QwtPlotZoomer(allPlot->canvas());
|
|
allZoomer->setRubberBand(QwtPicker::RectRubberBand);
|
|
allZoomer->setRubberBandPen(GColor(CPLOTSELECT));
|
|
allZoomer->setTrackerMode(QwtPicker::AlwaysOff);
|
|
allZoomer->setEnabled(true);
|
|
|
|
// TODO: Hack for OS X one-button mouse
|
|
// allZoomer->initMousePattern(1);
|
|
|
|
// RightButton: zoom out by 1
|
|
// Ctrl+RightButton: zoom out to full size
|
|
allZoomer->setMousePattern(QwtEventPattern::MouseSelect1,
|
|
Qt::LeftButton, Qt::ShiftModifier);
|
|
allZoomer->setMousePattern(QwtEventPattern::MouseSelect2,
|
|
Qt::RightButton, Qt::ControlModifier);
|
|
allZoomer->setMousePattern(QwtEventPattern::MouseSelect3,
|
|
Qt::RightButton);
|
|
|
|
allPanner = new QwtPlotPanner(allPlot->canvas());
|
|
allPanner->setMouseButton(Qt::MidButton);
|
|
|
|
// TODO: zoomer doesn't interact well with automatic axis resizing
|
|
|
|
// tooltip on hover over point
|
|
allPlot->tooltip = new LTMToolTip(QwtPlot::xBottom, QwtAxisId(QwtAxis::yLeft, 2).id,
|
|
QwtPicker::VLineRubberBand,
|
|
QwtPicker::AlwaysOn,
|
|
allPlot->canvas(),
|
|
"");
|
|
allPlot->tooltip->setRubberBand(QwtPicker::VLineRubberBand);
|
|
allPlot->tooltip->setMousePattern(QwtEventPattern::MouseSelect1, Qt::LeftButton);
|
|
allPlot->tooltip->setTrackerPen(QColor(Qt::black));
|
|
QColor inv(Qt::white);
|
|
inv.setAlpha(0);
|
|
allPlot->tooltip->setRubberBandPen(inv);
|
|
allPlot->tooltip->setEnabled(true);
|
|
|
|
allPlot->_canvasPicker = new LTMCanvasPicker(allPlot);
|
|
|
|
connect(context, SIGNAL(intervalHover(IntervalItem*)), allPlot, SLOT(intervalHover(IntervalItem*)));
|
|
connect(allPlot->_canvasPicker, SIGNAL(pointHover(QwtPlotCurve*, int)), allPlot, SLOT(pointHover(QwtPlotCurve*, int)));
|
|
connect(allPlot->tooltip, SIGNAL(moved(const QPoint &)), this, SLOT(plotPickerMoved(const QPoint &)));
|
|
connect(allPlot->tooltip, SIGNAL(appended(const QPoint &)), this, SLOT(plotPickerSelected(const QPoint &)));
|
|
|
|
QwtPlotMarker* allMarker1 = new QwtPlotMarker();
|
|
allMarker1->setLineStyle(QwtPlotMarker::VLine);
|
|
allMarker1->attach(allPlot);
|
|
allMarker1->setLabelAlignment(Qt::AlignTop|Qt::AlignRight);
|
|
allPlot->standard->allMarker1=allMarker1;
|
|
|
|
QwtPlotMarker* allMarker2 = new QwtPlotMarker();
|
|
allMarker2->setLineStyle(QwtPlotMarker::VLine);
|
|
allMarker2->attach(allPlot);
|
|
allMarker2->setLabelAlignment(Qt::AlignTop|Qt::AlignRight);
|
|
allPlot->standard->allMarker2=allMarker2;
|
|
|
|
//
|
|
// stack view
|
|
//
|
|
stackPlotLayout = new QVBoxLayout();
|
|
stackPlotLayout->setSpacing(0);
|
|
stackPlotLayout->setContentsMargins(0,0,0,0);
|
|
|
|
stackWidget = new QWidget(this);
|
|
stackWidget->setAutoFillBackground(false);
|
|
stackWidget->setLayout(stackPlotLayout);
|
|
stackWidget->setPalette(palette);
|
|
|
|
stackFrame = new QScrollArea(this);
|
|
#ifdef Q_OS_WIN
|
|
QStyle *cde = QStyleFactory::create(OS_STYLE);
|
|
stackFrame->setStyle(cde);
|
|
#endif
|
|
stackFrame->hide();
|
|
stackFrame->setAutoFillBackground(false);
|
|
stackFrame->setWidgetResizable(true);
|
|
stackFrame->setWidget(stackWidget);
|
|
stackFrame->setFrameStyle(QFrame::NoFrame);
|
|
stackFrame->setContentsMargins(0,0,0,0);
|
|
stackFrame->setPalette(palette);
|
|
|
|
//
|
|
// series stack view
|
|
//
|
|
seriesstackPlotLayout = new QVBoxLayout();
|
|
seriesstackPlotLayout->setSpacing(0);
|
|
seriesstackPlotLayout->setContentsMargins(0,0,0,0);
|
|
seriesstackWidget = new QWidget(this);
|
|
seriesstackWidget->setAutoFillBackground(true);
|
|
seriesstackWidget->setLayout(seriesstackPlotLayout);
|
|
seriesstackWidget->setPalette(palette);
|
|
|
|
seriesstackFrame = new QScrollArea(this);
|
|
#ifdef Q_OS_WIN
|
|
cde = QStyleFactory::create(OS_STYLE);
|
|
seriesstackFrame->setStyle(cde);
|
|
#endif
|
|
seriesstackFrame->hide();
|
|
seriesstackFrame->setAutoFillBackground(false);
|
|
seriesstackFrame->setWidgetResizable(true);
|
|
seriesstackFrame->setWidget(seriesstackWidget);
|
|
seriesstackFrame->setFrameStyle(QFrame::NoFrame);
|
|
seriesstackFrame->setContentsMargins(0,0,0,0);
|
|
seriesstackFrame->setPalette(palette);
|
|
|
|
//
|
|
// Compare - AllPlots stack
|
|
//
|
|
comparePlotLayout = new QVBoxLayout();
|
|
comparePlotLayout->setSpacing(0);
|
|
comparePlotLayout->setContentsMargins(0,0,0,0);
|
|
comparePlotWidget = new QWidget(this);
|
|
comparePlotWidget->setAutoFillBackground(false);
|
|
comparePlotWidget->setLayout(comparePlotLayout);
|
|
comparePlotWidget->setPalette(palette);
|
|
|
|
comparePlotFrame = new QScrollArea(this);
|
|
#ifdef Q_OS_WIN
|
|
cde = QStyleFactory::create(OS_STYLE);
|
|
comparePlotWidget->setStyle(cde);
|
|
#endif
|
|
comparePlotFrame->hide();
|
|
comparePlotFrame->setAutoFillBackground(false);
|
|
comparePlotFrame->setWidgetResizable(true);
|
|
comparePlotFrame->setWidget(comparePlotWidget);
|
|
comparePlotFrame->setFrameStyle(QFrame::NoFrame);
|
|
comparePlotFrame->setContentsMargins(0,0,0,0);
|
|
comparePlotFrame->setPalette(palette);
|
|
|
|
allStack->addWidget(comparePlotFrame);
|
|
|
|
//
|
|
// allPlot view
|
|
//
|
|
allPlotLayout = new QVBoxLayout;
|
|
allPlotLayout->setSpacing(0);
|
|
allPlotLayout->setContentsMargins(0,0,0,0);
|
|
allPlotFrame = new QScrollArea(this);
|
|
#ifdef Q_OS_WIN
|
|
cde = QStyleFactory::create(OS_STYLE);
|
|
allPlotFrame->setStyle(cde);
|
|
#endif
|
|
allPlotFrame->setFrameStyle(QFrame::NoFrame);
|
|
allPlotFrame->setAutoFillBackground(false);
|
|
allPlotFrame->setContentsMargins(0,0,0,0);
|
|
|
|
spanSlider = new QxtSpanSlider(Qt::Horizontal, this);
|
|
spanSlider->setFocusPolicy(Qt::NoFocus);
|
|
spanSlider->setHandleMovementMode(QxtSpanSlider::NoOverlapping);
|
|
spanSlider->setLowerValue(0);
|
|
spanSlider->setUpperValue(15);
|
|
|
|
QFont small;
|
|
small.setPointSize(6);
|
|
|
|
scrollLeft = new QPushButton("<", this);
|
|
scrollLeft->setFont(small);
|
|
scrollLeft->setAutoRepeat(true);
|
|
scrollLeft->setFixedHeight(16);
|
|
scrollLeft->setFixedWidth(16);
|
|
scrollLeft->setContentsMargins(0,0,0,0);
|
|
|
|
scrollRight = new QPushButton(">", this);
|
|
scrollRight->setFont(small);
|
|
scrollRight->setAutoRepeat(true);
|
|
scrollRight->setFixedHeight(16);
|
|
scrollRight->setFixedWidth(16);
|
|
scrollRight->setContentsMargins(0,0,0,0);
|
|
|
|
#ifdef Q_OS_MAC
|
|
// BUG in QMacStyle and painting of spanSlider
|
|
// so we use a plain style to avoid it, but only
|
|
// on a MAC, since win and linux are fine
|
|
#if QT_VERSION > 0x5000
|
|
QStyle *style = QStyleFactory::create("fusion");
|
|
#else
|
|
QStyle *style = QStyleFactory::create("Cleanlooks");
|
|
#endif
|
|
spanSlider->setStyle(style);
|
|
scrollLeft->setStyle(style);
|
|
scrollRight->setStyle(style);
|
|
#endif
|
|
|
|
fullPlot = new AllPlot(this, this, context);
|
|
fullPlot->standard->grid->enableY(false);
|
|
fullPlot->setFixedHeight(100);
|
|
fullPlot->setCanvasBackground(GColor(CRIDEPLOTBACKGROUND));
|
|
fullPlot->setHighlightIntervals(false);
|
|
fullPlot->setPaintBrush(0);
|
|
static_cast<QwtPlotCanvas*>(fullPlot->canvas())->setBorderRadius(0);
|
|
fullPlot->setWantAxis(false);
|
|
fullPlot->setContentsMargins(0,0,0,0);
|
|
|
|
HelpWhatsThis *helpFull = new HelpWhatsThis(fullPlot);
|
|
fullPlot->setWhatsThis(helpFull->getWhatsThisText(HelpWhatsThis::ChartRides_Performance));
|
|
|
|
intervalPlot = new AllPlotInterval(this, context);
|
|
intervalPlot->setFixedHeight(100);
|
|
intervalPlot->setCanvasBackground(GColor(CRIDEPLOTBACKGROUND));
|
|
static_cast<QwtPlotCanvas*>(intervalPlot->canvas())->setBorderRadius(0);
|
|
intervalPlot->setContentsMargins(0,0,0,0);
|
|
|
|
// tooltip on hover over point
|
|
/*intervalPlot->tooltip = new LTMToolTip(QwtPlot::xBottom, QwtAxis::yLeft,
|
|
QwtPicker::VLineRubberBand,
|
|
QwtPicker::AlwaysOn,
|
|
intervalPlot->canvas(),
|
|
"");
|
|
intervalPlot->tooltip->setRubberBand(QwtPicker::VLineRubberBand);
|
|
intervalPlot->tooltip->setMousePattern(QwtEventPattern::MouseSelect1, Qt::LeftButton);
|
|
intervalPlot->tooltip->setTrackerPen(QColor(Qt::black));
|
|
intervalPlot->tooltip->setRubberBandPen(inv);
|
|
intervalPlot->tooltip->setEnabled(true);*/
|
|
|
|
|
|
// allPlotStack contains the allPlot and the stack by series
|
|
// because both want the optional fullplot at the bottom
|
|
allPlotStack = new QStackedWidget(this);
|
|
allPlotStack->addWidget(allStack);
|
|
allPlotStack->addWidget(seriesstackFrame);
|
|
allPlotStack->setCurrentIndex(0);
|
|
|
|
HelpWhatsThis *helpStack = new HelpWhatsThis(allPlotStack);
|
|
allPlotStack->setWhatsThis(helpStack->getWhatsThisText(HelpWhatsThis::ChartRides_Performance));
|
|
|
|
allPlotLayout->addWidget(allPlotStack);
|
|
allPlotFrame->setLayout(allPlotLayout);
|
|
|
|
allPlotLayout->addWidget(intervalPlot);
|
|
|
|
|
|
// controls...
|
|
controlsLayout = new QGridLayout;
|
|
controlsLayout->setSpacing(0);
|
|
controlsLayout->setContentsMargins(5,5,5,5);
|
|
controlsLayout->addWidget(fullPlot, 0,1);
|
|
controlsLayout->addWidget(spanSlider, 1,1);
|
|
controlsLayout->addWidget(scrollLeft,1,0);
|
|
controlsLayout->addWidget(scrollRight,1,2);
|
|
controlsLayout->setRowStretch(0, 10);
|
|
controlsLayout->setRowStretch(1, 1);
|
|
controlsLayout->setContentsMargins(0,0,0,0);
|
|
#ifdef Q_OS_MAC
|
|
// macs dpscing is weird
|
|
//controlsLayout->setSpacing(5);
|
|
#else
|
|
controlsLayout->setSpacing(0);
|
|
#endif
|
|
allPlotLayout->addLayout(controlsLayout);
|
|
allPlotLayout->setStretch(0,100);
|
|
allPlotLayout->setStretch(1,20);
|
|
|
|
QVBoxLayout *vlayout = new QVBoxLayout;
|
|
vlayout->setContentsMargins(2,0,2,2);
|
|
vlayout->setSpacing(0);
|
|
vlayout->addWidget(allPlotFrame);
|
|
vlayout->addWidget(stackFrame);
|
|
vlayout->setSpacing(1);
|
|
|
|
// put a helper on the screen for mouse over intervals...
|
|
overlayIntervals = new IntervalSummaryWindow(context);
|
|
addHelper(tr("Intervals"), overlayIntervals);
|
|
|
|
//mainLayout->addLayout(vlayout,0,0);
|
|
//mainLayout->addWidget(revealBackground,0,0, Qt::AlignTop);
|
|
//mainLayout->addWidget(revealControls,0,0, Qt::AlignTop);
|
|
//revealBackground->raise();
|
|
//revealControls->raise();
|
|
setChartLayout(vlayout);
|
|
|
|
// common controls
|
|
connect(showPower, SIGNAL(currentIndexChanged(int)), this, SLOT(setShowPower(int)));
|
|
connect(showCad, SIGNAL(stateChanged(int)), this, SLOT(setShowCad(int)));
|
|
connect(showTorque, SIGNAL(stateChanged(int)), this, SLOT(setShowTorque(int)));
|
|
connect(showHr, SIGNAL(stateChanged(int)), this, SLOT(setShowHr(int)));
|
|
connect(showTcore, SIGNAL(stateChanged(int)), this, SLOT(setShowTcore(int)));
|
|
connect(showPowerD, SIGNAL(stateChanged(int)), this, SLOT(setShowPowerD(int)));
|
|
connect(showCadD, SIGNAL(stateChanged(int)), this, SLOT(setShowCadD(int)));
|
|
connect(showTorqueD, SIGNAL(stateChanged(int)), this, SLOT(setShowTorqueD(int)));
|
|
connect(showHrD, SIGNAL(stateChanged(int)), this, SLOT(setShowHrD(int)));
|
|
connect(showNP, SIGNAL(stateChanged(int)), this, SLOT(setShowNP(int)));
|
|
connect(showRV, SIGNAL(stateChanged(int)), this, SLOT(setShowRV(int)));
|
|
connect(showRCad, SIGNAL(stateChanged(int)), this, SLOT(setShowRCad(int)));
|
|
connect(showRGCT, SIGNAL(stateChanged(int)), this, SLOT(setShowRGCT(int)));
|
|
connect(showGear, SIGNAL(stateChanged(int)), this, SLOT(setShowGear(int)));
|
|
connect(showSmO2, SIGNAL(stateChanged(int)), this, SLOT(setShowSmO2(int)));
|
|
connect(showtHb, SIGNAL(stateChanged(int)), this, SLOT(setShowtHb(int)));
|
|
connect(showO2Hb, SIGNAL(stateChanged(int)), this, SLOT(setShowO2Hb(int)));
|
|
connect(showHHb, SIGNAL(stateChanged(int)), this, SLOT(setShowHHb(int)));
|
|
connect(showATISS, SIGNAL(stateChanged(int)), this, SLOT(setShowATISS(int)));
|
|
connect(showANTISS, SIGNAL(stateChanged(int)), this, SLOT(setShowANTISS(int)));
|
|
connect(showXP, SIGNAL(stateChanged(int)), this, SLOT(setShowXP(int)));
|
|
connect(showAP, SIGNAL(stateChanged(int)), this, SLOT(setShowAP(int)));
|
|
connect(showSpeed, SIGNAL(stateChanged(int)), this, SLOT(setShowSpeed(int)));
|
|
connect(showAccel, SIGNAL(stateChanged(int)), this, SLOT(setShowAccel(int)));
|
|
connect(showAlt, SIGNAL(stateChanged(int)), this, SLOT(setShowAlt(int)));
|
|
connect(showSlope, SIGNAL(stateChanged(int)), this, SLOT(setShowSlope(int)));
|
|
connect(showAltSlope, SIGNAL(currentIndexChanged(int)), this, SLOT(setShowAltSlope(int)));
|
|
connect(showTemp, SIGNAL(stateChanged(int)), this, SLOT(setShowTemp(int)));
|
|
connect(showWind, SIGNAL(stateChanged(int)), this, SLOT(setShowWind(int)));
|
|
connect(showW, SIGNAL(stateChanged(int)), this, SLOT(setShowW(int)));
|
|
connect(showBalance, SIGNAL(stateChanged(int)), this, SLOT(setShowBalance(int)));
|
|
connect(showPS, SIGNAL(stateChanged(int)), this, SLOT(setShowPS(int)));
|
|
connect(showTE, SIGNAL(stateChanged(int)), this, SLOT(setShowTE(int)));
|
|
connect(showPCO, SIGNAL(stateChanged(int)), this, SLOT(setShowPCO(int)));
|
|
connect(showDC, SIGNAL(stateChanged(int)), this, SLOT(setShowDC(int)));
|
|
connect(showPPP, SIGNAL(stateChanged(int)), this, SLOT(setShowPPP(int)));
|
|
|
|
connect(showGrid, SIGNAL(stateChanged(int)), this, SLOT(setShowGrid(int)));
|
|
connect(showFull, SIGNAL(stateChanged(int)), this, SLOT(setShowFull(int)));
|
|
connect(showInterval, SIGNAL(stateChanged(int)), this, SLOT(setShowInterval(int)));
|
|
connect(showHelp, SIGNAL(stateChanged(int)), this, SLOT(setShowHelp(int)));
|
|
connect(showStack, SIGNAL(stateChanged(int)), this, SLOT(showStackChanged(int)));
|
|
connect(rStack, SIGNAL(stateChanged(int)), this, SLOT(showStackChanged(int)));
|
|
connect(showBySeries, SIGNAL(stateChanged(int)), this, SLOT(showBySeriesChanged(int)));
|
|
connect(rBySeries, SIGNAL(stateChanged(int)), this, SLOT(showBySeriesChanged(int)));
|
|
connect(rFull, SIGNAL(stateChanged(int)), this, SLOT(setShowFull(int)));
|
|
connect(rHelp, SIGNAL(stateChanged(int)), this, SLOT(setShowHelp(int)));
|
|
connect(paintBrush, SIGNAL(stateChanged(int)), this, SLOT(setPaintBrush(int)));
|
|
connect(comboDistance, SIGNAL(currentIndexChanged(int)), this, SLOT(setByDistance(int)));
|
|
connect(smoothSlider, SIGNAL(valueChanged(int)), this, SLOT(setSmoothingFromSlider()));
|
|
connect(smoothLineEdit, SIGNAL(editingFinished()), this, SLOT(setSmoothingFromLineEdit()));
|
|
connect(rSmoothSlider, SIGNAL(valueChanged(int)), this, SLOT(setrSmoothingFromSlider()));
|
|
connect(rSmoothEdit, SIGNAL(editingFinished()), this, SLOT(setrSmoothingFromLineEdit()));
|
|
|
|
// normal view
|
|
connect(spanSlider, SIGNAL(lowerPositionChanged(int)), this, SLOT(zoomChanged()));
|
|
connect(spanSlider, SIGNAL(upperPositionChanged(int)), this, SLOT(zoomChanged()));
|
|
|
|
// stacked view
|
|
connect(scrollLeft, SIGNAL(clicked()), this, SLOT(moveLeft()));
|
|
connect(scrollRight, SIGNAL(clicked()), this, SLOT(moveRight()));
|
|
connect(stackZoomSlider, SIGNAL(valueChanged(int)), this, SLOT(stackZoomSliderChanged()));
|
|
|
|
// GC signals
|
|
connect(this, SIGNAL(rideItemChanged(RideItem*)), this, SLOT(rideSelected()));
|
|
connect(context, SIGNAL(rideDirty(RideItem*)), this, SLOT(rideSelected()));
|
|
connect(context, SIGNAL(rideChanged(RideItem*)), this, SLOT(forceReplot()));
|
|
connect(context, SIGNAL(configChanged(qint32)), this, SLOT(configChanged(qint32)));
|
|
connect(context->athlete, SIGNAL(zonesChanged()), this, SLOT(zonesChanged()));
|
|
connect(context, SIGNAL(intervalsChanged()), this, SLOT(intervalsChanged()));
|
|
connect(context, SIGNAL(intervalZoom(IntervalItem*)), this, SLOT(zoomInterval(IntervalItem*)));
|
|
connect(context, SIGNAL(zoomOut()), this, SLOT(zoomOut()));
|
|
connect(context, SIGNAL(intervalSelected()), this, SLOT(intervalSelected()));
|
|
connect(context, SIGNAL(rideDeleted(RideItem*)), this, SLOT(rideDeleted(RideItem*)));
|
|
|
|
// comparing things
|
|
connect(context, SIGNAL(compareIntervalsStateChanged(bool)), this, SLOT(compareChanged()));
|
|
connect(context, SIGNAL(compareIntervalsChanged()), this, SLOT(compareChanged()));
|
|
|
|
// set initial colors
|
|
configChanged(CONFIG_APPEARANCE);
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::configChanged(qint32 state)
|
|
{
|
|
setUpdatesEnabled(false);
|
|
|
|
setProperty("color", GColor(CRIDEPLOTBACKGROUND));
|
|
|
|
// Container widgets should not paint
|
|
// since they tend to use naff defaults and
|
|
// 'complicate' or 'make busy' the general
|
|
// look and feel
|
|
QPalette palette;
|
|
palette.setBrush(QPalette::Background, QBrush(GColor(CRIDEPLOTBACKGROUND)));
|
|
setPalette(palette); // propagates to children
|
|
|
|
// set style sheets
|
|
#ifndef Q_OS_MAC
|
|
allPlotFrame->setStyleSheet(TabView::ourStyleSheet());
|
|
comparePlotFrame->setStyleSheet(TabView::ourStyleSheet());
|
|
seriesstackFrame->setStyleSheet(TabView::ourStyleSheet());
|
|
stackFrame->setStyleSheet(TabView::ourStyleSheet());
|
|
overlayIntervals->setStyleSheet(TabView::ourStyleSheet());
|
|
#endif
|
|
|
|
// set palettes
|
|
allStack->setPalette(palette);
|
|
allPlotStack->setPalette(palette);
|
|
allPlotFrame->setPalette(palette);
|
|
allPlotFrame->viewport()->setPalette(palette); // its a scroll area
|
|
|
|
comparePlotFrame->setPalette(palette);
|
|
comparePlotWidget->setPalette(palette);
|
|
seriesstackFrame->setPalette(palette);
|
|
seriesstackWidget->setPalette(palette);
|
|
stackFrame->setPalette(palette);
|
|
stackWidget->setPalette(palette);
|
|
stackZoomSlider->setPalette(palette);
|
|
scrollLeft->setPalette(palette);
|
|
scrollRight->setPalette(palette);
|
|
|
|
|
|
fullPlot->setCanvasBackground(GColor(CRIDEPLOTBACKGROUND));
|
|
fullPlot->setPalette(palette);
|
|
fullPlot->configChanged(state);
|
|
fullPlot->update();
|
|
|
|
intervalPlot->setCanvasBackground(GColor(CRIDEPLOTBACKGROUND));
|
|
intervalPlot->setPalette(palette);
|
|
intervalPlot->configChanged(state);
|
|
intervalPlot->update();
|
|
|
|
// allPlot of course
|
|
allPlot->setCanvasBackground(GColor(CRIDEPLOTBACKGROUND));
|
|
allPlot->setPalette(palette);
|
|
allPlot->configChanged(state);
|
|
allPlot->update();
|
|
|
|
// and then the stacked plot
|
|
foreach (AllPlot *plot, allPlots) {
|
|
plot->setCanvasBackground(GColor(CRIDEPLOTBACKGROUND));
|
|
plot->setPalette(palette);
|
|
plot->configChanged(state);
|
|
plot->update();
|
|
}
|
|
|
|
// and then the series plots
|
|
foreach (AllPlot *plot, seriesPlots) {
|
|
plot->setCanvasBackground(GColor(CRIDEPLOTBACKGROUND));
|
|
plot->setPalette(palette);
|
|
plot->configChanged(state);
|
|
plot->update();
|
|
}
|
|
|
|
// and then the compaer plots
|
|
foreach (AllPlot *plot, allComparePlots) {
|
|
plot->setCanvasBackground(GColor(CRIDEPLOTBACKGROUND));
|
|
plot->setPalette(palette);
|
|
plot->configChanged(state);
|
|
plot->update();
|
|
}
|
|
|
|
setUpdatesEnabled(true);
|
|
|
|
// we're going to replot, but only if we're active
|
|
// and all the other guff
|
|
RideItem *ride = myRideItem;
|
|
if (!amVisible()) {
|
|
stale = true;
|
|
return;
|
|
}
|
|
|
|
// ignore if null, or manual / empty
|
|
if (!ride || !ride->ride() || !ride->ride()->dataPoints().count()) return;
|
|
|
|
// reset the charts etc
|
|
if (isCompare()) {
|
|
|
|
compareChanged();
|
|
|
|
} else {
|
|
|
|
// ok replot with the new config!
|
|
redrawFullPlot();
|
|
redrawAllPlot();
|
|
redrawStackPlot();
|
|
}
|
|
|
|
// just force a replot if wbal changed
|
|
// and we are actually plotting wbal !
|
|
if (state & CONFIG_WBAL && showW->isChecked()) forceReplot();
|
|
}
|
|
|
|
QString
|
|
AllPlotWindow::getUserData() const
|
|
{
|
|
QString returning;
|
|
foreach(UserData *x, userDataSeries)
|
|
returning += x->settings();
|
|
|
|
return returning;
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::setUserData(QString settings)
|
|
{
|
|
// wipe whats there
|
|
foreach(UserData *x, userDataSeries) delete x;
|
|
userDataSeries.clear();
|
|
|
|
// snip into discrete user data xml snippets
|
|
QRegExp snippet("(\\<userdata .*\\<\\/userdata\\>)");
|
|
snippet.setMinimal(true); // don't match too much
|
|
QStringList snips;
|
|
int pos = 0;
|
|
|
|
while ((pos = snippet.indexIn(settings, pos)) != -1) {
|
|
snips << snippet.cap(1);
|
|
pos += snippet.matchedLength();
|
|
}
|
|
|
|
// now create and add each series
|
|
foreach(QString set, snips)
|
|
userDataSeries << new UserData(set);
|
|
|
|
// fill with the current rideItem
|
|
setRideForUserData();
|
|
|
|
// tell full plot we have some and get allplot
|
|
// to match too, since it sets from fullplot
|
|
fullPlot->standard->setUserData(userDataSeries);
|
|
allPlot->standard->setUserData(userDataSeries);
|
|
|
|
// and update table
|
|
refreshCustomTable();
|
|
|
|
// replot
|
|
forceReplot();
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::setRideForUserData()
|
|
{
|
|
if (!current) return;
|
|
|
|
// user data needs refreshing
|
|
foreach(UserData *x, userDataSeries) x->setRideItem(current);
|
|
}
|
|
|
|
//
|
|
// configuring user data series
|
|
//
|
|
void
|
|
AllPlotWindow::refreshCustomTable(int indexSelectedItem)
|
|
{
|
|
// clear then repopulate custom table settings to reflect
|
|
// the current LTMSettings.
|
|
customTable->clear();
|
|
|
|
// get headers back
|
|
QStringList header;
|
|
header << tr("Name") << tr("Formula");
|
|
customTable->setHorizontalHeaderLabels(header);
|
|
|
|
QTableWidgetItem *selected = new QTableWidgetItem();
|
|
// now lets add a row for each metric
|
|
customTable->setRowCount(userDataSeries.count());
|
|
int i=0;
|
|
foreach (UserData *x, userDataSeries) {
|
|
|
|
QTableWidgetItem *t = new QTableWidgetItem();
|
|
t->setText(x->name); // only metrics .. for now ..
|
|
t->setFlags(t->flags() & (~Qt::ItemIsEditable));
|
|
customTable->setItem(i,0,t);
|
|
|
|
t = new QTableWidgetItem();
|
|
t->setText(x->formula);
|
|
t->setFlags(t->flags() & (~Qt::ItemIsEditable));
|
|
customTable->setItem(i,1,t);
|
|
|
|
// keep the selected item from previous step (relevant for moving up/down)
|
|
if (indexSelectedItem == i) {
|
|
selected = t;
|
|
}
|
|
|
|
i++;
|
|
}
|
|
|
|
if (selected) {
|
|
customTable->setCurrentItem(selected);
|
|
}
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::editUserData()
|
|
{
|
|
QList<QTableWidgetItem*> items = customTable->selectedItems();
|
|
if (items.count() < 1) return;
|
|
|
|
int index = customTable->row(items.first());
|
|
|
|
UserData edit(userDataSeries[index]->name,
|
|
userDataSeries[index]->units,
|
|
userDataSeries[index]->formula,
|
|
userDataSeries[index]->color);
|
|
|
|
EditUserDataDialog dialog(context, &edit);
|
|
|
|
if (dialog.exec()) {
|
|
|
|
// apply!
|
|
userDataSeries[index]->formula = edit.formula;
|
|
userDataSeries[index]->name = edit.name;
|
|
userDataSeries[index]->units = edit.units;
|
|
userDataSeries[index]->color = edit.color;
|
|
|
|
// update
|
|
refreshCustomTable();
|
|
|
|
// tell full plot we have some.
|
|
fullPlot->standard->setUserData(userDataSeries);
|
|
allPlot->standard->setUserData(userDataSeries);
|
|
|
|
// replot
|
|
forceReplot();
|
|
|
|
}
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::doubleClicked( int row, int )
|
|
{
|
|
UserData edit(userDataSeries[row]->name,
|
|
userDataSeries[row]->units,
|
|
userDataSeries[row]->formula,
|
|
userDataSeries[row]->color);
|
|
|
|
EditUserDataDialog dialog(context, &edit);
|
|
|
|
if (dialog.exec()) {
|
|
|
|
// apply!
|
|
userDataSeries[row]->formula = edit.formula;
|
|
userDataSeries[row]->name = edit.name;
|
|
userDataSeries[row]->units = edit.units;
|
|
userDataSeries[row]->color = edit.color;
|
|
|
|
// update
|
|
refreshCustomTable();
|
|
|
|
// tell full plot we have some.
|
|
fullPlot->standard->setUserData(userDataSeries);
|
|
allPlot->standard->setUserData(userDataSeries);
|
|
|
|
// replot
|
|
forceReplot();
|
|
}
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::deleteUserData()
|
|
{
|
|
QList<QTableWidgetItem*> items = customTable->selectedItems();
|
|
if (items.count() < 1) return;
|
|
|
|
int index = customTable->row(items.first());
|
|
UserData *deleteme = userDataSeries[index];
|
|
|
|
// wipe
|
|
userDataSeries.removeAt(index);
|
|
delete deleteme;
|
|
|
|
// refresh
|
|
refreshCustomTable();
|
|
|
|
// tell full plot we have some.
|
|
fullPlot->standard->setUserData(userDataSeries);
|
|
allPlot->standard->setUserData(userDataSeries);
|
|
|
|
// replot
|
|
forceReplot();
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::addUserData()
|
|
{
|
|
UserData add;
|
|
EditUserDataDialog dialog(context, &add);
|
|
|
|
if (dialog.exec()) {
|
|
// apply
|
|
userDataSeries.append(new UserData(add.name, add.units, add.formula, add.color));
|
|
|
|
// refresh
|
|
refreshCustomTable();
|
|
|
|
// tell full plot we have some.
|
|
fullPlot->standard->setUserData(userDataSeries);
|
|
allPlot->standard->setUserData(userDataSeries);
|
|
|
|
// replot
|
|
forceReplot();
|
|
}
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::moveUserDataUp()
|
|
{
|
|
QList<QTableWidgetItem*> items = customTable->selectedItems();
|
|
if (items.count() < 1) return;
|
|
|
|
int index = customTable->row(items.first());
|
|
|
|
if (index > 0) {
|
|
userDataSeries.swap(index, index-1);
|
|
// refresh
|
|
refreshCustomTable(index-1);
|
|
|
|
// tell full plot we have some.
|
|
fullPlot->standard->setUserData(userDataSeries);
|
|
allPlot->standard->setUserData(userDataSeries);
|
|
|
|
// replot
|
|
forceReplot();
|
|
}
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::moveUserDataDown()
|
|
{
|
|
QList<QTableWidgetItem*> items = customTable->selectedItems();
|
|
if (items.count() < 1) return;
|
|
|
|
int index = customTable->row(items.first());
|
|
|
|
if (index+1 < userDataSeries.size()) {
|
|
userDataSeries.swap(index, index+1);
|
|
// refresh
|
|
refreshCustomTable(index+1);
|
|
|
|
// tell full plot we have some.
|
|
fullPlot->standard->setUserData(userDataSeries);
|
|
allPlot->standard->setUserData(userDataSeries);
|
|
|
|
// replot
|
|
forceReplot();
|
|
}
|
|
}
|
|
|
|
bool
|
|
AllPlotWindow::event(QEvent *event)
|
|
{
|
|
// nasty nasty nasty hack to move widgets as soon as the widget geometry
|
|
// is set properly by the layout system, by default the width is 100 and
|
|
// we wait for it to be set properly then put our helper widget on the RHS
|
|
if (event->type() == QEvent::Resize && geometry().width() != 100) {
|
|
|
|
// put somewhere nice on first show
|
|
if (firstShow) {
|
|
firstShow = false;
|
|
helperWidget()->move(mainWidget()->geometry().width()-275, 50);
|
|
helperWidget()->raise();
|
|
|
|
if (isShowHelp()) helperWidget()->show();
|
|
else helperWidget()->hide();
|
|
}
|
|
|
|
// if off the screen move on screen
|
|
if (helperWidget()->geometry().x() > geometry().width()) {
|
|
helperWidget()->move(mainWidget()->geometry().width()-275, 50);
|
|
}
|
|
}
|
|
return QWidget::event(event);
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::compareChanged()
|
|
{
|
|
if (!amVisible()) {
|
|
if (context->isCompareIntervals) compareStale = true; // switched on
|
|
else stale = true; // switched off
|
|
return;
|
|
}
|
|
|
|
// we get busy so lets turn off updates till we're done
|
|
setUpdatesEnabled(false);
|
|
|
|
// clean up old
|
|
foreach(AllPlotObject *p, compareIntervalCurves) delete p;
|
|
compareIntervalCurves.clear();
|
|
|
|
// clean away old compare user data
|
|
foreach(QList<UserData*>user, compareUserDataSeries) {
|
|
foreach(UserData *p, user)
|
|
delete p;
|
|
}
|
|
compareUserDataSeries.clear();
|
|
|
|
// new ones ..
|
|
if (context->isCompareIntervals) {
|
|
|
|
// generate the user data series for each interval
|
|
foreach(CompareInterval ci, context->compareIntervals) {
|
|
QList<UserData*> list;
|
|
foreach(UserData *u, userDataSeries) {
|
|
UserData *p = new UserData(u->name, u->units, u->formula, ci.color); // use context for interval
|
|
p->setRideItem(ci.rideItem);
|
|
list << p;
|
|
}
|
|
compareUserDataSeries << list;
|
|
}
|
|
|
|
// first, lets init fullPlot, just in case its never
|
|
// been set (ie, switched to us before ever plotting a ride
|
|
if (myRideItem) fullPlot->setDataFromRide(myRideItem, QList<UserData*>());
|
|
|
|
// and even if the current ride is blank, we're not
|
|
// going to be blank !!
|
|
setIsBlank(false);
|
|
|
|
//
|
|
// SETUP INTERVALPLOT FOR COMPARE MODE
|
|
//
|
|
// No interval plot in compare mode yet
|
|
intervalPlot->hide();
|
|
|
|
//
|
|
// SETUP FULLPLOT FOR COMPARE MODE
|
|
//
|
|
double maxKM=0, maxSECS=0;
|
|
|
|
fullPlot->standard->setVisible(false);
|
|
if (fullPlot->smooth < 1) fullPlot->smooth = 1;
|
|
int k=0;
|
|
foreach(CompareInterval ci, context->compareIntervals) {
|
|
|
|
AllPlotObject *po = new AllPlotObject(fullPlot, compareUserDataSeries[k]);
|
|
if (ci.isChecked()) fullPlot->setDataFromRideFile(ci.data, po, compareUserDataSeries[k]);
|
|
|
|
// what was the maximum x value?
|
|
if (po->maxKM > maxKM) maxKM = po->maxKM;
|
|
if (po->maxSECS > maxSECS) maxSECS = po->maxSECS;
|
|
|
|
// prettify / hide unnecessary guff
|
|
po->setColor(ci.color);
|
|
po->hideUnwanted();
|
|
|
|
// remember
|
|
compareIntervalCurves << po;
|
|
|
|
// next
|
|
k++;
|
|
}
|
|
|
|
// what is the longest compareInterval?
|
|
if (fullPlot->bydist) fullPlot->setAxisScale(QwtPlot::xBottom, 0, maxKM);
|
|
else fullPlot->setAxisScale(QwtPlot::xBottom, 0, maxSECS/60);
|
|
|
|
// now set it it in all the compare objects so they all get set
|
|
// to the same time / duration and all the data is set too
|
|
k=0;
|
|
foreach (AllPlotObject *po, compareIntervalCurves) {
|
|
po->maxKM = maxKM;
|
|
po->maxSECS = maxSECS;
|
|
k++;
|
|
}
|
|
|
|
if (fullPlot->bydist == false) {
|
|
spanSlider->setMinimum(0);
|
|
spanSlider->setMaximum(maxSECS);
|
|
} else {
|
|
spanSlider->setMinimum(0);
|
|
spanSlider->setMaximum(maxKM * 1000);
|
|
}
|
|
spanSlider->setLowerValue(spanSlider->minimum());
|
|
spanSlider->setUpperValue(spanSlider->maximum());
|
|
|
|
// redraw for red/no-red title
|
|
fullPlot->replot();
|
|
|
|
//
|
|
// SETUP ALLPLOT AS A STACK FOR EACH INTERVAL
|
|
//
|
|
allStack->setCurrentIndex(1);
|
|
|
|
// first lets wipe the old ones
|
|
foreach (AllPlot *ap, allComparePlots) delete ap;
|
|
allComparePlots.clear();
|
|
if (comparePlotLayout->count() == 1) {
|
|
comparePlotLayout->takeAt(0); // remove the stretch
|
|
}
|
|
|
|
// now lets throw up one for each interval that
|
|
// is checked
|
|
int i=0;
|
|
foreach(CompareInterval ci, context->compareIntervals) {
|
|
|
|
// create a new one using the interval data object and
|
|
// referencing fullPlot for the user prefs etc
|
|
AllPlot *ap = new AllPlot(this, this, context);
|
|
ap->bydist = fullPlot->bydist;
|
|
ap->setShadeZones(showPower->currentIndex() == 0);
|
|
|
|
// user data series needs setting up
|
|
ap->setDataFromObject(compareIntervalCurves[i], fullPlot);
|
|
|
|
// simpler to keep the indexes aligned
|
|
if (!ci.isChecked()) ap->hide();
|
|
|
|
// tooltip on hover over point -- consider moving this to AllPlot (!)
|
|
ap->tooltip = new LTMToolTip(QwtPlot::xBottom, QwtAxisId(QwtAxis::yLeft, 2).id,
|
|
QwtPicker::VLineRubberBand,
|
|
QwtPicker::AlwaysOn,
|
|
ap->canvas(),
|
|
"");
|
|
ap->tooltip->setRubberBand(QwtPicker::VLineRubberBand);
|
|
ap->tooltip->setMousePattern(QwtEventPattern::MouseSelect1, Qt::LeftButton);
|
|
ap->tooltip->setTrackerPen(QColor(Qt::black));
|
|
QColor inv(Qt::white);
|
|
inv.setAlpha(0);
|
|
ap->tooltip->setRubberBandPen(inv);
|
|
ap->tooltip->setEnabled(true);
|
|
|
|
ap->_canvasPicker = new LTMCanvasPicker(ap);
|
|
connect(ap->_canvasPicker, SIGNAL(pointHover(QwtPlotCurve*, int)), ap, SLOT(pointHover(QwtPlotCurve*, int)));
|
|
|
|
// format it for our purposes
|
|
if (fullPlot->bydist) ap->setAxisScale(QwtPlot::xBottom, 0, maxKM);
|
|
else ap->setAxisScale(QwtPlot::xBottom, 0, maxSECS/60.00f);
|
|
ap->setFixedHeight(120 + (stackWidth *4));
|
|
|
|
// add to layout
|
|
comparePlotLayout->addWidget(ap);
|
|
allComparePlots << ap;
|
|
|
|
i++;
|
|
}
|
|
comparePlotLayout->addStretch();
|
|
|
|
//
|
|
// SETUP STACK SERIES
|
|
//
|
|
|
|
// Wipe away whatever is there
|
|
foreach(AllPlot *plot, seriesPlots) delete plot;
|
|
seriesPlots.clear();
|
|
// and the stretch
|
|
while (seriesstackPlotLayout->count()) {
|
|
delete seriesstackPlotLayout->takeAt(0);
|
|
}
|
|
|
|
// work out what we want to see
|
|
QList<SeriesWanted> wanted;
|
|
SeriesWanted s;
|
|
if (showPower->currentIndex() < 2) { s.one = RideFile::watts; s.two = RideFile::none; wanted << s;};
|
|
if (showW->isChecked()) { s.one = RideFile::wprime; s.two = RideFile::none; wanted << s;};
|
|
if (showPowerD->isChecked()) { s.one = RideFile::wattsd; s.two = RideFile::none; wanted << s;};
|
|
if (showHr->isChecked()) { s.one = RideFile::hr; s.two = RideFile::none; wanted << s;};
|
|
if (showTcore->isChecked()) { s.one = RideFile::tcore; s.two = RideFile::none; wanted << s;};
|
|
if (showHrD->isChecked()) { s.one = RideFile::hrd; s.two = RideFile::none; wanted << s;};
|
|
if (showSpeed->isChecked()) { s.one = RideFile::kph; s.two = RideFile::none; wanted << s;};
|
|
if (showAccel->isChecked()) { s.one = RideFile::kphd; s.two = RideFile::none; wanted << s;};
|
|
if (showCad->isChecked()) { s.one = RideFile::cad; s.two = RideFile::none; wanted << s;};
|
|
if (showCadD->isChecked()) { s.one = RideFile::cadd; s.two = RideFile::none; wanted << s;};
|
|
if (showTorque->isChecked()) { s.one = RideFile::nm; s.two = RideFile::none; wanted << s;};
|
|
if (showTorqueD->isChecked()) { s.one = RideFile::nmd; s.two = RideFile::none; wanted << s;};
|
|
if (showAlt->isChecked()) { s.one = RideFile::alt; s.two = RideFile::none; wanted << s;};
|
|
if (showSlope->isChecked()) { s.one = RideFile::slope; s.two = RideFile::none; wanted << s;};
|
|
if (showAltSlope->currentIndex() > 0) { s.one = RideFile::alt; s.two = RideFile::slope; wanted << s;}; // ALT/SLOPE !
|
|
if (showTemp->isChecked()) { s.one = RideFile::temp; s.two = RideFile::none; wanted << s;};
|
|
if (showWind->isChecked()) { s.one = RideFile::headwind; s.two = RideFile::none; wanted << s;};
|
|
if (showNP->isChecked()) { s.one = RideFile::NP; s.two = RideFile::none; wanted << s;};
|
|
if (showRV->isChecked()) { s.one = RideFile::rvert; s.two = RideFile::none; wanted << s;};
|
|
if (showRCad->isChecked()) { s.one = RideFile::rcad; s.two = RideFile::none; wanted << s;};
|
|
if (showRGCT->isChecked()) { s.one = RideFile::rcontact; s.two = RideFile::none; wanted << s;};
|
|
if (showGear->isChecked()) { s.one = RideFile::gear; s.two = RideFile::none; wanted << s;};
|
|
if (showSmO2->isChecked()) { s.one = RideFile::smo2; s.two = RideFile::none; wanted << s;};
|
|
if (showtHb->isChecked()) { s.one = RideFile::thb; s.two = RideFile::none; wanted << s;};
|
|
if (showO2Hb->isChecked()) { s.one = RideFile::o2hb; s.two = RideFile::none; wanted << s;};
|
|
if (showHHb->isChecked()) { s.one = RideFile::hhb; s.two = RideFile::none; wanted << s;};
|
|
if (showATISS->isChecked()) { s.one = RideFile::aTISS; s.two = RideFile::none; wanted << s;};
|
|
if (showANTISS->isChecked()) { s.one = RideFile::anTISS; s.two = RideFile::none; wanted << s;};
|
|
if (showXP->isChecked()) { s.one = RideFile::xPower; s.two = RideFile::none; wanted << s;};
|
|
if (showAP->isChecked()) { s.one = RideFile::aPower; s.two = RideFile::none; wanted << s;};
|
|
if (showBalance->isChecked()) { s.one = RideFile::lrbalance; s.two = RideFile::none; wanted << s;};
|
|
|
|
// and the user series
|
|
for(int k=0; k<userDataSeries.count(); k++) {
|
|
s.one = static_cast<RideFile::SeriesType>(RideFile::none + 1 + k);
|
|
s.two = RideFile::none;
|
|
wanted << s;
|
|
}
|
|
|
|
/*
|
|
if (showTE->isChecked()) {
|
|
s.one = RideFile::lte; s.two = RideFile::none; wanted << s;
|
|
s.one = RideFile::rte; s.two = RideFile::none; wanted << s;
|
|
}
|
|
if (showPS->isChecked()) {
|
|
s.one = RideFile::lps; s.two = RideFile::none; wanted << s;
|
|
s.one = RideFile::rps; s.two = RideFile::none; wanted << s;
|
|
}
|
|
if (showPCO->isChecked()) {
|
|
s.one = RideFile::lpco; s.two = RideFile::rpco; wanted << s;
|
|
}
|
|
if (showDC->isChecked()) {
|
|
s.one = RideFile::lppb; s.two = RideFile::lppe; wanted << s;
|
|
s.one = RideFile::rppb; s.two = RideFile::rppe; wanted << s;
|
|
}
|
|
if (showPPP->isChecked()) {
|
|
s.one = RideFile::lpppb; s.two = RideFile::lpppe; wanted << s;
|
|
s.one = RideFile::rpppb; s.two = RideFile::rpppe; wanted << s;
|
|
}*/
|
|
|
|
// create blank and add to gui
|
|
QPalette palette;
|
|
palette.setBrush(QPalette::Background, Qt::NoBrush);
|
|
|
|
foreach(SeriesWanted x, wanted) {
|
|
|
|
// create and setup with normal gui stuff
|
|
AllPlot *plot = new AllPlot(this, this, context, x.one, x.two, false);
|
|
plot->setPalette(palette);
|
|
plot->setAutoFillBackground(false);
|
|
plot->setFixedHeight(120+(stackWidth*4));
|
|
|
|
// tooltip on hover over point -- consider moving this to AllPlot (!)
|
|
plot->tooltip = new LTMToolTip(QwtPlot::xBottom, QwtAxisId(QwtAxis::yLeft, 2).id,
|
|
QwtPicker::VLineRubberBand,
|
|
QwtPicker::AlwaysOn,
|
|
plot->canvas(),
|
|
"");
|
|
plot->tooltip->setRubberBand(QwtPicker::VLineRubberBand);
|
|
plot->tooltip->setMousePattern(QwtEventPattern::MouseSelect1, Qt::LeftButton);
|
|
plot->tooltip->setTrackerPen(QColor(Qt::black));
|
|
QColor inv(Qt::white);
|
|
inv.setAlpha(0);
|
|
plot->tooltip->setRubberBandPen(inv);
|
|
plot->tooltip->setEnabled(true);
|
|
|
|
plot->_canvasPicker = new LTMCanvasPicker(plot);
|
|
connect(plot->_canvasPicker, SIGNAL(pointHover(QwtPlotCurve*, int)), plot, SLOT(pointHover(QwtPlotCurve*, int)));
|
|
// No x axis titles
|
|
plot->bydist = fullPlot->bydist;
|
|
if (x.one == RideFile::watts) plot->setShadeZones(showPower->currentIndex() == 0);
|
|
else plot->setShadeZones(false);
|
|
plot->setAxisVisible(QwtPlot::xBottom, true);
|
|
plot->enableAxis(QwtPlot::xBottom, true);
|
|
plot->setAxisTitle(QwtPlot::xBottom,NULL);
|
|
|
|
// get rid of the User Data axis
|
|
for(int k=0; k<userDataSeries.count(); k++)
|
|
plot->setAxisVisible(QwtAxisId(QwtAxis::yRight,4 + k), false);
|
|
|
|
// common y axis
|
|
QwtScaleDraw *sd = new QwtScaleDraw;
|
|
sd->setTickLength(QwtScaleDiv::MajorTick, 3);
|
|
sd->enableComponent(QwtScaleDraw::Ticks, false);
|
|
sd->enableComponent(QwtScaleDraw::Backbone, false);
|
|
plot->setAxisScaleDraw(QwtPlot::yLeft, sd);
|
|
|
|
// default paletter override below if needed
|
|
QPalette pal;
|
|
pal.setColor(QPalette::WindowText, RideFile::colorFor(x.one));
|
|
pal.setColor(QPalette::Text, RideFile::colorFor(x.one));
|
|
|
|
// y-axis title and colour
|
|
if (x.one == RideFile::alt && x.two == RideFile::slope) {
|
|
|
|
// alt/slope special case
|
|
plot->setAxisTitle(QwtPlot::yLeft, tr("Alt/Slope"));
|
|
plot->showAltSlopeState = allPlot->showAltSlopeState;
|
|
plot->setAltSlopePlotStyle(allPlot->standard->altSlopeCurve);
|
|
|
|
} else {
|
|
|
|
// user defined series
|
|
if (x.one > RideFile::none) {
|
|
int index = (int)(x.one) - (RideFile::none + 1);
|
|
plot->setAxisTitle(QwtPlot::yLeft, userDataSeries[index]->name);
|
|
pal.setColor(QPalette::WindowText, userDataSeries[index]->color);
|
|
pal.setColor(QPalette::Text, userDataSeries[index]->color);
|
|
} else {
|
|
// everything else
|
|
plot->setAxisTitle(QwtPlot::yLeft, RideFile::seriesName(x.one));
|
|
}
|
|
}
|
|
|
|
plot->axisWidget(QwtPlot::yLeft)->setPalette(pal);
|
|
|
|
// remember them
|
|
seriesstackPlotLayout->addWidget(plot);
|
|
seriesPlots << plot;
|
|
}
|
|
|
|
seriesstackPlotLayout->addStretch();
|
|
|
|
// now lets get each of them loaded up with data and in the right format!
|
|
foreach(AllPlot *compare, seriesPlots) {
|
|
|
|
// update the one already there
|
|
compare->standard->setVisible(false);
|
|
compare->setDataFromPlots(allComparePlots);
|
|
|
|
// format it for our purposes
|
|
compare->bydist = fullPlot->bydist;
|
|
if (fullPlot->bydist) compare->setAxisScale(QwtPlot::xBottom, 0, maxKM);
|
|
else compare->setAxisScale(QwtPlot::xBottom, 0, maxSECS/60.00f);
|
|
compare->setXTitle();
|
|
|
|
compare->replot();
|
|
}
|
|
|
|
// now remove any series plots that are empty
|
|
for(int i=0; i<seriesPlots.count();) {
|
|
if (seriesPlots[i]->compares.count() == 0 || seriesPlots[i]->compares[0]->data()->size() == 0) {
|
|
delete seriesPlots[i];
|
|
seriesPlots.removeAt(i);
|
|
} else {
|
|
i++;
|
|
}
|
|
}
|
|
|
|
// ok, we're done
|
|
|
|
} else {
|
|
|
|
if (showInterval->isChecked())
|
|
intervalPlot->show();
|
|
|
|
// reset to normal view?
|
|
fullPlot->standard->setVisible(true);
|
|
|
|
// back to allplot
|
|
allStack->setCurrentIndex(0);
|
|
|
|
// reset by just calling ride selected
|
|
// and setting stale to true.. simpler this way
|
|
stale = true;
|
|
rideSelected();
|
|
}
|
|
|
|
// we're not stale anymore
|
|
compareStale = false;
|
|
|
|
// set the widgets straight
|
|
setAllPlotWidgets(NULL);
|
|
|
|
// Now we're done lets paint
|
|
setUpdatesEnabled(true);
|
|
repaint();
|
|
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::redrawAllPlot()
|
|
{
|
|
// refresh if shown or used as basis for stacked series (ie zooming off fullPlot)
|
|
if (((showStack->isChecked() && showBySeries->isChecked()) || !showStack->isChecked()) && current) {
|
|
|
|
RideItem *ride = current;
|
|
|
|
int startidx, stopidx;
|
|
if (fullPlot->bydist == true) {
|
|
startidx =ride->ride()->distanceIndex((double)spanSlider->lowerValue()/(double)1000);
|
|
stopidx = ride->ride()->distanceIndex((double)spanSlider->upperValue()/(double)1000);
|
|
} else {
|
|
startidx = ride->ride()->timeIndex(spanSlider->lowerValue());
|
|
stopidx = ride->ride()->timeIndex(spanSlider->upperValue());
|
|
}
|
|
|
|
// need more than 1 sample to plot
|
|
if (stopidx - startidx > 1) {
|
|
allPlot->setDataFromPlot(fullPlot, startidx, stopidx);
|
|
allZoomer->setZoomBase();
|
|
//allPlot->setTitle("");
|
|
allPlot->replot();
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::redrawFullPlot()
|
|
{
|
|
// always performed since the data is used
|
|
// by both the stack plots and the allplot
|
|
RideItem *ride = current;
|
|
|
|
// null rides are possible on new cyclist
|
|
if (!ride) return;
|
|
|
|
// hide the usual plot decorations etc
|
|
fullPlot->setShowPower(1);
|
|
//We now use the window background color
|
|
//fullPlot->setCanvasBackground(GColor(CPLOTTHUMBNAIL));
|
|
static_cast<QwtPlotCanvas*>(fullPlot->canvas())->setBorderRadius(0);
|
|
fullPlot->standard->grid->enableY(false);
|
|
|
|
// use the ride to decide
|
|
if (fullPlot->bydist)
|
|
fullPlot->setAxisScale(QwtPlot::xBottom,
|
|
ride->ride()->dataPoints().first()->km * (context->athlete->useMetricUnits ? 1 : MILES_PER_KM),
|
|
ride->ride()->dataPoints().last()->km * (context->athlete->useMetricUnits ? 1 : MILES_PER_KM));
|
|
else
|
|
fullPlot->setAxisScale(QwtPlot::xBottom, ride->ride()->dataPoints().first()->secs/60,
|
|
ride->ride()->dataPoints().last()->secs/60);
|
|
|
|
fullPlot->replot();
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::redrawIntervalPlot()
|
|
{
|
|
// always performed since the data is used
|
|
// by both the stack plots and the allplot
|
|
RideItem *ride = current;
|
|
|
|
// null rides are possible on new cyclist
|
|
if (!ride) return;
|
|
|
|
static_cast<QwtPlotCanvas*>(intervalPlot->canvas())->setBorderRadius(0);
|
|
|
|
// use the ride to decide
|
|
if (intervalPlot->bydist)
|
|
intervalPlot->setAxisScale(QwtPlot::xBottom,
|
|
ride->ride()->dataPoints().first()->km * (context->athlete->useMetricUnits ? 1 : MILES_PER_KM),
|
|
ride->ride()->dataPoints().last()->km * (context->athlete->useMetricUnits ? 1 : MILES_PER_KM));
|
|
else
|
|
intervalPlot->setAxisScale(QwtPlot::xBottom, ride->ride()->dataPoints().first()->secs/60,
|
|
ride->ride()->dataPoints().last()->secs/60);
|
|
|
|
intervalPlot->replot();
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::redrawStackPlot()
|
|
{
|
|
if (showStack->isChecked()) {
|
|
|
|
// turn off display updates whilst we
|
|
// do this, it takes a while and is prone
|
|
// to screen flicker
|
|
stackFrame->setUpdatesEnabled(false);
|
|
|
|
|
|
// plot stack view ..
|
|
if (!showBySeries->isChecked()) {
|
|
|
|
// BY TIME / DISTANCE
|
|
|
|
// remove current plots - then recreate
|
|
resetStackedDatas();
|
|
|
|
// now they are all set, lets replot
|
|
foreach(AllPlot *plot, allPlots) plot->replot();
|
|
|
|
} else {
|
|
|
|
// BY SERIES
|
|
resetSeriesStackedDatas();
|
|
|
|
// now they are all set, lets replot
|
|
foreach(AllPlot *plot, seriesPlots) plot->replot();
|
|
}
|
|
|
|
// we're done, go update the display now
|
|
stackFrame->setUpdatesEnabled(true);
|
|
}
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::zoomChanged()
|
|
{
|
|
if (isCompare()) {
|
|
|
|
// zoom in all the compare plots
|
|
foreach (AllPlot *plot, allComparePlots) {
|
|
if (fullPlot->bydist) plot->setAxisScale(QwtPlot::xBottom, spanSlider->lowerValue()/1000.00f, spanSlider->upperValue()/1000.00f);
|
|
else plot->setAxisScale(QwtPlot::xBottom, spanSlider->lowerValue() / 60.00f, spanSlider->upperValue() / 60.00f);
|
|
|
|
plot->replot();
|
|
}
|
|
|
|
// and the series plots
|
|
foreach (AllPlot *plot, seriesPlots) {
|
|
if (fullPlot->bydist) plot->setAxisScale(QwtPlot::xBottom, spanSlider->lowerValue()/1000.00f, spanSlider->upperValue()/1000.00f);
|
|
else plot->setAxisScale(QwtPlot::xBottom, spanSlider->lowerValue() / 60.00f, spanSlider->upperValue() / 60.00f);
|
|
|
|
plot->replot();
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
redrawAllPlot();
|
|
redrawStackPlot(); // series stacks!
|
|
}
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::moveLeft()
|
|
{
|
|
// move across by 5% of the span, or to zero if not much left
|
|
int span = spanSlider->upperValue() - spanSlider->lowerValue();
|
|
int delta = span / 20;
|
|
if (delta > (spanSlider->lowerValue() - spanSlider->minimum()))
|
|
delta = spanSlider->lowerValue() - spanSlider->minimum();
|
|
|
|
spanSlider->setLowerValue(spanSlider->lowerValue()-delta);
|
|
spanSlider->setUpperValue(spanSlider->upperValue()-delta);
|
|
zoomChanged();
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::moveRight()
|
|
{
|
|
// move across by 5% of the span, or to zero if not much left
|
|
int span = spanSlider->upperValue() - spanSlider->lowerValue();
|
|
int delta = span / 20;
|
|
if (delta > (spanSlider->maximum() - spanSlider->upperValue()))
|
|
delta = spanSlider->maximum() - spanSlider->upperValue();
|
|
|
|
spanSlider->setLowerValue(spanSlider->lowerValue()+delta);
|
|
spanSlider->setUpperValue(spanSlider->upperValue()+delta);
|
|
zoomChanged();
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::forceReplot()
|
|
{
|
|
stale=true;
|
|
rideSelected();
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::rideSelected()
|
|
{
|
|
// compare mode ignores ride selection
|
|
if (isVisible() && isCompare()) {
|
|
if (compareStale) compareChanged();
|
|
return;
|
|
}
|
|
|
|
RideItem *ride = myRideItem;
|
|
|
|
if (ride == NULL) current = NULL;
|
|
|
|
// ignore if not active
|
|
if (!amVisible()) {
|
|
stale = true;
|
|
setupSeriesStack = setupStack = false;
|
|
return;
|
|
}
|
|
|
|
// ignore if null, or manual / empty
|
|
if (!ride || !ride->ride() || !ride->ride()->dataPoints().count()) {
|
|
current = NULL;
|
|
setIsBlank(true);
|
|
return;
|
|
}
|
|
else
|
|
setIsBlank(false);
|
|
|
|
// we already plotted it!
|
|
//XXX the !ride->isDirty() code below makes GC crash when selecting
|
|
//XXX on the canvas ?!??!? No idea why, but commenting out for now
|
|
//XXX if (!ride->isDirty() && ride == current && stale == false) return;
|
|
if (ride == current && stale == false) return;
|
|
|
|
// ok, its now the current ride
|
|
current = ride;
|
|
|
|
// setup user data if needed
|
|
setRideForUserData();
|
|
|
|
// clear any previous selections
|
|
clearSelection();
|
|
|
|
// setup the control widgets, dependant on
|
|
// data present in this ride, needs to happen
|
|
// before we set the plots below...
|
|
setAllPlotWidgets(ride);
|
|
|
|
// setup the charts to reflect current ride selection
|
|
fullPlot->setDataFromRide(ride, userDataSeries);
|
|
intervalPlot->setDataFromRide(ride);
|
|
|
|
|
|
// Fixup supplied by Josef Gebel
|
|
int startidx, stopidx;
|
|
if ( fullPlot->bydist == true ) {
|
|
startidx = ride->ride()->distanceIndex( ( double ) spanSlider->lowerValue() / 1000.0 );
|
|
stopidx = ride->ride()->distanceIndex( ( double ) spanSlider->upperValue() / 1000.0 );
|
|
} else {
|
|
startidx = ride->ride()->timeIndex( spanSlider->lowerValue() );
|
|
stopidx = ride->ride()->timeIndex( spanSlider->upperValue() );
|
|
}
|
|
|
|
// redraw all the plots, they will check
|
|
// to see if they are currently visible
|
|
// and only redraw if neccessary
|
|
redrawFullPlot();
|
|
redrawAllPlot();
|
|
redrawIntervalPlot();
|
|
|
|
// we need to reset the stacks as the ride has changed
|
|
// but it may ignore if not in stacked mode.
|
|
setupSeriesStack = setupStack = false;
|
|
|
|
setupStackPlots();
|
|
setupSeriesStackPlots();
|
|
|
|
stale = false;
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::rideDeleted(RideItem *ride)
|
|
{
|
|
if (ride == myRideItem) {
|
|
// we have nothing to show
|
|
setProperty("ride", QVariant::fromValue<RideItem*>(NULL));
|
|
|
|
// notify all the plots, because when zones are redrawn
|
|
// they will try and reference AllPlot::rideItem
|
|
if (!isCompare()) {
|
|
setAllPlotWidgets(NULL);
|
|
fullPlot->setDataFromRide(NULL,QList<UserData*>());
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::zonesChanged()
|
|
{
|
|
if (!amVisible()) {
|
|
stale = true;
|
|
return;
|
|
}
|
|
|
|
allPlot->refreshZoneLabels();
|
|
allPlot->replot();
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::intervalsChanged()
|
|
{
|
|
if (!amVisible()) {
|
|
stale = true;
|
|
return;
|
|
}
|
|
|
|
// show selection on fullplot too
|
|
fullPlot->refreshIntervalMarkers();
|
|
fullPlot->replot();
|
|
|
|
intervalPlot->refreshIntervals();
|
|
intervalPlot->replot();
|
|
|
|
// allPlot of course
|
|
allPlot->refreshIntervalMarkers();
|
|
allPlot->replot();
|
|
|
|
// and then the stacked plot
|
|
foreach (AllPlot *plot, allPlots) {
|
|
plot->refreshIntervalMarkers();
|
|
plot->replot();
|
|
}
|
|
|
|
// and then the series plots
|
|
foreach (AllPlot *plot, seriesPlots) {
|
|
plot->refreshIntervalMarkers();
|
|
plot->replot();
|
|
}
|
|
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::intervalSelected()
|
|
{
|
|
if (isCompare() || !amVisible()) {
|
|
stale = true;
|
|
return;
|
|
}
|
|
|
|
if (active == true) return;
|
|
|
|
// the intervals are highlighted
|
|
// in the plot automatically, we just
|
|
// need to replot, depending upon
|
|
// which mode we are in...
|
|
hideSelection();
|
|
if (showStack->isChecked()) {
|
|
|
|
if (showBySeries->isChecked()) {
|
|
foreach (AllPlot *plot, seriesPlots)
|
|
plot->replot();
|
|
} else {
|
|
foreach (AllPlot *plot, allPlots)
|
|
plot->replot();
|
|
}
|
|
} else {
|
|
fullPlot->replot();
|
|
allPlot->replot();
|
|
}
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::setStacked(int value)
|
|
{
|
|
showStack->setChecked(value);
|
|
rStack->setChecked(value);
|
|
|
|
// enables / disable as needed
|
|
if (showStack->isChecked()) {
|
|
showBySeries->setEnabled(true);
|
|
rBySeries->setEnabled(true);
|
|
} else {
|
|
showBySeries->setEnabled(false);
|
|
rBySeries->setEnabled(false);
|
|
}
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::setBySeries(int value)
|
|
{
|
|
showBySeries->setChecked(value);
|
|
rBySeries->setChecked(value);
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::setSmoothingFromSlider()
|
|
{
|
|
// active tells us we have been triggered by
|
|
// the setSmoothingFromLineEdit which will also
|
|
// recalculates smoothing, lets not double up...
|
|
if (active) return;
|
|
else active = true;
|
|
|
|
if (allPlot->smooth != smoothSlider->value()) {
|
|
setSmoothing(smoothSlider->value());
|
|
smoothLineEdit->setText(QString("%1").arg(fullPlot->smooth));
|
|
rSmoothEdit->setText(QString("%1").arg(fullPlot->smooth));
|
|
rSmoothSlider->setValue(rSmoothSlider->value());
|
|
}
|
|
active = false;
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::setrSmoothingFromSlider()
|
|
{
|
|
// active tells us we have been triggered by
|
|
// the setSmoothingFromLineEdit which will also
|
|
// recalculates smoothing, lets not double up...
|
|
if (active) return;
|
|
else active = true;
|
|
|
|
if (allPlot->smooth != rSmoothSlider->value()) {
|
|
setSmoothing(rSmoothSlider->value());
|
|
rSmoothEdit->setText(QString("%1").arg(fullPlot->smooth));
|
|
smoothSlider->setValue(rSmoothSlider->value());
|
|
smoothLineEdit->setText(QString("%1").arg(fullPlot->smooth));
|
|
}
|
|
active = false;
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::setSmoothingFromLineEdit()
|
|
{
|
|
// active tells us we have been triggered by
|
|
// the setSmoothingFromSlider which will also
|
|
// recalculates smoothing, lets not double up...
|
|
if (active) return;
|
|
else active = true;
|
|
|
|
int value = smoothLineEdit->text().toInt();
|
|
if (value != fullPlot->smooth) {
|
|
smoothSlider->setValue(value);
|
|
rSmoothSlider->setValue(value);
|
|
setSmoothing(value);
|
|
}
|
|
active = false;
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::setrSmoothingFromLineEdit()
|
|
{
|
|
// active tells us we have been triggered by
|
|
// the setSmoothingFromSlider which will also
|
|
// recalculates smoothing, lets not double up...
|
|
if (active) return;
|
|
else active = true;
|
|
|
|
int value = rSmoothEdit->text().toInt();
|
|
if (value != fullPlot->smooth) {
|
|
rSmoothSlider->setValue(value);
|
|
smoothSlider->setValue(value);
|
|
setSmoothing(value);
|
|
}
|
|
active = false;
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::setAllPlotWidgets(RideItem *ride)
|
|
{
|
|
// this routine sets up the display widgets
|
|
// depending upon what data is available in the
|
|
// ride. It also hides/shows widgets depending
|
|
// upon wether we are in 'normal' mode or
|
|
// stacked plot mode
|
|
if (!isCompare()) {
|
|
|
|
// set for currently selected ride
|
|
if (!ride) return;
|
|
|
|
// checkboxes to show/hide specific data series...
|
|
const RideFileDataPresent *dataPresent = ride->ride()->areDataPresent();
|
|
if (ride->ride() && ride->ride()->deviceType() != QString("Manual CSV")) {
|
|
|
|
showPowerD->setEnabled(dataPresent->watts);
|
|
showCadD->setEnabled(dataPresent->cad);
|
|
showTorqueD->setEnabled(dataPresent->nm);
|
|
showHrD->setEnabled(dataPresent->hr);
|
|
showPower->setEnabled(dataPresent->watts);
|
|
showCad->setEnabled(dataPresent->cad);
|
|
showTorque->setEnabled(dataPresent->nm);
|
|
showHr->setEnabled(dataPresent->hr);
|
|
showTcore->setEnabled(dataPresent->hr);
|
|
showSpeed->setEnabled(dataPresent->kph);
|
|
showAccel->setEnabled(dataPresent->kph);
|
|
showAlt->setEnabled(dataPresent->alt);
|
|
showAltSlope->setEnabled(dataPresent->alt);
|
|
showSlope->setEnabled(dataPresent->slope);
|
|
showTemp->setEnabled(dataPresent->temp);
|
|
showWind->setEnabled(dataPresent->headwind);
|
|
showBalance->setEnabled(dataPresent->lrbalance);
|
|
} else {
|
|
showAccel->setEnabled(false);
|
|
showPowerD->setEnabled(false);
|
|
showCadD->setEnabled(false);
|
|
showTorqueD->setEnabled(false);
|
|
showHrD->setEnabled(false);
|
|
showPower->setEnabled(false);
|
|
showHr->setEnabled(false);
|
|
showTcore->setEnabled(false);
|
|
showSpeed->setEnabled(false);
|
|
showCad->setEnabled(false);
|
|
showAlt->setEnabled(false);
|
|
showAltSlope->setEnabled(false);
|
|
showSlope->setEnabled(false);
|
|
showTemp->setEnabled(false);
|
|
showWind->setEnabled(false);
|
|
showTorque->setEnabled(false);
|
|
showBalance->setEnabled(false);
|
|
}
|
|
|
|
// turn on/off shading, if it's not available
|
|
bool shade;
|
|
if (dataPresent->watts) shade = (showPower->currentIndex() == 0);
|
|
else shade = false;
|
|
allPlot->setShadeZones(shade);
|
|
foreach (AllPlot *plot, allPlots) plot->setShadeZones(shade);
|
|
allPlot->setShowGrid(showGrid->checkState() == Qt::Checked);
|
|
foreach (AllPlot *plot, allPlots) plot->setShowGrid(showGrid->checkState() == Qt::Checked);
|
|
|
|
// set the SpanSlider for the ride length, by default
|
|
// show the entire ride (the user can adjust later)
|
|
if (fullPlot->bydist == false) {
|
|
spanSlider->setMinimum(ride->ride()->dataPoints().first()->secs);
|
|
spanSlider->setMaximum(ride->ride()->dataPoints().last()->secs);
|
|
spanSlider->setLowerValue(spanSlider->minimum());
|
|
spanSlider->setUpperValue(spanSlider->maximum());
|
|
} else {
|
|
spanSlider->setMinimum(ride->ride()->dataPoints().first()->km * 1000);
|
|
spanSlider->setMaximum(ride->ride()->dataPoints().last()->km * 1000);
|
|
spanSlider->setLowerValue(spanSlider->minimum());
|
|
spanSlider->setUpperValue(spanSlider->maximum());
|
|
}
|
|
}
|
|
|
|
// now set the visible plots, depending upon whether
|
|
// we are in stacked mode or not
|
|
if (!isCompare() && showStack->isChecked() && !showBySeries->isChecked()) {
|
|
|
|
// ALL PLOT STACK ORIGINAL AS CODED BY DAMIEN
|
|
|
|
// hide normal view
|
|
allPlotFrame->hide();
|
|
allPlot->hide();
|
|
fullPlot->hide();
|
|
controlsLayout->setRowStretch(0, 0);
|
|
controlsLayout->setRowStretch(1, 0);
|
|
|
|
// show stacked view
|
|
stackFrame->show();
|
|
|
|
} else {
|
|
|
|
// hide stack plots (segmented by time/distance)
|
|
stackFrame->hide();
|
|
|
|
// show normal view
|
|
allPlotFrame->show();
|
|
allPlot->show();
|
|
|
|
if (showStack->isChecked() && (isCompare() || showBySeries->isChecked())) {
|
|
|
|
// STACK SERIES LANES SHOWING
|
|
allPlotStack->setCurrentIndex(1);
|
|
|
|
} else {
|
|
|
|
// ALLPLOT
|
|
allPlotStack->setCurrentIndex(0);
|
|
|
|
if (isCompare()) {
|
|
|
|
// COMPARE ALL PLOTS
|
|
allStack->setCurrentIndex(1); // compare mode stack of all plots
|
|
|
|
} else {
|
|
|
|
// NORMAL SINGLE ALL PLOT
|
|
allStack->setCurrentIndex(0); // normal single allplot
|
|
}
|
|
|
|
}
|
|
|
|
// FIXUP FULL PLOT!
|
|
if (showFull->isChecked()) {
|
|
fullPlot->show();
|
|
controlsLayout->setRowStretch(0, 100);
|
|
controlsLayout->setRowStretch(1, 20);
|
|
} else {
|
|
fullPlot->hide();
|
|
|
|
if (isCompare()) {
|
|
controlsLayout->setRowStretch(0, 100);
|
|
controlsLayout->setRowStretch(1, 00);
|
|
} else {
|
|
controlsLayout->setRowStretch(0, 100);
|
|
controlsLayout->setRowStretch(1, 00);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::zoomOut()
|
|
{
|
|
// we don't do that in compare mode
|
|
if (isCompare()) return;
|
|
|
|
// set them to maximums to avoid overlapping
|
|
// when we set them below, daft but works
|
|
spanSlider->setLowerValue(spanSlider->minimum());
|
|
spanSlider->setUpperValue(spanSlider->maximum());
|
|
zoomChanged();
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::zoomInterval(IntervalItem *which)
|
|
{
|
|
// we don't do that in compare mode
|
|
if (isCompare()) return;
|
|
|
|
// use the span slider to highlight
|
|
// when we are in normal mode.
|
|
|
|
// set them to maximums to avoid overlapping
|
|
// when we set them below, daft but works
|
|
spanSlider->setLowerValue(spanSlider->minimum());
|
|
spanSlider->setUpperValue(spanSlider->maximum());
|
|
|
|
if (!allPlot->bydist) {
|
|
spanSlider->setLowerValue(which->start);
|
|
spanSlider->setUpperValue(which->stop);
|
|
} else {
|
|
spanSlider->setLowerValue(which->startKM * (double)1000);
|
|
spanSlider->setUpperValue(which->stopKM * (double)1000);
|
|
}
|
|
zoomChanged();
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::plotPickerSelected(const QPoint &pos)
|
|
{
|
|
// we don't do selection in compare mode
|
|
if (isCompare()) return;
|
|
|
|
QwtPlotPicker* pick = qobject_cast<QwtPlotPicker *>(sender());
|
|
AllPlot* plot = qobject_cast<AllPlot *>(pick->plot());
|
|
double xValue = plot->invTransform(QwtPlot::xBottom, pos.x());
|
|
|
|
setStartSelection(plot, xValue);
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::plotPickerMoved(const QPoint &pos)
|
|
{
|
|
// we don't do selection in compare mode
|
|
if (isCompare()) return;
|
|
|
|
QString name = QString(tr("Selection #%1 ")).arg(selection);
|
|
|
|
// which picker and plot send this signal?
|
|
QwtPlotPicker* pick = qobject_cast<QwtPlotPicker *>(sender());
|
|
AllPlot* plot = qobject_cast<AllPlot *>(pick->plot());
|
|
|
|
int posX = pos.x();
|
|
int posY = plot->y()+pos.y()+50;
|
|
|
|
if (showStack->isChecked()) {
|
|
|
|
// need to highlight across stacked plots
|
|
foreach (AllPlot *_plot, (showBySeries->isChecked() ? seriesPlots : allPlots)) {
|
|
|
|
// mark the start of selection on every plot
|
|
_plot->standard->allMarker1->setValue(plot->standard->allMarker1->value());
|
|
|
|
if (_plot->y()<=plot->y() && posY<_plot->y()){
|
|
|
|
if (_plot->transform(QwtPlot::xBottom, _plot->standard->allMarker2->xValue())>0) {
|
|
setEndSelection(_plot, 0, false, name);
|
|
_plot->standard->allMarker2->setLabel(QString(""));
|
|
}
|
|
|
|
} else if (_plot->y()>=plot->y() && posY>_plot->y()+_plot->height()) {
|
|
|
|
if (_plot->transform(QwtPlot::xBottom, _plot->standard->allMarker2->xValue())<plot->width()){
|
|
setEndSelection(_plot, _plot->transform(QwtPlot::xBottom, plot->width()), false, name);
|
|
}
|
|
}
|
|
else if (posY>_plot->y() && posY<_plot->y()+_plot->height()) {
|
|
|
|
if (pos.x()<6) {
|
|
posX = 6;
|
|
} else if (!_plot->bydist && pos.x()>_plot->transform(QwtPlot::xBottom,
|
|
fullPlot->standard->timeArray[fullPlot->standard->timeArray.size()-1])) {
|
|
posX = _plot->transform(QwtPlot::xBottom, fullPlot->standard->timeArray[fullPlot->standard->timeArray.size()-1]);
|
|
} else if (plot->bydist && pos.x()>_plot->transform(QwtPlot::xBottom,
|
|
fullPlot->standard->distanceArray[fullPlot->standard->distanceArray.size()-1])) {
|
|
posX = fullPlot->transform(QwtPlot::xBottom,
|
|
fullPlot->standard->distanceArray[fullPlot->standard->distanceArray.size()-1]);
|
|
}
|
|
|
|
setEndSelection(_plot, _plot->invTransform(QwtPlot::xBottom, posX), true, name);
|
|
|
|
if (plot->y()<_plot->y()) {
|
|
plot->standard->allMarker1->setLabel(_plot->standard->allMarker1->label());
|
|
plot->standard->allMarker2->setLabel(_plot->standard->allMarker2->label());
|
|
}
|
|
|
|
} else {
|
|
|
|
_plot->standard->allMarker1->hide();
|
|
_plot->standard->allMarker2->hide();
|
|
|
|
}
|
|
}
|
|
|
|
} else {
|
|
|
|
// working on AllPlot
|
|
double xValue = plot->invTransform(QwtPlot::xBottom, pos.x());
|
|
setEndSelection(plot, xValue, true, name);
|
|
}
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::setStartSelection(AllPlot* plot, double xValue)
|
|
{
|
|
// we don't do selection in compare mode
|
|
if (isCompare()) return;
|
|
|
|
QwtPlotMarker* allMarker1 = plot->standard->allMarker1;
|
|
|
|
selection++;
|
|
|
|
if (!allMarker1->isVisible() || allMarker1->xValue() != xValue) {
|
|
allMarker1->setValue(xValue, plot->bydist ? 0 : 100);
|
|
allMarker1->show();
|
|
}
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::setEndSelection(AllPlot* plot, double xValue, bool newInterval, QString name)
|
|
{
|
|
// we don't do selection in compare mode
|
|
if (isCompare()) return;
|
|
|
|
active = true;
|
|
|
|
QwtPlotMarker* allMarker1 = plot->standard->allMarker1;
|
|
QwtPlotMarker* allMarker2 = plot->standard->allMarker2;
|
|
|
|
if (!allMarker2->isVisible() || allMarker2->xValue() != xValue) {
|
|
|
|
allMarker2->setValue(xValue, plot->bydist ? 0 : 100);
|
|
allMarker2->show();
|
|
|
|
double x1, x2; // time or distance depending upon mode selected
|
|
|
|
// swap to low-high if neccessary
|
|
if (allMarker1->xValue()>allMarker2->xValue()){
|
|
x2 = allMarker1->xValue();
|
|
x1 = allMarker2->xValue();
|
|
} else {
|
|
x1 = allMarker1->xValue();
|
|
x2 = allMarker2->xValue();
|
|
}
|
|
|
|
RideItem *ride = current;
|
|
|
|
double distance1 = -1;
|
|
double distance2 = -1;
|
|
double duration1 = -1;
|
|
double duration2 = -1;
|
|
|
|
// if we are in distance mode then x1 and x2 are distances
|
|
// we need to make sure they are in KM for the rest of this
|
|
// code.
|
|
if (plot->bydist) {
|
|
|
|
if (context->athlete->useMetricUnits == false) {
|
|
// convert to metric
|
|
x1 *= KM_PER_MILE;
|
|
x2 *= KM_PER_MILE;
|
|
}
|
|
|
|
// distance to time
|
|
distance1 = x1;
|
|
distance2 = x2;
|
|
duration1 = ride->ride()->distanceToTime(x1);
|
|
duration2 = ride->ride()->distanceToTime(x2);
|
|
|
|
} else {
|
|
|
|
// convert to seconds from minutes
|
|
x1 *=60;
|
|
x2 *=60;
|
|
|
|
// time to distance
|
|
duration1 = x1;
|
|
duration2 = x2;
|
|
distance1 = ride->ride()->timeToDistance(x1);
|
|
distance2 = ride->ride()->timeToDistance(x2);
|
|
}
|
|
|
|
if (newInterval) {
|
|
|
|
// what we go already ?
|
|
QList<IntervalItem*> users = ride->intervals(RideFileInterval::USER);
|
|
|
|
// are we adjusting an existing interval? - if so delete it and readd it
|
|
if (users.count() > 0 && users.last()->name.startsWith(name)) {
|
|
|
|
// update interval - could do via a IntervalItem::setXX() function
|
|
IntervalItem *interval = users.last();
|
|
interval->setValues(interval->name, duration1, duration2, distance1, distance2);
|
|
|
|
} else {
|
|
|
|
//create a new one
|
|
IntervalItem *interval = ride->newInterval(name, duration1, duration2, distance1, distance2);
|
|
interval->selected = true;
|
|
|
|
// rebuild list
|
|
context->notifyIntervalsUpdate(ride);
|
|
}
|
|
|
|
// charts need to update
|
|
context->notifyIntervalsChanged();
|
|
}
|
|
}
|
|
active = false;
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::clearSelection()
|
|
{
|
|
// we don't do selection in compare mode
|
|
if (isCompare()) return;
|
|
|
|
selection = 0;
|
|
allPlot->standard->allMarker1->setVisible(false);
|
|
allPlot->standard->allMarker2->setVisible(false);
|
|
|
|
foreach (AllPlot *plot, allPlots) {
|
|
plot->standard->allMarker1->setVisible(false);
|
|
plot->standard->allMarker2->setVisible(false);
|
|
}
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::hideSelection()
|
|
{
|
|
// we don't do selection in compare mode
|
|
if (isCompare()) return;
|
|
|
|
if (showStack->isChecked()) {
|
|
foreach (AllPlot *plot, allPlots) {
|
|
plot->standard->allMarker1->setVisible(false);
|
|
plot->standard->allMarker2->setVisible(false);
|
|
plot->replot();
|
|
}
|
|
} else {
|
|
fullPlot->replot();
|
|
allPlot->standard->allMarker1->setVisible(false);
|
|
allPlot->standard->allMarker2->setVisible(false);
|
|
allPlot->replot();
|
|
}
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::setHovering(int value)
|
|
{
|
|
showHover->setChecked(value);
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::setShowPower(int value)
|
|
{
|
|
showPower->setCurrentIndex(value);
|
|
|
|
// compare mode selfcontained update
|
|
if (isCompare()) {
|
|
compareChanged();
|
|
return;
|
|
}
|
|
|
|
// we only show the power shading on the
|
|
// allPlot / stack plots, not on the fullPlot
|
|
allPlot->setShowPower(value);
|
|
if (!showStack->isChecked())
|
|
allPlot->replot();
|
|
|
|
// redraw
|
|
foreach (AllPlot *plot, allPlots)
|
|
plot->setShowPower(value);
|
|
|
|
// now replot 'em - to avoid flicker
|
|
if (showStack->isChecked()) {
|
|
stackFrame->setUpdatesEnabled(false); // don't repaint whilst we do this...
|
|
foreach (AllPlot *plot, allPlots)
|
|
plot->replot();
|
|
stackFrame->setUpdatesEnabled(true); // don't repaint whilst we do this...
|
|
}
|
|
|
|
// and the series stacks too
|
|
forceSetupSeriesStackPlots(); // scope changed so force redraw
|
|
}
|
|
|
|
|
|
void
|
|
AllPlotWindow::setShowHr(int value)
|
|
{
|
|
showHr->setChecked(value);
|
|
|
|
// compare mode selfcontained update
|
|
if (isCompare()) {
|
|
compareChanged();
|
|
return;
|
|
}
|
|
|
|
bool checked = ( ( value == Qt::Checked ) && showHr->isEnabled()) ? true : false;
|
|
|
|
allPlot->setShowHr(checked);
|
|
foreach (AllPlot *plot, allPlots)
|
|
plot->setShowHr(checked);
|
|
// and the series stacks too
|
|
forceSetupSeriesStackPlots(); // scope changed so force redraw
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::setShowTcore(int value)
|
|
{
|
|
showTcore->setChecked(value);
|
|
|
|
// compare mode selfcontained update
|
|
if (isCompare()) {
|
|
compareChanged();
|
|
return;
|
|
}
|
|
|
|
bool checked = ( ( value == Qt::Checked ) && showTcore->isEnabled()) ? true : false;
|
|
allPlot->setShowTcore(checked);
|
|
foreach (AllPlot *plot, allPlots)
|
|
plot->setShowTcore(checked);
|
|
// and the series stacks too
|
|
forceSetupSeriesStackPlots(); // scope changed so force redraw
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::setShowNP(int value)
|
|
{
|
|
showNP->setChecked(value);
|
|
|
|
// compare mode selfcontained update
|
|
if (isCompare()) {
|
|
compareChanged();
|
|
return;
|
|
}
|
|
|
|
bool checked = ( ( value == Qt::Checked ) && showNP->isEnabled()) ? true : false;
|
|
|
|
// recalc only does it if it needs to
|
|
if (value && current && current->ride()) current->ride()->recalculateDerivedSeries();
|
|
|
|
allPlot->setShowNP(checked);
|
|
foreach (AllPlot *plot, allPlots)
|
|
plot->setShowNP(checked);
|
|
// and the series stacks too
|
|
forceSetupSeriesStackPlots(); // scope changed so force redraw
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::setShowANTISS(int value)
|
|
{
|
|
showANTISS->setChecked(value);
|
|
|
|
// compare mode selfcontained update
|
|
if (isCompare()) {
|
|
compareChanged();
|
|
return;
|
|
}
|
|
|
|
bool checked = ( ( value == Qt::Checked ) && showANTISS->isEnabled()) ? true : false;
|
|
|
|
// recalc only does it if it needs to
|
|
if (value && current && current->ride()) current->ride()->recalculateDerivedSeries();
|
|
|
|
allPlot->setShowANTISS(checked);
|
|
foreach (AllPlot *plot, allPlots)
|
|
plot->setShowANTISS(checked);
|
|
// and the series stacks too
|
|
forceSetupSeriesStackPlots(); // scope changed so force redraw
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::setShowATISS(int value)
|
|
{
|
|
showATISS->setChecked(value);
|
|
|
|
// compare mode selfcontained update
|
|
if (isCompare()) {
|
|
compareChanged();
|
|
return;
|
|
}
|
|
|
|
bool checked = ( ( value == Qt::Checked ) && showATISS->isEnabled()) ? true : false;
|
|
|
|
// recalc only does it if it needs to
|
|
if (value && current && current->ride()) current->ride()->recalculateDerivedSeries();
|
|
|
|
allPlot->setShowATISS(checked);
|
|
foreach (AllPlot *plot, allPlots)
|
|
plot->setShowATISS(checked);
|
|
// and the series stacks too
|
|
forceSetupSeriesStackPlots(); // scope changed so force redraw
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::setShowXP(int value)
|
|
{
|
|
showXP->setChecked(value);
|
|
|
|
// compare mode selfcontained update
|
|
if (isCompare()) {
|
|
compareChanged();
|
|
return;
|
|
}
|
|
|
|
bool checked = ( ( value == Qt::Checked ) && showXP->isEnabled()) ? true : false;
|
|
|
|
// recalc only does it if it needs to
|
|
if (value && current && current->ride()) current->ride()->recalculateDerivedSeries();
|
|
|
|
allPlot->setShowXP(checked);
|
|
foreach (AllPlot *plot, allPlots)
|
|
plot->setShowXP(checked);
|
|
// and the series stacks too
|
|
forceSetupSeriesStackPlots(); // scope changed so force redraw
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::setShowAP(int value)
|
|
{
|
|
showAP->setChecked(value);
|
|
|
|
// compare mode selfcontained update
|
|
if (isCompare()) {
|
|
compareChanged();
|
|
return;
|
|
}
|
|
|
|
bool checked = ( ( value == Qt::Checked ) && showAP->isEnabled()) ? true : false;
|
|
|
|
// recalc only does it if it needs to
|
|
if (value && current && current->ride()) current->ride()->recalculateDerivedSeries();
|
|
|
|
allPlot->setShowAP(checked);
|
|
foreach (AllPlot *plot, allPlots)
|
|
plot->setShowAP(checked);
|
|
// and the series stacks too
|
|
forceSetupSeriesStackPlots(); // scope changed so force redraw
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::setShowSpeed(int value)
|
|
{
|
|
showSpeed->setChecked(value);
|
|
|
|
// compare mode selfcontained update
|
|
if (isCompare()) {
|
|
compareChanged();
|
|
return;
|
|
}
|
|
|
|
bool checked = ( ( value == Qt::Checked ) && showSpeed->isEnabled()) ? true : false;
|
|
|
|
allPlot->setShowSpeed(checked);
|
|
foreach (AllPlot *plot, allPlots)
|
|
plot->setShowSpeed(checked);
|
|
// and the series stacks too
|
|
forceSetupSeriesStackPlots(); // scope changed so force redraw
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::setShowAccel(int value)
|
|
{
|
|
showAccel->setChecked(value);
|
|
|
|
// compare mode selfcontained update
|
|
if (isCompare()) {
|
|
compareChanged();
|
|
return;
|
|
}
|
|
|
|
bool checked = ( ( value == Qt::Checked ) && showAccel->isEnabled()) ? true : false;
|
|
|
|
allPlot->setShowAccel(checked);
|
|
foreach (AllPlot *plot, allPlots)
|
|
plot->setShowAccel(checked);
|
|
// and the series stacks too
|
|
forceSetupSeriesStackPlots(); // scope changed so force redraw
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::setShowPowerD(int value)
|
|
{
|
|
showPowerD->setChecked(value);
|
|
|
|
// compare mode selfcontained update
|
|
if (isCompare()) {
|
|
compareChanged();
|
|
return;
|
|
}
|
|
|
|
bool checked = ( ( value == Qt::Checked ) && showPowerD->isEnabled()) ? true : false;
|
|
|
|
allPlot->setShowPowerD(checked);
|
|
foreach (AllPlot *plot, allPlots)
|
|
plot->setShowPowerD(checked);
|
|
// and the series stacks too
|
|
forceSetupSeriesStackPlots(); // scope changed so force redraw
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::setShowCadD(int value)
|
|
{
|
|
showCadD->setChecked(value);
|
|
|
|
// compare mode selfcontained update
|
|
if (isCompare()) {
|
|
compareChanged();
|
|
return;
|
|
}
|
|
|
|
bool checked = ( ( value == Qt::Checked ) && showCadD->isEnabled()) ? true : false;
|
|
|
|
allPlot->setShowCadD(checked);
|
|
foreach (AllPlot *plot, allPlots)
|
|
plot->setShowCadD(checked);
|
|
// and the series stacks too
|
|
forceSetupSeriesStackPlots(); // scope changed so force redraw
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::setShowTorqueD(int value)
|
|
{
|
|
showTorqueD->setChecked(value);
|
|
|
|
// compare mode selfcontained update
|
|
if (isCompare()) {
|
|
compareChanged();
|
|
return;
|
|
}
|
|
|
|
bool checked = ( ( value == Qt::Checked ) && showTorqueD->isEnabled()) ? true : false;
|
|
|
|
allPlot->setShowTorqueD(checked);
|
|
foreach (AllPlot *plot, allPlots)
|
|
plot->setShowTorqueD(checked);
|
|
// and the series stacks too
|
|
forceSetupSeriesStackPlots(); // scope changed so force redraw
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::setShowHrD(int value)
|
|
{
|
|
showHrD->setChecked(value);
|
|
|
|
// compare mode selfcontained update
|
|
if (isCompare()) {
|
|
compareChanged();
|
|
return;
|
|
}
|
|
|
|
bool checked = ( ( value == Qt::Checked ) && showHrD->isEnabled()) ? true : false;
|
|
|
|
allPlot->setShowHrD(checked);
|
|
foreach (AllPlot *plot, allPlots)
|
|
plot->setShowHrD(checked);
|
|
// and the series stacks too
|
|
forceSetupSeriesStackPlots(); // scope changed so force redraw
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::setShowCad(int value)
|
|
{
|
|
showCad->setChecked(value);
|
|
|
|
// compare mode selfcontained update
|
|
if (isCompare()) {
|
|
compareChanged();
|
|
return;
|
|
}
|
|
|
|
bool checked = ( ( value == Qt::Checked ) && showCad->isEnabled()) ? true : false;
|
|
|
|
allPlot->setShowCad(checked);
|
|
foreach (AllPlot *plot, allPlots)
|
|
plot->setShowCad(checked);
|
|
// and the series stacks too
|
|
forceSetupSeriesStackPlots(); // scope changed so force redraw
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::setShowAlt(int value)
|
|
{
|
|
showAlt->setChecked(value);
|
|
|
|
// compare mode selfcontained update
|
|
if (isCompare()) {
|
|
compareChanged();
|
|
return;
|
|
}
|
|
|
|
bool checked = ( ( value == Qt::Checked ) && showAlt->isEnabled()) ? true : false;
|
|
|
|
allPlot->setShowAlt(checked);
|
|
foreach (AllPlot *plot, allPlots)
|
|
plot->setShowAlt(checked);
|
|
// and the series stacks too
|
|
forceSetupSeriesStackPlots(); // scope changed so force redraw
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::setShowSlope(int value)
|
|
{
|
|
showSlope->setChecked(value);
|
|
|
|
// compare mode selfcontained update
|
|
if (isCompare()) {
|
|
compareChanged();
|
|
return;
|
|
}
|
|
|
|
bool checked = ( ( value == Qt::Checked ) && showSlope->isEnabled()) ? true : false;
|
|
|
|
allPlot->setShowSlope (checked);
|
|
foreach (AllPlot *plot, allPlots)
|
|
plot->setShowSlope(checked);
|
|
// and the series stacks too
|
|
forceSetupSeriesStackPlots(); // scope changed so force redraw
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::setShowAltSlope(int value)
|
|
{
|
|
showAltSlope->setCurrentIndex(value);
|
|
|
|
// compare mode selfcontained update
|
|
if (isCompare()) {
|
|
allPlot->showAltSlopeState = value;
|
|
compareChanged();
|
|
return;
|
|
}
|
|
|
|
allPlot->setShowAltSlope(value);
|
|
|
|
foreach (AllPlot *plot, allPlots)
|
|
plot->setShowAltSlope(value);
|
|
|
|
// and the series stacks too
|
|
forceSetupSeriesStackPlots(); // scope changed so force redraw
|
|
}
|
|
|
|
|
|
|
|
void
|
|
AllPlotWindow::setShowTemp(int value)
|
|
{
|
|
showTemp->setChecked(value);
|
|
|
|
// compare mode selfcontained update
|
|
if (isCompare()) {
|
|
compareChanged();
|
|
return;
|
|
}
|
|
|
|
bool checked = ( ( value == Qt::Checked ) && showTemp->isEnabled()) ? true : false;
|
|
|
|
allPlot->setShowTemp(checked);
|
|
foreach (AllPlot *plot, allPlots)
|
|
plot->setShowTemp(checked);
|
|
// and the series stacks too
|
|
forceSetupSeriesStackPlots(); // scope changed so force redraw
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::setShowRV(int value)
|
|
{
|
|
showRV->setChecked(value);
|
|
|
|
// compare mode selfcontained update
|
|
if (isCompare()) {
|
|
compareChanged();
|
|
return;
|
|
}
|
|
|
|
bool checked = (( value == Qt::Checked ) && showRV->isEnabled()) ? true : false;
|
|
|
|
allPlot->setShowRV(checked);
|
|
foreach (AllPlot *plot, allPlots)
|
|
plot->setShowRV(checked);
|
|
|
|
// and the series stacks too
|
|
forceSetupSeriesStackPlots(); // scope changed so force redraw
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::setShowRGCT(int value)
|
|
{
|
|
showRGCT->setChecked(value);
|
|
|
|
// compare mode selfcontained update
|
|
if (isCompare()) {
|
|
compareChanged();
|
|
return;
|
|
}
|
|
|
|
bool checked = (( value == Qt::Checked ) && showRGCT->isEnabled()) ? true : false;
|
|
|
|
allPlot->setShowRGCT(checked);
|
|
foreach (AllPlot *plot, allPlots)
|
|
plot->setShowRGCT(checked);
|
|
|
|
// and the series stacks too
|
|
forceSetupSeriesStackPlots(); // scope changed so force redraw
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::setShowRCad(int value)
|
|
{
|
|
showRCad->setChecked(value);
|
|
|
|
// compare mode selfcontained update
|
|
if (isCompare()) {
|
|
compareChanged();
|
|
return;
|
|
}
|
|
|
|
bool checked = (( value == Qt::Checked ) && showRCad->isEnabled()) ? true : false;
|
|
|
|
allPlot->setShowRCad(checked);
|
|
foreach (AllPlot *plot, allPlots)
|
|
plot->setShowRCad(checked);
|
|
|
|
// and the series stacks too
|
|
forceSetupSeriesStackPlots(); // scope changed so force redraw
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::setShowSmO2(int value)
|
|
{
|
|
showSmO2->setChecked(value);
|
|
|
|
// compare mode selfcontained update
|
|
if (isCompare()) {
|
|
compareChanged();
|
|
return;
|
|
}
|
|
|
|
bool checked = (( value == Qt::Checked ) && showSmO2->isEnabled()) ? true : false;
|
|
|
|
allPlot->setShowSmO2(checked);
|
|
foreach (AllPlot *plot, allPlots)
|
|
plot->setShowSmO2(checked);
|
|
|
|
// and the series stacks too
|
|
forceSetupSeriesStackPlots(); // scope changed so force redraw
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::setShowtHb(int value)
|
|
{
|
|
showtHb->setChecked(value);
|
|
|
|
// compare mode selfcontained update
|
|
if (isCompare()) {
|
|
compareChanged();
|
|
return;
|
|
}
|
|
|
|
bool checked = (( value == Qt::Checked ) && showtHb->isEnabled()) ? true : false;
|
|
|
|
allPlot->setShowtHb(checked);
|
|
foreach (AllPlot *plot, allPlots)
|
|
plot->setShowtHb(checked);
|
|
|
|
// and the series stacks too
|
|
forceSetupSeriesStackPlots(); // scope changed so force redraw
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::setShowO2Hb(int value)
|
|
{
|
|
showO2Hb->setChecked(value);
|
|
|
|
// compare mode selfcontained update
|
|
if (isCompare()) {
|
|
compareChanged();
|
|
return;
|
|
}
|
|
|
|
bool checked = (( value == Qt::Checked ) && showO2Hb->isEnabled()) ? true : false;
|
|
|
|
allPlot->setShowO2Hb(checked);
|
|
foreach (AllPlot *plot, allPlots)
|
|
plot->setShowO2Hb(checked);
|
|
|
|
// and the series stacks too
|
|
forceSetupSeriesStackPlots(); // scope changed so force redraw
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::setShowHHb(int value)
|
|
{
|
|
showHHb->setChecked(value);
|
|
|
|
// compare mode selfcontained update
|
|
if (isCompare()) {
|
|
compareChanged();
|
|
return;
|
|
}
|
|
|
|
bool checked = (( value == Qt::Checked ) && showHHb->isEnabled()) ? true : false;
|
|
|
|
allPlot->setShowHHb(checked);
|
|
foreach (AllPlot *plot, allPlots)
|
|
plot->setShowHHb(checked);
|
|
|
|
// and the series stacks too
|
|
forceSetupSeriesStackPlots(); // scope changed so force redraw
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::setShowGear(int value)
|
|
{
|
|
showGear->setChecked(value);
|
|
|
|
// compare mode selfcontained update
|
|
if (isCompare()) {
|
|
compareChanged();
|
|
return;
|
|
}
|
|
|
|
bool checked = (( value == Qt::Checked ) && showGear->isEnabled()) ? true : false;
|
|
|
|
allPlot->setShowGear(checked);
|
|
foreach (AllPlot *plot, allPlots)
|
|
plot->setShowGear(checked);
|
|
|
|
// and the series stacks too
|
|
forceSetupSeriesStackPlots(); // scope changed so force redraw
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::setShowWind(int value)
|
|
{
|
|
showWind->setChecked(value);
|
|
|
|
// compare mode selfcontained update
|
|
if (isCompare()) {
|
|
compareChanged();
|
|
return;
|
|
}
|
|
|
|
bool checked = (( value == Qt::Checked ) && showWind->isEnabled()) ? true : false;
|
|
|
|
allPlot->setShowWind(checked);
|
|
foreach (AllPlot *plot, allPlots)
|
|
plot->setShowWind(checked);
|
|
|
|
// and the series stacks too
|
|
forceSetupSeriesStackPlots(); // scope changed so force redraw
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::setShowW(int value)
|
|
{
|
|
showW->setChecked(value);
|
|
|
|
// compare mode selfcontained update
|
|
if (isCompare()) {
|
|
compareChanged();
|
|
return;
|
|
}
|
|
|
|
bool checked = ( ( value == Qt::Checked ) && showW->isEnabled()) ? true : false;
|
|
|
|
allPlot->setShowW(checked);
|
|
foreach (AllPlot *plot, allPlots)
|
|
plot->setShowW(checked);
|
|
|
|
// refresh W' data if needed
|
|
if (checked && current && current->ride()) {
|
|
|
|
// redraw
|
|
redrawFullPlot();
|
|
redrawAllPlot();
|
|
redrawStackPlot();
|
|
}
|
|
|
|
// and the series stacks too
|
|
forceSetupSeriesStackPlots(); // scope changed so force redraw
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::setShowTorque(int value)
|
|
{
|
|
showTorque->setChecked(value);
|
|
bool checked = ( ( value == Qt::Checked ) && showTorque->isEnabled()) ? true : false;
|
|
|
|
// compare mode selfcontained update
|
|
if (isCompare()) {
|
|
compareChanged();
|
|
return;
|
|
}
|
|
|
|
allPlot->setShowTorque(checked);
|
|
foreach (AllPlot *plot, allPlots)
|
|
plot->setShowTorque(checked);
|
|
// and the series stacks too
|
|
forceSetupSeriesStackPlots(); // scope changed so force redraw
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::setShowBalance(int value)
|
|
{
|
|
showBalance->setChecked(value);
|
|
|
|
// compare mode selfcontained update
|
|
if (isCompare()) {
|
|
compareChanged();
|
|
return;
|
|
}
|
|
|
|
bool checked = ( ( value == Qt::Checked ) && showBalance->isEnabled()) ? true : false;
|
|
|
|
allPlot->setShowBalance(checked);
|
|
foreach (AllPlot *plot, allPlots)
|
|
plot->setShowBalance(checked);
|
|
// and the series stacks too
|
|
forceSetupSeriesStackPlots(); // scope changed so force redraw
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::setShowPS(int value)
|
|
{
|
|
showPS->setChecked(value);
|
|
|
|
// compare mode selfcontained update
|
|
if (isCompare()) {
|
|
compareChanged();
|
|
return;
|
|
}
|
|
|
|
bool checked = ( ( value == Qt::Checked ) && showPS->isEnabled()) ? true : false;
|
|
|
|
allPlot->setShowPS(checked);
|
|
foreach (AllPlot *plot, allPlots)
|
|
plot->setShowPS(checked);
|
|
// and the series stacks too
|
|
forceSetupSeriesStackPlots(); // scope changed so force redraw
|
|
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::setShowTE(int value)
|
|
{
|
|
showTE->setChecked(value);
|
|
|
|
// compare mode selfcontained update
|
|
if (isCompare()) {
|
|
compareChanged();
|
|
return;
|
|
}
|
|
|
|
bool checked = ( ( value == Qt::Checked ) && showTE->isEnabled()) ? true : false;
|
|
|
|
allPlot->setShowTE(checked);
|
|
foreach (AllPlot *plot, allPlots)
|
|
plot->setShowTE(checked);
|
|
// and the series stacks too
|
|
forceSetupSeriesStackPlots(); // scope changed so force redraw
|
|
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::setShowPCO(int value)
|
|
{
|
|
showPCO->setChecked(value);
|
|
|
|
// compare mode selfcontained update
|
|
if (isCompare()) {
|
|
compareChanged();
|
|
return;
|
|
}
|
|
|
|
bool checked = ( ( value == Qt::Checked ) && showPCO->isEnabled()) ? true : false;
|
|
|
|
allPlot->setShowPCO(checked);
|
|
foreach (AllPlot *plot, allPlots)
|
|
plot->setShowPCO(checked);
|
|
// and the series stacks too
|
|
forceSetupSeriesStackPlots(); // scope changed so force redraw
|
|
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::setShowDC(int value)
|
|
{
|
|
showDC->setChecked(value);
|
|
|
|
// compare mode selfcontained update
|
|
if (isCompare()) {
|
|
compareChanged();
|
|
return;
|
|
}
|
|
|
|
bool checked = ( ( value == Qt::Checked ) && showDC->isEnabled()) ? true : false;
|
|
|
|
allPlot->setShowDC(checked);
|
|
foreach (AllPlot *plot, allPlots)
|
|
plot->setShowDC(checked);
|
|
// and the series stacks too
|
|
forceSetupSeriesStackPlots(); // scope changed so force redraw
|
|
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::setShowPPP(int value)
|
|
{
|
|
showPPP->setChecked(value);
|
|
|
|
// compare mode selfcontained update
|
|
if (isCompare()) {
|
|
compareChanged();
|
|
return;
|
|
}
|
|
|
|
bool checked = ( ( value == Qt::Checked ) && showPPP->isEnabled()) ? true : false;
|
|
|
|
allPlot->setShowPPP(checked);
|
|
foreach (AllPlot *plot, allPlots)
|
|
plot->setShowPPP(checked);
|
|
// and the series stacks too
|
|
forceSetupSeriesStackPlots(); // scope changed so force redraw
|
|
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::setShowHelp(int value)
|
|
{
|
|
rHelp->setChecked(value);
|
|
showHelp->setChecked(value);
|
|
if (showHelp->isChecked()) helperWidget()->show();
|
|
else helperWidget()->hide();
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::setShowFull(int value)
|
|
{
|
|
rFull->setChecked(value);
|
|
showFull->setChecked(value);
|
|
if (showFull->isChecked()) {
|
|
fullPlot->show();
|
|
allPlotLayout->setStretch(1,20);
|
|
}
|
|
else {
|
|
fullPlot->hide();
|
|
allPlotLayout->setStretch(1,0);
|
|
}
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::setShowInterval(int value)
|
|
{
|
|
showInterval->setChecked(value);
|
|
if (showInterval->isChecked()) {
|
|
intervalPlot->show();
|
|
//allPlotLayout->setStretch(1,20);
|
|
}
|
|
else {
|
|
intervalPlot->hide();
|
|
//allPlotLayout->setStretch(1,0);
|
|
}
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::setShowGrid(int value)
|
|
{
|
|
showGrid->setChecked(value);
|
|
|
|
if (isCompare()) {
|
|
|
|
// XXX
|
|
return;
|
|
|
|
} else {
|
|
|
|
allPlot->setShowGrid(value);
|
|
foreach (AllPlot *plot, allPlots)
|
|
plot->setShowGrid(value);
|
|
// and the series stacks too
|
|
forceSetupSeriesStackPlots(); // scope changed so force redraw
|
|
}
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::setPaintBrush(int value)
|
|
{
|
|
if (active == true) return;
|
|
|
|
if (isCompare()) {
|
|
// XXX
|
|
return;
|
|
}
|
|
|
|
active = true;
|
|
paintBrush->setChecked(value);
|
|
|
|
//if (!current) return;
|
|
|
|
allPlot->setPaintBrush(value);
|
|
foreach (AllPlot *plot, allPlots)
|
|
plot->setPaintBrush(value);
|
|
|
|
active = false;
|
|
// and the series stacks too
|
|
forceSetupSeriesStackPlots(); // scope changed so force redraw
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::setByDistance(int value)
|
|
{
|
|
if (value <0 || value >1 || active == true) return;
|
|
|
|
active = true;
|
|
comboDistance->setCurrentIndex(value);
|
|
|
|
// compare mode is self contained
|
|
if (isCompare()) {
|
|
fullPlot->bydist = value;
|
|
compareChanged();
|
|
active = false;
|
|
return;
|
|
}
|
|
|
|
fullPlot->setByDistance(value);
|
|
intervalPlot->setByDistance(value);
|
|
allPlot->setByDistance(value);
|
|
|
|
// refresh controls, specifically spanSlider
|
|
setAllPlotWidgets(fullPlot->rideItem);
|
|
|
|
// refresh
|
|
setupSeriesStack = setupStack = false;
|
|
redrawFullPlot();
|
|
redrawAllPlot();
|
|
setupStackPlots();
|
|
setupSeriesStackPlots();
|
|
redrawIntervalPlot();
|
|
|
|
active = false;
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::setSmoothing(int value)
|
|
{
|
|
//if (!current) return;
|
|
smoothSlider->setValue(value);
|
|
|
|
// Compare has LOTS of rides to smooth...
|
|
if (context->isCompareIntervals) {
|
|
|
|
// no zero smoothing when comparing -- we need the
|
|
// arrays to be initialised for all series
|
|
if (value < 1) value = 1;
|
|
fullPlot->setSmoothing(value);
|
|
|
|
setUpdatesEnabled(false);
|
|
|
|
// smooth each on full plots ...
|
|
foreach(AllPlotObject *po, compareIntervalCurves) {
|
|
fullPlot->recalc(po);
|
|
}
|
|
|
|
// .. and all plots too!
|
|
int i=0;
|
|
foreach (AllPlot *plot, allComparePlots) {
|
|
plot->setDataFromObject(compareIntervalCurves[i], allPlot);
|
|
i++;
|
|
}
|
|
// and series plots..
|
|
foreach (AllPlot *plot, seriesPlots) {
|
|
plot->setDataFromPlots(allComparePlots);
|
|
plot->replot(); // straight away this time
|
|
}
|
|
|
|
setUpdatesEnabled(true);
|
|
|
|
} else {
|
|
|
|
// recalculate etc
|
|
fullPlot->setSmoothing(value);
|
|
|
|
// redraw
|
|
redrawFullPlot();
|
|
redrawAllPlot();
|
|
redrawStackPlot();
|
|
}
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::resetSeriesStackedDatas()
|
|
{
|
|
if (!current) return;
|
|
|
|
// just reset from AllPlot
|
|
foreach(AllPlot *p, seriesPlots) {
|
|
p->setDataFromPlot(allPlot);
|
|
}
|
|
}
|
|
//
|
|
// Runs through the stacks and updates their contents
|
|
//
|
|
void
|
|
AllPlotWindow::resetStackedDatas()
|
|
{
|
|
if (!allPlot->rideItem || !allPlot->rideItem->ride() || !current) return;
|
|
|
|
int _stackWidth = stackWidth;
|
|
if (allPlot->bydist)
|
|
_stackWidth = stackWidth/3;
|
|
|
|
for(int i = 0 ; i < allPlots.count() ; i++)
|
|
{
|
|
AllPlot *plot = allPlots[i];
|
|
int startIndex, stopIndex;
|
|
if (plot->bydist) {
|
|
startIndex = allPlot->rideItem->ride()->distanceIndex(
|
|
(context->athlete->useMetricUnits ? 1 : KM_PER_MILE) * _stackWidth*i);
|
|
stopIndex = allPlot->rideItem->ride()->distanceIndex(
|
|
(context->athlete->useMetricUnits ? 1 : KM_PER_MILE) * _stackWidth*(i+1));
|
|
} else {
|
|
startIndex = allPlot->rideItem->ride()->timeIndex(60*_stackWidth*i);
|
|
stopIndex = allPlot->rideItem->ride()->timeIndex(60*_stackWidth*(i+1));
|
|
}
|
|
|
|
// Update AllPlot for stacked view
|
|
plot->setDataFromPlot(fullPlot, startIndex, stopIndex);
|
|
if (i != 0) plot->setTitle("");
|
|
}
|
|
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::stackZoomSliderChanged()
|
|
{
|
|
// slider moved!
|
|
setStackWidth(stackZoomWidth[stackZoomSlider->value()]);
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::setStackWidth(int width)
|
|
{
|
|
// derive width from allowed values -- this is for backward
|
|
// compatibility to ensure we always use a size that we are
|
|
// expecting and set the slider to the appropriate value
|
|
int i=0;
|
|
for (; i<8; i++) // there are 8 pre-set sizes
|
|
if (width <= stackZoomWidth[i]) break;
|
|
|
|
// we never found it
|
|
if (i == 8) i=7;
|
|
|
|
// did anything actually change?
|
|
if (stackZoomWidth[i] == stackWidth) return;
|
|
|
|
// set the value and the slider
|
|
stackWidth = stackZoomWidth[i];
|
|
stackZoomSlider->setValue(i);
|
|
|
|
resizeSeriesPlots(); // its only the size that needs to change
|
|
// no need to replot
|
|
|
|
resizeComparePlots();
|
|
|
|
// now lets do the plots...
|
|
setupStack = false; // force resize
|
|
setupStackPlots();
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::showStackChanged(int value)
|
|
{
|
|
|
|
showStack->setCheckState((Qt::CheckState)value);
|
|
rStack->setCheckState((Qt::CheckState)value);
|
|
|
|
if (isCompare()) {
|
|
setAllPlotWidgets(NULL); // no need to do anything fancy
|
|
return;
|
|
}
|
|
|
|
if (!current) return;
|
|
|
|
// enables / disable as needed
|
|
if (showStack->isChecked()) {
|
|
showBySeries->setEnabled(true);
|
|
rBySeries->setEnabled(true);
|
|
|
|
// all plot...
|
|
allPlotStack->setCurrentIndex(0);
|
|
if (isCompare()) allStack->setCurrentIndex(1); // compare mode stack of all plots
|
|
else allStack->setCurrentIndex(0); // normal single allplot
|
|
|
|
} else {
|
|
showBySeries->setEnabled(false);
|
|
rBySeries->setEnabled(false);
|
|
allPlotStack->setCurrentIndex(1);
|
|
}
|
|
|
|
// when we swap from normal to
|
|
// stacked view, save the mode so
|
|
// we can startup with the 'preferred'
|
|
// view next time. And replot for the
|
|
// target mode since it is probably
|
|
// out of date. Then call setAllPlotWidgets
|
|
// to make sure all the controls are setup
|
|
// and the right widgets are hidden/shown.
|
|
if (value) {
|
|
|
|
if (!showBySeries->isChecked()) {
|
|
|
|
// BY TIME / DISTANCE
|
|
|
|
// setup the stack plots if needed
|
|
setupStackPlots();
|
|
|
|
// refresh plots
|
|
resetStackedDatas();
|
|
|
|
// now they are all set, lets replot them
|
|
foreach(AllPlot *plot, allPlots) plot->replot();
|
|
|
|
} else {
|
|
|
|
// BY SERIES
|
|
|
|
// setup the stack plots if needed
|
|
setupSeriesStackPlots();
|
|
|
|
// refresh plots
|
|
resetSeriesStackedDatas();
|
|
|
|
// now they are all set, lets replot them
|
|
foreach(AllPlot *plot, seriesPlots) plot->replot();
|
|
|
|
}
|
|
|
|
} else {
|
|
// refresh plots
|
|
redrawAllPlot();
|
|
}
|
|
|
|
// reset the view
|
|
setAllPlotWidgets(current);
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::showBySeriesChanged(int value)
|
|
{
|
|
if (!current) return;
|
|
|
|
showBySeries->setCheckState((Qt::CheckState)value);
|
|
rBySeries->setCheckState((Qt::CheckState)value);
|
|
showStackChanged(showStack->checkState()); // force replot etc
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::forceSetupSeriesStackPlots()
|
|
{
|
|
setupSeriesStack = false;
|
|
setupSeriesStackPlots();
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::resizeSeriesPlots()
|
|
{
|
|
// calling setupdates enabled when its disabled
|
|
// causes all paint events to be flushed. We want
|
|
// to avoid that, since it causes a flicker.
|
|
bool update = seriesstackFrame->updatesEnabled();
|
|
|
|
if (update) seriesstackFrame->setUpdatesEnabled(false);
|
|
foreach (AllPlot *plot, seriesPlots)
|
|
plot->setFixedHeight(120 + (stackWidth *4));
|
|
if (update) seriesstackFrame->setUpdatesEnabled(true);
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::resizeComparePlots()
|
|
{
|
|
comparePlotFrame->setUpdatesEnabled(false);
|
|
foreach (AllPlot *plot, allComparePlots)
|
|
plot->setFixedHeight(120 + (stackWidth *4));
|
|
comparePlotFrame->setUpdatesEnabled(true);
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::setupSeriesStackPlots()
|
|
{
|
|
if (!isCompare() && (!showStack->isChecked() || !showBySeries->isChecked() || setupSeriesStack)) return;
|
|
|
|
QVBoxLayout *newLayout = new QVBoxLayout;
|
|
|
|
// this is NOT a memory leak (see ZZZ below)
|
|
seriesPlots.clear();
|
|
|
|
bool addHeadwind = false;
|
|
RideItem* rideItem = current;
|
|
if (!rideItem || !rideItem->ride() || rideItem->ride()->dataPoints().isEmpty()) return;
|
|
|
|
// the refresh takes a while and is prone
|
|
// to lots of flicker, we turn off updates
|
|
// whilst we switch from the old to the new
|
|
// stackWidget and plots
|
|
seriesstackFrame->setUpdatesEnabled(false);
|
|
|
|
QPalette palette;
|
|
palette.setBrush(QPalette::Background, Qt::NoBrush);
|
|
|
|
QList<SeriesWanted> serieslist;
|
|
SeriesWanted s;
|
|
// lets get a list of what we need to plot -- plot is same order as options in settings
|
|
if (showPower->currentIndex() < 2 && rideItem->ride()->areDataPresent()->watts) { s.one = RideFile::watts; s.two = RideFile::none; serieslist << s; }
|
|
if (showW->isChecked() && rideItem->ride()->areDataPresent()->watts) { s.one = RideFile::wprime; s.two = RideFile::none; serieslist << s; }
|
|
if (showPowerD->isChecked() && rideItem->ride()->areDataPresent()->watts) { s.one = RideFile::wattsd;s.two = RideFile::none; serieslist << s; }
|
|
if (showHr->isChecked() && rideItem->ride()->areDataPresent()->hr) { s.one = RideFile::hr; s.two = RideFile::none; serieslist << s; }
|
|
if (showTcore->isChecked() && rideItem->ride()->areDataPresent()->hr) { s.one = RideFile::tcore; s.two = RideFile::none; serieslist << s; }
|
|
if (showHrD->isChecked() && rideItem->ride()->areDataPresent()->hr) { s.one = RideFile::hrd; s.two = RideFile::none; serieslist << s; }
|
|
if (showSmO2->isChecked() && rideItem->ride()->areDataPresent()->smo2) { s.one = RideFile::smo2; s.two = RideFile::none; serieslist << s; }
|
|
if (showtHb->isChecked() && rideItem->ride()->areDataPresent()->thb) { s.one = RideFile::thb; s.two = RideFile::none; serieslist << s; }
|
|
if (showO2Hb->isChecked() && rideItem->ride()->areDataPresent()->o2hb) { s.one = RideFile::o2hb; s.two = RideFile::none; serieslist << s; }
|
|
if (showHHb->isChecked() && rideItem->ride()->areDataPresent()->hhb) { s.one = RideFile::hhb; s.two = RideFile::none; serieslist << s; }
|
|
if (showWind->isChecked() && rideItem->ride()->areDataPresent()->headwind) addHeadwind=true; //serieslist << RideFile::headwind;
|
|
if (showSpeed->isChecked() && rideItem->ride()->areDataPresent()->kph) {s.one = RideFile::kph; s.two = (addHeadwind ? RideFile::headwind : RideFile::none); serieslist << s; }
|
|
if (showAccel->isChecked() && rideItem->ride()->areDataPresent()->kph) { s.one = RideFile::kphd; s.two = RideFile::none; serieslist << s; }
|
|
if (showCad->isChecked() && rideItem->ride()->areDataPresent()->cad) { s.one = RideFile::cad; s.two = RideFile::none; serieslist << s; }
|
|
if (showCadD->isChecked() && rideItem->ride()->areDataPresent()->cad) { s.one = RideFile::cadd; s.two = RideFile::none; serieslist << s; }
|
|
if (showTorque->isChecked() && rideItem->ride()->areDataPresent()->nm) { s.one = RideFile::nm; s.two = RideFile::none; serieslist << s; }
|
|
if (showTorqueD->isChecked() && rideItem->ride()->areDataPresent()->nm) { s.one = RideFile::nmd; s.two = RideFile::none; serieslist << s; }
|
|
if (showAlt->isChecked() && rideItem->ride()->areDataPresent()->alt) { s.one = RideFile::alt; s.two = RideFile::none; serieslist << s; }
|
|
if (showAltSlope->currentIndex() > 0 && rideItem->ride()->areDataPresent()->alt) { s.one = RideFile::alt; s.two = RideFile::slope; serieslist << s; }
|
|
if (showSlope->isChecked() && rideItem->ride()->areDataPresent()->slope) { s.one = RideFile::slope; s.two = RideFile::none; serieslist << s; }
|
|
if (showTemp->isChecked() && rideItem->ride()->areDataPresent()->temp) { s.one = RideFile::temp; s.two = RideFile::none; serieslist << s; }
|
|
if (showNP->isChecked() && rideItem->ride()->areDataPresent()->watts) { s.one = RideFile::NP; s.two = RideFile::none; serieslist << s; }
|
|
if (showRV->isChecked() && rideItem->ride()->areDataPresent()->rvert) { s.one = RideFile::rvert; s.two = RideFile::none; serieslist << s; }
|
|
if (showRCad->isChecked() && rideItem->ride()->areDataPresent()->rcad) { s.one = RideFile::rcad; s.two = RideFile::none; serieslist << s; }
|
|
if (showRGCT->isChecked() && rideItem->ride()->areDataPresent()->rcontact) { s.one = RideFile::rcontact; s.two = RideFile::none; serieslist << s; }
|
|
if (showGear->isChecked() && rideItem->ride()->areDataPresent()->gear) { s.one = RideFile::gear; s.two = RideFile::none; serieslist << s; }
|
|
if (showATISS->isChecked() && rideItem->ride()->areDataPresent()->watts) { s.one = RideFile::aTISS; s.two = RideFile::none; serieslist << s; }
|
|
if (showANTISS->isChecked() && rideItem->ride()->areDataPresent()->watts) { s.one = RideFile::anTISS; s.two = RideFile::none; serieslist << s; }
|
|
if (showXP->isChecked() && rideItem->ride()->areDataPresent()->watts) { s.one = RideFile::xPower; s.two = RideFile::none; serieslist << s; }
|
|
if (showAP->isChecked() && rideItem->ride()->areDataPresent()->watts) { s.one = RideFile::aPower; s.two = RideFile::none; serieslist << s; }
|
|
if (showBalance->isChecked() && rideItem->ride()->areDataPresent()->lrbalance) { s.one = RideFile::lrbalance; s.two = RideFile::none; serieslist << s; }
|
|
if (showTE->isChecked() && rideItem->ride()->areDataPresent()->lte) { s.one = RideFile::lte; s.two = RideFile::none; serieslist << s;
|
|
s.one = RideFile::rte; s.two = RideFile::none; serieslist << s; }
|
|
if (showPS->isChecked() && rideItem->ride()->areDataPresent()->lps) { s.one = RideFile::lps; s.two = RideFile::none; serieslist << s;
|
|
s.one = RideFile::rps; s.two = RideFile::none; serieslist << s; }
|
|
if (showPCO->isChecked() && rideItem->ride()->areDataPresent()->lpco) { s.one = RideFile::lpco; s.two = RideFile::rpco; serieslist << s;}
|
|
if (showDC->isChecked() && rideItem->ride()->areDataPresent()->lppb) { s.one = RideFile::lppb; s.two = RideFile::lppe; serieslist << s;
|
|
s.one = RideFile::rppb; s.two = RideFile::rppe; serieslist << s; }
|
|
if (showPPP->isChecked() && rideItem->ride()->areDataPresent()->lpppb) { s.one = RideFile::lpppb; s.two = RideFile::lpppe; serieslist << s;
|
|
s.one = RideFile::rpppb; s.two = RideFile::rpppe; serieslist << s; }
|
|
|
|
// and the user series
|
|
for(int k=0; k<userDataSeries.count(); k++) {
|
|
s.one = static_cast<RideFile::SeriesType>(RideFile::none + 1 + k);
|
|
s.two = RideFile::none;
|
|
serieslist << s;
|
|
}
|
|
|
|
bool first = true;
|
|
foreach(SeriesWanted x, serieslist) {
|
|
|
|
// create that plot
|
|
AllPlot *_allPlot = new AllPlot(this, this, context, x.one, x.two, first);
|
|
_allPlot->setAutoFillBackground(false);
|
|
_allPlot->setPalette(palette);
|
|
_allPlot->setPaintBrush(paintBrush->checkState());
|
|
_allPlot->setDataFromPlot(allPlot); // will clone all settings and data for the series
|
|
// being plotted, only works for one series plotting
|
|
|
|
if (x.one == RideFile::watts) _allPlot->setShadeZones(showPower->currentIndex() == 0);
|
|
else _allPlot->setShadeZones(false);
|
|
first = false;
|
|
|
|
// add to the list
|
|
seriesPlots.append(_allPlot);
|
|
addPickers(_allPlot);
|
|
newLayout->addWidget(_allPlot);
|
|
_allPlot->setFixedHeight(120+(stackWidth*4));
|
|
|
|
// No x axis titles
|
|
_allPlot->setAxisVisible(QwtPlot::xBottom, true);
|
|
_allPlot->enableAxis(QwtPlot::xBottom, true);
|
|
_allPlot->setAxisTitle(QwtPlot::xBottom,NULL);
|
|
_allPlot->setAxisMaxMinor(QwtPlot::xBottom, 0);
|
|
_allPlot->setAxisMaxMinor(QwtPlot::yLeft, 0);
|
|
_allPlot->setAxisMaxMinor(QwtAxisId(QwtAxis::yLeft,1), 0);
|
|
_allPlot->setAxisMaxMinor(QwtPlot::yRight, 0);
|
|
_allPlot->setAxisMaxMinor(QwtAxisId(QwtAxis::yRight,2).id, 0);
|
|
_allPlot->setAxisMaxMinor(QwtAxisId(QwtAxis::yRight,3).id, 0);
|
|
|
|
// controls
|
|
_allPlot->replot();
|
|
}
|
|
|
|
newLayout->addStretch();
|
|
|
|
// lets make sure the size matches the user preferences
|
|
resizeSeriesPlots(); // << checks if updates enabled and doesn't reenable
|
|
|
|
// set new widgets
|
|
QPalette old = seriesstackWidget->palette();
|
|
seriesstackWidget = new QWidget(this);
|
|
seriesstackWidget->setPalette(old);
|
|
seriesstackWidget->setAutoFillBackground(false);
|
|
seriesstackWidget->setLayout(newLayout);
|
|
seriesstackFrame->setWidget(seriesstackWidget);
|
|
|
|
// lets remember the layout
|
|
seriesstackPlotLayout = newLayout;
|
|
|
|
// ZZZZ zap old widgets - is NOT required
|
|
// since setWidget above will destroy
|
|
// the ScrollArea's children
|
|
// not neccessary --> foreach (AllPlot *plot, oldPlots) delete plot;
|
|
// not neccessary --> delete stackPlotLayout;
|
|
// not neccessary --> delete stackWidget;
|
|
|
|
// we are now happy for a screen refresh to take place
|
|
seriesstackFrame->setUpdatesEnabled(true);
|
|
|
|
#if 0
|
|
// first lets wipe out the current plots
|
|
// since we cache out above we need to
|
|
// track and manage via below
|
|
#endif
|
|
setupSeriesStack = true; // we're clean
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::setupStackPlots()
|
|
{
|
|
// recreate all the stack plots
|
|
// they are all attached to the
|
|
// stackWidget, which we ultimately
|
|
// destroy in this function and replace
|
|
// with a new one. This is to avoid some
|
|
// nasty flickers and simplifies the code
|
|
// for refreshing.
|
|
if (!showStack->isChecked() || showBySeries->isChecked() || setupStack) return;
|
|
|
|
// since we cache out above we need to
|
|
// track and manage via below
|
|
setupStack = true;
|
|
|
|
// ************************************
|
|
// EDIT WITH CAUTION -- THIS HAS BEEN
|
|
// OPTIMISED FOR PERFORMANCE AS WELL AS
|
|
// FOR SCREEN FLICKER. IT IS A LITTLE
|
|
// COMPLICATED
|
|
// ************************************
|
|
QVBoxLayout *newLayout = new QVBoxLayout;
|
|
|
|
// this is NOT a memory leak (see ZZZ below)
|
|
allPlots.clear();
|
|
|
|
int _stackWidth = stackWidth;
|
|
if (fullPlot->bydist) _stackWidth = stackWidth/3;
|
|
|
|
RideItem* rideItem = current;
|
|
|
|
// don't try and plot for null files
|
|
if (!rideItem || !rideItem->ride() || rideItem->ride()->dataPoints().isEmpty()) return;
|
|
|
|
double duration = rideItem->ride()->dataPoints().last()->secs;
|
|
double distance = (context->athlete->useMetricUnits ? 1 : MILES_PER_KM) * rideItem->ride()->dataPoints().last()->km;
|
|
int nbplot;
|
|
|
|
if (fullPlot->bydist)
|
|
nbplot = (int)floor(distance/_stackWidth)+1;
|
|
else
|
|
nbplot = (int)floor(duration/_stackWidth/60)+1;
|
|
|
|
QPalette palette;
|
|
palette.setBrush(QPalette::Background, Qt::NoBrush);
|
|
|
|
for(int i = 0 ; i < nbplot ; i++) {
|
|
|
|
// calculate the segment of ride this stack plot contains
|
|
int startIndex, stopIndex;
|
|
if (fullPlot->bydist) {
|
|
startIndex = fullPlot->rideItem->ride()->distanceIndex((context->athlete->useMetricUnits ?
|
|
1 : KM_PER_MILE) * _stackWidth*i);
|
|
stopIndex = fullPlot->rideItem->ride()->distanceIndex((context->athlete->useMetricUnits ?
|
|
1 : KM_PER_MILE) * _stackWidth*(i+1));
|
|
} else {
|
|
startIndex = fullPlot->rideItem->ride()->timeIndex(60*_stackWidth*i);
|
|
stopIndex = fullPlot->rideItem->ride()->timeIndex(60*_stackWidth*(i+1));
|
|
}
|
|
|
|
// we need at least one point to plot
|
|
if (stopIndex - startIndex < 2) break;
|
|
|
|
// create that plot
|
|
AllPlot *_allPlot = new AllPlot(this, this, context);
|
|
_allPlot->setAutoFillBackground(false);
|
|
_allPlot->setPalette(palette);
|
|
_allPlot->setPaintBrush(paintBrush->checkState());
|
|
|
|
// add to the list
|
|
allPlots.append(_allPlot);
|
|
addPickers(_allPlot);
|
|
newLayout->addWidget(_allPlot);
|
|
|
|
// Update AllPlot for stacked view
|
|
_allPlot->setDataFromPlot(fullPlot, startIndex, stopIndex);
|
|
_allPlot->setAxisScale(QwtPlot::xBottom, _stackWidth*i, _stackWidth*(i+1), 15/stackWidth);
|
|
|
|
_allPlot->setFixedHeight(120+stackWidth*4);
|
|
|
|
// No x axis titles
|
|
_allPlot->setAxisVisible(QwtPlot::xBottom, true);
|
|
_allPlot->enableAxis(QwtPlot::xBottom, true);
|
|
_allPlot->setAxisTitle(QwtPlot::xBottom,NULL);
|
|
_allPlot->setAxisMaxMinor(QwtPlot::xBottom, 0);
|
|
_allPlot->setAxisMaxMinor(QwtPlot::yLeft, 0);
|
|
_allPlot->setAxisMaxMinor(QwtAxisId(QwtAxis::yLeft,1), 0);
|
|
_allPlot->setAxisMaxMinor(QwtPlot::yRight, 0);
|
|
_allPlot->setAxisMaxMinor(QwtAxisId(QwtAxis::yRight,2).id, 0);
|
|
_allPlot->setAxisMaxMinor(QwtAxisId(QwtAxis::yRight,3).id, 0);
|
|
|
|
// controls
|
|
_allPlot->setShadeZones(showPower->currentIndex() == 0);
|
|
_allPlot->setShowPower(showPower->currentIndex());
|
|
_allPlot->setShowHr( (showHr->isEnabled()) ? ( showHr->checkState() == Qt::Checked ) : false );
|
|
_allPlot->setShowTcore( (showTcore->isEnabled()) ? ( showTcore->checkState() == Qt::Checked ) : false );
|
|
_allPlot->setShowSpeed((showSpeed->isEnabled()) ? ( showSpeed->checkState() == Qt::Checked ) : false );
|
|
_allPlot->setShowAccel((showAccel->isEnabled()) ? ( showAccel->checkState() == Qt::Checked ) : false );
|
|
_allPlot->setShowPowerD((showPowerD->isEnabled()) ? ( showPowerD->checkState() == Qt::Checked ) : false );
|
|
_allPlot->setShowCadD((showCadD->isEnabled()) ? ( showCadD->checkState() == Qt::Checked ) : false );
|
|
_allPlot->setShowTorqueD((showTorqueD->isEnabled()) ? ( showTorqueD->checkState() == Qt::Checked ) : false );
|
|
_allPlot->setShowHrD((showHrD->isEnabled()) ? ( showHrD->checkState() == Qt::Checked ) : false );
|
|
_allPlot->setShowCad((showCad->isEnabled()) ? ( showCad->checkState() == Qt::Checked ) : false );
|
|
_allPlot->setShowAlt((showAlt->isEnabled()) ? ( showAlt->checkState() == Qt::Checked ) : false );
|
|
_allPlot->setShowSlope((showSlope->isEnabled()) ? ( showSlope->checkState() == Qt::Checked ) : false );
|
|
_allPlot->setShowAltSlope(showAltSlope->currentIndex());
|
|
_allPlot->setShowTemp((showTemp->isEnabled()) ? ( showTemp->checkState() == Qt::Checked ) : false );
|
|
_allPlot->setShowTorque((showTorque->isEnabled()) ? ( showTorque->checkState() == Qt::Checked ) : false );
|
|
_allPlot->setShowW((showW->isEnabled()) ? ( showW->checkState() == Qt::Checked ) : false );
|
|
_allPlot->setShowATISS((showATISS->isEnabled()) ? ( showATISS->checkState() == Qt::Checked ) : false );
|
|
_allPlot->setShowANTISS((showANTISS->isEnabled()) ? ( showANTISS->checkState() == Qt::Checked ) : false );
|
|
_allPlot->setShowGrid(showGrid->checkState() == Qt::Checked);
|
|
_allPlot->setPaintBrush(paintBrush->checkState());
|
|
_allPlot->setSmoothing(smoothSlider->value());
|
|
_allPlot->setByDistance(comboDistance->currentIndex());
|
|
_allPlot->setShowBalance((showBalance->isEnabled()) ? ( showBalance->checkState() == Qt::Checked ) : false );
|
|
_allPlot->setShowNP((showNP->isEnabled()) ? ( showNP->checkState() == Qt::Checked ) : false );
|
|
_allPlot->setShowRV((showRV->isEnabled()) ? ( showRV->checkState() == Qt::Checked ) : false );
|
|
_allPlot->setShowRCad((showRCad->isEnabled()) ? ( showRCad->checkState() == Qt::Checked ) : false );
|
|
_allPlot->setShowRGCT((showRGCT->isEnabled()) ? ( showRGCT->checkState() == Qt::Checked ) : false );
|
|
_allPlot->setShowGear((showGear->isEnabled()) ? ( showGear->checkState() == Qt::Checked ) : false );
|
|
_allPlot->setShowSmO2((showSmO2->isEnabled()) ? ( showSmO2->checkState() == Qt::Checked ) : false );
|
|
_allPlot->setShowtHb((showtHb->isEnabled()) ? ( showtHb->checkState() == Qt::Checked ) : false );
|
|
_allPlot->setShowO2Hb((showO2Hb->isEnabled()) ? ( showO2Hb->checkState() == Qt::Checked ) : false );
|
|
_allPlot->setShowHHb((showHHb->isEnabled()) ? ( showHHb->checkState() == Qt::Checked ) : false );
|
|
_allPlot->setShowXP((showXP->isEnabled()) ? ( showXP->checkState() == Qt::Checked ) : false );
|
|
_allPlot->setShowAP((showAP->isEnabled()) ? ( showAP->checkState() == Qt::Checked ) : false );
|
|
_allPlot->setShowTE((showTE->isEnabled()) ? ( showTE->checkState() == Qt::Checked ) : false );
|
|
_allPlot->setShowPS((showPS->isEnabled()) ? ( showPS->checkState() == Qt::Checked ) : false );
|
|
_allPlot->setShowPCO((showPCO->isEnabled()) ? ( showPCO->checkState() == Qt::Checked ) : false );
|
|
_allPlot->setShowDC((showDC->isEnabled()) ? ( showDC->checkState() == Qt::Checked ) : false );
|
|
_allPlot->setShowPPP((showPPP->isEnabled()) ? ( showPPP->checkState() == Qt::Checked ) : false );
|
|
|
|
_allPlot->replot();
|
|
}
|
|
newLayout->addStretch();
|
|
|
|
// the refresh takes a while and is prone
|
|
// to lots of flicker, we turn off updates
|
|
// whilst we switch from the old to the new
|
|
// stackWidget and plots
|
|
stackFrame->setUpdatesEnabled(false);
|
|
|
|
// set new widgets
|
|
QPalette old = stackWidget->palette();
|
|
stackWidget = new QWidget(this);
|
|
stackWidget->setPalette(old);
|
|
stackWidget->setAutoFillBackground(false);
|
|
stackWidget->setLayout(newLayout);
|
|
stackFrame->setWidget(stackWidget);
|
|
|
|
// ZZZZ zap old widgets - is NOT required
|
|
// since setWidget above will destroy
|
|
// the ScrollArea's children
|
|
// not neccessary --> foreach (AllPlot *plot, oldPlots) delete plot;
|
|
// not neccessary --> delete stackPlotLayout;
|
|
// not neccessary --> delete stackWidget;
|
|
|
|
// we are now happy for a screen refresh to take place
|
|
stackFrame->setUpdatesEnabled(true);
|
|
|
|
}
|
|
|
|
void
|
|
AllPlotWindow::addPickers(AllPlot *_allPlot)
|
|
{
|
|
QwtPlotMarker* allMarker1 = new QwtPlotMarker();
|
|
allMarker1->setLineStyle(QwtPlotMarker::VLine);
|
|
allMarker1->attach(_allPlot);
|
|
allMarker1->setLabelAlignment(Qt::AlignTop|Qt::AlignRight);
|
|
_allPlot->standard->allMarker1 = allMarker1;
|
|
|
|
QwtPlotMarker* allMarker2 = new QwtPlotMarker();
|
|
allMarker2->setLineStyle(QwtPlotMarker::VLine);
|
|
allMarker2->attach(_allPlot);
|
|
allMarker2->setLabelAlignment(Qt::AlignTop|Qt::AlignRight);
|
|
_allPlot->standard->allMarker2 = allMarker2;
|
|
|
|
// use the tooltip picker rather than a standard picker
|
|
_allPlot->tooltip = new LTMToolTip(QwtPlot::xBottom, QwtAxisId(QwtAxis::yLeft, 2).id,
|
|
QwtPicker::VLineRubberBand,
|
|
QwtPicker::AlwaysOn,
|
|
_allPlot->canvas(),
|
|
"");
|
|
_allPlot->tooltip->setRubberBand(QwtPicker::VLineRubberBand);
|
|
_allPlot->tooltip->setMousePattern(QwtEventPattern::MouseSelect1, Qt::LeftButton);
|
|
_allPlot->tooltip->setTrackerPen(QColor(Qt::black));
|
|
QColor inv(Qt::white);
|
|
inv.setAlpha(0);
|
|
_allPlot->tooltip->setRubberBandPen(inv);
|
|
_allPlot->tooltip->setEnabled(true);
|
|
|
|
_allPlot->_canvasPicker = new LTMCanvasPicker(_allPlot);
|
|
connect(context, SIGNAL(intervalHover(IntervalItem*)), _allPlot, SLOT(intervalHover(IntervalItem*)));
|
|
connect(_allPlot->_canvasPicker, SIGNAL(pointHover(QwtPlotCurve*, int)), _allPlot, SLOT(pointHover(QwtPlotCurve*, int)));
|
|
connect(_allPlot->tooltip, SIGNAL(moved(const QPoint &)), this, SLOT(plotPickerMoved(const QPoint &)));
|
|
connect(_allPlot->tooltip, SIGNAL(appended(const QPoint &)), this, SLOT(plotPickerSelected(const QPoint &)));
|
|
}
|