2021-01-01 21:18:51 +00:00
|
|
|
// SPDX-License-Identifier: GPL-2.0
|
|
|
|
// A small custom bar series, which displays information
|
|
|
|
// when hovering over a bar. The QtCharts bar series were
|
|
|
|
// too inflexible with respect to placement of the bars.
|
|
|
|
#ifndef BAR_SERIES_H
|
|
|
|
#define BAR_SERIES_H
|
|
|
|
|
2021-01-18 21:29:34 +00:00
|
|
|
#include "statshelper.h"
|
2021-01-01 21:18:51 +00:00
|
|
|
#include "statsseries.h"
|
|
|
|
#include "statsvariables.h"
|
|
|
|
|
|
|
|
#include <memory>
|
|
|
|
#include <vector>
|
2021-01-19 15:09:56 +00:00
|
|
|
#include <QColor>
|
2021-01-15 21:48:32 +00:00
|
|
|
#include <QRectF>
|
2021-01-01 21:18:51 +00:00
|
|
|
|
2021-01-15 21:48:32 +00:00
|
|
|
class ChartBarItem;
|
|
|
|
class ChartTextItem;
|
2021-01-11 12:22:39 +00:00
|
|
|
struct InformationBox;
|
|
|
|
struct StatsVariable;
|
2021-01-01 21:18:51 +00:00
|
|
|
|
|
|
|
class BarSeries : public StatsSeries {
|
|
|
|
public:
|
|
|
|
// There are three versions of creating bar series: for value-based (mean, etc) charts, for counts
|
|
|
|
// based charts and for stacked bar charts with multiple items.
|
|
|
|
struct CountItem {
|
|
|
|
double lowerBound, upperBound;
|
2021-01-20 13:36:59 +00:00
|
|
|
std::vector<dive *> dives;
|
2021-01-01 21:18:51 +00:00
|
|
|
std::vector<QString> label;
|
|
|
|
QString binName;
|
|
|
|
int total;
|
|
|
|
};
|
|
|
|
struct ValueItem {
|
|
|
|
double lowerBound, upperBound;
|
|
|
|
double value;
|
|
|
|
std::vector<QString> label;
|
|
|
|
QString binName;
|
2021-01-20 13:36:59 +00:00
|
|
|
StatsOperationResults res; // Contains the dives
|
2021-01-01 21:18:51 +00:00
|
|
|
};
|
|
|
|
struct MultiItem {
|
2021-01-20 13:36:59 +00:00
|
|
|
struct Item {
|
|
|
|
std::vector<dive *> dives;
|
|
|
|
std::vector<QString> label;
|
|
|
|
};
|
2021-01-01 21:18:51 +00:00
|
|
|
double lowerBound, upperBound;
|
2021-01-20 13:36:59 +00:00
|
|
|
std::vector<Item> items;
|
2021-01-01 21:18:51 +00:00
|
|
|
QString binName;
|
|
|
|
};
|
|
|
|
|
|
|
|
// If the horizontal flag is true, independent variable is plotted on the y-axis.
|
|
|
|
// A non-empty valueBinNames vector flags that this is a stacked bar chart.
|
|
|
|
// In that case, a valueVariable must also be provided.
|
|
|
|
// For count-based bar series in one variable, valueVariable is null.
|
|
|
|
// Note: this expects that all items are added with increasing pos
|
|
|
|
// and that no bar is inside another bar, i.e. lowerBound and upperBound
|
|
|
|
// are ordered identically.
|
2021-01-18 11:35:22 +00:00
|
|
|
BarSeries(StatsView &view, StatsAxis *xAxis, StatsAxis *yAxis,
|
2021-01-01 21:18:51 +00:00
|
|
|
bool horizontal, const QString &categoryName,
|
2021-01-20 13:36:59 +00:00
|
|
|
std::vector<CountItem> items);
|
2021-01-18 11:35:22 +00:00
|
|
|
BarSeries(StatsView &view, StatsAxis *xAxis, StatsAxis *yAxis,
|
2021-01-01 21:18:51 +00:00
|
|
|
bool horizontal, const QString &categoryName, const StatsVariable *valueVariable,
|
2021-01-20 13:36:59 +00:00
|
|
|
std::vector<ValueItem> items);
|
2021-01-18 11:35:22 +00:00
|
|
|
BarSeries(StatsView &view, StatsAxis *xAxis, StatsAxis *yAxis,
|
2021-01-01 21:18:51 +00:00
|
|
|
bool horizontal, bool stacked, const QString &categoryName, const StatsVariable *valueVariable,
|
|
|
|
std::vector<QString> valueBinNames,
|
2021-01-20 13:36:59 +00:00
|
|
|
std::vector<MultiItem> items);
|
2021-01-01 21:18:51 +00:00
|
|
|
~BarSeries();
|
|
|
|
|
|
|
|
void updatePositions() override;
|
|
|
|
bool hover(QPointF pos) override;
|
|
|
|
void unhighlight() override;
|
2021-02-08 16:07:37 +00:00
|
|
|
bool selectItemsUnderMouse(const QPointF &point, SelectionModifier modifier) override;
|
2021-01-17 12:34:18 +00:00
|
|
|
|
2021-01-01 21:18:51 +00:00
|
|
|
private:
|
2021-01-18 11:35:22 +00:00
|
|
|
BarSeries(StatsView &view, StatsAxis *xAxis, StatsAxis *yAxis,
|
2021-01-01 21:18:51 +00:00
|
|
|
bool horizontal, bool stacked, const QString &categoryName, const StatsVariable *valueVariable,
|
|
|
|
std::vector<QString> valueBinNames);
|
|
|
|
|
|
|
|
struct Index {
|
|
|
|
int bar;
|
|
|
|
int subitem;
|
|
|
|
Index();
|
|
|
|
Index(int bar, int subitem);
|
|
|
|
bool operator==(const Index &i2) const;
|
2021-02-10 19:59:34 +00:00
|
|
|
bool operator<=(const Index &i2) const;
|
2021-01-01 21:18:51 +00:00
|
|
|
};
|
2021-02-10 19:59:34 +00:00
|
|
|
void inc(Index &index);
|
2021-01-01 21:18:51 +00:00
|
|
|
|
|
|
|
// Get item under mouse pointer, or -1 if none
|
|
|
|
Index getItemUnderMouse(const QPointF &f) const;
|
|
|
|
|
|
|
|
// A label that is composed of multiple lines
|
|
|
|
struct BarLabel {
|
2021-01-18 21:29:34 +00:00
|
|
|
ChartItemPtr<ChartTextItem> item;
|
2021-01-01 21:18:51 +00:00
|
|
|
bool isOutside; // Is shown outside of bar
|
2021-01-15 21:48:32 +00:00
|
|
|
BarLabel(StatsView &view, const std::vector<QString> &labels, int bin_nr, int binCount);
|
2021-01-01 21:18:51 +00:00
|
|
|
void setVisible(bool visible);
|
2021-02-16 16:05:39 +00:00
|
|
|
void updatePosition(bool horizontal, bool center, const QRectF &rect, int bin_nr, int binCount,
|
|
|
|
const QColor &background, const StatsTheme &theme);
|
|
|
|
void highlight(bool highlight, int bin_nr, int binCount, const QColor &background, const StatsTheme &theme);
|
2021-01-01 21:18:51 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct SubItem {
|
2021-01-18 21:29:34 +00:00
|
|
|
ChartItemPtr<ChartBarItem> item;
|
2021-01-20 13:36:59 +00:00
|
|
|
std::vector<dive *> dives;
|
2021-01-01 21:18:51 +00:00
|
|
|
std::unique_ptr<BarLabel> label;
|
|
|
|
double value_from;
|
|
|
|
double value_to;
|
|
|
|
int bin_nr;
|
2021-02-07 13:33:48 +00:00
|
|
|
bool selected;
|
2021-01-19 15:09:56 +00:00
|
|
|
QColor fill;
|
2021-01-05 11:11:46 +00:00
|
|
|
void updatePosition(BarSeries *series, bool horizontal, bool stacked,
|
2021-02-16 16:05:39 +00:00
|
|
|
double from, double to, int binCount, const StatsTheme &theme);
|
|
|
|
void highlight(bool highlight, int binCount, const StatsTheme &theme);
|
2021-01-01 21:18:51 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct Item {
|
|
|
|
double lowerBound, upperBound;
|
|
|
|
std::vector<SubItem> subitems;
|
|
|
|
QRectF rect;
|
|
|
|
const QString binName;
|
|
|
|
StatsOperationResults res;
|
|
|
|
int total;
|
2021-01-15 21:48:32 +00:00
|
|
|
Item(BarSeries *series, double lowerBound, double upperBound,
|
2021-01-01 21:18:51 +00:00
|
|
|
std::vector<SubItem> subitems,
|
|
|
|
const QString &binName, const StatsOperationResults &res, int total, bool horizontal,
|
2021-02-16 16:05:39 +00:00
|
|
|
bool stacked, int binCount,
|
|
|
|
const StatsTheme &theme);
|
|
|
|
void updatePosition(BarSeries *series, bool horizontal, bool stacked, int binCount,
|
|
|
|
const StatsTheme &theme);
|
|
|
|
void highlight(int subitem, bool highlight, int binCount, const StatsTheme &theme);
|
2021-01-01 21:18:51 +00:00
|
|
|
int getSubItemUnderMouse(const QPointF &f, bool horizontal, bool stacked) const;
|
|
|
|
};
|
|
|
|
|
2021-01-18 21:29:34 +00:00
|
|
|
ChartItemPtr<InformationBox> information;
|
2021-01-01 21:18:51 +00:00
|
|
|
std::vector<Item> items;
|
|
|
|
bool horizontal;
|
|
|
|
bool stacked;
|
|
|
|
QString categoryName;
|
|
|
|
const StatsVariable *valueVariable; // null: this is count based
|
|
|
|
std::vector<QString> valueBinNames;
|
|
|
|
Index highlighted;
|
2021-02-10 19:59:34 +00:00
|
|
|
Index lastClicked;
|
2021-01-20 13:36:59 +00:00
|
|
|
struct SubItemDesc {
|
|
|
|
double v;
|
|
|
|
std::vector<dive *> dives;
|
|
|
|
std::vector<QString> label;
|
|
|
|
};
|
|
|
|
std::vector<SubItem> makeSubItems(SubItemDesc item) const;
|
|
|
|
std::vector<SubItem> makeSubItems(std::vector<SubItemDesc> items) const;
|
2021-01-01 21:18:51 +00:00
|
|
|
void add_item(double lowerBound, double upperBound, std::vector<SubItem> subitems,
|
|
|
|
const QString &binName, const StatsOperationResults &res, int total, bool horizontal,
|
|
|
|
bool stacked);
|
|
|
|
std::vector<QString> makeInfo(const Item &item, int subitem) const;
|
|
|
|
int binCount() const;
|
2021-02-07 13:33:48 +00:00
|
|
|
void divesSelected(const QVector<dive *> &) override;
|
2021-01-01 21:18:51 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
#endif
|