File indexing completed on 2024-05-19 15:09:25

0001 /*
0002     This file is part of the KDE project
0003 
0004     SPDX-FileCopyrightText: 2014 Fredrik Höglund <fredrik@kde.org>
0005     SPDX-FileCopyrightText: 2014 Marco Martin <mart@kde.org>
0006 
0007     SPDX-License-Identifier: LGPL-2.0-or-later
0008 */
0009 
0010 #ifndef PLASMA_PLOTTER_H
0011 #define PLASMA_PLOTTER_H
0012 
0013 #include <epoxy/gl.h>
0014 
0015 // qopengl.h declares GLdouble as a typedef of float when Qt is built
0016 // with GLES support.  This conflicts with the epoxy/gl_generated.h
0017 // declaration, so we have to prevent the Qt header from being #included.
0018 #define QOPENGL_H
0019 
0020 #ifndef QOPENGLF_APIENTRY
0021 #define QOPENGLF_APIENTRY GLAPIENTRY
0022 #endif
0023 
0024 #ifndef QOPENGLF_APIENTRYP
0025 #define QOPENGLF_APIENTRYP GLAPIENTRYP
0026 #endif
0027 
0028 #include <QMutex>
0029 #include <QPointer>
0030 #include <QQmlListProperty>
0031 #include <QQuickItem>
0032 #include <QQuickWindow>
0033 
0034 class PlotSGNode;
0035 
0036 /**
0037  * a Plotter can draw a graph of values arriving from an arbitrary number of data sources
0038  * to show their evolution in time.
0039  * an example can be a plot of the network transfer speed or CPU temperature over time.
0040  * Multiple plots can be fitted in the same graph, either stacked or intersected.
0041  */
0042 class PlotData : public QObject
0043 {
0044     Q_OBJECT
0045     /**
0046      * text Label of the data set: note this is purely a model, it will need a Label somewhere to be actually painted
0047      */
0048     Q_PROPERTY(QString label READ label WRITE setLabel NOTIFY labelChanged)
0049 
0050     /**
0051      * Color to plot this data set
0052      */
0053     Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)
0054 
0055     /**
0056      * All the values currently in this data set
0057      */
0058     Q_PROPERTY(QList<qreal> values READ values NOTIFY valuesChanged)
0059 
0060     /**
0061      * Maximum value of this data set
0062      */
0063     Q_PROPERTY(qreal max READ max NOTIFY maxChanged)
0064 
0065     /**
0066      * Minimum value of this data set
0067      */
0068     Q_PROPERTY(qreal min READ min NOTIFY minChanged)
0069 
0070 public:
0071     PlotData(QObject *parent = nullptr);
0072 
0073     void setColor(const QColor &color);
0074     QColor color() const;
0075 
0076     void addSample(qreal value);
0077 
0078     QList<qreal> values() const;
0079 
0080     QVector<qreal> m_normalizedValues;
0081 
0082     qreal max() const;
0083     qreal min() const;
0084 
0085     void setSampleSize(int size);
0086 
0087     QString label() const;
0088     void setLabel(const QString &label);
0089 
0090 Q_SIGNALS:
0091     void colorChanged();
0092     void valuesChanged();
0093     void maxChanged();
0094     void minChanged();
0095     void labelChanged();
0096 
0097 private:
0098     QString m_label;
0099     QColor m_color;
0100     QList<qreal> m_values;
0101 
0102     qreal m_min;
0103     qreal m_max;
0104     int m_sampleSize;
0105 };
0106 
0107 class Plotter : public QQuickItem
0108 {
0109     Q_OBJECT
0110     Q_PROPERTY(QQmlListProperty<PlotData> dataSets READ dataSets)
0111 
0112     /**
0113      * maximum value among all graphs
0114      */
0115     Q_PROPERTY(qreal max READ max NOTIFY maxChanged)
0116 
0117     /**
0118      * minimum value among all graphs
0119      */
0120     Q_PROPERTY(qreal min READ min NOTIFY minChanged)
0121 
0122     /**
0123      * draw at most n samples, if new samples are pushed old values are started to be thrown away
0124      */
0125     Q_PROPERTY(int sampleSize READ sampleSize WRITE setSampleSize NOTIFY sampleSizeChanged)
0126 
0127     /**
0128      * if true stack the graphs one on top of each other instead of just painting one on top of each other
0129      */
0130     Q_PROPERTY(bool stacked READ isStacked WRITE setStacked NOTIFY stackedChanged)
0131 
0132     /**
0133      * If true, the graph is automatically scaled to always fit in the Plotter area
0134      */
0135     Q_PROPERTY(bool autoRange READ isAutoRange WRITE setAutoRange NOTIFY autoRangeChanged)
0136 
0137     /**
0138      * Always represents the values scaled between this and rangeMin
0139      * If autoRange is true, this property just holds the minimum value
0140      */
0141     Q_PROPERTY(qreal rangeMax READ rangeMax WRITE setRangeMax NOTIFY rangeMaxChanged)
0142 
0143     /**
0144      * Always represents the values scaled between this and rangeMax
0145      * If autoRange is true, this property just holds the maximum value
0146      */
0147     Q_PROPERTY(qreal rangeMin READ rangeMin WRITE setRangeMin NOTIFY rangeMinChanged)
0148 
0149     /**
0150      * Color of the grid lines
0151      */
0152     Q_PROPERTY(QColor gridColor READ gridColor WRITE setGridColor NOTIFY gridColorChanged)
0153 
0154     /**
0155      * The number of horizontal lines drawn across the view between 0 and rangeMax at the top of the plotter at rangeMax
0156      * This does not include the bottom line
0157      * Setting this to 0 will disable grid lines
0158      *
0159      * The default value is 5
0160      */
0161     Q_PROPERTY(int horizontalGridLineCount READ horizontalGridLineCount WRITE setHorizontalGridLineCount NOTIFY horizontalGridLineCountChanged)
0162 
0163     // Q_CLASSINFO("DefaultProperty", "dataSets")
0164 
0165 public:
0166     Plotter(QQuickItem *parent = nullptr);
0167     ~Plotter() override;
0168 
0169     qreal max() const;
0170     qreal min() const;
0171 
0172     int sampleSize() const;
0173     void setSampleSize(int size);
0174 
0175     bool isStacked() const;
0176     void setStacked(bool stacked);
0177 
0178     bool isAutoRange() const;
0179     void setAutoRange(bool autorange);
0180 
0181     qreal rangeMax() const;
0182     void setRangeMax(qreal max);
0183 
0184     qreal rangeMin() const;
0185     void setRangeMin(qreal min);
0186 
0187     void setHorizontalGridLineCount(int count);
0188     int horizontalGridLineCount();
0189 
0190     void setGridColor(const QColor &color);
0191     QColor gridColor() const;
0192 
0193     QQmlListProperty<PlotData> dataSets();
0194     static void dataSet_append(QQmlListProperty<PlotData> *list, PlotData *item);
0195     static int dataSet_count(QQmlListProperty<PlotData> *list);
0196     static PlotData *dataSet_at(QQmlListProperty<PlotData> *list, int pos);
0197     static void dataSet_clear(QQmlListProperty<PlotData> *list);
0198 
0199     Q_INVOKABLE void addSample(qreal value);
0200     Q_INVOKABLE void addSample(const QList<qreal> &value);
0201 
0202 protected:
0203     void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) override;
0204 
0205 private:
0206     QSGNode *updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *updatePaintNodeData) override final;
0207     QPainterPath interpolate(const QVector<qreal> &p, qreal x0, qreal x1) const;
0208     void normalizeData();
0209 
0210 Q_SIGNALS:
0211     void maxChanged();
0212     void minChanged();
0213     void sampleSizeChanged();
0214     void stackedChanged();
0215     void autoRangeChanged();
0216     void rangeMaxChanged();
0217     void rangeMinChanged();
0218     void gridColorChanged();
0219     void horizontalGridLineCountChanged();
0220 
0221 private Q_SLOTS:
0222     void render();
0223 
0224 private:
0225     QList<PlotData *> m_plotData;
0226 
0227     GLuint m_fbo = 0;
0228     PlotSGNode *m_node = nullptr;
0229     qreal m_min;
0230     qreal m_max;
0231     qreal m_rangeMax;
0232     qreal m_rangeMin;
0233     int m_sampleSize;
0234     int m_horizontalLineCount;
0235     bool m_stacked;
0236     bool m_autoRange;
0237     QColor m_gridColor;
0238 
0239     QMatrix4x4 m_matrix;
0240     bool m_initialized = false;
0241     bool m_haveMSAA;
0242     bool m_haveFramebufferBlit;
0243     bool m_haveInternalFormatQuery;
0244     GLenum m_internalFormat;
0245     int m_samples;
0246     QPointer<QQuickWindow> m_window;
0247     QMutex m_mutex;
0248 };
0249 
0250 #endif