summaryrefslogtreecommitdiffstats
path: root/stats/statshelper.h
diff options
context:
space:
mode:
Diffstat (limited to 'stats/statshelper.h')
-rw-r--r--stats/statshelper.h79
1 files changed, 79 insertions, 0 deletions
diff --git a/stats/statshelper.h b/stats/statshelper.h
index 0ea39763d..29dc083a4 100644
--- a/stats/statshelper.h
+++ b/stats/statshelper.h
@@ -4,9 +4,11 @@
// is for historical reasons to ease transition from QtCharts
// and might be removed.
#ifndef STATSHELPER_H
+#define STATSHELPER_H
#include <memory>
#include <QGraphicsScene>
+#include <QSGNode>
template <typename T, class... Args>
T *createItem(QGraphicsScene *scene, Args&&... args)
@@ -22,4 +24,81 @@ std::unique_ptr<T> createItemPtr(QGraphicsScene *scene, Args&&... args)
return std::unique_ptr<T>(createItem<T>(scene, std::forward<Args>(args)...));
}
+// 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)
+{
+}
+
+template <typename Node>
+void HideableQSGNode<Node>::setVisible(bool visible)
+{
+ hidden = !visible;
+}
+
#endif