mirror of
https://github.com/GoldenCheetah/GoldenCheetah.git
synced 2026-02-13 16:18:42 +00:00
184
src/Pages.cpp
184
src/Pages.cpp
@@ -19,11 +19,13 @@ ConfigurationPage::ConfigurationPage(MainWindow *main) : main(main)
|
||||
QWidget *config = new QWidget(this);
|
||||
QVBoxLayout *configLayout = new QVBoxLayout(config);
|
||||
colorsPage = new ColorsPage(main);
|
||||
summaryMetrics = new SummaryMetricsPage;
|
||||
intervalMetrics = new IntervalMetricsPage;
|
||||
metadataPage = new MetadataPage(main);
|
||||
|
||||
tabs->addTab(config, tr("Basic Settings"));
|
||||
tabs->addTab(colorsPage, tr("Colors"));
|
||||
tabs->addTab(summaryMetrics, tr("Summary Metrics"));
|
||||
tabs->addTab(intervalMetrics, tr("Interval Metrics"));
|
||||
tabs->addTab(metadataPage, tr("Ride Data"));
|
||||
|
||||
@@ -227,6 +229,7 @@ void
|
||||
ConfigurationPage::saveClicked()
|
||||
{
|
||||
colorsPage->saveClicked();
|
||||
summaryMetrics->saveClicked();
|
||||
intervalMetrics->saveClicked();
|
||||
metadataPage->saveClicked();
|
||||
}
|
||||
@@ -930,6 +933,187 @@ IntervalMetricsPage::saveClicked()
|
||||
settings->setValue(GC_SETTINGS_INTERVAL_METRICS, metrics.join(","));
|
||||
}
|
||||
|
||||
|
||||
SummaryMetricsPage::SummaryMetricsPage(QWidget *parent) :
|
||||
QWidget(parent), changed(false)
|
||||
{
|
||||
availList = new QListWidget;
|
||||
availList->setSortingEnabled(true);
|
||||
availList->setSelectionMode(QAbstractItemView::SingleSelection);
|
||||
QVBoxLayout *availLayout = new QVBoxLayout;
|
||||
availLayout->addWidget(new QLabel(tr("Available Metrics")));
|
||||
availLayout->addWidget(availList);
|
||||
selectedList = new QListWidget;
|
||||
selectedList->setSelectionMode(QAbstractItemView::SingleSelection);
|
||||
QVBoxLayout *selectedLayout = new QVBoxLayout;
|
||||
selectedLayout->addWidget(new QLabel(tr("Selected Metrics")));
|
||||
selectedLayout->addWidget(selectedList);
|
||||
upButton = new QPushButton("Move up");
|
||||
downButton = new QPushButton("Move down");
|
||||
leftButton = new QPushButton("Exclude");
|
||||
rightButton = new QPushButton("Include");
|
||||
QVBoxLayout *buttonGrid = new QVBoxLayout;
|
||||
QHBoxLayout *upLayout = new QHBoxLayout;
|
||||
QHBoxLayout *inexcLayout = new QHBoxLayout;
|
||||
QHBoxLayout *downLayout = new QHBoxLayout;
|
||||
|
||||
upLayout->addStretch();
|
||||
upLayout->addWidget(upButton);
|
||||
upLayout->addStretch();
|
||||
|
||||
inexcLayout->addStretch();
|
||||
inexcLayout->addWidget(leftButton);
|
||||
inexcLayout->addWidget(rightButton);
|
||||
inexcLayout->addStretch();
|
||||
|
||||
downLayout->addStretch();
|
||||
downLayout->addWidget(downButton);
|
||||
downLayout->addStretch();
|
||||
|
||||
buttonGrid->addStretch();
|
||||
buttonGrid->addLayout(upLayout);
|
||||
buttonGrid->addLayout(inexcLayout);
|
||||
buttonGrid->addLayout(downLayout);
|
||||
buttonGrid->addStretch();
|
||||
|
||||
QHBoxLayout *hlayout = new QHBoxLayout;
|
||||
hlayout->addLayout(availLayout);
|
||||
hlayout->addLayout(buttonGrid);
|
||||
hlayout->addLayout(selectedLayout);
|
||||
setLayout(hlayout);
|
||||
|
||||
QString s;
|
||||
boost::shared_ptr<QSettings> settings = GetApplicationSettings();
|
||||
if (settings->contains(GC_SETTINGS_SUMMARY_METRICS))
|
||||
s = settings->value(GC_SETTINGS_SUMMARY_METRICS).toString();
|
||||
else
|
||||
s = GC_SETTINGS_SUMMARY_METRICS_DEFAULT;
|
||||
QStringList selectedMetrics = s.split(",");
|
||||
|
||||
const RideMetricFactory &factory = RideMetricFactory::instance();
|
||||
for (int i = 0; i < factory.metricCount(); ++i) {
|
||||
QString symbol = factory.metricName(i);
|
||||
if (selectedMetrics.contains(symbol))
|
||||
continue;
|
||||
QSharedPointer<RideMetric> m(factory.newMetric(symbol));
|
||||
QString name = m->name();
|
||||
name.replace(tr("™"), tr(" (TM)"));
|
||||
QListWidgetItem *item = new QListWidgetItem(name);
|
||||
item->setData(Qt::UserRole, symbol);
|
||||
availList->addItem(item);
|
||||
}
|
||||
foreach (QString symbol, selectedMetrics) {
|
||||
if (!factory.haveMetric(symbol))
|
||||
continue;
|
||||
QSharedPointer<RideMetric> m(factory.newMetric(symbol));
|
||||
QString name = m->name();
|
||||
name.replace(tr("™"), tr(" (TM)"));
|
||||
QListWidgetItem *item = new QListWidgetItem(name);
|
||||
item->setData(Qt::UserRole, symbol);
|
||||
selectedList->addItem(item);
|
||||
}
|
||||
|
||||
upButton->setEnabled(false);
|
||||
downButton->setEnabled(false);
|
||||
leftButton->setEnabled(false);
|
||||
rightButton->setEnabled(false);
|
||||
|
||||
connect(upButton, SIGNAL(clicked()), this, SLOT(upClicked()));
|
||||
connect(downButton, SIGNAL(clicked()), this, SLOT(downClicked()));
|
||||
connect(leftButton, SIGNAL(clicked()), this, SLOT(leftClicked()));
|
||||
connect(rightButton, SIGNAL(clicked()), this, SLOT(rightClicked()));
|
||||
connect(availList, SIGNAL(itemSelectionChanged()),
|
||||
this, SLOT(availChanged()));
|
||||
connect(selectedList, SIGNAL(itemSelectionChanged()),
|
||||
this, SLOT(selectedChanged()));
|
||||
}
|
||||
|
||||
void
|
||||
SummaryMetricsPage::upClicked()
|
||||
{
|
||||
assert(!selectedList->selectedItems().isEmpty());
|
||||
QListWidgetItem *item = selectedList->selectedItems().first();
|
||||
int row = selectedList->row(item);
|
||||
assert(row > 0);
|
||||
selectedList->takeItem(row);
|
||||
selectedList->insertItem(row - 1, item);
|
||||
selectedList->setCurrentItem(item);
|
||||
changed = true;
|
||||
}
|
||||
|
||||
void
|
||||
SummaryMetricsPage::downClicked()
|
||||
{
|
||||
assert(!selectedList->selectedItems().isEmpty());
|
||||
QListWidgetItem *item = selectedList->selectedItems().first();
|
||||
int row = selectedList->row(item);
|
||||
assert(row < selectedList->count() - 1);
|
||||
selectedList->takeItem(row);
|
||||
selectedList->insertItem(row + 1, item);
|
||||
selectedList->setCurrentItem(item);
|
||||
changed = true;
|
||||
}
|
||||
|
||||
void
|
||||
SummaryMetricsPage::leftClicked()
|
||||
{
|
||||
assert(!selectedList->selectedItems().isEmpty());
|
||||
QListWidgetItem *item = selectedList->selectedItems().first();
|
||||
selectedList->takeItem(selectedList->row(item));
|
||||
availList->addItem(item);
|
||||
changed = true;
|
||||
}
|
||||
|
||||
void
|
||||
SummaryMetricsPage::rightClicked()
|
||||
{
|
||||
assert(!availList->selectedItems().isEmpty());
|
||||
QListWidgetItem *item = availList->selectedItems().first();
|
||||
availList->takeItem(availList->row(item));
|
||||
selectedList->addItem(item);
|
||||
changed = true;
|
||||
}
|
||||
|
||||
void
|
||||
SummaryMetricsPage::availChanged()
|
||||
{
|
||||
rightButton->setEnabled(!availList->selectedItems().isEmpty());
|
||||
}
|
||||
|
||||
void
|
||||
SummaryMetricsPage::selectedChanged()
|
||||
{
|
||||
if (selectedList->selectedItems().isEmpty()) {
|
||||
upButton->setEnabled(false);
|
||||
downButton->setEnabled(false);
|
||||
leftButton->setEnabled(false);
|
||||
return;
|
||||
}
|
||||
QListWidgetItem *item = selectedList->selectedItems().first();
|
||||
int row = selectedList->row(item);
|
||||
if (row == 0)
|
||||
upButton->setEnabled(false);
|
||||
else
|
||||
upButton->setEnabled(true);
|
||||
if (row == selectedList->count() - 1)
|
||||
downButton->setEnabled(false);
|
||||
else
|
||||
downButton->setEnabled(true);
|
||||
leftButton->setEnabled(true);
|
||||
}
|
||||
|
||||
void
|
||||
SummaryMetricsPage::saveClicked()
|
||||
{
|
||||
if (!changed)
|
||||
return;
|
||||
QStringList metrics;
|
||||
for (int i = 0; i < selectedList->count(); ++i)
|
||||
metrics << selectedList->item(i)->data(Qt::UserRole).toString();
|
||||
boost::shared_ptr<QSettings> settings = GetApplicationSettings();
|
||||
settings->setValue(GC_SETTINGS_SUMMARY_METRICS, metrics.join(","));
|
||||
}
|
||||
|
||||
MetadataPage::MetadataPage(MainWindow *main) : main(main)
|
||||
{
|
||||
QVBoxLayout *layout = new QVBoxLayout(this);
|
||||
|
||||
32
src/Pages.h
32
src/Pages.h
@@ -35,6 +35,7 @@ class QHBoxLayout;
|
||||
class QVBoxLayout;
|
||||
class ColorsPage;
|
||||
class IntervalMetricsPage;
|
||||
class SummaryMetricsPage;
|
||||
class MetadataPage;
|
||||
class KeywordsPage;
|
||||
class FieldsPage;
|
||||
@@ -66,6 +67,7 @@ class ConfigurationPage : public QWidget
|
||||
private:
|
||||
MainWindow *main;
|
||||
ColorsPage *colorsPage;
|
||||
SummaryMetricsPage *summaryMetrics;
|
||||
IntervalMetricsPage *intervalMetrics;
|
||||
MetadataPage *metadataPage;
|
||||
|
||||
@@ -228,6 +230,36 @@ class IntervalMetricsPage : public QWidget
|
||||
QPushButton *rightButton;
|
||||
};
|
||||
|
||||
class SummaryMetricsPage : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
SummaryMetricsPage(QWidget *parent = NULL);
|
||||
|
||||
public slots:
|
||||
|
||||
void upClicked();
|
||||
void downClicked();
|
||||
void leftClicked();
|
||||
void rightClicked();
|
||||
void availChanged();
|
||||
void selectedChanged();
|
||||
void saveClicked();
|
||||
|
||||
protected:
|
||||
|
||||
bool changed;
|
||||
QListWidget *availList;
|
||||
QListWidget *selectedList;
|
||||
QPushButton *upButton;
|
||||
QPushButton *downButton;
|
||||
QPushButton *leftButton;
|
||||
QPushButton *rightButton;
|
||||
};
|
||||
|
||||
|
||||
class KeywordsPage : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@@ -108,7 +108,25 @@ RideSummaryWindow::htmlSummary() const
|
||||
NULL
|
||||
};
|
||||
|
||||
const char *metricColumn[] = {
|
||||
QString s;
|
||||
|
||||
if (settings->contains(GC_SETTINGS_SUMMARY_METRICS))
|
||||
s = settings->value(GC_SETTINGS_SUMMARY_METRICS).toString();
|
||||
else
|
||||
s = GC_SETTINGS_SUMMARY_METRICS_DEFAULT;
|
||||
QStringList metricColumnList = s.split(",");
|
||||
|
||||
char **metricColumnTmp;
|
||||
// Copy QStringList to char **
|
||||
metricColumnTmp = new char*[metricColumnList.size() + 1];
|
||||
for (int i = 0; i < metricColumnList.size(); i++) {
|
||||
metricColumnTmp[i] = new char[strlen(metricColumnList.at(i).toStdString().c_str())+1];
|
||||
memcpy(metricColumnTmp[i], metricColumnList.at(i).toStdString().c_str(), strlen(metricColumnList.at(i).toStdString().c_str())+1);
|
||||
}
|
||||
metricColumnTmp[metricColumnList.size()] = NULL;
|
||||
char const **metricColumn = (const char**)metricColumnTmp;
|
||||
|
||||
/*const char *metricColumn[] = {
|
||||
"skiba_xpower",
|
||||
"skiba_relative_intensity",
|
||||
"skiba_bike_score",
|
||||
@@ -117,7 +135,7 @@ RideSummaryWindow::htmlSummary() const
|
||||
"trimp_points",
|
||||
"aerobic_decoupling",
|
||||
NULL
|
||||
};
|
||||
};*/
|
||||
|
||||
summary += "<table border=0 cellspacing=10><tr>";
|
||||
for (int i = 0; i < columns; ++i) {
|
||||
@@ -135,6 +153,7 @@ RideSummaryWindow::htmlSummary() const
|
||||
for (int j = 0;; ++j) {
|
||||
const char *symbol = metricsList[j];
|
||||
if (!symbol) break;
|
||||
|
||||
RideMetricPtr m = rideItem->metrics.value(symbol);
|
||||
QString name = m->name().replace(QRegExp(tr("^Average ")), "");
|
||||
if (m->units(metricUnits) == "seconds" || m->units(metricUnits) == tr("seconds")) {
|
||||
|
||||
@@ -31,11 +31,13 @@
|
||||
#define GC_SETTINGS_SUMMARYSPLITTER_SIZES "mainwindow/summarysplittersizes"
|
||||
#define GC_SETTINGS_CALENDAR_SIZES "mainwindow/calendarSizes"
|
||||
#define GC_TABS_TO_HIDE "mainwindow/tabsToHide"
|
||||
#define GC_SETTINGS_SUMMARY_METRICS "rideSummaryWindow/summaryMetrics"
|
||||
#define GC_SETTINGS_INTERVAL_METRICS "rideSummaryWindow/intervalMetrics"
|
||||
#define GC_RIDE_PLOT_SMOOTHING "ridePlot/Smoothing"
|
||||
#define GC_RIDE_PLOT_STACK "ridePlot/Stack"
|
||||
#define GC_PERF_MAN_METRIC "performanceManager/metric"
|
||||
#define GC_HIST_BIN_WIDTH "histogamWindow/binWidth"
|
||||
#define GC_SETTINGS_SUMMARY_METRICS_DEFAULT "skiba_xpower,skiba_relative_intensity,skiba_bike_score,daniels_points,daniels_equivalent_power,trimp_points,aerobic_decoupling"
|
||||
#define GC_SETTINGS_INTERVAL_METRICS_DEFAULT "workout_time,total_distance,total_work,average_power,skiba_xpower,max_power,average_hr,ninety_five_percent_hr,average_cad,average_speed"
|
||||
#define GC_DATETIME_FORMAT "ddd MMM dd, yyyy, hh:mm AP"
|
||||
#define GC_UNIT "unit"
|
||||
|
||||
@@ -293,6 +293,58 @@ public:
|
||||
RideMetric *clone() const { return new TRIMPZonalPoints(*this); }
|
||||
};
|
||||
|
||||
|
||||
// RPE is the rate of percieved exercion (borg scale).
|
||||
// Is a numerical value the riders give in "average" fatigue of the training session he percieved.
|
||||
//
|
||||
// Calculate the session RPE that is the product of RPE * time (minutes) of training/race ride. I
|
||||
// We have 3 different "training load" parameters:
|
||||
// - internal load (TRIMPS)
|
||||
// - external load (bikescore/TSS)
|
||||
// - perceived load (session RPE)
|
||||
//
|
||||
class SessionRPE : public RideMetric {
|
||||
Q_DECLARE_TR_FUNCTIONS(TRIMPPoints)
|
||||
|
||||
double score;
|
||||
|
||||
public:
|
||||
|
||||
SessionRPE() : score(0.0)
|
||||
{
|
||||
setSymbol("session_rpe");
|
||||
#ifdef ENABLE_METRICS_TRANSLATION
|
||||
setInternalName("Session RPE");
|
||||
}
|
||||
void initialize() {
|
||||
#endif
|
||||
setName(tr("Session RPE"));
|
||||
setMetricUnits("");
|
||||
setImperialUnits("");
|
||||
setType(RideMetric::Total);
|
||||
}
|
||||
void compute(const RideFile *rideFile,
|
||||
const Zones *, int ,
|
||||
const HrZones *hrZones, int hrZoneRange,
|
||||
const QHash<QString,RideMetric*> &deps)
|
||||
{
|
||||
// use RPE value in ride metadata
|
||||
double rpe = rideFile->getTag("RPE", "0.0").toDouble();
|
||||
|
||||
assert(deps.contains("workout_time"));
|
||||
const RideMetric *workoutTimeMetric = deps.value("workout_time");
|
||||
assert(workoutTimeMetric);
|
||||
|
||||
double secs = workoutTimeMetric->value(true);
|
||||
|
||||
// ok lets work the score out
|
||||
score = ((secs == 0.0 || rpe == 0) ? 0.0 : secs/60 *rpe);
|
||||
setValue(score);
|
||||
}
|
||||
|
||||
RideMetric *clone() const { return new SessionRPE(*this); }
|
||||
};
|
||||
|
||||
static bool added() {
|
||||
QVector<QString> deps;
|
||||
deps.append("workout_time");
|
||||
@@ -312,6 +364,10 @@ static bool added() {
|
||||
deps.append("time_in_zone_H4");
|
||||
deps.append("time_in_zone_H5");
|
||||
RideMetricFactory::instance().addMetric(TRIMPZonalPoints(), &deps);
|
||||
|
||||
deps.clear();
|
||||
deps.append("workout_time");
|
||||
RideMetricFactory::instance().addMetric(SessionRPE(), &deps);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user