statistics: show selected dives in scatter plot

As a visual feedback, show the selected dives in the scatter
plot. React to application-wide selection changes. Currently,
the dive list is deactivated while in statistics mode, but
that may change.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
This commit is contained in:
Berthold Stoeger 2021-01-31 20:48:12 +01:00 committed by Dirk Hohndel
parent 5c098eea29
commit d85b321784
9 changed files with 68 additions and 8 deletions

View file

@ -108,7 +108,7 @@ static const int scatterItemDiameter = 10;
static const int scatterItemBorder = 1;
ChartScatterItem::ChartScatterItem(StatsView &v, ChartZValue z) : HideableChartItem(v, z),
positionDirty(false), textureDirty(false), highlighted(false)
positionDirty(false), textureDirty(false), highlight(Highlight::Unselected)
{
rect.setSize(QSizeF(static_cast<double>(scatterItemDiameter), static_cast<double>(scatterItemDiameter)));
}
@ -138,12 +138,27 @@ static QSGTexture *createScatterTexture(StatsView &view, const QColor &color, co
// QApplication finished its thread leads to crashes. Therefore, these
// are now normal pointers and the texture objects are leaked.
static QSGTexture *scatterItemTexture = nullptr;
static QSGTexture *scatterItemSelectedTexture = nullptr;
static QSGTexture *scatterItemHighlightedTexture = nullptr;
QSGTexture *ChartScatterItem::getTexture() const
{
switch (highlight) {
default:
case Highlight::Unselected:
return scatterItemTexture;
case Highlight::Selected:
return scatterItemSelectedTexture;
case Highlight::Highlighted:
return scatterItemHighlightedTexture;
}
}
void ChartScatterItem::render()
{
if (!scatterItemTexture) {
scatterItemTexture = createScatterTexture(view, fillColor, borderColor);
scatterItemSelectedTexture = createScatterTexture(view, selectedColor, selectedBorderColor);
scatterItemHighlightedTexture = createScatterTexture(view, highlightedColor, highlightedBorderColor);
}
if (!node) {
@ -153,7 +168,7 @@ void ChartScatterItem::render()
}
updateVisible();
if (textureDirty) {
node->node->setTexture(highlighted ? scatterItemHighlightedTexture : scatterItemTexture);
node->node->setTexture(getTexture());
textureDirty = false;
}
if (positionDirty) {
@ -181,11 +196,11 @@ bool ChartScatterItem::contains(QPointF point) const
return squareDist(point, rect.center()) <= (scatterItemDiameter / 2.0) * (scatterItemDiameter / 2.0);
}
void ChartScatterItem::setHighlight(bool highlightedIn)
void ChartScatterItem::setHighlight(Highlight highlightIn)
{
if (highlighted == highlightedIn)
if (highlight == highlightIn)
return;
highlighted = highlightedIn;
highlight = highlightIn;
textureDirty = true;
markDirty();
}

View file

@ -174,16 +174,23 @@ public:
ChartScatterItem(StatsView &v, ChartZValue z);
~ChartScatterItem();
// Currently, there is no highlighted and selected status.
enum class Highlight {
Unselected,
Selected,
Highlighted
};
void setPos(QPointF pos); // Specifies the *center* of the item.
void setHighlight(bool highlight); // In the future, support different kinds of scatter items.
void setHighlight(Highlight highlight); // In the future, support different kinds of scatter items.
void render() override; // Only call on render thread!
QRectF getRect() const;
bool contains(QPointF point) const;
private:
QSGTexture *getTexture() const;
QRectF rect;
QSizeF textureSize;
bool positionDirty, textureDirty;
bool highlighted;
Highlight highlight;
};
// Implementation detail of templates - move to serparate header file

View file

@ -27,6 +27,7 @@ ScatterSeries::~ScatterSeries()
ScatterSeries::Item::Item(StatsView &view, ScatterSeries *series, dive *d, double pos, double value) :
item(view.createChartItem<ChartScatterItem>(ChartZValue::Series)),
d(d),
selected(d->selected),
pos(pos),
value(value)
{
@ -40,7 +41,11 @@ void ScatterSeries::Item::updatePosition(ScatterSeries *series)
void ScatterSeries::Item::highlight(bool highlight)
{
item->setHighlight(highlight);
ChartScatterItem::Highlight status = d->selected ?
ChartScatterItem::Highlight::Selected : ChartScatterItem::Highlight::Unselected;
if (highlight)
status = ChartScatterItem::Highlight::Highlighted;
item->setHighlight(status);
}
void ScatterSeries::append(dive *d, double pos, double value)
@ -164,3 +169,15 @@ void ScatterSeries::unhighlight()
items[idx].highlight(false);
highlighted.clear();
}
void ScatterSeries::divesSelected(const QVector<dive *> &)
{
for (Item &item: items) {
if (item.selected != item.d->selected) {
item.selected = item.d->selected;
int idx = &item - &items[0];
bool highlight = std::find(highlighted.begin(), highlighted.end(), idx) != highlighted.end();
item.highlight(highlight);
}
}
}

View file

@ -36,6 +36,7 @@ private:
struct Item {
ChartItemPtr<ChartScatterItem> item;
dive *d;
bool selected;
double pos, value;
Item(StatsView &view, ScatterSeries *series, dive *d, double pos, double value);
void updatePosition(ScatterSeries *series);
@ -47,6 +48,7 @@ private:
std::vector<int> highlighted;
const StatsVariable &varX;
const StatsVariable &varY;
void divesSelected(const QVector<dive *> &) override;
};
#endif

View file

@ -8,6 +8,8 @@
inline const QColor backgroundColor(Qt::white);
inline const QColor fillColor(0x44, 0x76, 0xaa);
inline const QColor borderColor(0x66, 0xb2, 0xff);
inline const QColor selectedColor(0xaa, 0x76, 0x44);
inline const QColor selectedBorderColor(0xff, 0xb2, 0x66);
inline const QColor highlightedColor(Qt::yellow);
inline const QColor highlightedBorderColor(0xaa, 0xaa, 0x22);
inline const QColor darkLabelColor(Qt::black);

View file

@ -16,3 +16,7 @@ QPointF StatsSeries::toScreen(QPointF p)
return xAxis && yAxis ? QPointF(xAxis->toScreen(p.x()), yAxis->toScreen(p.y()))
: QPointF(0.0, 0.0);
}
void StatsSeries::divesSelected(const QVector<dive *> &)
{
}

View file

@ -8,6 +8,7 @@
class StatsAxis;
class StatsView;
struct dive;
class StatsSeries {
public:
@ -17,6 +18,7 @@ public:
virtual bool hover(QPointF pos) = 0; // Called on mouse movement. Return true if an item of this series is highlighted.
virtual void unhighlight() = 0; // Unhighlight any highlighted item.
virtual void selectItemsUnderMouse(const QPointF &pos) = 0;
virtual void divesSelected(const QVector<dive *> &dives);
protected:
StatsView &view;

View file

@ -46,6 +46,7 @@ StatsView::StatsView(QQuickItem *parent) : QQuickItem(parent),
connect(&diveListNotifier, &DiveListNotifier::divesDeleted, this, &StatsView::replotIfVisible);
connect(&diveListNotifier, &DiveListNotifier::dataReset, this, &StatsView::replotIfVisible);
connect(&diveListNotifier, &DiveListNotifier::settingsChanged, this, &StatsView::replotIfVisible);
connect(&diveListNotifier, &DiveListNotifier::divesSelected, this, &StatsView::divesSelected);
setAcceptHoverEvents(true);
setAcceptedMouseButtons(Qt::LeftButton);
@ -345,6 +346,15 @@ void StatsView::replotIfVisible()
plot(state);
}
void StatsView::divesSelected(const QVector<dive *> &dives)
{
if (isVisible()) {
for (auto &series: series)
series->divesSelected(dives);
}
update();
}
void StatsView::mouseMoveEvent(QMouseEvent *event)
{
if (!draggedItem)

View file

@ -64,6 +64,7 @@ public:
void deleteChartItem(ChartItemPtr<T> &item);
private slots:
void replotIfVisible();
void divesSelected(const QVector<dive *> &dives);
private:
// QtQuick related things
bool backgroundDirty;