summaryrefslogtreecommitdiffstats
path: root/stats/chartitem.cpp
diff options
context:
space:
mode:
authorGravatar Berthold Stoeger <bstoeger@mail.tuwien.ac.at>2021-01-12 15:20:05 +0100
committerGravatar bstoeger <32835590+bstoeger@users.noreply.github.com>2021-01-20 08:47:18 +0100
commit2b961414d7a52d442f5ecd8c2e42e43d044d0d5e (patch)
treeb1d6c47b94dfc80481aaad2e3cfde35335646576 /stats/chartitem.cpp
parent9be23b5f3f8373ba115f4e66e77c0537abe982b2 (diff)
downloadsubsurface-2b961414d7a52d442f5ecd8c2e42e43d044d0d5e.tar.gz
statistics: draw legend as a QSGNode
In order not to waste CPU by constantly rerendering the chart, we must use these weird OpenGL QSGNode things. The interface is appallingly low-level and unfriendly. As a first test, try to convert the legend. Create a wrapper class that represents a rectangular item with a texture and that will certainly need some (lots of) optimization. Make sure that all low-level QSG-objects are only accessed in the rendering thread. This means that the wrapper has to maintain a notion of "dirtiness" of the state. I.e. which part of the QSG-objects have to be modified. From the low-level wrapper derive a class that draws a rounded rectangle for every resize. The child class of that must then paint on the rectangle after every resize. That looks all not very fortunate, but it displays a legend and will make it possible to move the legend without and drawing operations, only shifting around an OpenGL surface. The render thread goes through all chart-items and rerenders them if dirty. Currently, on deletion of these items, this list is not reset. I.e. currently it is not supported to remove individual items. Only the full scene can be cleared! Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Diffstat (limited to 'stats/chartitem.cpp')
-rw-r--r--stats/chartitem.cpp107
1 files changed, 107 insertions, 0 deletions
diff --git a/stats/chartitem.cpp b/stats/chartitem.cpp
new file mode 100644
index 000000000..c0fc50841
--- /dev/null
+++ b/stats/chartitem.cpp
@@ -0,0 +1,107 @@
+// SPDX-License-Identifier: GPL-2.0
+#include "chartitem.h"
+#include "statsview.h"
+
+#include <cmath>
+#include <QQuickWindow>
+#include <QSGImageNode>
+#include <QSGTexture>
+
+static int round_up(double f)
+{
+ return static_cast<int>(ceil(f));
+}
+
+ChartItem::ChartItem(StatsView &v) :
+ dirty(false), view(v), positionDirty(false), textureDirty(false)
+{
+}
+
+ChartItem::~ChartItem()
+{
+ painter.reset(); // Make sure to destroy painter before image that is painted on
+ view.unregisterChartItem(this);
+}
+
+QSizeF ChartItem::sceneSize() const
+{
+ return view.size();
+}
+
+void ChartItem::setTextureDirty()
+{
+ textureDirty = true;
+ dirty = true;
+}
+
+void ChartItem::setPositionDirty()
+{
+ positionDirty = true;
+ dirty = true;
+}
+
+void ChartItem::render()
+{
+ if (!dirty)
+ return;
+ if (!node) {
+ node.reset(view.w()->createImageNode());
+ view.addQSGNode(node.get(), 0);
+ }
+ if (!img) {
+ resize(QSizeF(1,1));
+ img->fill(Qt::transparent);
+ }
+ if (textureDirty) {
+ texture.reset(view.w()->createTextureFromImage(*img, QQuickWindow::TextureHasAlphaChannel));
+ node->setTexture(texture.get());
+ textureDirty = false;
+ }
+ if (positionDirty) {
+ node->setRect(rect);
+ positionDirty = false;
+ }
+ dirty = false;
+}
+
+void ChartItem::resize(QSizeF size)
+{
+ painter.reset();
+ img.reset(new QImage(round_up(size.width()), round_up(size.height()), QImage::Format_ARGB32));
+ painter.reset(new QPainter(img.get()));
+ painter->setRenderHint(QPainter::Antialiasing);
+ rect.setSize(size);
+ setTextureDirty();
+}
+
+void ChartItem::setPos(QPointF pos)
+{
+ rect.moveTopLeft(pos);
+ setPositionDirty();
+}
+
+QRectF ChartItem::getRect() const
+{
+ return rect;
+}
+
+ChartRectItem::ChartRectItem(StatsView &v, const QPen &pen, const QBrush &brush, double radius) : ChartItem(v),
+ pen(pen), brush(brush), radius(radius)
+{
+}
+
+ChartRectItem::~ChartRectItem()
+{
+}
+
+void ChartRectItem::resize(QSizeF size)
+{
+ ChartItem::resize(size);
+ img->fill(Qt::transparent);
+ painter->setPen(pen);
+ painter->setBrush(brush);
+ QSize imgSize = img->size();
+ int width = pen.width();
+ QRect rect(width / 2, width / 2, imgSize.width() - width, imgSize.height() - width);
+ painter->drawRoundedRect(rect, radius, radius, Qt::AbsoluteSize);
+}