Skip to content

Commit

Permalink
statistics: convert chart to QQuickItem
Browse files Browse the repository at this point in the history
It turns out that the wrong base class was used for the chart.
QQuickWidget can only be used on desktop, not in a mobile UI.

Therefore, turn this into a QQuickItem and move the container
QQuickWidget into desktop-only code.

Currently, this code is insane: The chart is rendered onto a
QGraphicsScene (as it was before), which is then rendered into
a QImage, which is transformed into a QSGTexture, which is then
projected onto the device. This is performed on every mouse
move event, since these events in general change the position
of the info-box.

The plan is to slowly convert elements such as the info-box into
QQuickItems. Browsing the QtQuick documentation, this will
not be much fun.

Also note that the rendering currently tears, flickers and has
antialiasing artifacts, most likely owing to integer (QImage)
to floating point (QGraphicsScene, QQuickItem) conversion
problems. The data flow is
QGraphicsScene (float) -> QImage (int) -> QQuickItem (float).

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
  • Loading branch information
bstoeger authored and dirkhh committed Jan 10, 2021
1 parent f6b857b commit e7907c4
Show file tree
Hide file tree
Showing 32 changed files with 298 additions and 268 deletions.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,7 @@ endif()
#set up the subsurface_link_libraries variable
set(SUBSURFACE_LINK_LIBRARIES ${SUBSURFACE_LINK_LIBRARIES} ${LIBDIVECOMPUTER_LIBRARIES} ${LIBGIT2_LIBRARIES} ${LIBUSB_LIBRARIES} ${LIBMTP_LIBRARIES})
if (NOT SUBSURFACE_TARGET_EXECUTABLE MATCHES "DownloaderExecutable")
qt5_add_resources(SUBSURFACE_RESOURCES subsurface.qrc map-widget/qml/map-widget.qrc stats/qml/statsview.qrc)
qt5_add_resources(SUBSURFACE_RESOURCES subsurface.qrc map-widget/qml/map-widget.qrc desktop-widgets/qml/statsview2.qrc)
endif()

# hack to build successfully on LGTM
Expand Down
4 changes: 4 additions & 0 deletions backend-shared/roundrectitem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ RoundRectItem::RoundRectItem(double radius, QGraphicsItem *parent) : QGraphicsRe
{
}

RoundRectItem::RoundRectItem(double radius) : RoundRectItem(radius, nullptr)
{
}

void RoundRectItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *)
{
painter->save();
Expand Down
1 change: 1 addition & 0 deletions backend-shared/roundrectitem.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
class RoundRectItem : public QGraphicsRectItem {
public:
RoundRectItem(double radius, QGraphicsItem *parent);
RoundRectItem(double radius);
private:
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
double radius;
Expand Down
6 changes: 6 additions & 0 deletions desktop-widgets/qml/statsview2.qml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
import QtQuick 2.0
import org.subsurfacedivelog.mobile 1.0

StatsView {
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<RCC>
<qresource prefix="/qml">
<file>statsview.qml</file>
<file>statsview2.qml</file>
</qresource>
</RCC>
17 changes: 13 additions & 4 deletions desktop-widgets/statswidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ QSize ChartItemDelegate::sizeHint(const QStyleOptionViewItem &option, const QMod
return size;
}

static const QUrl urlStatsView = QUrl(QStringLiteral("qrc:/qml/statsview2.qml"));
StatsWidget::StatsWidget(QWidget *parent) : QWidget(parent)
{
ui.setupUi(this);
Expand All @@ -83,6 +84,13 @@ StatsWidget::StatsWidget(QWidget *parent) : QWidget(parent)
connect(ui.var1Binner, QOverload<int>::of(&QComboBox::activated), this, &StatsWidget::var1BinnerChanged);
connect(ui.var2Binner, QOverload<int>::of(&QComboBox::activated), this, &StatsWidget::var2BinnerChanged);
connect(ui.var2Operation, QOverload<int>::of(&QComboBox::activated), this, &StatsWidget::var2OperationChanged);

ui.stats->setSource(urlStatsView);
ui.stats->setResizeMode(QQuickWidget::SizeRootObjectToView);
QQuickItem *root = ui.stats->rootObject();
view = qobject_cast<StatsView *>(root);
if (!view)
qWarning("Oops. The root of the StatsView is not a StatsView.");
}

// Initialize QComboBox with list of variables
Expand All @@ -96,7 +104,7 @@ static void setVariableList(QComboBox *combo, const StatsState::VariableList &li
}

// Initialize QComboBox and QLabel of binners. Hide if there are no binners.
static void setBinList(QLabel *label, QComboBox *combo, const StatsState::BinnerList &list)
static void setBinList(QComboBox *combo, const StatsState::BinnerList &list)
{
combo->clear();
combo->setEnabled(!list.binners.empty());
Expand All @@ -114,8 +122,8 @@ void StatsWidget::updateUi()
int pos = charts.update(uiState.charts);
ui.chartType->setCurrentIndex(pos);
ui.chartType->setItemDelegate(new ChartItemDelegate);
setBinList(ui.var1BinnerLabel, ui.var1Binner, uiState.binners1);
setBinList(ui.var2BinnerLabel, ui.var2Binner, uiState.binners2);
setBinList(ui.var1Binner, uiState.binners1);
setBinList(ui.var2Binner, uiState.binners2);
setVariableList(ui.var2Operation, uiState.operations2);

// Add checkboxes for additional features
Expand All @@ -129,7 +137,8 @@ void StatsWidget::updateUi()
ui.features->addWidget(check);
}

ui.stats->plot(state);
if (view)
view->plot(state);
}

void StatsWidget::closeStats()
Expand Down
2 changes: 2 additions & 0 deletions desktop-widgets/statswidget.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <memory>

class QCheckBox;
class StatsView;

class StatsWidget : public QWidget {
Q_OBJECT
Expand All @@ -27,6 +28,7 @@ private
private:
Ui::StatsWidget ui;
StatsState state;
StatsView *view;
void updateUi();
std::vector<std::unique_ptr<QCheckBox>> features;

Expand Down
10 changes: 1 addition & 9 deletions desktop-widgets/statswidget.ui
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@
</layout>
</item>
<item>
<widget class="StatsView" name="stats">
<widget class="QQuickWidget" name="stats">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
Expand All @@ -116,14 +116,6 @@
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>StatsView</class>
<extends>QQuickWidget</extends>
<header>stats/statsview.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources>
<include location="../subsurface.qrc"/>
</resources>
Expand Down
31 changes: 16 additions & 15 deletions stats/barseries.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include "barseries.h"
#include "informationbox.h"
#include "statscolors.h"
#include "statshelper.h"
#include "statstranslations.h"
#include "zvalues.h"

Expand All @@ -27,19 +28,19 @@ bool BarSeries::Index::operator==(const Index &i2) const
return std::tie(bar, subitem) == std::tie(i2.bar, i2.subitem);
}

BarSeries::BarSeries(QtCharts::QChart *chart, StatsAxis *xAxis, StatsAxis *yAxis,
BarSeries::BarSeries(QGraphicsScene *scene, StatsAxis *xAxis, StatsAxis *yAxis,
bool horizontal, bool stacked, const QString &categoryName,
const StatsVariable *valueVariable, std::vector<QString> valueBinNames) :
StatsSeries(chart, xAxis, yAxis),
StatsSeries(scene, xAxis, yAxis),
horizontal(horizontal), stacked(stacked), categoryName(categoryName),
valueVariable(valueVariable), valueBinNames(std::move(valueBinNames))
{
}

BarSeries::BarSeries(QtCharts::QChart *chart, StatsAxis *xAxis, StatsAxis *yAxis,
BarSeries::BarSeries(QGraphicsScene *scene, StatsAxis *xAxis, StatsAxis *yAxis,
bool horizontal, const QString &categoryName,
const std::vector<CountItem> &items) :
BarSeries(chart, xAxis, yAxis, horizontal, false, categoryName, nullptr, std::vector<QString>())
BarSeries(scene, xAxis, yAxis, horizontal, false, categoryName, nullptr, std::vector<QString>())
{
for (const CountItem &item: items) {
StatsOperationResults res;
Expand All @@ -50,22 +51,22 @@ BarSeries::BarSeries(QtCharts::QChart *chart, StatsAxis *xAxis, StatsAxis *yAxis
}
}

BarSeries::BarSeries(QtCharts::QChart *chart, StatsAxis *xAxis, StatsAxis *yAxis,
BarSeries::BarSeries(QGraphicsScene *scene, StatsAxis *xAxis, StatsAxis *yAxis,
bool horizontal, const QString &categoryName, const StatsVariable *valueVariable,
const std::vector<ValueItem> &items) :
BarSeries(chart, xAxis, yAxis, horizontal, false, categoryName, valueVariable, std::vector<QString>())
BarSeries(scene, xAxis, yAxis, horizontal, false, categoryName, valueVariable, std::vector<QString>())
{
for (const ValueItem &item: items) {
add_item(item.lowerBound, item.upperBound, makeSubItems(item.value, item.label),
item.binName, item.res, -1, horizontal, stacked);
}
}

BarSeries::BarSeries(QtCharts::QChart *chart, StatsAxis *xAxis, StatsAxis *yAxis,
BarSeries::BarSeries(QGraphicsScene *scene, StatsAxis *xAxis, StatsAxis *yAxis,
bool horizontal, bool stacked, const QString &categoryName, const StatsVariable *valueVariable,
std::vector<QString> valueBinNames,
const std::vector<MultiItem> &items) :
BarSeries(chart, xAxis, yAxis, horizontal, stacked, categoryName, valueVariable, std::move(valueBinNames))
BarSeries(scene, xAxis, yAxis, horizontal, stacked, categoryName, valueVariable, std::move(valueBinNames))
{
for (const MultiItem &item: items) {
StatsOperationResults res;
Expand All @@ -85,12 +86,12 @@ BarSeries::~BarSeries()
{
}

BarSeries::BarLabel::BarLabel(QtCharts::QChart *chart, const std::vector<QString> &labels, int bin_nr, int binCount) :
BarSeries::BarLabel::BarLabel(QGraphicsScene *scene, const std::vector<QString> &labels, int bin_nr, int binCount) :
totalWidth(0.0), totalHeight(0.0), isOutside(false)
{
items.reserve(labels.size());
for (const QString &label: labels) {
items.emplace_back(new QGraphicsSimpleTextItem(chart));
items.emplace_back(createItem<QGraphicsSimpleTextItem>(scene));
items.back()->setText(label);
items.back()->setZValue(ZValues::seriesLabels);
QRectF rect = items.back()->boundingRect();
Expand Down Expand Up @@ -175,7 +176,7 @@ void BarSeries::BarLabel::updatePosition(bool horizontal, bool center, const QRe
highlight(false, bin_nr, binCount);
}

BarSeries::Item::Item(QtCharts::QChart *chart, BarSeries *series, double lowerBound, double upperBound,
BarSeries::Item::Item(QGraphicsScene *scene, BarSeries *series, double lowerBound, double upperBound,
std::vector<SubItem> subitemsIn,
const QString &binName, const StatsOperationResults &res, int total,
bool horizontal, bool stacked, int binCount) :
Expand Down Expand Up @@ -264,9 +265,9 @@ std::vector<BarSeries::SubItem> BarSeries::makeSubItems(const std::vector<std::p
int bin_nr = 0;
for (auto &[v, label]: values) {
if (v > 0.0) {
res.push_back({ std::make_unique<QGraphicsRectItem>(chart), {}, from, from + v, bin_nr });
res.push_back({ createItemPtr<QGraphicsRectItem>(scene), {}, from, from + v, bin_nr });
if (!label.empty())
res.back().label = std::make_unique<BarLabel>(chart, label, bin_nr, binCount());
res.back().label = std::make_unique<BarLabel>(scene, label, bin_nr, binCount());
}
if (stacked)
from += v;
Expand All @@ -292,7 +293,7 @@ void BarSeries::add_item(double lowerBound, double upperBound, std::vector<SubIt
// Don't add empty items, as that messes with the "find item under mouse" routine.
if (subitems.empty())
return;
items.emplace_back(chart, this, lowerBound, upperBound, std::move(subitems), binName, res,
items.emplace_back(scene, this, lowerBound, upperBound, std::move(subitems), binName, res,
total, horizontal, stacked, binCount());
}

Expand Down Expand Up @@ -403,7 +404,7 @@ bool BarSeries::hover(QPointF pos)
Item &item = items[highlighted.bar];
item.highlight(index.subitem, true, binCount());
if (!information)
information.reset(new InformationBox(chart));
information = createItemPtr<InformationBox>(scene);
information->setText(makeInfo(item, highlighted.subitem), pos);
} else {
information.reset();
Expand Down
16 changes: 7 additions & 9 deletions stats/barseries.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,7 @@
#include <vector>
#include <QGraphicsRectItem>

namespace QtCharts {
class QAbstractAxis;
}
class QGraphicsScene;
class InformationBox;
class StatsVariable;

Expand Down Expand Up @@ -49,13 +47,13 @@ class BarSeries : public StatsSeries {
// 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.
BarSeries(QtCharts::QChart *chart, StatsAxis *xAxis, StatsAxis *yAxis,
BarSeries(QGraphicsScene *scene, StatsAxis *xAxis, StatsAxis *yAxis,
bool horizontal, const QString &categoryName,
const std::vector<CountItem> &items);
BarSeries(QtCharts::QChart *chart, StatsAxis *xAxis, StatsAxis *yAxis,
BarSeries(QGraphicsScene *scene, StatsAxis *xAxis, StatsAxis *yAxis,
bool horizontal, const QString &categoryName, const StatsVariable *valueVariable,
const std::vector<ValueItem> &items);
BarSeries(QtCharts::QChart *chart, StatsAxis *xAxis, StatsAxis *yAxis,
BarSeries(QGraphicsScene *scene, StatsAxis *xAxis, StatsAxis *yAxis,
bool horizontal, bool stacked, const QString &categoryName, const StatsVariable *valueVariable,
std::vector<QString> valueBinNames,
const std::vector<MultiItem> &items);
Expand All @@ -65,7 +63,7 @@ class BarSeries : public StatsSeries {
bool hover(QPointF pos) override;
void unhighlight() override;
private:
BarSeries(QtCharts::QChart *chart, StatsAxis *xAxis, StatsAxis *yAxis,
BarSeries(QGraphicsScene *scene, StatsAxis *xAxis, StatsAxis *yAxis,
bool horizontal, bool stacked, const QString &categoryName, const StatsVariable *valueVariable,
std::vector<QString> valueBinNames);

Expand All @@ -85,7 +83,7 @@ class BarSeries : public StatsSeries {
std::vector<std::unique_ptr<QGraphicsSimpleTextItem>> items;
double totalWidth, totalHeight; // Size of the item
bool isOutside; // Is shown outside of bar
BarLabel(QtCharts::QChart *chart, const std::vector<QString> &labels, int bin_nr, int binCount);
BarLabel(QGraphicsScene *scene, const std::vector<QString> &labels, int bin_nr, int binCount);
void setVisible(bool visible);
void updatePosition(bool horizontal, bool center, const QRectF &rect, int bin_nr, int binCount);
void highlight(bool highlight, int bin_nr, int binCount);
Expand All @@ -109,7 +107,7 @@ class BarSeries : public StatsSeries {
const QString binName;
StatsOperationResults res;
int total;
Item(QtCharts::QChart *chart, BarSeries *series, double lowerBound, double upperBound,
Item(QGraphicsScene *scene, BarSeries *series, double lowerBound, double upperBound,
std::vector<SubItem> subitems,
const QString &binName, const StatsOperationResults &res, int total, bool horizontal,
bool stacked, int binCount);
Expand Down
21 changes: 12 additions & 9 deletions stats/boxseries.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include "boxseries.h"
#include "informationbox.h"
#include "statscolors.h"
#include "statshelper.h"
#include "statstranslations.h"
#include "zvalues.h"

Expand All @@ -12,9 +13,9 @@
static const double boxWidth = 0.8; // 1.0 = full width of category
static const int boxBorderWidth = 2;

BoxSeries::BoxSeries(QtCharts::QChart *chart, StatsAxis *xAxis, StatsAxis *yAxis,
BoxSeries::BoxSeries(QGraphicsScene *scene, StatsAxis *xAxis, StatsAxis *yAxis,
const QString &variable, const QString &unit, int decimals) :
StatsSeries(chart, xAxis, yAxis),
StatsSeries(scene, xAxis, yAxis),
variable(variable), unit(unit), decimals(decimals), highlighted(-1)
{
}
Expand All @@ -23,12 +24,8 @@ BoxSeries::~BoxSeries()
{
}

BoxSeries::Item::Item(QtCharts::QChart *chart, BoxSeries *series, double lowerBound, double upperBound,
BoxSeries::Item::Item(QGraphicsScene *scene, BoxSeries *series, double lowerBound, double upperBound,
const StatsQuartiles &q, const QString &binName) :
box(chart),
topWhisker(chart), bottomWhisker(chart),
topBar(chart), bottomBar(chart),
center(chart),
lowerBound(lowerBound), upperBound(upperBound), q(q),
binName(binName)
{
Expand All @@ -38,6 +35,12 @@ BoxSeries::Item::Item(QtCharts::QChart *chart, BoxSeries *series, double lowerBo
topBar.setZValue(ZValues::series);
bottomBar.setZValue(ZValues::series);
center.setZValue(ZValues::series);
scene->addItem(&box);
scene->addItem(&topWhisker);
scene->addItem(&bottomWhisker);
scene->addItem(&topBar);
scene->addItem(&bottomBar);
scene->addItem(&center);
highlight(false);
updatePosition(series);
}
Expand Down Expand Up @@ -89,7 +92,7 @@ void BoxSeries::Item::updatePosition(BoxSeries *series)

void BoxSeries::append(double lowerBound, double upperBound, const StatsQuartiles &q, const QString &binName)
{
items.emplace_back(new Item(chart, this, lowerBound, upperBound, q, binName));
items.emplace_back(new Item(scene, this, lowerBound, upperBound, q, binName));
}

void BoxSeries::updatePositions()
Expand Down Expand Up @@ -147,7 +150,7 @@ bool BoxSeries::hover(QPointF pos)
Item &item = *items[highlighted];
item.highlight(true);
if (!information)
information.reset(new InformationBox(chart));
information = createItemPtr<InformationBox>(scene);
information->setText(formatInformation(item), pos);
} else {
information.reset();
Expand Down
5 changes: 3 additions & 2 deletions stats/boxseries.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,11 @@
#include <QGraphicsRectItem>

class InformationBox;
class QGraphicsScene;

class BoxSeries : public StatsSeries {
public:
BoxSeries(QtCharts::QChart *chart, StatsAxis *xAxis, StatsAxis *yAxis,
BoxSeries(QGraphicsScene *scene, StatsAxis *xAxis, StatsAxis *yAxis,
const QString &variable, const QString &unit, int decimals);
~BoxSeries();

Expand All @@ -44,7 +45,7 @@ class BoxSeries : public StatsSeries {
double lowerBound, upperBound;
StatsQuartiles q;
QString binName;
Item(QtCharts::QChart *chart, BoxSeries *series, double lowerBound, double upperBound, const StatsQuartiles &q, const QString &binName);
Item(QGraphicsScene *scene, BoxSeries *series, double lowerBound, double upperBound, const StatsQuartiles &q, const QString &binName);
void updatePosition(BoxSeries *series);
void highlight(bool highlight);
};
Expand Down
Loading

0 comments on commit e7907c4

Please sign in to comment.