aboutsummaryrefslogtreecommitdiffstats
path: root/stats/statshelper.h
diff options
context:
space:
mode:
Diffstat (limited to 'stats/statshelper.h')
-rw-r--r--stats/statshelper.h135
1 files changed, 122 insertions, 13 deletions
diff --git a/stats/statshelper.h b/stats/statshelper.h
index 0ea39763d..6b4a30ab5 100644
--- a/stats/statshelper.h
+++ b/stats/statshelper.h
@@ -1,25 +1,134 @@
// SPDX-License-Identifier: GPL-2.0
-// Helper functions to render the stats. Currently only
-// contains a small template to create scene-items. This
-// is for historical reasons to ease transition from QtCharts
-// and might be removed.
+// Helper functions to render the stats. Currently contains
+// QSGNode template jugglery to overcome API flaws.
#ifndef STATSHELPER_H
+#define STATSHELPER_H
#include <memory>
-#include <QGraphicsScene>
+#include <QSGNode>
-template <typename T, class... Args>
-T *createItem(QGraphicsScene *scene, Args&&... args)
+// A stupid pointer class that initializes to null and can be copy
+// assigned. This is for historical reasons: unique_ptrs to ChartItems
+// were replaced by plain pointers. Instead of nulling the plain pointers
+// in the constructors, use this. Ultimately, we might think about making
+// this thing smarter, once removal of individual ChartItems is implemented.
+template <typename T>
+class ChartItemPtr {
+ friend class StatsView; // Only the stats view can create these pointers
+ T *ptr;
+ ChartItemPtr(T *ptr) : ptr(ptr)
+ {
+ }
+public:
+ ChartItemPtr() : ptr(nullptr)
+ {
+ }
+ ChartItemPtr(const ChartItemPtr &p) : ptr(p.ptr)
+ {
+ }
+ void reset()
+ {
+ ptr = nullptr;
+ }
+ ChartItemPtr &operator=(const ChartItemPtr &p)
+ {
+ ptr = p.ptr;
+ return *this;
+ }
+ operator bool() const
+ {
+ return !!ptr;
+ }
+ bool operator!() const
+ {
+ return !ptr;
+ }
+ T &operator*() const
+ {
+ return *ptr;
+ }
+ T *operator->() const
+ {
+ return ptr;
+ }
+};
+
+// In general, we want chart items to be hideable. For example to show/hide
+// labels on demand. Very sadly, the QSG API is absolutely terrible with
+// respect to temporarily disabling. Instead of simply having a flag,
+// a QSGNode is queried using the "isSubtreeBlocked()" virtual function(!).
+//
+// Not only is this a slow operation performed on every single node, it
+// also is often not possible to override this function: For improved
+// performance, the documentation recommends to create QSG nodes via
+// QQuickWindow. This provides nodes optimized for the actual hardware.
+// However, this obviously means that these nodes cannot be derived from!
+//
+// In that case, there are two possibilities: Add a proxy node with an
+// overridden "isSubtreeBlocked()" function or remove the node from the
+// scene. The former was chosen here, because it is less complex.
+//
+// The following slightly cryptic templates are used to unify the two
+// cases: The QSGNode is generated by our own code or the QSGNode is
+// obtained from QQuickWindow.
+//
+// The "HideableQSGNode<Node>" template augments the QSGNode "Node"
+// by a "setVisible()" function and overrides "isSubtreeBlocked()"
+//
+// The "QSGProxyNode<Node>" template is a QSGNode with a single
+// child of type "Node".
+//
+// Thus, if the node can be created, use:
+// HideableQSGNode<NodeTypeThatCanBeCreated> node
+// and if the node can only be obtained from QQuickWindow, use:
+// HideableQSGNode<QSGProxyNode<NodeThatCantBeCreated>> node
+// The latter should obviously be typedef-ed.
+//
+// Yes, that's all horrible, but if nothing else it teaches us about
+// composition.
+template <typename Node>
+class HideableQSGNode : public Node {
+ bool hidden;
+ bool isSubtreeBlocked() const override final;
+public:
+ template<class... Args>
+ HideableQSGNode(bool visible, Args&&... args);
+ void setVisible(bool visible);
+};
+
+template <typename Node>
+class QSGProxyNode : public QSGNode {
+public:
+ std::unique_ptr<Node> node;
+ QSGProxyNode(Node *node);
+};
+
+// Implementation detail of templates - move to serparate header file
+template <typename Node>
+QSGProxyNode<Node>::QSGProxyNode(Node *node) : node(node)
+{
+ appendChildNode(node);
+}
+
+template <typename Node>
+bool HideableQSGNode<Node>::isSubtreeBlocked() const
+{
+ return hidden;
+}
+
+template <typename Node>
+template<class... Args>
+HideableQSGNode<Node>::HideableQSGNode(bool visible, Args&&... args) :
+ Node(std::forward<Args>(args)...),
+ hidden(!visible)
{
- T *res = new T(std::forward<Args>(args)...);
- scene->addItem(res);
- return res;
}
-template <typename T, class... Args>
-std::unique_ptr<T> createItemPtr(QGraphicsScene *scene, Args&&... args)
+template <typename Node>
+void HideableQSGNode<Node>::setVisible(bool visible)
{
- return std::unique_ptr<T>(createItem<T>(scene, std::forward<Args>(args)...));
+ hidden = !visible;
+ Node::markDirty(QSGNode::DirtySubtreeBlocked);
}
#endif