mirror of
https://github.com/subsurface/subsurface.git
synced 2025-02-19 22:16:15 +00:00
The code was wrong, because it deleted the ChartItems in the main UI thread, not the render thread. This would delete the QSG nodes in the UI thread and then crash on mobile. Therefore refactor this part of the code by adding the items to be deleted to a list that will be deleted by the render thread. As a drop in replacement of std::unique_ptr, implement a silly ChartItemPtr class, which auto-initializes to null. This turns the deterministic and easily controlled memory management into a steaming pile of insanity. Obviously, this can be made much more elegant, but this has to do for now. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
181 lines
6.7 KiB
C++
181 lines
6.7 KiB
C++
// SPDX-License-Identifier: GPL-2.0
|
|
#ifndef STATS_VIEW_H
|
|
#define STATS_VIEW_H
|
|
|
|
#include "statsstate.h"
|
|
#include "statshelper.h"
|
|
#include <memory>
|
|
#include <QFont>
|
|
#include <QImage>
|
|
#include <QPainter>
|
|
#include <QQuickItem>
|
|
|
|
struct dive;
|
|
struct StatsBinner;
|
|
struct StatsBin;
|
|
struct StatsState;
|
|
struct StatsVariable;
|
|
|
|
class StatsSeries;
|
|
class CategoryAxis;
|
|
class ChartItem;
|
|
class ChartTextItem;
|
|
class CountAxis;
|
|
class HistogramAxis;
|
|
class HistogramMarker;
|
|
class QuartileMarker;
|
|
class RegressionItem;
|
|
class StatsAxis;
|
|
class StatsGrid;
|
|
class Legend;
|
|
class QSGTexture;
|
|
class RootNode; // Internal implementation detail
|
|
|
|
enum class ChartSubType : int;
|
|
enum class ChartZValue : int;
|
|
enum class StatsOperation : int;
|
|
|
|
class StatsView : public QQuickItem {
|
|
Q_OBJECT
|
|
public:
|
|
StatsView();
|
|
StatsView(QQuickItem *parent);
|
|
~StatsView();
|
|
|
|
void plot(const StatsState &state);
|
|
QQuickWindow *w() const; // Make window available to items
|
|
QSizeF size() const;
|
|
QRectF plotArea() const;
|
|
void addQSGNode(QSGNode *node, ChartZValue z); // Must only be called in render thread!
|
|
void registerChartItem(ChartItem &item);
|
|
void registerDirtyChartItem(ChartItem &item);
|
|
|
|
// Create a chart item and add it to the scene.
|
|
// The item must not be deleted by the caller, but can be
|
|
// scheduled for deletion using deleteChartItem() below.
|
|
// Most items can be made invisible, which is preferred over deletion.
|
|
// All items on the scene will be deleted once the chart is reset.
|
|
template <typename T, class... Args>
|
|
ChartItemPtr<T> createChartItem(Args&&... args);
|
|
|
|
template <typename T>
|
|
void deleteChartItem(ChartItemPtr<T> &item);
|
|
private slots:
|
|
void replotIfVisible();
|
|
private:
|
|
bool resetChart;
|
|
|
|
// QtQuick related things
|
|
QRectF plotRect;
|
|
QSGNode *updatePaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *updatePaintNodeData) override;
|
|
|
|
void plotAreaChanged(const QSizeF &size);
|
|
void reset(); // clears all series and axes
|
|
void setAxes(StatsAxis *x, StatsAxis *y);
|
|
void plotBarChart(const std::vector<dive *> &dives,
|
|
ChartSubType subType,
|
|
const StatsVariable *categoryVariable, const StatsBinner *categoryBinner,
|
|
const StatsVariable *valueVariable, const StatsBinner *valueBinner, bool labels, bool legend);
|
|
void plotValueChart(const std::vector<dive *> &dives,
|
|
ChartSubType subType,
|
|
const StatsVariable *categoryVariable, const StatsBinner *categoryBinner,
|
|
const StatsVariable *valueVariable, StatsOperation valueAxisOperation, bool labels);
|
|
void plotDiscreteCountChart(const std::vector<dive *> &dives,
|
|
ChartSubType subType,
|
|
const StatsVariable *categoryVariable, const StatsBinner *categoryBinner, bool labels);
|
|
void plotPieChart(const std::vector<dive *> &dives,
|
|
const StatsVariable *categoryVariable, const StatsBinner *categoryBinner, bool labels, bool legend);
|
|
void plotDiscreteBoxChart(const std::vector<dive *> &dives,
|
|
const StatsVariable *categoryVariable, const StatsBinner *categoryBinner, const StatsVariable *valueVariable);
|
|
void plotDiscreteScatter(const std::vector<dive *> &dives,
|
|
const StatsVariable *categoryVariable, const StatsBinner *categoryBinner,
|
|
const StatsVariable *valueVariable, bool quartiles);
|
|
void plotHistogramCountChart(const std::vector<dive *> &dives,
|
|
ChartSubType subType,
|
|
const StatsVariable *categoryVariable, const StatsBinner *categoryBinner,
|
|
bool labels, bool showMedian, bool showMean);
|
|
void plotHistogramValueChart(const std::vector<dive *> &dives,
|
|
ChartSubType subType,
|
|
const StatsVariable *categoryVariable, const StatsBinner *categoryBinner,
|
|
const StatsVariable *valueVariable, StatsOperation valueAxisOperation, bool labels);
|
|
void plotHistogramStackedChart(const std::vector<dive *> &dives,
|
|
ChartSubType subType,
|
|
const StatsVariable *categoryVariable, const StatsBinner *categoryBinner,
|
|
const StatsVariable *valueVariable, const StatsBinner *valueBinner, bool labels, bool legend);
|
|
void plotHistogramBoxChart(const std::vector<dive *> &dives,
|
|
const StatsVariable *categoryVariable, const StatsBinner *categoryBinner, const StatsVariable *valueVariable);
|
|
void plotScatter(const std::vector<dive *> &dives, const StatsVariable *categoryVariable, const StatsVariable *valueVariable);
|
|
void setTitle(const QString &);
|
|
void updateTitlePos(); // After resizing, set title to correct position
|
|
void plotChart();
|
|
|
|
template <typename T, class... Args>
|
|
T *createSeries(Args&&... args);
|
|
|
|
template <typename T, class... Args>
|
|
T *createAxis(const QString &title, Args&&... args);
|
|
|
|
template<typename T>
|
|
CategoryAxis *createCategoryAxis(const QString &title, const StatsBinner &binner,
|
|
const std::vector<T> &bins, bool isHorizontal);
|
|
template<typename T>
|
|
HistogramAxis *createHistogramAxis(const QString &title, const StatsBinner &binner,
|
|
const std::vector<T> &bins, bool isHorizontal);
|
|
CountAxis *createCountAxis(int maxVal, bool isHorizontal);
|
|
|
|
// Helper functions to add feature to the chart
|
|
void addLineMarker(double pos, double low, double high, const QPen &pen, bool isHorizontal);
|
|
|
|
void addHistogramMarker(double pos, QColor color, bool isHorizontal, StatsAxis *xAxis, StatsAxis *yAxis);
|
|
|
|
StatsState state;
|
|
QFont titleFont;
|
|
std::vector<std::unique_ptr<StatsSeries>> series;
|
|
std::unique_ptr<StatsGrid> grid;
|
|
std::vector<ChartItemPtr<QuartileMarker>> quartileMarkers;
|
|
std::vector<ChartItemPtr<HistogramMarker>> histogramMarkers;
|
|
StatsSeries *highlightedSeries;
|
|
StatsAxis *xAxis, *yAxis;
|
|
ChartItemPtr<ChartTextItem> title;
|
|
ChartItemPtr<Legend> legend;
|
|
Legend *draggedItem;
|
|
ChartItemPtr<RegressionItem> regressionItem;
|
|
QPointF dragStartMouse, dragStartItem;
|
|
|
|
void hoverEnterEvent(QHoverEvent *event) override;
|
|
void hoverMoveEvent(QHoverEvent *event) override;
|
|
void mousePressEvent(QMouseEvent *event) override;
|
|
void mouseReleaseEvent(QMouseEvent *event) override;
|
|
void mouseMoveEvent(QMouseEvent *event) override;
|
|
RootNode *rootNode;
|
|
|
|
// There are three double linked lists of chart items:
|
|
// clean items, dirty items and items to be deleted.
|
|
struct ChartItemList {
|
|
ChartItemList();
|
|
ChartItem *first, *last;
|
|
void append(ChartItem &item);
|
|
void remove(ChartItem &item);
|
|
void clear();
|
|
void splice(ChartItemList &list);
|
|
};
|
|
ChartItemList cleanItems, dirtyItems, deletedItems;
|
|
void deleteChartItemInternal(ChartItem &item);
|
|
};
|
|
|
|
// This implementation detail must be known to users of the class.
|
|
// Perhaps move it into a statsview_impl.h file.
|
|
template <typename T, class... Args>
|
|
ChartItemPtr<T> StatsView::createChartItem(Args&&... args)
|
|
{
|
|
return ChartItemPtr(new T(*this, std::forward<Args>(args)...));
|
|
}
|
|
|
|
template <typename T>
|
|
void StatsView::deleteChartItem(ChartItemPtr<T> &item)
|
|
{
|
|
deleteChartItemInternal(*item);
|
|
item.reset();
|
|
}
|
|
|
|
#endif
|