55 changes: 43 additions & 12 deletions src/Charts/OverviewItems.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ class ProgressBar;
#define ROUTEPOINTS 250

// types we use start from 100 to avoid clashing with main chart types
enum OverviewItemType { RPE=100, METRIC, META, ZONE, INTERVAL, PMC, ROUTE, KPI, TOPN, DONUT, ACTIVITIES, ATHLETE, DATATABLE };
enum OverviewItemType { RPE=100, METRIC, META, ZONE, INTERVAL, PMC, ROUTE, KPI,
TOPN, DONUT, ACTIVITIES, ATHLETE, DATATABLE, USERCHART };

//
// Configuration widget for ALL Overview Items
Expand Down Expand Up @@ -110,7 +111,8 @@ class KPIOverviewItem : public ChartSpaceItem
void itemGeometryChanged();
void setData(RideItem *item);
void setDateRange(DateRange);
QWidget *config() { return new OverviewItemConfig(this); }

QWidget *config() { return configwidget ; }

// create and config
static ChartSpaceItem *create(ChartSpace *parent) { return new KPIOverviewItem(parent, "CP Estimate", 0, 360, "{ round(estimate(cp3,cp)); }", "watts", false); }
Expand All @@ -125,6 +127,7 @@ class KPIOverviewItem : public ChartSpaceItem

// progress bar viz
ProgressBar *progressbar;
OverviewItemConfig *configwidget;
};

class DataOverviewItem : public ChartSpaceItem
Expand All @@ -141,7 +144,8 @@ class DataOverviewItem : public ChartSpaceItem
void setData(RideItem *item);
void setDateRange(DateRange);
void postProcess(); // work with data returned from program
QWidget *config() { return new OverviewItemConfig(this); }

QWidget *config() { return configwidget; }

// create and config
static ChartSpaceItem *create(ChartSpace *parent);
Expand All @@ -160,6 +164,7 @@ class DataOverviewItem : public ChartSpaceItem
// display control
bool multirow;
QList<double> columnWidths;
OverviewItemConfig *configwidget;
};

class RPEOverviewItem : public ChartSpaceItem
Expand All @@ -175,7 +180,8 @@ class RPEOverviewItem : public ChartSpaceItem
void itemGeometryChanged();
void setData(RideItem *item);
void setDateRange(DateRange) {} // doesn't support trends view
QWidget *config() { return new OverviewItemConfig(this); }

QWidget *config() { return configwidget; }

// create and config
static ChartSpaceItem *create(ChartSpace *parent) { return new RPEOverviewItem(parent, "RPE"); }
Expand All @@ -187,6 +193,7 @@ class RPEOverviewItem : public ChartSpaceItem
// for setting sparkline & painting
bool up, showrange;
QString value, upper, lower, mean;
OverviewItemConfig *configwidget;
};

class MetricOverviewItem : public ChartSpaceItem
Expand All @@ -202,7 +209,8 @@ class MetricOverviewItem : public ChartSpaceItem
void itemGeometryChanged();
void setData(RideItem *item);
void setDateRange(DateRange);
QWidget *config() { return new OverviewItemConfig(this); }

QWidget *config() { return configwidget; }

// create and config
static ChartSpaceItem *create(ChartSpace *parent) { return new MetricOverviewItem(parent, "PowerIndex", "power_index"); }
Expand All @@ -219,6 +227,8 @@ class MetricOverviewItem : public ChartSpaceItem
int rank; // rank 1,2 or 3
QString beststring;
QPixmap gold, silver, bronze; // medals

OverviewItemConfig *configwidget;
};

// top N uses this to hold details for date range
Expand Down Expand Up @@ -259,7 +269,8 @@ class TopNOverviewItem : public ChartSpaceItem
void setData(RideItem *) {} // doesn't support analysis view
void setDateRange(DateRange);
QRectF hotspot();
QWidget *config() { return new OverviewItemConfig(this); }

QWidget *config() { return configwidget; }

// create and config
static ChartSpaceItem *create(ChartSpace *parent) { return new TopNOverviewItem(parent, "PowerIndex", "power_index"); }
Expand All @@ -280,6 +291,8 @@ class TopNOverviewItem : public ChartSpaceItem

// interaction
bool click;

OverviewItemConfig *configwidget;
};

class MetaOverviewItem : public ChartSpaceItem
Expand All @@ -295,7 +308,8 @@ class MetaOverviewItem : public ChartSpaceItem
void itemGeometryChanged();
void setData(RideItem *item);
void setDateRange(DateRange) {} // doesn't support trends view
QWidget *config() { return new OverviewItemConfig(this); }

QWidget *config() { return configwidget; }

// create and config
static ChartSpaceItem *create(ChartSpace *parent) { return new MetaOverviewItem(parent, tr("Workout Code"), "Workout Code"); }
Expand All @@ -308,6 +322,8 @@ class MetaOverviewItem : public ChartSpaceItem
QString value, upper, lower, mean;

Sparkline *sparkline;

OverviewItemConfig *configwidget;
};

class PMCOverviewItem : public ChartSpaceItem
Expand All @@ -323,14 +339,17 @@ class PMCOverviewItem : public ChartSpaceItem
void itemGeometryChanged();
void setData(RideItem *item);
void setDateRange(DateRange) {} // doesn't support trends view
QWidget *config() { return new OverviewItemConfig(this); }

QWidget *config() { return configwidget ; }

// create and config
static ChartSpaceItem *create(ChartSpace *parent) { return new PMCOverviewItem(parent, "coggan_tss"); }

QString symbol;

double sts, lts, sb, rr, stress;

OverviewItemConfig *configwidget;
};

class ZoneOverviewItem : public ChartSpaceItem
Expand All @@ -347,7 +366,8 @@ class ZoneOverviewItem : public ChartSpaceItem
void setData(RideItem *item);
void setDateRange(DateRange);
void dragChanged(bool x);
QWidget *config() { return new OverviewItemConfig(this); }

QWidget *config() { return configwidget; }

// create and config
static ChartSpaceItem *create(ChartSpace *parent) { return new ZoneOverviewItem(parent, tr("Power Zones"), RideFile::watts, false); }
Expand All @@ -360,6 +380,8 @@ class ZoneOverviewItem : public ChartSpaceItem
QBarSeries *barseries;
QStringList categories;
QBarCategoryAxis *barcategoryaxis;

OverviewItemConfig *configwidget;
};

struct aggmeta {
Expand All @@ -384,7 +406,8 @@ class DonutOverviewItem : public ChartSpaceItem
void setData(RideItem *) {} // trends view only
void setDateRange(DateRange);
void dragChanged(bool x);
QWidget *config() { return new OverviewItemConfig(this); }

QWidget *config() { return configwidget ; }

// create and config
static ChartSpaceItem *create(ChartSpace *parent) { return new DonutOverviewItem(parent, tr("Sport"), "ride_count", "Sport"); }
Expand All @@ -403,6 +426,8 @@ class DonutOverviewItem : public ChartSpaceItem
QBarSeries *barseries;
QBarCategoryAxis *barcategoryaxis;

OverviewItemConfig *configwidget;

public slots:
void hoverSlice(QPieSlice *slice, bool state);
};
Expand All @@ -420,12 +445,15 @@ class RouteOverviewItem : public ChartSpaceItem
void itemGeometryChanged();
void setData(RideItem *item);
void setDateRange(DateRange) {} // doesn't support trends view
QWidget *config() { return new OverviewItemConfig(this); }

QWidget *config() { return configwidget; }

// create and config
static ChartSpaceItem *create(ChartSpace *parent) { return new RouteOverviewItem(parent, tr("Route")); }

Routeline *routeline;

OverviewItemConfig *configwidget;
};

class IntervalOverviewItem : public ChartSpaceItem
Expand All @@ -441,7 +469,8 @@ class IntervalOverviewItem : public ChartSpaceItem
void itemGeometryChanged();
void setData(RideItem *item);
void setDateRange(DateRange);
QWidget *config() { return new OverviewItemConfig(this); }

QWidget *config() { return configwidget; }

// create and config
static ChartSpaceItem *createInterval(ChartSpace *parent) { return new IntervalOverviewItem(parent, tr("Intervals"), "elapsed_time", "average_power", "workout_time"); }
Expand All @@ -450,6 +479,8 @@ class IntervalOverviewItem : public ChartSpaceItem
QString xsymbol, ysymbol, zsymbol;
int xdp, ydp;
BubbleViz *bubble;

OverviewItemConfig *configwidget;
};


Expand Down
66 changes: 35 additions & 31 deletions src/Charts/UserChart.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,39 +35,32 @@
#include <QScrollArea>
#include <QDialog>

UserChart::UserChart(Context *context, bool rangemode) : GcChartWindow(context), context(context), rangemode(rangemode), stale(true), last(NULL)
UserChart::UserChart(QWidget *parent, Context *context, bool rangemode)
: QWidget(parent), context(context), rangemode(rangemode), stale(true), last(NULL), ride(NULL)
{
HelpWhatsThis *helpContents = new HelpWhatsThis(this);
this->setWhatsThis(helpContents->getWhatsThisText(HelpWhatsThis::Chart_User));

// the config
settingsTool = new UserChartSettings(context, rangemode, chartinfo, seriesinfo, axisinfo);
setControls(settingsTool);
settingsTool_ = new UserChartSettings(context, rangemode, chartinfo, seriesinfo, axisinfo);
settingsTool_->hide();

// layout
QVBoxLayout *main=new QVBoxLayout();
setChartLayout(main); // we're a gcchartwindow
setLayout(main);
main->setSpacing(0);
main->setContentsMargins(0,0,0,0);

// the chart
chart = new GenericChart(this, context);
main->addWidget(chart);

// when a ride is selected
if (!rangemode) {
connect(this, SIGNAL(rideItemChanged(RideItem*)), this, SLOT(setRide(RideItem*)));
} else {
connect(this, SIGNAL(dateRangeChanged(DateRange)), SLOT(setDateRange(DateRange)));
connect(context, SIGNAL(homeFilterChanged()), this, SLOT(refresh()));
connect(context, SIGNAL(filterChanged()), this, SLOT(refresh()));
connect(this, SIGNAL(perspectiveFilterChanged(QString)), this, SLOT(refresh()));
}
// when a ride is selected, etc we get notified by our parent
// which is a UserChartWindow or a UserChartOverviewItem

// need to refresh when chart settings change
connect(settingsTool, SIGNAL(chartConfigChanged()), this, SLOT(chartConfigChanged()));
// but we do need to refresh when chart settings change
connect(settingsTool_, SIGNAL(chartConfigChanged()), this, SLOT(chartConfigChanged()));
connect(context, SIGNAL(configChanged(qint32)), this, SLOT(configChanged(qint32)));
connect(this, SIGNAL(perspectiveChanged(Perspective*)), this, SLOT(refresh()));

configChanged(0);
}
Expand Down Expand Up @@ -97,25 +90,25 @@ UserChart::configChanged(qint32)
void
UserChart::chartConfigChanged()
{
if (!myRideItem) return;
if (!ride) return;

stale = true;

if (rangemode) setDateRange(context->currentDateRange());
else setRide(myRideItem);
else setRide(ride);
}

//
// Ride selected
//
void
UserChart::setRide(RideItem *item)
UserChart::setRide(const RideItem *item)
{
// not being shown so just ignore
if (!amVisible()) { stale=true; return; }
if (!isVisible()) { stale=true; return; }

// make sure its not NULL etc
if (item == NULL || item->ride() == NULL) return;
if (item == NULL || const_cast<RideItem*>(item)->ride() == NULL) return;

// have we already seen it?
if (last == item && !stale) return;
Expand All @@ -126,29 +119,29 @@ UserChart::setRide(RideItem *item)
ride = last = item;
stale = false;

dr=DateRange(); // always set to no range
//dr=DateRange(); // always set to no range

refresh();
}

void
UserChart::setDateRange(DateRange d)
{
if (!amVisible()) return;
if (!isVisible()) return;

// we don't really need to worry too much
// about not refreshing as it doesn't get
// called so often in trends view.
dr = d;
ride = myRideItem; // always current
ride = context->currentRideItem(); // always current

refresh();
}

void
UserChart::refresh()
{
if (!amVisible()) { stale=true; return; }
if (!isVisible()) { stale=true; return; }

// ok, we've run out of excuses, looks like we need to plot
chart->initialiseChart(chartinfo.title, chartinfo.type, chartinfo.animate, chartinfo.legendpos, chartinfo.stack, chartinfo.orientation);
Expand All @@ -169,7 +162,7 @@ UserChart::setRide(RideItem *item)

// cast so we can work with it
UserChartData *ucd = static_cast<UserChartData*>(series.user1);
ucd->compute(ride, Specification(), dr);
ucd->compute(const_cast<RideItem*>(ride), Specification(), dr);
series.xseries = ucd->x.asNumeric();
series.yseries = ucd->y.asNumeric();
series.fseries = ucd->f.asString();
Expand Down Expand Up @@ -464,9 +457,9 @@ UserChart::applySettings(QString x)
}

// update configuration widgets to reflect new settings loaded
settingsTool->refreshChartInfo();
settingsTool->refreshSeriesTab();
settingsTool->refreshAxesTab();
settingsTool_->refreshChartInfo();
settingsTool_->refreshSeriesTab();
settingsTool_->refreshAxesTab();

// config changed...
chartConfigChanged();
Expand All @@ -476,12 +469,15 @@ UserChart::applySettings(QString x)
// core user chart settings
//
UserChartSettings::UserChartSettings(Context *context, bool rangemode, GenericChartInfo &chart, QList<GenericSeriesInfo> &series, QList<GenericAxisInfo> &axes) :
context(context), rangemode(rangemode), chartinfo(chart), seriesinfo(series), axisinfo(axes), updating(false)
QWidget(NULL), context(context), rangemode(rangemode), chartinfo(chart), seriesinfo(series), axisinfo(axes), updating(false)
{
HelpWhatsThis *helpConfig = new HelpWhatsThis(this);
this->setWhatsThis(helpConfig->getWhatsThisText(HelpWhatsThis::Chart_User));

QVBoxLayout *layout = new QVBoxLayout(this);
setMinimumHeight(350*dpiYFactor);
setMinimumWidth(450*dpiXFactor);

layout = new QVBoxLayout(this);
tabs = new QTabWidget(this);
layout->addWidget(tabs);

Expand Down Expand Up @@ -664,6 +660,14 @@ UserChartSettings::UserChartSettings(Context *context, bool rangemode, GenericCh
connect(orientation, SIGNAL(currentIndexChanged(int)), this, SLOT(updateChartInfo()));
}

void
UserChartSettings::insertLayout(QLayout *p)
{
// e.g. UserChartOverviewItem adds a layout for editing
// the chart name
layout->insertLayout(0, p);
}

void
UserChartSettings::refreshChartInfo()
{
Expand Down
25 changes: 15 additions & 10 deletions src/Charts/UserChart.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,19 +36,18 @@
// the chart
class UserChartSettings;
class DataFilterEdit;
class UserChart : public GcChartWindow {
class UserChart : public QWidget {

Q_OBJECT

// settings are saved as a json document and parsed using qt5 json support
// we can rely on JSON support since we also need Qt Charts which is qt5 also
Q_PROPERTY(QString settings READ settings WRITE applySettings USER true)

friend class ::Leaf; // data filter eval accessing our curve data

public:

UserChart(Context *context, bool rangemode);
UserChart(QWidget *parent, Context *context, bool rangemode);

// config widget, for user to configure the chart
UserChartSettings *settingsTool() { return settingsTool_; }

// for read and write of settings via chart properties
QString settings() const;
Expand All @@ -57,7 +56,7 @@ class UserChart : public GcChartWindow {
public slots:

// runtime - ride item changed
void setRide(RideItem*);
void setRide(const RideItem*);

// runtime - date range was selected
void setDateRange(DateRange);
Expand Down Expand Up @@ -89,13 +88,13 @@ class UserChart : public GcChartWindow {
Context *context;
bool rangemode;
bool stale;
RideItem *last; // the last ride we plotted

RideItem *ride;
const RideItem *last; // the last ride we plotted
const RideItem *ride;
DateRange dr;

GenericChart *chart;
UserChartSettings *settingsTool;
UserChartSettings *settingsTool_;
};

class UserChartSettings : public QWidget {
Expand All @@ -105,6 +104,9 @@ class UserChartSettings : public QWidget {
public:
UserChartSettings(Context *, bool rangemode, GenericChartInfo &, QList<GenericSeriesInfo> &, QList<GenericAxisInfo> &);

// we want some additional config?
void insertLayout(QLayout *);

private:
Context *context;
bool rangemode;
Expand All @@ -114,6 +116,9 @@ class UserChartSettings : public QWidget {
QList<GenericSeriesInfo> &seriesinfo;
QList<GenericAxisInfo> &axisinfo;

// layout widget, can have other stuff inserted...
QVBoxLayout *layout;

// tabs
QTabWidget *tabs;
QWidget *chartpage;
Expand Down
101 changes: 101 additions & 0 deletions src/Charts/UserChartOverviewItem.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/*
* Copyright (c) 2021 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 "UserChartOverviewItem.h"
#include "UserChart.h"

UserChartOverviewItem::UserChartOverviewItem(ChartSpace *parent, QString name, QString settings) : ChartSpaceItem(parent, name)
{

// a META widget, "RPE" using the FOSTER modified 0-10 scale
this->type = OverviewItemType::USERCHART;

// default is a bit bigger
span = 2;
deep = 30;

// create the chart and place on scene
chart = new UserChart(NULL, parent->context, parent->scope == OverviewScope::TRENDS ? true : false);
chart->hide();
proxy = parent->getScene()->addWidget(chart);
proxy->setParent(this);
proxy->setZValue(20); // tile is 10, dragging is 100

// name editor
QFormLayout *form = new QFormLayout();
nameEdit = new QLineEdit(parent);
nameEdit->setText(name);
form->addRow(new QLabel(tr("Name")), nameEdit);
chart->settingsTool()->insertLayout(form);

// settings... a boring one on first showing.
setConfig(settings);

connect(nameEdit, SIGNAL(textEdited(QString)), this, SLOT(nameChanged()));
}

UserChartOverviewItem::~UserChartOverviewItem() { }

void
UserChartOverviewItem::nameChanged()
{
name = nameEdit->text();
}

void
UserChartOverviewItem::setData(RideItem *item)
{
if (item == NULL || item->ride() == NULL) return;
chart->setRide(item);
}
void
UserChartOverviewItem::setDateRange(DateRange dr)
{
chart->setDateRange(dr);
}

void
UserChartOverviewItem::dragging(bool /*isdragging*/)
{
// we previously hid user charts due to rendering speed
// and how it affects the user experience when dragging charts
// around, but this was an artefact of a legend bug
// see github issue:
//
// https://github.com/GoldenCheetah/GoldenCheetah/issues/3989
//
// so we don't worry about hiding during drag operations
// any more, but left here in case it becomes an issue
// in the future
//if (isdragging) chart->hide();
//else chart->show();
}

void
UserChartOverviewItem::itemGeometryChanged() {

QRectF geom = geometry();
proxy->setGeometry(QRectF(geom.x()+40,geom.y()+(ROWHEIGHT*2),geom.width()-80, geom.height()-((ROWHEIGHT*2)+40)));

if (drag) chart->hide();
else /*if (parent->state != ChartSpace::DRAG)*/ chart->show();
}

// proxy and chart does the work for us
void
UserChartOverviewItem::itemPaint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *) { }
70 changes: 70 additions & 0 deletions src/Charts/UserChartOverviewItem.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*
* Copyright (c) 2021 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
*/

#ifndef _GC_UserChartOverviewItem
#define _GC_UserChartOverviewItem_h 1

// basics
#include "ChartSpace.h"
#include "OverviewItems.h"
#include "GenericChart.h"
#include "UserChart.h"

#include <QGraphicsProxyWidget>

class QLineEdit;
class UserChartOverviewItem : public ChartSpaceItem
{
Q_OBJECT

public:

UserChartOverviewItem(ChartSpace *parent, QString name, QString config);
~UserChartOverviewItem();

void dragging(bool);
void itemPaint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *);
void itemGeometryChanged();
void setData(RideItem *item);
void setDateRange(DateRange);
QWidget *config() { return chart->settingsTool(); }

// create a blank one
static ChartSpaceItem *create(ChartSpace *parent) { return new UserChartOverviewItem(parent, "User Chart",
"{ \"title\": \" \",\n\"description\": \"A description of the chart, mostly useful when the chart is uploaded to the cloud to let others know what this chart is useful for etc. \",\n\"type\": 2,\n\"animate\": false,\n\"legendpos\": 2,\n\"stack\": false,\n\"orientation\": 1,\n\"SERIES\": [\n{ \"name\": \"Power \", \"group\": \" \", \"xname\": \"Cadence \", \"yname\": \"watts \", \"program\": \"{\\n finalise {\\n # we just fetch samples at end\\n xx <- samples(CADENCE);\\n yy <- samples(POWER);\\n }\\n\\n x { xx; }\\n y { yy; }\\n}\\n \", \"line\": 0, \"symbol\": 1, \"size\": 14, \"color\": \"#010112\", \"opacity\": 100, \"legend\": true, \"opengl\": false, \"datalabels\": false, \"fill\": false},\n{ \"name\": \"LR \", \"group\": \" \", \"xname\": \"Cadence \", \"yname\": \"watts \", \"program\": \"{\\n finalise {\\n # we just fetch samples at end\\n xx <- samples(CADENCE);\\n yy <- samples(POWER);\\n fit <- lr(xx,yy);\\n ex <- c(10,120);\\n wy <- c((ex[0]*fit[0])+fit[1],\\n (ex[1]*fit[0])+fit[1]);\\n \\n }\\n\\n x { ex; }\\n y { wy; }\\n}\\n \", \"line\": 2, \"symbol\": 1, \"size\": 3, \"color\": \"#01010b\", \"opacity\": 100, \"legend\": false, \"opengl\": false, \"datalabels\": false, \"fill\": false} ]\n,\n\"AXES\": [\n{ \"name\": \"Cadence \", \"type\": 0, \"orientation\": 1, \"align\": 1, \"minx\": 0, \"maxx\": 160, \"miny\": 0, \"maxy\": 0, \"visible\": true, \"fixed\": true, \"log\": false, \"minorgrid\": false, \"majorgrid\": true, \"labelcolor\": \"#6569a5\", \"axiscolor\": \"#6569a5\"},\n{ \"name\": \"watts \", \"type\": 0, \"orientation\": 2, \"align\": 1, \"minx\": 0, \"maxx\": 0, \"miny\": 0, \"maxy\": 1000, \"visible\": true, \"fixed\": false, \"log\": false, \"minorgrid\": false, \"majorgrid\": true, \"labelcolor\": \"#010112\", \"axiscolor\": \"#010112\"} ]\n} "); }

// settings get and set
QString getConfig() const { return chart->settings(); }
void setConfig(QString config) { chart->applySettings(config); }

public slots:

void nameChanged();

private:
// embedding
QGraphicsProxyWidget *proxy;
UserChart *chart;

// we need to edit the tile name since we use a
// custom config tool, it gets inserted into the
// standard user chart config dialog
QLineEdit *nameEdit;
};

#endif // _GC_UserChartOverviewItem_h
91 changes: 91 additions & 0 deletions src/Charts/UserChartWindow.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/*
* Copyright (c) 2020 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 "UserChartWindow.h"

#include "Colors.h"
#include "TabView.h"
#include "RideFileCommand.h"
#include "Utils.h"
#include "Tab.h"
#include "LTMTool.h"
#include "RideNavigator.h"
#include "ColorButton.h"
#include "MainWindow.h"
#include "UserChartData.h"
#include "TimeUtils.h"
#include "HelpWhatsThis.h"

#include <limits>
#include <QScrollArea>
#include <QDialog>

UserChartWindow::UserChartWindow(Context *context, bool rangemode) : GcChartWindow(context), context(context), rangemode(rangemode), stale(true), last(NULL)
{
HelpWhatsThis *helpContents = new HelpWhatsThis(this);
this->setWhatsThis(helpContents->getWhatsThisText(HelpWhatsThis::Chart_User));

chart = new UserChart(this, context, rangemode);

// the config
settingsTool_ = chart->settingsTool();
setControls(settingsTool_);

// layout
QVBoxLayout *main=new QVBoxLayout();
setChartLayout(main);
main->setSpacing(0);
main->setContentsMargins(0,0,0,0);
main->addWidget(chart);

// when a ride is selected
if (!rangemode) {
connect(this, SIGNAL(rideItemChanged(RideItem*)), this, SLOT(setRide(RideItem*)));
} else {
connect(this, SIGNAL(dateRangeChanged(DateRange)), SLOT(setDateRange(DateRange)));
connect(context, SIGNAL(homeFilterChanged()), this, SLOT(refresh()));
connect(context, SIGNAL(filterChanged()), this, SLOT(refresh()));
connect(this, SIGNAL(perspectiveFilterChanged(QString)), this, SLOT(refresh()));
}

// need to refresh when perspective selected
connect(this, SIGNAL(perspectiveChanged(Perspective*)), this, SLOT(refresh()));
}

//
// Ride selected
//
void
UserChartWindow::setRide(RideItem *item)
{
chart->setRide(item);
}

void
UserChartWindow::setDateRange(DateRange d)
{
chart->setDateRange(d);
}

void
UserChartWindow::refresh()
{
if (!amVisible()) { stale=true; return; }

chart->refresh();
}
67 changes: 67 additions & 0 deletions src/Charts/UserChartWindow.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* Copyright (c) 2020 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
*/

#ifndef _GC_UserChartWindow_h
#define _GC_UserChartWindow_h 1

#include "GoldenCheetah.h"
#include "UserChart.h"
#include "Context.h"
#include "Athlete.h"
#include "Colors.h"

class UserChartWindow : public GcChartWindow {

Q_OBJECT

// settings are maintained by the userchart widget, we are just a wrapper to include in a perspective.
Q_PROPERTY(QString settings READ settings WRITE applySettings USER true)

public:

UserChartWindow(Context *context, bool rangemode);

// for read and write of settings via chart properties
QString settings() const { return chart->settings(); }
void applySettings(QString x) { chart->applySettings(x); }

public slots:

// runtime - ride item changed
void setRide(RideItem*);

// runtime - date range was selected
void setDateRange(DateRange);

// redraw
void refresh();

private:

Context *context;
bool rangemode;
bool stale;
RideItem *last; // the last ride we plotted

RideItem *ride;
DateRange dr;

UserChart *chart;
UserChartSettings *settingsTool_;
};
#endif
15 changes: 14 additions & 1 deletion src/Gui/AddChartWizard.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@
//

// Main wizard - if passed a service name we are in edit mode, not add mode.
AddChartWizard::AddChartWizard(Context *context, ChartSpace *space, int scope) : QWizard(context->mainWindow), context(context), scope(scope), space(space)
AddChartWizard::AddChartWizard(Context *context, ChartSpace *space, int scope, ChartSpaceItem * &added)
: QWizard(context->mainWindow), context(context), scope(scope), space(space), added(added)
{
HelpWhatsThis *help = new HelpWhatsThis(this);
if (scope & OverviewScope::ANALYSIS) this->setWhatsThis(help->getWhatsThisText(HelpWhatsThis::ChartRides_Overview));
Expand Down Expand Up @@ -157,6 +158,18 @@ AddChartConfig::initializePage()
wizard->config->show();
}

AddChartConfig::~AddChartConfig()
{
// spare the config widget being destroyed
if (wizard->config) {
wizard->config->hide();
main->removeWidget(wizard->config);
wizard->config->setParent(NULL);
wizard->config = NULL;
wizard->added = wizard->item;
}
}

bool
AddChartConfig::validatePage()
{
Expand Down
7 changes: 6 additions & 1 deletion src/Gui/AddChartWizard.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ class AddChartWizard : public QWizard

public:

AddChartWizard(Context *context, ChartSpace *space, int scope);
AddChartWizard(Context *context, ChartSpace *space, int scope, ChartSpaceItem * &added);
QSize sizeHint() const { return QSize(600,650); }

Context *context;
Expand All @@ -49,6 +49,9 @@ class AddChartWizard : public QWizard
ChartSpaceItem *item;
QWidget *config;

// tell overview what we did
ChartSpaceItem * &added;

};

class AddChartType : public QWizardPage
Expand Down Expand Up @@ -80,6 +83,7 @@ class AddChartConfig : public QWizardPage

public:
AddChartConfig(AddChartWizard *);
~AddChartConfig(); // spare the item's config widget when we die
void initializePage();
bool validate() const { return true; }
bool isComplete() const { return true; }
Expand All @@ -93,6 +97,7 @@ class AddChartConfig : public QWizardPage
QVBoxLayout *main;
};


class AddChartFinal : public QWizardPage
{
Q_OBJECT
Expand Down
21 changes: 16 additions & 5 deletions src/Gui/ChartSpace.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -886,6 +886,11 @@ ChartSpace::eventFilter(QObject *, QEvent *event)
// work out the offset so we can move
// it around when we start dragging
state = DRAG;

// warn items we are dragging, they may temporarily
// hide widgets to make things faster
foreach(ChartSpaceItem *item, items) item->dragging(true);

item->invisible = true;
item->setDrag(true);
item->setZValue(100);
Expand Down Expand Up @@ -925,6 +930,12 @@ ChartSpace::eventFilter(QObject *, QEvent *event)
stateData.drag.item->placing = true;
}

if (state == DRAG) {
// tell items we are done dragging, they may temporarily
// hide widgets to make things faster, we need to show them again
foreach(ChartSpaceItem *item, items) item->dragging(false);
}

// end state;
state = NONE;

Expand Down Expand Up @@ -971,24 +982,24 @@ ChartSpace::eventFilter(QObject *, QEvent *event)
if (yresizecursor == false && item->geometry().height()-offy < 10) {

yresizecursor = true;
setCursor(QCursor(Qt::SizeVerCursor));
view->viewport()->setCursor(QCursor(Qt::SizeVerCursor));

} else if (yresizecursor == true && item->geometry().height()-offy > 10) {

yresizecursor = false;
setCursor(QCursor(Qt::ArrowCursor));
view->viewport()->setCursor(QCursor(Qt::ArrowCursor));

}

if (xresizecursor == false && item->geometry().width()-offx < 10) {

xresizecursor = true;
setCursor(QCursor(Qt::SizeHorCursor));
view->viewport()->setCursor(QCursor(Qt::SizeHorCursor));

} else if (xresizecursor == true && item->geometry().width()-offx > 10) {

xresizecursor = false;
setCursor(QCursor(Qt::ArrowCursor));
view->viewport()->setCursor(QCursor(Qt::ArrowCursor));

}

Expand All @@ -998,7 +1009,7 @@ ChartSpace::eventFilter(QObject *, QEvent *event)
// set it back to the normal arrow pointer
if (yresizecursor || xresizecursor || cursor().shape() != Qt::ArrowCursor) {
xresizecursor = yresizecursor = false;
setCursor(QCursor(Qt::ArrowCursor));
view->viewport()->setCursor(QCursor(Qt::ArrowCursor));
}
}

Expand Down
8 changes: 8 additions & 0 deletions src/Gui/ChartSpace.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,13 @@ class ChartSpaceItem : public QGraphicsWidget
void setShowConfig(bool x) { showconfig=x; update(); }
bool showConfig() const { return showconfig; }

// let item know that dragging is in process
// for some widgets (e.g. UserChart) this means
// its best to hide the widgets as rendering into
// the scene can be really slow. For other widgets
// it can be safely ignored.
virtual void dragging(bool) { }

// what type am I- managed by user
int type;

Expand Down Expand Up @@ -157,6 +164,7 @@ class ChartSpace : public QWidget
public:

ChartSpace(Context *context, int scope, GcWindow *window);
QGraphicsScene *getScene() { return scene; }

// current state for event processing
enum { NONE, DRAG, SPAN, XRESIZE, YRESIZE } state;
Expand Down
6 changes: 3 additions & 3 deletions src/Gui/GcWindowRegistry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@
#ifdef GC_HAVE_OVERVIEW
#include "Overview.h"
#endif
#include "UserChart.h"
#include "UserChartWindow.h"
// Not until v4.0
//#include "RouteWindow.h"

Expand Down Expand Up @@ -240,8 +240,8 @@ GcWindowRegistry::newGcWindow(GcWinID id, Context *context)
case GcWindowTypes::DateRangeSummary: // deprecated so now replace with overview
case GcWindowTypes::OverviewTrends: returning = new OverviewWindow(context, TRENDS); break;
case GcWindowTypes::SeasonPlan: returning = new PlanningWindow(context); break;
case GcWindowTypes::UserAnalysis: returning = new UserChart(context, false); break;
case GcWindowTypes::UserTrends: returning = new UserChart(context, true); break;
case GcWindowTypes::UserAnalysis: returning = new UserChartWindow(context, false); break;
case GcWindowTypes::UserTrends: returning = new UserChartWindow(context, true); break;
default: return NULL; break;
}
if (returning) returning->setProperty("type", QVariant::fromValue<GcWinID>(id));
Expand Down
6 changes: 4 additions & 2 deletions src/src.pro
Original file line number Diff line number Diff line change
Expand Up @@ -656,8 +656,10 @@ greaterThan(QT_MAJOR_VERSION, 4) {

# generic chart
DEFINES += GC_HAVE_GENERIC
HEADERS += Charts/UserChart.h Charts/UserChartData.h Charts/GenericChart.h Charts/GenericPlot.h Charts/GenericSelectTool.h Charts/GenericLegend.h
SOURCES += Charts/UserChart.cpp Charts/UserChartData.cpp Charts/GenericChart.cpp Charts/GenericPlot.cpp Charts/GenericSelectTool.cpp Charts/GenericLegend.cpp
HEADERS += Charts/UserChartWindow.h Charts/UserChartOverviewItem.h Charts/UserChart.h Charts/UserChartData.h \
Charts/GenericChart.h Charts/GenericPlot.h Charts/GenericSelectTool.h Charts/GenericLegend.h
SOURCES += Charts/UserChartWindow.cpp Charts/UserChartOverviewItem.cpp Charts/UserChart.cpp Charts/UserChartData.cpp \
Charts/GenericChart.cpp Charts/GenericPlot.cpp Charts/GenericSelectTool.cpp Charts/GenericLegend.cpp

}
}
Expand Down