diff --git a/stats/chartitem.cpp b/stats/chartitem.cpp index 77fc0eac4..034733188 100644 --- a/stats/chartitem.cpp +++ b/stats/chartitem.cpp @@ -19,7 +19,7 @@ static int round_up(double f) return static_cast(ceil(f)); } -ChartItem::ChartItem(StatsView &v, ChartZValue z) : +ChartItem::ChartItem(StatsView &v, size_t z) : dirty(false), prev(nullptr), next(nullptr), zValue(z), view(v) { @@ -42,7 +42,7 @@ void ChartItem::markDirty() view.registerDirtyChartItem(*this); } -ChartPixmapItem::ChartPixmapItem(StatsView &v, ChartZValue z) : HideableChartItem(v, z), +ChartPixmapItem::ChartPixmapItem(StatsView &v, size_t z) : HideableChartItem(v, z), positionDirty(false), textureDirty(false) { } @@ -111,7 +111,7 @@ QRectF ChartPixmapItem::getRect() const static const int scatterItemDiameter = 10; static const int scatterItemBorder = 1; -ChartScatterItem::ChartScatterItem(StatsView &v, ChartZValue z, const StatsTheme &theme, bool selected) : HideableChartItem(v, z), +ChartScatterItem::ChartScatterItem(StatsView &v, size_t z, const StatsTheme &theme, bool selected) : HideableChartItem(v, z), theme(theme), positionDirty(false), textureDirty(false), highlight(selected ? Highlight::Selected : Highlight::Unselected) @@ -214,7 +214,7 @@ QRectF ChartScatterItem::getRect() const return rect; } -ChartRectItem::ChartRectItem(StatsView &v, ChartZValue z, +ChartRectItem::ChartRectItem(StatsView &v, size_t z, const QPen &pen, const QBrush &brush, double radius) : ChartPixmapItem(v, z), pen(pen), brush(brush), radius(radius) { @@ -236,7 +236,7 @@ void ChartRectItem::resize(QSizeF size) painter->drawRoundedRect(rect, radius, radius, Qt::AbsoluteSize); } -ChartTextItem::ChartTextItem(StatsView &v, ChartZValue z, const QFont &f, const std::vector &text, bool center) : +ChartTextItem::ChartTextItem(StatsView &v, size_t z, const QFont &f, const std::vector &text, bool center) : ChartPixmapItem(v, z), f(f), center(center) { QFontMetrics fm(f); @@ -254,7 +254,7 @@ ChartTextItem::ChartTextItem(StatsView &v, ChartZValue z, const QFont &f, const resize(QSizeF(totalWidth, totalHeight)); } -ChartTextItem::ChartTextItem(StatsView &v, ChartZValue z, const QFont &f, const QString &text) : +ChartTextItem::ChartTextItem(StatsView &v, size_t z, const QFont &f, const QString &text) : ChartTextItem(v, z, f, std::vector({ text }), true) { } @@ -280,7 +280,7 @@ void ChartTextItem::setColor(const QColor &c, const QColor &background) setTextureDirty(); } -ChartPieItem::ChartPieItem(StatsView &v, ChartZValue z, const StatsTheme &theme, double borderWidth) : ChartPixmapItem(v, z), +ChartPieItem::ChartPieItem(StatsView &v, size_t z, const StatsTheme &theme, double borderWidth) : ChartPixmapItem(v, z), theme(theme), borderWidth(borderWidth) { @@ -322,7 +322,7 @@ void ChartPieItem::resize(QSizeF size) img->fill(Qt::transparent); } -ChartLineItemBase::ChartLineItemBase(StatsView &v, ChartZValue z, QColor color, double width) : HideableChartItem(v, z), +ChartLineItemBase::ChartLineItemBase(StatsView &v, size_t z, QColor color, double width) : HideableChartItem(v, z), color(color), width(width), positionDirty(false), materialDirty(false) { } @@ -416,7 +416,7 @@ void ChartRectLineItem::render() positionDirty = materialDirty = false; } -ChartBarItem::ChartBarItem(StatsView &v, ChartZValue z, const StatsTheme &theme, double borderWidth) : HideableChartItem(v, z), +ChartBarItem::ChartBarItem(StatsView &v, size_t z, const StatsTheme &theme, double borderWidth) : HideableChartItem(v, z), theme(theme), borderWidth(borderWidth), selected(false), positionDirty(false), colorDirty(false), selectedDirty(false) @@ -548,7 +548,7 @@ QRectF ChartBarItem::getRect() const return rect; } -ChartBoxItem::ChartBoxItem(StatsView &v, ChartZValue z, const StatsTheme &theme, double borderWidth) : +ChartBoxItem::ChartBoxItem(StatsView &v, size_t z, const StatsTheme &theme, double borderWidth) : ChartBarItem(v, z, theme, borderWidth) { } diff --git a/stats/chartitem.h b/stats/chartitem.h index 7baea1fe9..0e68fc920 100644 --- a/stats/chartitem.h +++ b/stats/chartitem.h @@ -18,7 +18,6 @@ class QSGTexture; class QSGTextureMaterial; class StatsTheme; class StatsView; -enum class ChartZValue : int; class ChartItem { public: @@ -26,10 +25,10 @@ public: virtual void render() = 0; bool dirty; // If true, call render() when rebuilding the scene ChartItem *prev, *next; // Double linked list of items - const ChartZValue zValue; + const size_t zValue; virtual ~ChartItem(); // Attention: must only be called by render thread. protected: - ChartItem(StatsView &v, ChartZValue z); + ChartItem(StatsView &v, size_t z); QSizeF sceneSize() const; StatsView &view; void markDirty(); @@ -38,7 +37,7 @@ protected: template class HideableChartItem : public ChartItem { protected: - HideableChartItem(StatsView &v, ChartZValue z); + HideableChartItem(StatsView &v, size_t z); std::unique_ptr node; bool visible; bool visibleChanged; @@ -56,7 +55,7 @@ using HideableChartProxyItem = HideableChartItem { public: - ChartPixmapItem(StatsView &v, ChartZValue z); + ChartPixmapItem(StatsView &v, size_t z); ~ChartPixmapItem(); void setPos(QPointF pos); @@ -78,7 +77,7 @@ private: // Draw a rectangular background after resize. Children are responsible for calling update(). class ChartRectItem : public ChartPixmapItem { public: - ChartRectItem(StatsView &v, ChartZValue z, const QPen &pen, const QBrush &brush, double radius); + ChartRectItem(StatsView &v, size_t z, const QPen &pen, const QBrush &brush, double radius); ~ChartRectItem(); void resize(QSizeF size); private: @@ -90,8 +89,8 @@ private: // Attention: text is only drawn after calling setColor()! class ChartTextItem : public ChartPixmapItem { public: - ChartTextItem(StatsView &v, ChartZValue z, const QFont &f, const std::vector &text, bool center); - ChartTextItem(StatsView &v, ChartZValue z, const QFont &f, const QString &text); + ChartTextItem(StatsView &v, size_t z, const QFont &f, const std::vector &text, bool center); + ChartTextItem(StatsView &v, size_t z, const QFont &f, const QString &text); void setColor(const QColor &color); // Draw on transparent background void setColor(const QColor &color, const QColor &background); // Fill rectangle with given background color private: @@ -108,7 +107,7 @@ private: // A pie chart item: draws disk segments onto a pixmap. class ChartPieItem : public ChartPixmapItem { public: - ChartPieItem(StatsView &v, ChartZValue z, const StatsTheme &theme, double borderWidth); + ChartPieItem(StatsView &v, size_t z, const StatsTheme &theme, double borderWidth); void drawSegment(double from, double to, QColor fill, QColor border, bool selected); // from and to are relative (0-1 is full disk). void resize(QSizeF size); // As in base class, but clears the canvas private: @@ -119,7 +118,7 @@ private: // Common data for line and rect items. Both are represented by two points. class ChartLineItemBase : public HideableChartItem> { public: - ChartLineItemBase(StatsView &v, ChartZValue z, QColor color, double width); + ChartLineItemBase(StatsView &v, size_t z, QColor color, double width); ~ChartLineItemBase(); void setLine(QPointF from, QPointF to); protected: @@ -148,7 +147,7 @@ public: // A bar in a bar chart: a rectangle bordered by lines. class ChartBarItem : public HideableChartProxyItem { public: - ChartBarItem(StatsView &v, ChartZValue z, const StatsTheme &theme, double borderWidth); + ChartBarItem(StatsView &v, size_t z, const StatsTheme &theme, double borderWidth); ~ChartBarItem(); void setColor(QColor color, QColor borderColor); void setRect(const QRectF &rect); @@ -178,7 +177,7 @@ private: // A box-and-whiskers item. This is a bit lazy: derive from the bar item and add whiskers. class ChartBoxItem : public ChartBarItem { public: - ChartBoxItem(StatsView &v, ChartZValue z, const StatsTheme &theme, double borderWidth); + ChartBoxItem(StatsView &v, size_t z, const StatsTheme &theme, double borderWidth); ~ChartBoxItem(); void setBox(const QRectF &rect, double min, double max, double median); // The rect describes Q1, Q3. QRectF getRect() const; // Note: this extends the center rectangle to include the whiskers. @@ -196,7 +195,7 @@ private: // scatter item here, but so it is for now. class ChartScatterItem : public HideableChartProxyItem { public: - ChartScatterItem(StatsView &v, ChartZValue z, const StatsTheme &theme, bool selected); + ChartScatterItem(StatsView &v, size_t z, const StatsTheme &theme, bool selected); ~ChartScatterItem(); // Currently, there is no highlighted and selected status. @@ -240,7 +239,7 @@ void HideableChartItem::createNode(Args&&... args) } template -HideableChartItem::HideableChartItem(StatsView &v, ChartZValue z) : ChartItem(v, z), +HideableChartItem::HideableChartItem(StatsView &v, size_t z) : ChartItem(v, z), visible(true), visibleChanged(false) { } diff --git a/stats/statsview.cpp b/stats/statsview.cpp index 130f3895a..1fd7866e7 100644 --- a/stats/statsview.cpp +++ b/stats/statsview.cpp @@ -21,7 +21,6 @@ #include "core/selection.h" #include "core/trip.h" -#include // for std::array #include #include #include @@ -35,6 +34,7 @@ static const double titleBorder = 2.0; // Border between title and chart static const double selectionLassoWidth = 2.0; // Border between title and chart StatsView::StatsView(QQuickItem *parent) : QQuickItem(parent), + maxZ(ChartZValue::Count), backgroundDirty(true), currentTheme(&getStatsTheme(false)), backgroundColor(currentTheme->backgroundColor), @@ -129,16 +129,18 @@ using ZNode = HideableQSGNode; class RootNode : public QSGNode { public: - RootNode(StatsView &view, QColor backgroundColor); + RootNode(StatsView &view, QColor backgroundColor, size_t maxZ); ~RootNode(); StatsView &view; std::unique_ptr backgroundNode; // solid background // We entertain one node per Z-level. - std::array, (size_t)ChartZValue::Count> zNodes; + std::vector> zNodes; }; -RootNode::RootNode(StatsView &view, QColor backgroundColor) : view(view) +RootNode::RootNode(StatsView &view, QColor backgroundColor, size_t maxZ) : view(view) { + zNodes.resize(maxZ); + // Add a background rectangle with a solid color. This could // also be done on the widget level, but would have to be done // separately for desktop and mobile, so do it here. @@ -172,7 +174,7 @@ QSGNode *StatsView::updatePaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNod // This is just a copy of what is found in Qt's documentation. RootNode *n = static_cast(oldNode); if (!n) - n = rootNode = new RootNode(*this, backgroundColor); + n = rootNode = new RootNode(*this, backgroundColor, maxZ); // Delete all chart items that are marked for deletion. freeDeletedChartItems(); @@ -217,9 +219,9 @@ void StatsView::emergencyShutdown() rootNode = nullptr; } -void StatsView::addQSGNode(QSGNode *node, ChartZValue z) +void StatsView::addQSGNode(QSGNode *node, size_t z) { - int idx = std::clamp((int)z, 0, (int)ChartZValue::Count - 1); + size_t idx = std::clamp(z, (size_t)0, maxZ); rootNode->zNodes[idx]->appendChildNode(node); } @@ -617,7 +619,7 @@ void StatsView::updateFeatures() // For labels, we are brutal: simply show/hide the whole z-level with the labels if (rootNode) - rootNode->zNodes[(int)ChartZValue::SeriesLabels]->setVisible(state.labels); + rootNode->zNodes[ChartZValue::SeriesLabels]->setVisible(state.labels); if (meanMarker) meanMarker->setVisible(state.mean); diff --git a/stats/statsview.h b/stats/statsview.h index a0a44bc89..a51bf9a53 100644 --- a/stats/statsview.h +++ b/stats/statsview.h @@ -34,7 +34,6 @@ class QSGTexture; class RootNode; // Internal implementation detail enum class ChartSubType : int; -enum class ChartZValue : int; enum class StatsOperation : int; enum class ChartSortMode : int; @@ -56,7 +55,7 @@ public: void setBackgroundColor(QColor color); // Chart must be replot for color to become effective. void setTheme(bool dark); // Chart must be replot for theme to become effective. const StatsTheme &getCurrentTheme() const; - void addQSGNode(QSGNode *node, ChartZValue z); // Must only be called in render thread! + void addQSGNode(QSGNode *node, size_t z); // Must only be called in render thread! void registerChartItem(ChartItem &item); void registerDirtyChartItem(ChartItem &item); void emergencyShutdown(); // Called when QQuick decides to delete our root node. @@ -76,6 +75,7 @@ private slots: void divesSelected(const QVector &dives); private: // QtQuick related things + size_t maxZ; bool backgroundDirty; QRectF plotRect; QSGNode *updatePaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *updatePaintNodeData) override; diff --git a/stats/zvalues.h b/stats/zvalues.h index dc84bdd99..39e0526a5 100644 --- a/stats/zvalues.h +++ b/stats/zvalues.h @@ -5,16 +5,21 @@ // drawn in order of addition to the scene. #ifndef ZVALUES_H -enum class ChartZValue { - Grid = 0, - Series, - Axes, - SeriesLabels, - ChartFeatures, // quartile markers and regression lines - Selection, - InformationBox, - Legend, - Count +// Encapsulating an enum in a struct is stupid, but allows us +// to not poison the namespace and yet autoconvert to int +// (in constrast to enum class). enum is so broken! +struct ChartZValue { + enum ZValues { + Grid = 0, + Series, + Axes, + SeriesLabels, + ChartFeatures, // quartile markers and regression lines + Selection, + InformationBox, + Legend, + Count + }; }; #endif