#8676 QtChart : Create curve legend widget for multiplot

This commit is contained in:
Magne Sjaastad 2022-03-23 13:07:08 +01:00
parent f45637b7f0
commit 696c6a15fa
14 changed files with 267 additions and 25 deletions

View File

@ -30,6 +30,8 @@
#include "cafPdmObject.h"
#include "qwt_legend_data.h"
namespace caf
{
template <>
@ -289,6 +291,14 @@ void RimPlot::handleDroppedObjects( const std::vector<caf::PdmObjectHandle*>& ob
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<RimPlotCurve*> RimPlot::visibleCurvesForLegend()
{
return {};
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------

View File

@ -35,6 +35,7 @@ class QWheelEvent;
class RiuPlotWidget;
class RiuPlotCurve;
class RiuPlotItem;
class RimPlotCurve;
//==================================================================================================
///
@ -101,6 +102,8 @@ public:
virtual caf::PdmObject* findPdmObjectFromPlotCurve( const RiuPlotCurve* curve ) const;
virtual void handleDroppedObjects( const std::vector<caf::PdmObjectHandle*>& objects );
virtual std::vector<RimPlotCurve*> visibleCurvesForLegend();
protected:
virtual RiuPlotWidget* doCreatePlotViewWidget( QWidget* parent ) = 0;

View File

@ -1789,6 +1789,34 @@ RimPlotAxisProperties* RimSummaryPlot::addNewAxisProperties( RiuPlotAxis plotAxi
return axisProperties;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<RimPlotCurve*> RimSummaryPlot::visibleCurvesForLegend()
{
std::vector<RimPlotCurve*> curves;
for ( auto c : summaryCurves() )
{
if ( !c->isCurveVisible() ) continue;
if ( !c->showInLegend() ) continue;
curves.push_back( c );
}
for ( auto curveSet : curveSets() )
{
if ( !curveSet->isCurvesVisible() ) continue;
if ( curveSet->colorMode() == RimEnsembleCurveSetColorManager::ColorMode::SINGLE_COLOR )
{
auto curveSetCurves = curveSet->curves();
if ( !curveSetCurves.empty() ) curves.push_back( curveSetCurves.front() );
}
}
return curves;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------

View File

@ -199,6 +199,8 @@ public:
RimPlotAxisProperties* addNewAxisProperties( RiaDefines::PlotAxis, const QString& name );
std::vector<RimPlotCurve*> visibleCurvesForLegend() override;
public:
// RimViewWindow overrides
void deleteViewWidget() override;

View File

@ -29,13 +29,16 @@
#include "RimContextCommandBuilder.h"
#include "RimMultiPlot.h"
#include "RimPlotCurve.h"
#include "RimWellLogTrack.h"
#include "RiuMainWindow.h"
#include "RiuPlotMainWindow.h"
#include "RiuPlotObjectPicker.h"
#include "RiuPlotWidget.h"
#include "RiuQtChartsPlotWidget.h"
#include "RiuQwtPlotLegend.h"
#include "RiuQwtPlotTools.h"
#include "RiuQwtPlotWidget.h"
#include "cafCmdFeatureMenuBuilder.h"
@ -176,6 +179,14 @@ void RiuMultiPlotPage::insertPlot( RiuPlotWidget* plotWidget, size_t index )
SIGNAL( legendDataChanged( const QVariant&, const QList<QwtLegendData>& ) ),
SLOT( updateLegend( const QVariant&, const QList<QwtLegendData>& ) ) );
}
else
{
auto qtchartPlotWidget = dynamic_cast<RiuQtChartsPlotWidget*>( plotWidget );
legend->connect( qtchartPlotWidget,
SIGNAL( legendDataChanged( const QList<QwtLegendData>& ) ),
SLOT( updateLegend( const QList<QwtLegendData>& ) ) );
}
QObject::connect( legend, SIGNAL( legendUpdated() ), this, SLOT( onLegendUpdated() ) );
legend->contentsWidget()->layout()->setAlignment( Qt::AlignBottom | Qt::AlignHCenter );

View File

@ -276,40 +276,48 @@ void RiuQtChartsPlotCurve::setSamplesInPlot( const std::vector<double>& xValues,
//--------------------------------------------------------------------------------------------------
void RiuQtChartsPlotCurve::updateScatterSeries()
{
if ( !scatterSeries() ) return;
double minX = std::numeric_limits<double>::max();
double maxX = -std::numeric_limits<double>::max();
QVector<QPointF> points = lineSeries()->pointsVector();
QVector<QPointF> points;
auto axes = lineSeries()->attachedAxes();
bool foundAxis = false;
for ( auto axis : axes )
if ( lineSeries() )
{
if ( axis->orientation() == Qt::Orientation::Horizontal )
points = lineSeries()->pointsVector();
bool foundAxis = false;
auto axes = lineSeries()->attachedAxes();
for ( auto axis : axes )
{
QtCharts::QValueAxis* valueAxis = dynamic_cast<QtCharts::QValueAxis*>( axis );
QtCharts::QDateTimeAxis* dateTimeAxis = dynamic_cast<QtCharts::QDateTimeAxis*>( axis );
if ( valueAxis )
if ( axis->orientation() == Qt::Orientation::Horizontal )
{
minX = valueAxis->min();
maxX = valueAxis->max();
foundAxis = true;
}
else if ( dateTimeAxis )
{
minX = dateTimeAxis->min().toMSecsSinceEpoch();
maxX = dateTimeAxis->max().toMSecsSinceEpoch();
foundAxis = true;
QtCharts::QValueAxis* valueAxis = dynamic_cast<QtCharts::QValueAxis*>( axis );
QtCharts::QDateTimeAxis* dateTimeAxis = dynamic_cast<QtCharts::QDateTimeAxis*>( axis );
if ( valueAxis )
{
minX = valueAxis->min();
maxX = valueAxis->max();
foundAxis = true;
}
else if ( dateTimeAxis )
{
minX = dateTimeAxis->min().toMSecsSinceEpoch();
maxX = dateTimeAxis->max().toMSecsSinceEpoch();
foundAxis = true;
}
}
}
}
if ( !foundAxis )
{
for ( auto p : points )
if ( !foundAxis )
{
minX = std::min( minX, p.x() );
maxX = std::max( maxX, p.x() );
for ( auto p : points )
{
minX = std::min( minX, p.x() );
maxX = std::max( maxX, p.x() );
}
}
}

View File

@ -138,6 +138,62 @@ void RiuQtChartsPlotCurveSymbol::applyToScatterSeries( QtCharts::QScatterSeries*
series->setColor( m_color );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QImage RiuQtChartsPlotCurveSymbol::image() const
{
if ( m_style == PointSymbolEnum::SYMBOL_NONE )
{
return QImage();
}
if ( m_style == PointSymbolEnum::SYMBOL_RECT )
{
return createRectImage();
}
else if ( m_style == PointSymbolEnum::SYMBOL_ELLIPSE )
{
return createEllipseImage();
}
else if ( m_style == PointSymbolEnum::SYMBOL_CROSS )
{
return createCrossImage();
}
else if ( m_style == PointSymbolEnum::SYMBOL_XCROSS )
{
return createXCrossImage();
}
else if ( m_style == PointSymbolEnum::SYMBOL_DIAMOND )
{
return createDiamondImage();
}
else if ( m_style == PointSymbolEnum::SYMBOL_HEXAGON )
{
return createHexagonImage();
}
else if ( m_style == PointSymbolEnum::SYMBOL_STAR1 )
{
return createStar1Image();
}
else if ( m_style == PointSymbolEnum::SYMBOL_STAR1 )
{
return createStar1Image();
}
else if ( m_style == PointSymbolEnum::SYMBOL_STAR2 )
{
return createStar2Image();
}
else if ( m_style == PointSymbolEnum::SYMBOL_TRIANGLE || m_style == PointSymbolEnum::SYMBOL_UP_TRIANGLE ||
m_style == PointSymbolEnum::SYMBOL_DOWN_TRIANGLE || m_style == PointSymbolEnum::SYMBOL_LEFT_TRIANGLE ||
m_style == PointSymbolEnum::SYMBOL_RIGHT_TRIANGLE )
{
return createTriangleImage( m_style );
}
return QImage();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------

View File

@ -60,6 +60,8 @@ public:
void applyToScatterSeries( QtCharts::QScatterSeries* series ) const;
QImage image() const;
private:
QImage createTriangleImage( RiuPlotCurveSymbol::PointSymbolEnum symbolStyle ) const;
QImage createRectImage() const;

View File

@ -34,6 +34,7 @@
#include "RiuQtChartsPlotCurve.h"
#include "RiuQtChartsToolTip.h"
#include "RiuQwtDateScaleWrapper.h"
#include "RiuQwtPlotTools.h"
#include "caf.h"
#include "cafAssert.h"
@ -333,6 +334,7 @@ void RiuQtChartsPlotWidget::clearLegend()
{
QLegend* legend = qtChart()->legend();
legend->detachFromChart();
legend->hide();
}
//--------------------------------------------------------------------------------------------------
@ -496,6 +498,11 @@ void RiuQtChartsPlotWidget::updateLayout()
void RiuQtChartsPlotWidget::updateLegend()
{
qtChart()->legend()->update();
auto curves = plotDefinition()->visibleCurvesForLegend();
auto legendData = RiuQwtPlotTools::createLegendData( curves );
emit legendDataChanged( legendData );
}
//--------------------------------------------------------------------------------------------------

View File

@ -28,6 +28,8 @@
#include "cafPdmObject.h"
#include "cafPdmPointer.h"
#include "qwt_legend_data.h"
#include <QPointer>
#include <set>
@ -219,6 +221,7 @@ protected:
signals:
void plotZoomed();
void legendDataChanged( const QList<QwtLegendData>& data );
private slots:
void axisRangeChanged();

View File

@ -18,6 +18,7 @@
#include "RiuQwtPlotLegend.h"
#include "qwt_dyngrid_layout.h"
#include "qwt_legend_label.h"
#include <QDebug>
#include <QResizeEvent>
@ -109,3 +110,28 @@ void RiuQwtPlotLegend::updateLegend( const QVariant& variant, const QList<QwtLeg
QwtLegend::updateLegend( variant, legendItems );
emit legendUpdated();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiuQwtPlotLegend::updateLegend( const QList<QwtLegendData>& legendData )
{
// Delete all existing widgets
deleteAll();
// Create legend widgets based on legendData
updateLegend( QVariant(), legendData );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiuQwtPlotLegend::deleteAll()
{
auto widgets = contentsWidget()->findChildren<QwtLegendLabel*>();
for ( auto w : widgets )
{
w->hide();
w->deleteLater();
}
}

View File

@ -28,10 +28,14 @@ public:
QSize sizeHint() const override;
public slots:
void updateLegend( const QVariant&, const QList<QwtLegendData>& ) override;
void updateLegend( const QList<QwtLegendData>& );
signals:
void legendUpdated();
private:
void deleteAll();
private:
int m_columnCount;
};

View File

@ -17,14 +17,21 @@
/////////////////////////////////////////////////////////////////////////////////
#include "RiuQwtPlotTools.h"
#include "RiuGuiTheme.h"
#include "RiaApplication.h"
#include "RiaColorTools.h"
#include "RiaPreferences.h"
#include "RiaQDateTimeTools.h"
#include "RimPlotCurve.h"
#include "RiuGuiTheme.h"
#include "RiuQtChartsPlotCurveSymbol.h"
#include "RiuQwtPlotLegend.h"
#include "qwt_date_scale_draw.h"
#include "qwt_date_scale_engine.h"
#include "qwt_graphic.h"
#include "qwt_painter.h"
#include "qwt_plot.h"
#include "qwt_plot_grid.h"
#include "qwt_plot_layout.h"
@ -32,6 +39,7 @@
#include "qwt_scale_widget.h"
#include <QRegExp>
#include <vector>
//--------------------------------------------------------------------------------------------------
@ -266,3 +274,71 @@ RiaDefines::PlotAxis RiuQwtPlotTools::fromQwtPlotAxis( QwtPlot::Axis axis )
return RiaDefines::PlotAxis::PLOT_AXIS_TOP;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiuQwtPlotTools::updateLegendData( RiuQwtPlotLegend* legend, const std::vector<RimPlotCurve*>& curves )
{
QList<QwtLegendData> legendDataList = createLegendData( curves );
legend->updateLegend( QVariant(), legendDataList );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QList<QwtLegendData> RiuQwtPlotTools::createLegendData( const std::vector<RimPlotCurve*>& curves )
{
QList<QwtLegendData> legendDataList;
for ( auto c : curves )
{
QwtLegendData test;
test.setValue( QwtLegendData::Role::TitleRole, c->curveName() );
c->updateUiIconFromPlotSymbol();
auto icon = c->uiIcon();
auto size = icon->availableSizes().first();
// see QwtPlotCurve::legendIcon
QwtGraphic graphic;
{
graphic.setDefaultSize( size );
graphic.setRenderHint( QwtGraphic::RenderPensUnscaled, true );
QPainter painter( &graphic );
painter.setRenderHint( QPainter::Antialiasing );
{
QPen pn;
pn.setCapStyle( Qt::FlatCap );
pn.setColor( RiaColorTools::toQColor( c->color() ) );
painter.setPen( pn );
const double y = 0.5 * size.height();
QwtPainter::drawLine( &painter, 0.0, y, size.width(), y );
}
if ( c->symbol() != RiuQtChartsPlotCurveSymbol::SYMBOL_NONE )
{
RiuQtChartsPlotCurveSymbol symbol( c->symbol() );
symbol.setSize( size.height() / 2, size.height() / 2 );
symbol.setColor( RiaColorTools::toQColor( c->color() ) );
auto image = symbol.image();
QPoint p( size.width() / 4, size.height() / 4 );
painter.drawImage( p, image );
}
}
QVariant v = QVariant::fromValue( graphic );
test.setValue( QwtLegendData::Role::IconRole, v );
legendDataList.push_back( test );
}
return legendDataList;
}

View File

@ -24,6 +24,9 @@
#include <qwt_plot.h>
#include <qwt_plot_shapeitem.h>
class RiuQwtPlotLegend;
class RimPlotCurve;
class RiuQwtPlotTools
{
public:
@ -61,6 +64,9 @@ public:
static QwtPlot::Axis toQwtPlotAxis( RiaDefines::PlotAxis );
static RiaDefines::PlotAxis fromQwtPlotAxis( QwtPlot::Axis );
static void updateLegendData( RiuQwtPlotLegend* legend, const std::vector<RimPlotCurve*>& curves );
static QList<QwtLegendData> createLegendData( const std::vector<RimPlotCurve*>& curves );
};
//--------------------------------------------------------------------------------------------------