mirror of
https://github.com/subsurface/subsurface.git
synced 2025-02-19 22:16:15 +00:00
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>
This commit is contained in:
parent
43b0ccca3e
commit
2943b1cbde
6 changed files with 80 additions and 6 deletions
|
@ -31,6 +31,21 @@ bool BarSeries::Index::operator==(const Index &i2) const
|
||||||
return std::tie(bar, subitem) == std::tie(i2.bar, i2.subitem);
|
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,
|
BarSeries::BarSeries(StatsView &view, StatsAxis *xAxis, StatsAxis *yAxis,
|
||||||
bool horizontal, bool stacked, const QString &categoryName,
|
bool horizontal, bool stacked, const QString &categoryName,
|
||||||
const StatsVariable *valueVariable, std::vector<QString> valueBinNames) :
|
const StatsVariable *valueVariable, std::vector<QString> valueBinNames) :
|
||||||
|
@ -415,9 +430,25 @@ bool BarSeries::selectItemsUnderMouse(const QPointF &pos, SelectionModifier modi
|
||||||
{
|
{
|
||||||
Index index = getItemUnderMouse(pos);
|
Index index = getItemUnderMouse(pos);
|
||||||
|
|
||||||
|
if (modifier.shift && index.bar < 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!modifier.shift || lastClicked.bar < 0)
|
||||||
|
lastClicked = index;
|
||||||
|
|
||||||
std::vector<dive *> divesUnderMouse;
|
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;
|
divesUnderMouse = items[index.bar].subitems[index.subitem].dives;
|
||||||
|
}
|
||||||
processSelection(std::move(divesUnderMouse), modifier);
|
processSelection(std::move(divesUnderMouse), modifier);
|
||||||
|
|
||||||
return index.bar >= 0;
|
return index.bar >= 0;
|
||||||
|
|
|
@ -82,7 +82,9 @@ private:
|
||||||
Index();
|
Index();
|
||||||
Index(int bar, int subitem);
|
Index(int bar, int subitem);
|
||||||
bool operator==(const Index &i2) const;
|
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
|
// Get item under mouse pointer, or -1 if none
|
||||||
Index getItemUnderMouse(const QPointF &f) const;
|
Index getItemUnderMouse(const QPointF &f) const;
|
||||||
|
@ -135,6 +137,7 @@ private:
|
||||||
const StatsVariable *valueVariable; // null: this is count based
|
const StatsVariable *valueVariable; // null: this is count based
|
||||||
std::vector<QString> valueBinNames;
|
std::vector<QString> valueBinNames;
|
||||||
Index highlighted;
|
Index highlighted;
|
||||||
|
Index lastClicked;
|
||||||
struct SubItemDesc {
|
struct SubItemDesc {
|
||||||
double v;
|
double v;
|
||||||
std::vector<dive *> dives;
|
std::vector<dive *> dives;
|
||||||
|
|
|
@ -18,7 +18,7 @@ static const int boxBorderWidth = 2.0;
|
||||||
BoxSeries::BoxSeries(StatsView &view, StatsAxis *xAxis, StatsAxis *yAxis,
|
BoxSeries::BoxSeries(StatsView &view, StatsAxis *xAxis, StatsAxis *yAxis,
|
||||||
const QString &variable, const QString &unit, int decimals) :
|
const QString &variable, const QString &unit, int decimals) :
|
||||||
StatsSeries(view, xAxis, yAxis),
|
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);
|
int index = getItemUnderMouse(pos);
|
||||||
|
|
||||||
|
if (modifier.shift && index < 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!modifier.shift || lastClicked < 0)
|
||||||
|
lastClicked = index;
|
||||||
|
|
||||||
std::vector<dive *> divesUnderMouse;
|
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;
|
divesUnderMouse = items[index]->q.dives;
|
||||||
|
}
|
||||||
processSelection(std::move(divesUnderMouse), modifier);
|
processSelection(std::move(divesUnderMouse), modifier);
|
||||||
|
|
||||||
return index >= 0;
|
return index >= 0;
|
||||||
|
|
|
@ -53,6 +53,7 @@ private:
|
||||||
ChartItemPtr<InformationBox> information;
|
ChartItemPtr<InformationBox> information;
|
||||||
std::vector<std::unique_ptr<Item>> items;
|
std::vector<std::unique_ptr<Item>> items;
|
||||||
int highlighted; // -1: no item highlighted
|
int highlighted; // -1: no item highlighted
|
||||||
|
int lastClicked; // -1: no item clicked
|
||||||
void divesSelected(const QVector<dive *> &) override;
|
void divesSelected(const QVector<dive *> &) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -81,7 +81,8 @@ PieSeries::PieSeries(StatsView &view, StatsAxis *xAxis, StatsAxis *yAxis, const
|
||||||
StatsSeries(view, xAxis, yAxis),
|
StatsSeries(view, xAxis, yAxis),
|
||||||
item(view.createChartItem<ChartPieItem>(ChartZValue::Series, pieBorderWidth)),
|
item(view.createChartItem<ChartPieItem>(ChartZValue::Series, pieBorderWidth)),
|
||||||
categoryName(categoryName),
|
categoryName(categoryName),
|
||||||
highlighted(-1)
|
highlighted(-1),
|
||||||
|
lastClicked(-1)
|
||||||
{
|
{
|
||||||
// Pie charts with many slices are unreadable. Therefore, subsume slices under
|
// Pie charts with many slices are unreadable. Therefore, subsume slices under
|
||||||
// a certain percentage as "other". But draw a minimum number of slices
|
// 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);
|
int index = getItemUnderMouse(pos);
|
||||||
|
|
||||||
|
if (modifier.shift && index < 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!modifier.shift || lastClicked < 0)
|
||||||
|
lastClicked = index;
|
||||||
|
|
||||||
std::vector<dive *> divesUnderMouse;
|
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;
|
divesUnderMouse = items[index].dives;
|
||||||
|
}
|
||||||
processSelection(std::move(divesUnderMouse), modifier);
|
processSelection(std::move(divesUnderMouse), modifier);
|
||||||
|
|
||||||
return index >= 0;
|
return index >= 0;
|
||||||
|
|
|
@ -65,7 +65,8 @@ private:
|
||||||
ChartItemPtr<InformationBox> information;
|
ChartItemPtr<InformationBox> information;
|
||||||
QPointF center; // center of drawing area
|
QPointF center; // center of drawing area
|
||||||
double radius; // radius of pie
|
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;
|
void divesSelected(const QVector<dive *> &) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue