summaryrefslogtreecommitdiffstats
path: root/stats
diff options
context:
space:
mode:
authorGravatar Berthold Stoeger <bstoeger@mail.tuwien.ac.at>2021-02-10 20:59:34 +0100
committerGravatar Dirk Hohndel <dirk@hohndel.org>2021-02-13 13:02:54 -0800
commit2943b1cbde1a60ef00f1878a27f811246d9b2bc3 (patch)
treed205caca81c2b4fe4fabed06c9f6d747617a4a30 /stats
parent43b0ccca3e8db081378d0924de257b4185b90464 (diff)
downloadsubsurface-2943b1cbde1a60ef00f1878a27f811246d9b2bc3.tar.gz
statistics: implement shift-selection of ranges
For all the series but the scatter series (which supports lasso selection), implement a range-selection using shift. The code is fairly similar for all series and one might think about factoring it out. But why bother? Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Diffstat (limited to 'stats')
-rw-r--r--stats/barseries.cpp33
-rw-r--r--stats/barseries.h3
-rw-r--r--stats/boxseries.cpp20
-rw-r--r--stats/boxseries.h1
-rw-r--r--stats/pieseries.cpp26
-rw-r--r--stats/pieseries.h3
6 files changed, 80 insertions, 6 deletions
diff --git a/stats/barseries.cpp b/stats/barseries.cpp
index 95b02111e..698a87738 100644
--- a/stats/barseries.cpp
+++ b/stats/barseries.cpp
@@ -31,6 +31,21 @@ bool BarSeries::Index::operator==(const Index &i2) const
return std::tie(bar, subitem) == std::tie(i2.bar, i2.subitem);
}
+// Note: only defined for valid indices.
+bool BarSeries::Index::operator<=(const Index &i2) const
+{
+ return std::tie(bar, subitem) <= std::tie(i2.bar, i2.subitem);
+}
+
+// Note: only defined for valid indices.
+void BarSeries::inc(Index &index)
+{
+ if (++index.subitem < binCount())
+ return;
+ ++index.bar;
+ index.subitem = 0;
+}
+
BarSeries::BarSeries(StatsView &view, StatsAxis *xAxis, StatsAxis *yAxis,
bool horizontal, bool stacked, const QString &categoryName,
const StatsVariable *valueVariable, std::vector<QString> valueBinNames) :
@@ -415,9 +430,25 @@ bool BarSeries::selectItemsUnderMouse(const QPointF &pos, SelectionModifier modi
{
Index index = getItemUnderMouse(pos);
+ if (modifier.shift && index.bar < 0)
+ return false;
+
+ if (!modifier.shift || lastClicked.bar < 0)
+ lastClicked = index;
+
std::vector<dive *> divesUnderMouse;
- if (index.bar >= 0)
+ if (modifier.shift && lastClicked.bar >= 0 && index.bar >= 0) {
+ Index first = lastClicked;
+ Index last = index;
+ if (last <= first)
+ std::swap(first, last);
+ for (Index idx = first; idx <= last; inc(idx)) {
+ const std::vector<dive *> &dives = items[idx.bar].subitems[idx.subitem].dives;
+ divesUnderMouse.insert(divesUnderMouse.end(), dives.begin(), dives.end());
+ }
+ } else if (index.bar >= 0) {
divesUnderMouse = items[index.bar].subitems[index.subitem].dives;
+ }
processSelection(std::move(divesUnderMouse), modifier);
return index.bar >= 0;
diff --git a/stats/barseries.h b/stats/barseries.h
index 6779e5b6c..c14ce9ee2 100644
--- a/stats/barseries.h
+++ b/stats/barseries.h
@@ -82,7 +82,9 @@ private:
Index();
Index(int bar, int subitem);
bool operator==(const Index &i2) const;
+ bool operator<=(const Index &i2) const;
};
+ void inc(Index &index);
// Get item under mouse pointer, or -1 if none
Index getItemUnderMouse(const QPointF &f) const;
@@ -135,6 +137,7 @@ private:
const StatsVariable *valueVariable; // null: this is count based
std::vector<QString> valueBinNames;
Index highlighted;
+ Index lastClicked;
struct SubItemDesc {
double v;
std::vector<dive *> dives;
diff --git a/stats/boxseries.cpp b/stats/boxseries.cpp
index 1bbfa2cfc..c1e5537c4 100644
--- a/stats/boxseries.cpp
+++ b/stats/boxseries.cpp
@@ -18,7 +18,7 @@ static const int boxBorderWidth = 2.0;
BoxSeries::BoxSeries(StatsView &view, StatsAxis *xAxis, StatsAxis *yAxis,
const QString &variable, const QString &unit, int decimals) :
StatsSeries(view, xAxis, yAxis),
- variable(variable), unit(unit), decimals(decimals), highlighted(-1)
+ variable(variable), unit(unit), decimals(decimals), highlighted(-1), lastClicked(-1)
{
}
@@ -150,9 +150,25 @@ bool BoxSeries::selectItemsUnderMouse(const QPointF &pos, SelectionModifier modi
{
int index = getItemUnderMouse(pos);
+ if (modifier.shift && index < 0)
+ return false;
+
+ if (!modifier.shift || lastClicked < 0)
+ lastClicked = index;
+
std::vector<dive *> divesUnderMouse;
- if (index >= 0)
+ if (modifier.shift && lastClicked >= 0 && index >= 0) {
+ int first = lastClicked;
+ int last = index;
+ if (last < first)
+ std::swap(first, last);
+ for (int idx = first; idx <= last; ++idx) {
+ const std::vector<dive *> &dives = items[idx]->q.dives;
+ divesUnderMouse.insert(divesUnderMouse.end(), dives.begin(), dives.end());
+ }
+ } else if (index >= 0) {
divesUnderMouse = items[index]->q.dives;
+ }
processSelection(std::move(divesUnderMouse), modifier);
return index >= 0;
diff --git a/stats/boxseries.h b/stats/boxseries.h
index 75e6cfa49..f7bf21183 100644
--- a/stats/boxseries.h
+++ b/stats/boxseries.h
@@ -53,6 +53,7 @@ private:
ChartItemPtr<InformationBox> information;
std::vector<std::unique_ptr<Item>> items;
int highlighted; // -1: no item highlighted
+ int lastClicked; // -1: no item clicked
void divesSelected(const QVector<dive *> &) override;
};
diff --git a/stats/pieseries.cpp b/stats/pieseries.cpp
index 2a518debe..994ca8a57 100644
--- a/stats/pieseries.cpp
+++ b/stats/pieseries.cpp
@@ -81,7 +81,8 @@ PieSeries::PieSeries(StatsView &view, StatsAxis *xAxis, StatsAxis *yAxis, const
StatsSeries(view, xAxis, yAxis),
item(view.createChartItem<ChartPieItem>(ChartZValue::Series, pieBorderWidth)),
categoryName(categoryName),
- highlighted(-1)
+ highlighted(-1),
+ lastClicked(-1)
{
// Pie charts with many slices are unreadable. Therefore, subsume slices under
// a certain percentage as "other". But draw a minimum number of slices
@@ -270,9 +271,30 @@ bool PieSeries::selectItemsUnderMouse(const QPointF &pos, SelectionModifier modi
{
int index = getItemUnderMouse(pos);
+ if (modifier.shift && index < 0)
+ return false;
+
+ if (!modifier.shift || lastClicked < 0)
+ lastClicked = index;
+
std::vector<dive *> divesUnderMouse;
- if (index >= 0)
+ if (modifier.shift && lastClicked >= 0 && index >= 0) {
+ // Selecting a range in a pie plot is a bit special due to its cyclic nature.
+ // One way would be to always select the "shorter" path, but that would restrict the user.
+ // Thus, always select in the "positive" direction, i.e. clockwise.
+ int idx = lastClicked;
+ int last = index;
+ for (;;) {
+ const std::vector<dive *> &dives = items[idx].dives;
+ divesUnderMouse.insert(divesUnderMouse.end(), dives.begin(), dives.end());
+ if (idx == last)
+ break;
+ if (++idx >= (int)items.size())
+ idx = 0;
+ }
+ } else if (index >= 0) {
divesUnderMouse = items[index].dives;
+ }
processSelection(std::move(divesUnderMouse), modifier);
return index >= 0;
diff --git a/stats/pieseries.h b/stats/pieseries.h
index 1a132ebc3..7545e5176 100644
--- a/stats/pieseries.h
+++ b/stats/pieseries.h
@@ -65,7 +65,8 @@ private:
ChartItemPtr<InformationBox> information;
QPointF center; // center of drawing area
double radius; // radius of pie
- int highlighted;
+ int highlighted; // -1: no item highlighted
+ int lastClicked; // -1: no item clicked
void divesSelected(const QVector<dive *> &) override;
};