aboutsummaryrefslogtreecommitdiffstats
path: root/stats/chartitem.h
diff options
context:
space:
mode:
Diffstat (limited to 'stats/chartitem.h')
-rw-r--r--stats/chartitem.h222
1 files changed, 222 insertions, 0 deletions
diff --git a/stats/chartitem.h b/stats/chartitem.h
new file mode 100644
index 000000000..cf20f55a8
--- /dev/null
+++ b/stats/chartitem.h
@@ -0,0 +1,222 @@
+// SPDX-License-Identifier: GPL-2.0
+// Wrappers around QSGImageNode that allow painting onto an image
+// and then turning that into a texture to be displayed in a QQuickItem.
+#ifndef CHART_ITEM_H
+#define CHART_ITEM_H
+
+#include "statshelper.h"
+
+#include <memory>
+#include <QPainter>
+
+class QSGGeometry;
+class QSGGeometryNode;
+class QSGFlatColorMaterial;
+class QSGImageNode;
+class QSGRectangleNode;
+class QSGTexture;
+class StatsView;
+enum class ChartZValue : int;
+
+class ChartItem {
+public:
+ virtual void render() = 0; // Only call on render thread!
+ bool dirty; // If true, call render() when rebuilding the scene
+ ChartItem *prev, *next; // Double linked list of items
+ const ChartZValue zValue;
+ virtual ~ChartItem(); // Attention: must only be called by render thread.
+protected:
+ ChartItem(StatsView &v, ChartZValue z);
+ QSizeF sceneSize() const;
+ StatsView &view;
+ void markDirty();
+};
+
+template <typename Node>
+class HideableChartItem : public ChartItem {
+protected:
+ HideableChartItem(StatsView &v, ChartZValue z);
+ std::unique_ptr<Node> node;
+ bool visible;
+ bool visibleChanged;
+ template<class... Args>
+ void createNode(Args&&... args); // Call to create node with visibility flag.
+ void updateVisible(); // Must be called by child class to update visibility flag!
+public:
+ void setVisible(bool visible);
+};
+
+// A shortcut for ChartItems based on a hideable proxy item
+template <typename Node>
+using HideableChartProxyItem = HideableChartItem<HideableQSGNode<QSGProxyNode<Node>>>;
+
+// A chart item that blits a precalculated pixmap onto the scene.
+class ChartPixmapItem : public HideableChartProxyItem<QSGImageNode> {
+public:
+ ChartPixmapItem(StatsView &v, ChartZValue z);
+ ~ChartPixmapItem();
+
+ void setPos(QPointF pos);
+ void render() override; // Only call on render thread!
+ QRectF getRect() const;
+protected:
+ void resize(QSizeF size); // Resets the canvas. Attention: image is *unitialized*.
+ std::unique_ptr<QPainter> painter;
+ std::unique_ptr<QImage> img;
+ void setTextureDirty();
+ void setPositionDirty();
+ QRectF rect;
+private:
+ bool positionDirty; // true if the position changed since last render
+ bool textureDirty; // true if the pixmap changed since last render
+ std::unique_ptr<QSGTexture> texture;
+};
+
+// Draw a rectangular background after resize. Children are responsible for calling update().
+class ChartRectItem : public ChartPixmapItem {
+public:
+ ChartRectItem(StatsView &v, ChartZValue z, const QPen &pen, const QBrush &brush, double radius);
+ ~ChartRectItem();
+ void resize(QSizeF size);
+private:
+ QPen pen;
+ QBrush brush;
+ double radius;
+};
+
+// Attention: text is only drawn after calling setColor()!
+class ChartTextItem : public ChartPixmapItem {
+public:
+ ChartTextItem(StatsView &v, ChartZValue z, const QFont &f, const std::vector<QString> &text, bool center);
+ ChartTextItem(StatsView &v, ChartZValue z, const QFont &f, const QString &text);
+ void setColor(const QColor &color); // Draw on transparent background
+ void setColor(const QColor &color, const QColor &background); // Fill rectangle with given background color
+private:
+ QFont f;
+ double fontHeight;
+ bool center;
+ struct Item {
+ QString s;
+ double width;
+ };
+ std::vector<Item> items;
+};
+
+// A pie chart item: draws disk segments onto a pixmap.
+class ChartPieItem : public ChartPixmapItem {
+public:
+ ChartPieItem(StatsView &v, ChartZValue z, double borderWidth);
+ void drawSegment(double from, double to, QColor fill, QColor border); // from and to are relative (0-1 is full disk).
+ void resize(QSizeF size); // As in base class, but clears the canvas
+private:
+ double borderWidth;
+};
+
+class ChartLineItem : public HideableChartItem<HideableQSGNode<QSGGeometryNode>> {
+public:
+ ChartLineItem(StatsView &v, ChartZValue z, QColor color, double width);
+ ~ChartLineItem();
+ void setLine(QPointF from, QPointF to);
+ void render() override; // Only call on render thread!
+private:
+ QPointF from, to;
+ QColor color;
+ double width;
+ bool horizontal;
+ bool positionDirty;
+ bool materialDirty;
+ std::unique_ptr<QSGFlatColorMaterial> material;
+ std::unique_ptr<QSGGeometry> geometry;
+};
+
+// A bar in a bar chart: a rectangle bordered by lines.
+class ChartBarItem : public HideableChartProxyItem<QSGRectangleNode> {
+public:
+ ChartBarItem(StatsView &v, ChartZValue z, double borderWidth, bool horizontal);
+ ~ChartBarItem();
+ void setColor(QColor color, QColor borderColor);
+ void setRect(const QRectF &rect);
+ QRectF getRect() const;
+ void render() override; // Only call on render thread!
+protected:
+ QColor color, borderColor;
+ double borderWidth;
+ QRectF rect;
+ bool horizontal;
+ bool positionDirty;
+ bool colorDirty;
+ std::unique_ptr<QSGGeometryNode> borderNode;
+ std::unique_ptr<QSGFlatColorMaterial> borderMaterial;
+ std::unique_ptr<QSGGeometry> borderGeometry;
+};
+
+// A box-and-whiskers item. This is a bit lazy: derive from the bar item and add whiskers.
+class ChartBoxItem : public ChartBarItem {
+public:
+ ChartBoxItem(StatsView &v, ChartZValue z, double borderWidth);
+ ~ChartBoxItem();
+ void setBox(const QRectF &rect, double min, double max, double median); // The rect describes Q1, Q3.
+ QRectF getRect() const; // Note: this extends the center rectangle to include the whiskers.
+ void render() override; // Only call on render thread!
+private:
+ double min, max, median;
+ std::unique_ptr<QSGGeometryNode> whiskersNode;
+ std::unique_ptr<QSGFlatColorMaterial> whiskersMaterial;
+ std::unique_ptr<QSGGeometry> whiskersGeometry;
+};
+
+// An item in a scatter chart. This is not simply a normal pixmap item,
+// because we want that all items share the *same* texture for memory
+// efficiency. It is somewhat questionable to define the form of the
+// scatter item here, but so it is for now.
+class ChartScatterItem : public HideableChartProxyItem<QSGImageNode> {
+public:
+ ChartScatterItem(StatsView &v, ChartZValue z);
+ ~ChartScatterItem();
+
+ void setPos(QPointF pos); // Specifies the *center* of the item.
+ void setHighlight(bool highlight); // In the future, support different kinds of scatter items.
+ void render() override; // Only call on render thread!
+ QRectF getRect() const;
+ bool contains(QPointF point) const;
+private:
+ QRectF rect;
+ QSizeF textureSize;
+ bool positionDirty, textureDirty;
+ bool highlighted;
+};
+
+// Implementation detail of templates - move to serparate header file
+template <typename Node>
+void HideableChartItem<Node>::setVisible(bool visibleIn)
+{
+ if (visible == visibleIn)
+ return;
+ visible = visibleIn;
+ visibleChanged = true;
+ markDirty();
+}
+
+template <typename Node>
+template<class... Args>
+void HideableChartItem<Node>::createNode(Args&&... args)
+{
+ node.reset(new Node(visible, std::forward<Args>(args)...));
+ visibleChanged = false;
+}
+
+template <typename Node>
+HideableChartItem<Node>::HideableChartItem(StatsView &v, ChartZValue z) : ChartItem(v, z),
+ visible(true), visibleChanged(false)
+{
+}
+
+template <typename Node>
+void HideableChartItem<Node>::updateVisible()
+{
+ if (visibleChanged)
+ node->setVisible(visible);
+ visibleChanged = false;
+}
+
+#endif