diff options
Diffstat (limited to 'stats/statshelper.h')
-rw-r--r-- | stats/statshelper.h | 79 |
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 |