From d736a9eaf1d5f218630c34d91db52fde22e3746a Mon Sep 17 00:00:00 2001 From: Jussi Kuokkanen Date: Sat, 12 Aug 2023 20:46:35 +0300 Subject: [PATCH] draw filler lines in QGraphicsView::drawForeground Fixes segfaults and logic errors; simpler code --- src/tuxclocker-qt/widgets/DragChartView.cpp | 93 +++++++-------------- src/tuxclocker-qt/widgets/DragChartView.hpp | 6 +- 2 files changed, 31 insertions(+), 68 deletions(-) diff --git a/src/tuxclocker-qt/widgets/DragChartView.cpp b/src/tuxclocker-qt/widgets/DragChartView.cpp index 881a855..a0990be 100644 --- a/src/tuxclocker-qt/widgets/DragChartView.cpp +++ b/src/tuxclocker-qt/widgets/DragChartView.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -21,13 +22,6 @@ DragChartView::DragChartView(QWidget *parent) : QChartView(parent) { m_scatterPressed = false; - m_leftLineFillerItem = new QGraphicsLineItem; - m_rightLineFillerItem = new QGraphicsLineItem; - m_leftLineFillerItem->setPen(fillerLinePen()); - m_rightLineFillerItem->setPen(fillerLinePen()); - - chart()->scene()->addItem(m_leftLineFillerItem); - chart()->scene()->addItem(m_rightLineFillerItem); chart()->legend()->setVisible(false); m_chartMargin = m_series.markerSize() / 2; @@ -70,42 +64,6 @@ DragChartView::DragChartView(QWidget *parent) : QChartView(parent) { m_yAxis.blockSignals(false); }); - // Delete filler items when points are removed - connect(&m_series, &QScatterSeries::pointRemoved, [=]() { - chart()->scene()->removeItem(m_lineFillerItems.last()); - delete m_lineFillerItems.last(); - m_lineFillerItems.pop_back(); - drawFillerLines(&m_series); - }); - - // Add filler item when point is added - connect(&m_series, &QScatterSeries::pointAdded, [=]() { - if (m_series.pointsVector().length() < 2) - return; - - auto item = new QGraphicsLineItem; - item->setPen(fillerLinePen()); - m_lineFillerItems.append(item); - chart()->scene()->addItem(item); - drawFillerLines(&m_series); - }); - - connect(&m_series, &QScatterSeries::pointsReplaced, [=]() { - // Delete filler items - for (auto item : m_lineFillerItems) { - delete item; - } - m_lineFillerItems.clear(); - // Create new ones - for (int i = 0; i < m_series.pointsVector().length(); i++) { - auto item = new QGraphicsLineItem; - item->setPen(fillerLinePen()); - m_lineFillerItems.append(item); - chart()->scene()->addItem(item); - } - drawFillerLines(&m_series); - }); - connect(&m_series, &QScatterSeries::pressed, [=](QPointF point) { m_dragCanStart = true; m_latestScatterPoint = point; @@ -180,7 +138,6 @@ bool DragChartView::event(QEvent *event) { if (event->type() == QEvent::Resize || event->type() == QEvent::UpdateLater) { // Chart has a geometry when this is true - drawFillerLines(&m_series); } if (event->type() == QEvent::Leave && !m_dragActive) { @@ -267,8 +224,6 @@ void DragChartView::mouseMoveEvent(QMouseEvent *event) { } replaceMovedPoint(m_latestScatterPoint, point); } - - drawFillerLines(&m_series); } void DragChartView::mouseReleaseEvent(QMouseEvent *event) { @@ -277,7 +232,6 @@ void DragChartView::mouseReleaseEvent(QMouseEvent *event) { if (!m_scatterPressed && m_limitRect.contains(chart()->mapToValue(event->pos()))) { // Add a new point to series m_series.append(chart()->mapToValue(event->pos())); - drawFillerLines(&m_series); } m_toolTipLabel->hide(); @@ -304,8 +258,6 @@ void DragChartView::wheelEvent(QWheelEvent *event) { zoomX(factor); event->accept(); - drawFillerLines(&m_series); - QChartView::wheelEvent(event); } @@ -341,28 +293,43 @@ QVector DragChartView::sortPointFByAscendingX(const QVector po return sorted; } -void DragChartView::drawFillerLines(QScatterSeries *series) { - // TODO: line isn't drawn between points whose x is the same - // Sort points by ascending x - QVector sorted = sortPointFByAscendingX(series->pointsVector()); +void DragChartView::drawForeground(QPainter *painter, const QRectF &rect) { + auto points = sortPointFByAscendingX(m_series.pointsVector()); - if (sorted.isEmpty()) { + if (points.empty()) { + QChartView::drawForeground(painter, rect); return; } - for (int i = 0; i < sorted.length() - 1; i++) { - m_lineFillerItems[i]->setLine(QLineF( - chart()->mapToPosition(sorted[i]), chart()->mapToPosition(sorted[i + 1]))); + // TODO: filler line lingers around even without items, until the chart is updated + // Filler line between left edge and first point + auto first = chart()->mapToPosition(points.first()); + auto start = chart()->mapToPosition(QPointF{m_xAxis.min(), points.first().y()}); + + QPainterPath path; + path.moveTo(start); + path.lineTo(first); + + // Between points + if (points.length() > 1) { + for (auto &point : points) { + auto realPos = chart()->mapToPosition(point); + path.lineTo(realPos); + path.moveTo(realPos); + } } - m_leftLineFillerItem->setLine( - QLineF(chart()->mapToPosition(QPointF(m_xAxis.min(), sorted[0].y())), - chart()->mapToPosition(sorted[0]))); + // Last point -> right edge + auto last = chart()->mapToPosition(points.last()); + auto end = chart()->mapToPosition(QPointF{m_xAxis.max(), points.last().y()}); - m_rightLineFillerItem->setLine(QLineF(chart()->mapToPosition(sorted.last()), - chart()->mapToPosition(QPointF(m_xAxis.max(), sorted.last().y())))); + path.moveTo(last); + path.lineTo(end); - chart()->update(); + painter->setPen(fillerLinePen()); + painter->drawPath(path); + + QChartView::drawForeground(painter, rect); } bool DragChartView::eventFilter(QObject *obj, QEvent *event) { diff --git a/src/tuxclocker-qt/widgets/DragChartView.hpp b/src/tuxclocker-qt/widgets/DragChartView.hpp index 12f4c0d..b9ce527 100644 --- a/src/tuxclocker-qt/widgets/DragChartView.hpp +++ b/src/tuxclocker-qt/widgets/DragChartView.hpp @@ -19,6 +19,7 @@ public: void setRange(qreal xmin, qreal xmax, qreal ymin, qreal ymax); protected: bool event(QEvent *); + void drawForeground(QPainter *, const QRectF &) override; void mousePressEvent(QMouseEvent *); void mouseMoveEvent(QMouseEvent *); void mouseReleaseEvent(QMouseEvent *); @@ -50,7 +51,6 @@ private: bool m_scatterPressed; // For detecting if mouse release should delete or add a new point QVector sortPointFByAscendingX(const QVector points); - void drawFillerLines(QScatterSeries *series); void zoomX(qreal); QLabel *m_toolTipLabel; @@ -60,9 +60,5 @@ private: bool m_dragActive; QPointF m_latestScatterPoint; void replaceMovedPoint(const QPointF old, const QPointF new_); - QVector - m_lineFillerItems; // Filler lines between points whose amount is n - 1 for nonzero n - QGraphicsLineItem *m_leftLineFillerItem; - QGraphicsLineItem *m_rightLineFillerItem; QValueAxis m_xAxis, m_yAxis; };