diff options
-rw-r--r-- | stats/chartitem.cpp | 15 | ||||
-rw-r--r-- | stats/chartitem.h | 5 | ||||
-rw-r--r-- | stats/statsview.cpp | 58 | ||||
-rw-r--r-- | stats/statsview.h | 7 |
4 files changed, 49 insertions, 36 deletions
diff --git a/stats/chartitem.cpp b/stats/chartitem.cpp index 6fef5e44f..aeb395d41 100644 --- a/stats/chartitem.cpp +++ b/stats/chartitem.cpp @@ -14,13 +14,15 @@ static int round_up(double f) } ChartItem::ChartItem(StatsView &v, ChartZValue z) : - dirty(false), zValue(z), view(v) + dirty(false), dirtyPrev(nullptr), dirtyNext(nullptr), + zValue(z), view(v) { } ChartItem::~ChartItem() { - view.unregisterChartItem(this); + if (dirty) + view.unregisterDirtyChartItem(*this); } QSizeF ChartItem::sceneSize() const @@ -41,19 +43,17 @@ ChartPixmapItem::~ChartPixmapItem() void ChartPixmapItem::setTextureDirty() { textureDirty = true; - dirty = true; + view.registerDirtyChartItem(*this); } void ChartPixmapItem::setPositionDirty() { positionDirty = true; - dirty = true; + view.registerDirtyChartItem(*this); } void ChartPixmapItem::render() { - if (!dirty) - return; if (!node) { node.reset(view.w()->createImageNode()); view.addQSGNode(node.get(), zValue); @@ -71,7 +71,6 @@ void ChartPixmapItem::render() node->setRect(rect); positionDirty = false; } - dirty = false; } void ChartPixmapItem::resize(QSizeF size) @@ -161,5 +160,5 @@ void ChartLineItem::setLine(QPointF fromIn, QPointF toIn) from = fromIn; to = toIn; positionDirty = true; - dirty = true; + view.registerDirtyChartItem(*this); } diff --git a/stats/chartitem.h b/stats/chartitem.h index 5dab8d1ea..f13cb3bc4 100644 --- a/stats/chartitem.h +++ b/stats/chartitem.h @@ -19,9 +19,10 @@ class ChartItem { public: ChartItem(StatsView &v, ChartZValue z); virtual ~ChartItem(); - virtual void render() = 0; // Only call on render thread! + virtual void render() = 0; // Only call on render thread! QRectF getRect() const; - bool dirty; // If true, call render() when rebuilding the scene + bool dirty; // If true, call render() when rebuilding the scene + ChartItem *dirtyPrev, *dirtyNext; // Double linked list of dirty items const ChartZValue zValue; protected: QSizeF sceneSize() const; diff --git a/stats/statsview.cpp b/stats/statsview.cpp index e893c3ebb..40d23eed3 100644 --- a/stats/statsview.cpp +++ b/stats/statsview.cpp @@ -36,9 +36,10 @@ StatsView::StatsView(QQuickItem *parent) : QQuickItem(parent), xAxis(nullptr), yAxis(nullptr), draggedItem(nullptr), - rootNode(nullptr) + rootNode(nullptr), + firstDirtyChartItem(nullptr), + lastDirtyChartItem(nullptr) { - chartItems.reset(new std::vector<ChartItem *>[(size_t)ChartZValue::Count]); setFlag(ItemHasContents, true); connect(&diveListNotifier, &DiveListNotifier::numShownChanged, this, &StatsView::replotIfVisible); @@ -124,11 +125,11 @@ QSGNode *StatsView::updatePaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNod plotAreaChanged(plotRect.size()); } - for (int i = 0; i < (int)ChartZValue::Count; ++i) { - for (ChartItem *item: chartItems[i]) { - if (item->dirty) - item->render(); - } + for (ChartItem *item = std::exchange(firstDirtyChartItem, nullptr); item; + item = std::exchange(item->dirtyNext, nullptr)) { + item->render(); + item->dirty = false; + item->dirtyPrev = nullptr; } img->fill(Qt::transparent); @@ -145,22 +146,34 @@ void StatsView::addQSGNode(QSGNode *node, ChartZValue z) rootNode->zNodes[idx]->appendChildNode(node); } -// Currently this does an inefficient linear search in the chart-item vector. -// However, we entertain one vector of items per Z-value and currently -// only the infobox is explicitly deleted, which has a unique Z-value. -void StatsView::unregisterChartItem(const ChartItem *item) +void StatsView::unregisterDirtyChartItem(ChartItem &item) { - int idx = std::clamp((int)item->zValue, 0, (int)ChartZValue::Count - 1); - std::vector<ChartItem *> &v = chartItems[idx]; - auto it = std::find(v.begin(), v.end(), item); - if (it != v.end()) - v.erase(it); + if (!item.dirty) + return; + if (item.dirtyNext) + item.dirtyNext->dirtyPrev = item.dirtyPrev; + else + lastDirtyChartItem = item.dirtyPrev; + if (item.dirtyPrev) + item.dirtyPrev->dirtyNext = item.dirtyNext; + else + firstDirtyChartItem = item.dirtyNext; + item.dirtyPrev = item.dirtyNext = nullptr; + item.dirty = false; } -void StatsView::registerChartItem(ChartItem *item) +void StatsView::registerDirtyChartItem(ChartItem &item) { - int idx = std::clamp((int)item->zValue, 0, (int)ChartZValue::Count - 1); - chartItems[idx].push_back(item); + if (item.dirty) + return; + if (!firstDirtyChartItem) { + firstDirtyChartItem = &item; + } else { + item.dirtyPrev = lastDirtyChartItem; + lastDirtyChartItem->dirtyNext = &item; + } + lastDirtyChartItem = &item; + item.dirty = true; } QQuickWindow *StatsView::w() const @@ -326,9 +339,10 @@ void StatsView::reset() highlightedSeries = nullptr; xAxis = yAxis = nullptr; draggedItem = nullptr; - if (rootNode) { - for (int i = 0; i < (int)ChartZValue::Count; ++i) - chartItems[i].clear(); // non-owning pointers + for (ChartItem *item = std::exchange(firstDirtyChartItem, nullptr); item; + item = std::exchange(item->dirtyNext, nullptr)) { + item->dirty = false; + item->dirtyPrev = nullptr; } legend.reset(); series.clear(); diff --git a/stats/statsview.h b/stats/statsview.h index c8e850d9b..f472e1e16 100644 --- a/stats/statsview.h +++ b/stats/statsview.h @@ -54,8 +54,8 @@ public: QQuickWindow *w() const; // Make window available to items QSizeF size() const; void addQSGNode(QSGNode *node, ChartZValue z); // Must only be called in render thread! - void registerChartItem(ChartItem *item); - void unregisterChartItem(const ChartItem *item); + void registerDirtyChartItem(ChartItem &item); + void unregisterDirtyChartItem(ChartItem &item); template <typename T, class... Args> std::unique_ptr<T> createChartItem(Args&&... args); @@ -142,7 +142,6 @@ private: StatsState state; QFont titleFont; - std::unique_ptr<std::vector<ChartItem *>[]> chartItems; std::vector<std::unique_ptr<StatsAxis>> axes; std::unique_ptr<StatsGrid> grid; std::vector<std::unique_ptr<StatsSeries>> series; @@ -162,6 +161,7 @@ private: void mouseReleaseEvent(QMouseEvent *event) override; void mouseMoveEvent(QMouseEvent *event) override; RootNode *rootNode; + ChartItem *firstDirtyChartItem, *lastDirtyChartItem; }; // This implementation detail must be known to users of the class. @@ -170,7 +170,6 @@ template <typename T, class... Args> std::unique_ptr<T> StatsView::createChartItem(Args&&... args) { std::unique_ptr<T> res(new T(*this, std::forward<Args>(args)...)); - registerChartItem(res.get()); return res; } |