Skip to content

Commit

Permalink
Fixup UserChart mouse interaction on a Chartspace
Browse files Browse the repository at this point in the history
.. when a user chart is placed on an overview we filter mouse
   events from the chartspace and not the widget due to
   events being discarded.

   See this issue for more details:
   #3992
  • Loading branch information
liversedge committed Aug 3, 2021
1 parent 171882d commit 98e49c3
Show file tree
Hide file tree
Showing 8 changed files with 92 additions and 18 deletions.
10 changes: 8 additions & 2 deletions src/Charts/GenericChart.cpp
Expand Up @@ -42,7 +42,7 @@
// honoured too, since multiple series stacked can get
// cramped, so these are placed into a scroll area
//
GenericChart::GenericChart(QWidget *parent, Context *context) : QWidget(parent), context(context)
GenericChart::GenericChart(QWidget *parent, Context *context) : QWidget(parent), context(context), item(NULL)
{
// for scrollarea, since we see a little of it.
QPalette palette;
Expand Down Expand Up @@ -114,6 +114,12 @@ GenericChart::setBackgroundColor(QColor bgcolor)
}
}

void
GenericChart::setGraphicsItem(QGraphicsItem *item)
{
this->item = item;
}

// set chart settings
bool
GenericChart::initialiseChart(QString title, int type, bool animate, int legendpos, bool stack, int orientation, double scale)
Expand Down Expand Up @@ -349,7 +355,7 @@ GenericChart::finaliseChart()

if (index <0) {
// new one required
newPlots[i].plot = new GenericPlot(this, context);
newPlots[i].plot = new GenericPlot(this, context, item);

target->addWidget(newPlots[i].plot);
target->setStretchFactor(newPlots[i].plot, 10);// make them all the same
Expand Down
3 changes: 3 additions & 0 deletions src/Charts/GenericChart.h
Expand Up @@ -246,6 +246,7 @@ class GenericAxisInfo {
};

// the chart
class ChartSpace;
class GenericChart : public QWidget {

Q_OBJECT
Expand Down Expand Up @@ -281,6 +282,7 @@ class GenericChart : public QWidget {

// plot background
void setBackgroundColor(QColor);
void setGraphicsItem(QGraphicsItem *item);

// post processing clean up / add decorations / helpers etc
void finaliseChart();
Expand Down Expand Up @@ -324,5 +326,6 @@ class GenericChart : public QWidget {
private:
Context *context;
QScrollArea *stackFrame;
QGraphicsItem *item;
};
#endif
74 changes: 61 additions & 13 deletions src/Charts/GenericPlot.cpp
Expand Up @@ -25,13 +25,16 @@
#include "RideCache.h"
#include "Utils.h"

#include "ChartSpace.h"
#include "UserChartOverviewItem.h"

#include <limits>

// used to format dates/times on axes
QString GenericPlot::gl_dateformat = QString("dd MMM yy");
QString GenericPlot::gl_timeformat = QString("hh:mm:ss");

GenericPlot::GenericPlot(QWidget *parent, Context *context) : QWidget(parent), context(context)
GenericPlot::GenericPlot(QWidget *parent, Context *context, QGraphicsItem *item) : QWidget(parent), context(context), item(item)
{
setAutoFillBackground(true);

Expand Down Expand Up @@ -64,8 +67,17 @@ GenericPlot::GenericPlot(QWidget *parent, Context *context) : QWidget(parent), c
chartview->setRenderHint(QPainter::Antialiasing);

// watch mouse hover etc on the chartview and scene
chartview->setMouseTracking(true);
chartview->scene()->installEventFilter(this);
if (item == NULL) {
chartview->setMouseTracking(true);
chartview->scene()->installEventFilter(this);
installEventFilter(this);
} else {

// we get events from the chartspace becuase
// when we are embedded via QGraphicsProxyWidget
// mouse events go missing.
item->scene()->installEventFilter(this);
}

// add selector
selector = new GenericSelectTool(this);
Expand All @@ -74,9 +86,6 @@ GenericPlot::GenericPlot(QWidget *parent, Context *context) : QWidget(parent), c
// the legend at the top for now
legend = new GenericLegend(context, this);

// filter ESC so we can stop scripts
installEventFilter(this);

// add all widgets to the view
mainLayout->addWidget(legend);
holder=mainLayout;
Expand Down Expand Up @@ -109,11 +118,37 @@ GenericPlot::seriesClicked(QAbstractSeries*series, GPointF point)
if (item) context->notifyRideSelected(item);
}
}
bool GenericPlot::eventFilter(QObject *obj, QEvent *e) { return eventHandler(1, obj, e); }

// source 0=scene, 1=widget
// we can intercept events from the QT Chart's chartview or a chartspace
bool GenericPlot::eventFilter(QObject *obj, QEvent *e)
{

if (item == NULL) return eventHandler(0, obj, e);

// space is non null and not busy dragging and resizing etc
if ((e->type() == QEvent::GraphicsSceneMousePress ||
e->type() == QEvent::GraphicsSceneMouseRelease ||
e->type() == QEvent::GraphicsSceneMouseMove) &&

// the line below is naughty- it assumes we are embedded via a userchartoverview item- if we
// embed R or Python charts on the overview in the future this line will cause a SEGV- I took the
// decision that the performance improvement on screen when dragging and moving
// overview items was worth the filthy code. if you just delete it (or comment it out)
// the code will still be fine, its just here to optimise out unneccessary event processing.
static_cast<UserChartOverviewItem*>(static_cast<QGraphicsProxyWidget*>(item)->parent())->chartspace()->state == ChartSpace::NONE &&

item->sceneBoundingRect().contains(static_cast<QGraphicsSceneMouseEvent*>(e)->scenePos())) {

// send, as-is, they will have to map co-ordinates
return eventHandler(1, obj, e);
}

return false;
}

// source 0=chart scene, 1= chart space scene
bool
GenericPlot::eventHandler(int, void *, QEvent *e)
GenericPlot::eventHandler(int source, void *, QEvent *e)
{
static bool block=false;

Expand All @@ -122,7 +157,23 @@ GenericPlot::eventHandler(int, void *, QEvent *e)
else block=true;

// where is the cursor?
QPointF spos=QPointF();
QPointF spos;
if ((e->type() == QEvent::GraphicsSceneMousePress ||
e->type() == QEvent::GraphicsSceneMouseRelease ||
e->type() == QEvent::GraphicsSceneMouseMove)) {

// map to the proxy coordinates
if (source == 0) { // chartview coordinates already
spos = static_cast<QGraphicsSceneMouseEvent*>(e)->scenePos();
} else {

// map to proxy
spos = item->mapFromScene(static_cast<QGraphicsSceneMouseEvent*>(e)->scenePos());

// now add in our relative coordinates wthin the item (our topleft is relative to the proxy topleft)
spos -= chartview->geometry().topLeft();
}
}

// so we want to trigger a scene update?
bool updatescene = false;
Expand All @@ -135,23 +186,20 @@ GenericPlot::eventHandler(int, void *, QEvent *e)
// mouse clicked
case QEvent::GraphicsSceneMousePress:
{
spos = static_cast<QGraphicsSceneMouseEvent*>(e)->scenePos();
updatescene = selector->clicked(spos);
}
break;

// mouse released
case QEvent::GraphicsSceneMouseRelease:
{
spos = static_cast<QGraphicsSceneMouseEvent*>(e)->scenePos();
updatescene = selector->released(spos);
}
break;

// mouse move
case QEvent::GraphicsSceneMouseMove:
{
spos = static_cast<QGraphicsSceneMouseEvent*>(e)->scenePos();
updatescene = selector->moved(spos);
}
break;
Expand Down
4 changes: 3 additions & 1 deletion src/Charts/GenericPlot.h
Expand Up @@ -57,6 +57,7 @@ class GenericSelectTool;
class GenericAxisInfo;

// the chart
class ChartSpace;
class GenericPlot : public QWidget {

Q_OBJECT
Expand All @@ -70,7 +71,7 @@ class GenericPlot : public QWidget {
friend class GenericSelectTool;
friend class GenericLegend;

GenericPlot(QWidget *parent, Context *context);
GenericPlot(QWidget *parent, Context *context, QGraphicsItem *item);

// some helper functions
static QColor seriesColor(QAbstractSeries* series);
Expand Down Expand Up @@ -151,6 +152,7 @@ class GenericPlot : public QWidget {

private:
Context *context;
QGraphicsItem *item;
int charttype;

// curves
Expand Down
9 changes: 8 additions & 1 deletion src/Charts/UserChart.cpp
Expand Up @@ -36,7 +36,7 @@
#include <QDialog>

UserChart::UserChart(QWidget *parent, Context *context, bool rangemode)
: QWidget(parent), context(context), rangemode(rangemode), stale(true), last(NULL), ride(NULL)
: QWidget(parent), context(context), rangemode(rangemode), stale(true), last(NULL), ride(NULL), item(NULL)
{
HelpWhatsThis *helpContents = new HelpWhatsThis(this);
this->setWhatsThis(helpContents->getWhatsThisText(HelpWhatsThis::Chart_User));
Expand Down Expand Up @@ -101,6 +101,13 @@ UserChart::setBackgroundColor(QColor bgcolor)
}
}

void
UserChart::setGraphicsItem(QGraphicsItem *item)
{
this->item = item;
chart->setGraphicsItem(item);
}

void
UserChart::chartConfigChanged()
{
Expand Down
3 changes: 3 additions & 0 deletions src/Charts/UserChart.h
Expand Up @@ -34,6 +34,7 @@
#include "DataFilter.h"

// the chart
class ChartSpace;
class UserChartSettings;
class DataFilterEdit;
class UserChart : public QWidget {
Expand All @@ -55,6 +56,7 @@ class UserChart : public QWidget {

// set background for all charts, legends etc
void setBackgroundColor(QColor bgcolor);
void setGraphicsItem(QGraphicsItem *);

public slots:

Expand Down Expand Up @@ -98,6 +100,7 @@ class UserChart : public QWidget {
DateRange dr;

GenericChart *chart;
QGraphicsItem *item;
UserChartSettings *settingsTool_;
};

Expand Down
3 changes: 2 additions & 1 deletion src/Charts/UserChartOverviewItem.cpp
Expand Up @@ -19,7 +19,7 @@
#include "UserChartOverviewItem.h"
#include "UserChart.h"

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

// a META widget, "RPE" using the FOSTER modified 0-10 scale
Expand All @@ -36,6 +36,7 @@ UserChartOverviewItem::UserChartOverviewItem(ChartSpace *parent, QString name, Q
proxy = parent->getScene()->addWidget(chart);
proxy->setParent(this);
proxy->setZValue(20); // tile is 10, dragging is 100
chart->setGraphicsItem(proxy);// only watch the smallest space

// name editor
QFormLayout *form = new QFormLayout();
Expand Down
4 changes: 4 additions & 0 deletions src/Charts/UserChartOverviewItem.h
Expand Up @@ -48,6 +48,9 @@ class UserChartOverviewItem : public ChartSpaceItem
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,\"scale\": 2.5, \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} "); }

// chartspace
ChartSpace *chartspace() const { return space_; }

// settings get and set
QString getConfig() const { return chart->settings(); }
void setConfig(QString config) { chart->applySettings(config); }
Expand All @@ -61,6 +64,7 @@ class UserChartOverviewItem : public ChartSpaceItem
// embedding
QGraphicsProxyWidget *proxy;
UserChart *chart;
ChartSpace *space_;

// we need to edit the tile name since we use a
// custom config tool, it gets inserted into the
Expand Down

0 comments on commit 98e49c3

Please sign in to comment.