diff options
author | Berthold Stoeger <bstoeger@mail.tuwien.ac.at> | 2021-02-10 20:59:34 +0100 |
---|---|---|
committer | Dirk Hohndel <dirk@hohndel.org> | 2021-02-13 13:02:54 -0800 |
commit | 2943b1cbde1a60ef00f1878a27f811246d9b2bc3 (patch) | |
tree | d205caca81c2b4fe4fabed06c9f6d747617a4a30 | |
parent | 43b0ccca3e8db081378d0924de257b4185b90464 (diff) | |
download | subsurface-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>
-rw-r--r-- | stats/barseries.cpp | 33 | ||||
-rw-r--r-- | stats/barseries.h | 3 | ||||
-rw-r--r-- | stats/boxseries.cpp | 20 | ||||
-rw-r--r-- | stats/boxseries.h | 1 | ||||
-rw-r--r-- | stats/pieseries.cpp | 26 | ||||
-rw-r--r-- | stats/pieseries.h | 3 |
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; }; |