From 72fc47e003740554a3421b9945a38a234a2832d1 Mon Sep 17 00:00:00 2001 From: Kristian Bendiksen Date: Mon, 7 Mar 2022 13:47:56 +0100 Subject: [PATCH] #8452 QtCharts: Add fill color and pattern --- .../RimPlotCurveAppearance.cpp | 2 + .../UserInterface/RiuQtChartsPlotCurve.cpp | 108 +++++++++++++++--- .../UserInterface/RiuQtChartsPlotCurve.h | 6 + .../UserInterface/RiuQtChartsPlotWidget.cpp | 16 +++ .../UserInterface/RiuQtChartsPlotWidget.h | 5 +- 5 files changed, 118 insertions(+), 19 deletions(-) diff --git a/ApplicationLibCode/ProjectDataModel/RimPlotCurveAppearance.cpp b/ApplicationLibCode/ProjectDataModel/RimPlotCurveAppearance.cpp index 17161f0231..62d84becd4 100644 --- a/ApplicationLibCode/ProjectDataModel/RimPlotCurveAppearance.cpp +++ b/ApplicationLibCode/ProjectDataModel/RimPlotCurveAppearance.cpp @@ -69,6 +69,7 @@ void RimPlotCurveAppearance::FillStyle::setUp() addItem( Qt::BDiagPattern, "DIAG_FILL", "Diagonal Lines" ); addItem( Qt::CrossPattern, "CROSS_FILL", "Mesh" ); addItem( Qt::DiagCrossPattern, "DIAG_CROSS_FILL", "Diagonal Mesh" ); + setDefault( Qt::NoBrush ); } } // namespace caf @@ -386,6 +387,7 @@ void RimPlotCurveAppearance::resetAppearance() setLineStyle( RiuQwtPlotCurveDefines::LineStyleEnum::STYLE_SOLID ); setSymbol( RiuPlotCurveSymbol::SYMBOL_NONE ); setSymbolSkipDistance( 10 ); + setFillStyle( Qt::NoBrush ); } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationLibCode/UserInterface/RiuQtChartsPlotCurve.cpp b/ApplicationLibCode/UserInterface/RiuQtChartsPlotCurve.cpp index 2e0620d7d1..8916f6d8c4 100644 --- a/ApplicationLibCode/UserInterface/RiuQtChartsPlotCurve.cpp +++ b/ApplicationLibCode/UserInterface/RiuQtChartsPlotCurve.cpp @@ -44,11 +44,16 @@ RiuQtChartsPlotCurve::RiuQtChartsPlotCurve( RimPlotCurve* ownerRimCurve, const Q m_lineSeries = new QtCharts::QLineSeries(); m_lineSeries->setName( title ); + m_areaSeries = new QtCharts::QAreaSeries(); + m_areaSeries->setName( title ); + m_scatterSeries = new QtCharts::QScatterSeries(); m_scatterSeries->setName( title ); m_axisX = RiuPlotAxis::defaultBottom(); m_axisY = RiuPlotAxis::defaultLeft(); + + m_isVisibleInLegend = false; } //-------------------------------------------------------------------------------------------------- @@ -69,6 +74,15 @@ RiuQtChartsPlotCurve::~RiuQtChartsPlotCurve() delete line; } + auto* area = areaSeries(); + if ( area ) + { + m_plotWidget->qtChart()->removeSeries( area ); + + // removeSeries() releases chart ownership of the data, delete data to avoid memory leak + delete area; + } + auto* scatter = scatterSeries(); if ( scatter ) { @@ -83,6 +97,9 @@ RiuQtChartsPlotCurve::~RiuQtChartsPlotCurve() delete m_lineSeries; m_lineSeries = nullptr; + delete m_areaSeries; + m_areaSeries = nullptr; + delete m_scatterSeries; m_scatterSeries = nullptr; } @@ -95,6 +112,7 @@ void RiuQtChartsPlotCurve::setTitle( const QString& title ) if ( !isQtChartObjectsPresent() ) return; lineSeries()->setName( title ); + areaSeries()->setName( title ); scatterSeries()->setName( title ); } @@ -117,6 +135,22 @@ void RiuQtChartsPlotCurve::setAppearance( RiuQwtPlotCurveDefines::LineStyleEnum lineSeries()->setPen( curvePen ); lineSeries()->setBrush( fillBrush ); + + areaSeries()->setPen( curvePen ); + areaSeries()->setBrush( fillBrush ); + + if ( fillBrush.style() == Qt::NoBrush ) + { + lineSeries()->show(); + areaSeries()->hide(); + setVisibleInLegend( m_isVisibleInLegend ); + } + else + { + lineSeries()->hide(); + areaSeries()->show(); + setVisibleInLegend( m_isVisibleInLegend ); + } } //-------------------------------------------------------------------------------------------------- @@ -127,6 +161,7 @@ void RiuQtChartsPlotCurve::setBrush( const QBrush& brush ) if ( !isQtChartObjectsPresent() ) return; lineSeries()->setBrush( brush ); + areaSeries()->setBrush( brush ); } //-------------------------------------------------------------------------------------------------- @@ -141,16 +176,19 @@ void RiuQtChartsPlotCurve::attachToPlot( RiuPlotWidget* plotWidget ) { m_plotWidget->qtChart()->legend()->setMarkerShape( QtCharts::QLegend::MarkerShape::MarkerShapeFromSeries ); setVisibleInLegend( true ); + lineSeries()->show(); } else { if ( !m_lineSeries ) m_lineSeries = new QtCharts::QLineSeries(); + if ( !m_areaSeries ) m_areaSeries = new QtCharts::QAreaSeries(); if ( !m_scatterSeries ) m_scatterSeries = new QtCharts::QScatterSeries(); - m_plotWidget->attach( this, m_lineSeries, m_scatterSeries, m_axisX, m_axisY ); + m_plotWidget->attach( this, m_lineSeries, m_areaSeries, m_scatterSeries, m_axisX, m_axisY ); // Plot widget takes ownership. m_lineSeries = nullptr; + m_areaSeries = nullptr; m_scatterSeries = nullptr; } @@ -181,6 +219,12 @@ void RiuQtChartsPlotCurve::detach() line->hide(); } + QtCharts::QAreaSeries* area = areaSeries(); + if ( area ) + { + area->hide(); + } + if ( scatterSeries() ) { scatterSeries()->hide(); @@ -210,8 +254,6 @@ void RiuQtChartsPlotCurve::setSamplesInPlot( const std::vector& xValues, CAF_ASSERT( xValues.size() == yValues.size() ); - QtCharts::QLineSeries* line = lineSeries(); - QVector values( static_cast( xValues.size() ) ); for ( int i = 0; i < static_cast( xValues.size() ); i++ ) @@ -219,8 +261,13 @@ void RiuQtChartsPlotCurve::setSamplesInPlot( const std::vector& xValues, values[i] = QPointF( xValues[i], yValues[i] ); } + QtCharts::QLineSeries* line = lineSeries(); line->replace( values ); + QtCharts::QLineSeries* upper = new QtCharts::QLineSeries; + upper->replace( values ); + areaSeries()->setUpperSeries( upper ); + updateScatterSeries(); } @@ -344,6 +391,7 @@ void RiuQtChartsPlotCurve::setXAxis( RiuPlotAxis axis ) if ( m_plotWidget ) { m_plotWidget->setXAxis( axis, lineSeries(), this ); + m_plotWidget->setXAxis( axis, areaSeries(), this ); m_plotWidget->setXAxis( axis, scatterSeries(), this ); } } @@ -357,6 +405,7 @@ void RiuQtChartsPlotCurve::setYAxis( RiuPlotAxis axis ) if ( m_plotWidget ) { m_plotWidget->setYAxis( axis, lineSeries(), this ); + m_plotWidget->setYAxis( axis, areaSeries(), this ); m_plotWidget->setYAxis( axis, scatterSeries(), this ); } } @@ -428,23 +477,21 @@ void RiuQtChartsPlotCurve::setVisibleInLegend( bool isVisibleInLegend ) if ( !m_plotWidget->qtChart()->legend()->isAttachedToChart() ) isVisibleInLegend = false; if ( !m_plotWidget->qtChart()->legend()->isVisible() ) isVisibleInLegend = false; - bool showScatterMarker = isVisibleInLegend; - if ( !m_symbol ) showScatterMarker = false; + bool showScatterMarker = isVisibleInLegend && m_symbol; + bool showLineMarker = isVisibleInLegend && !m_symbol; - if ( scatterSeries() ) - { - auto markers = m_plotWidget->qtChart()->legend()->markers( scatterSeries() ); - if ( !markers.isEmpty() ) markers[0]->setVisible( showScatterMarker ); - } + auto setLegendVisibility = [this]( auto series, bool isVisible ) { + if ( series ) + { + auto markers = m_plotWidget->qtChart()->legend()->markers( series ); + if ( !markers.isEmpty() ) markers[0]->setVisible( isVisible ); + } + }; - bool showLineMarker = isVisibleInLegend; - if ( showScatterMarker ) showLineMarker = false; - - if ( lineSeries() ) - { - auto lineSeriesMarkers = m_plotWidget->qtChart()->legend()->markers( lineSeries() ); - if ( !lineSeriesMarkers.isEmpty() ) lineSeriesMarkers[0]->setVisible( showLineMarker ); - } + m_isVisibleInLegend = showLineMarker || showScatterMarker; + setLegendVisibility( lineSeries(), showLineMarker ); + setLegendVisibility( areaSeries(), false ); + setLegendVisibility( scatterSeries(), showScatterMarker ); } //-------------------------------------------------------------------------------------------------- @@ -469,6 +516,17 @@ QtCharts::QScatterSeries* RiuQtChartsPlotCurve::scatterSeries() const return nullptr; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QtCharts::QAreaSeries* RiuQtChartsPlotCurve::areaSeries() const +{ + if ( m_areaSeries ) return m_areaSeries; + if ( m_plotWidget ) return dynamic_cast( m_plotWidget->getAreaSeries( this ) ); + + return nullptr; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -484,15 +542,29 @@ void RiuQtChartsPlotCurve::setSymbol( RiuPlotCurveSymbol* symbol ) { qtChartsSymbol->applyToScatterSeries( scatterSeries() ); updateScatterSeries(); + updateLineAndAreaSeries(); } } else { m_symbol.reset(); if ( scatterSeries() ) scatterSeries()->hide(); + updateLineAndAreaSeries(); } } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuQtChartsPlotCurve::updateLineAndAreaSeries() +{ + bool isFilled = areaSeries() && areaSeries()->brush().style() != Qt::NoBrush; + bool isLine = lineSeries() && lineSeries()->pen().style() != Qt::PenStyle::NoPen; + if ( areaSeries() ) areaSeries()->setVisible( isFilled ); + if ( lineSeries() ) lineSeries()->setVisible( isLine ); + setVisibleInLegend( m_isVisibleInLegend ); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationLibCode/UserInterface/RiuQtChartsPlotCurve.h b/ApplicationLibCode/UserInterface/RiuQtChartsPlotCurve.h index e5d9115871..d42e86192e 100644 --- a/ApplicationLibCode/UserInterface/RiuQtChartsPlotCurve.h +++ b/ApplicationLibCode/UserInterface/RiuQtChartsPlotCurve.h @@ -23,6 +23,7 @@ #include "cvfBoundingBox.h" +#include #include #include @@ -76,6 +77,8 @@ public: void setSymbol( RiuPlotCurveSymbol* symbol ) override; + void updateLineAndAreaSeries(); + RiuPlotCurveSymbol* createSymbol( RiuPlotCurveSymbol::PointSymbolEnum symbol ) const override; void updateScatterSeries(); @@ -89,14 +92,17 @@ private: bool isQtChartObjectsPresent() const; QtCharts::QLineSeries* lineSeries() const; QtCharts::QScatterSeries* scatterSeries() const; + QtCharts::QAreaSeries* areaSeries() const; cvf::BoundingBox computeBoundingBox() const; private: QtCharts::QLineSeries* m_lineSeries; QtCharts::QScatterSeries* m_scatterSeries; + QtCharts::QAreaSeries* m_areaSeries; std::shared_ptr m_symbol; QPointer m_plotWidget; RiuPlotAxis m_axisX; RiuPlotAxis m_axisY; + bool m_isVisibleInLegend; }; diff --git a/ApplicationLibCode/UserInterface/RiuQtChartsPlotWidget.cpp b/ApplicationLibCode/UserInterface/RiuQtChartsPlotWidget.cpp index 015654a8c6..ba5f9572ee 100644 --- a/ApplicationLibCode/UserInterface/RiuQtChartsPlotWidget.cpp +++ b/ApplicationLibCode/UserInterface/RiuQtChartsPlotWidget.cpp @@ -828,6 +828,7 @@ QChart* RiuQtChartsPlotWidget::qtChart() //-------------------------------------------------------------------------------------------------- void RiuQtChartsPlotWidget::attach( RiuPlotCurve* plotCurve, QAbstractSeries* lineSeries, + QAbstractSeries* areaSeries, QAbstractSeries* scatterSeries, RiuPlotAxis xAxis, RiuPlotAxis yAxis ) @@ -849,6 +850,7 @@ void RiuQtChartsPlotWidget::attach( RiuPlotCurve* plotCurve, auto qtChartsPlotCurve = dynamic_cast( plotCurve ); addToChart( m_lineSeriesMap, plotCurve, lineSeries, xAxis, yAxis, qtChartsPlotCurve ); + addToChart( m_areaSeriesMap, plotCurve, areaSeries, xAxis, yAxis, qtChartsPlotCurve ); addToChart( m_scatterSeriesMap, plotCurve, scatterSeries, xAxis, yAxis, qtChartsPlotCurve ); } @@ -858,6 +860,7 @@ void RiuQtChartsPlotWidget::attach( RiuPlotCurve* plotCurve, void RiuQtChartsPlotWidget::detach( RiuPlotCurve* plotCurve ) { m_lineSeriesMap.erase( plotCurve ); + m_areaSeriesMap.erase( plotCurve ); m_scatterSeriesMap.erase( plotCurve ); } @@ -873,6 +876,18 @@ QAbstractSeries* RiuQtChartsPlotWidget::getLineSeries( const RiuPlotCurve* plotC return nullptr; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QAbstractSeries* RiuQtChartsPlotWidget::getAreaSeries( const RiuPlotCurve* plotCurve ) const +{ + auto series = m_areaSeriesMap.find( const_cast( plotCurve ) ); + if ( series != m_areaSeriesMap.end() ) + return series->second; + else + return nullptr; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -895,6 +910,7 @@ void RiuQtChartsPlotWidget::detachItems( RiuPlotWidget::PlotItemType plotItemTyp if ( plotItemType == RiuPlotWidget::PlotItemType::CURVE ) { m_lineSeriesMap.clear(); + m_areaSeriesMap.clear(); m_scatterSeriesMap.clear(); qtChart()->removeAllSeries(); } diff --git a/ApplicationLibCode/UserInterface/RiuQtChartsPlotWidget.h b/ApplicationLibCode/UserInterface/RiuQtChartsPlotWidget.h index aaf51aac69..7c654f288c 100644 --- a/ApplicationLibCode/UserInterface/RiuQtChartsPlotWidget.h +++ b/ApplicationLibCode/UserInterface/RiuQtChartsPlotWidget.h @@ -161,13 +161,15 @@ public: QtCharts::QChart* qtChart(); void attach( RiuPlotCurve* plotCurve, - QtCharts::QAbstractSeries* lineseries, + QtCharts::QAbstractSeries* lineSeries, + QtCharts::QAbstractSeries* areaSeries, QtCharts::QAbstractSeries* scatterSeries, RiuPlotAxis xAxis, RiuPlotAxis yAxis ); void detach( RiuPlotCurve* plotCurve ); QtCharts::QAbstractSeries* getLineSeries( const RiuPlotCurve* plotCurve ) const; + QtCharts::QAbstractSeries* getAreaSeries( const RiuPlotCurve* plotCurve ) const; QtCharts::QAbstractSeries* getScatterSeries( const RiuPlotCurve* plotCurve ) const; void setXAxis( RiuPlotAxis axis, QtCharts::QAbstractSeries* series, RiuQtChartsPlotCurve* plotCurve ); @@ -235,6 +237,7 @@ private: std::map m_axesAutoScale; std::map m_lineSeriesMap; + std::map m_areaSeriesMap; std::map m_scatterSeriesMap; RiuQwtDateScaleWrapper* m_dateScaleWrapper;