///////////////////////////////////////////////////////////////////////////////// // // Copyright (C) 2019- Equinor ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. // // See the GNU General Public License at // for more details. // ///////////////////////////////////////////////////////////////////////////////// #include "RiuQwtPlotTools.h" #include "RiaApplication.h" #include "RiaColorTools.h" #include "RiaPreferences.h" #include "RiaQDateTimeTools.h" #include "RiuPlotAxis.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" #include "qwt_plot_shapeitem.h" #include "qwt_scale_widget.h" #include "qwt_axis.h" #include #include //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RiuQwtPlotTools::setCommonPlotBehaviour( QwtPlot* plot ) { // Plot background and frame look QPalette newPalette( plot->palette() ); newPalette.setColor( QPalette::Window, Qt::white ); plot->setPalette( newPalette ); plot->setAutoFillBackground( true ); plot->setCanvasBackground( Qt::white ); plot->plotLayout()->setCanvasMargin( 0, -1 ); QFrame* canvasFrame = dynamic_cast( plot->canvas() ); canvasFrame->setFrameShape( QFrame::Box ); // Grid QwtPlotGrid* grid = new QwtPlotGrid; grid->attach( plot ); QPen gridPen( Qt::SolidLine ); grid->setPen( gridPen ); RiuGuiTheme::styleQwtItem( grid ); // Axis number font int axisFontSize = caf::FontTools::absolutePointSize( RiaPreferences::current()->defaultPlotFontSize(), caf::FontTools::RelativeSize::Medium ); QFont axisFont = plot->axisFont( QwtAxis::XBottom ); axisFont.setPixelSize( caf::FontTools::pointSizeToPixelSize( axisFontSize ) ); plot->setAxisFont( QwtAxis::XBottom, axisFont ); plot->setAxisFont( QwtAxis::XTop, axisFont ); plot->setAxisFont( QwtAxis::YLeft, axisFont ); plot->setAxisFont( QwtAxis::YRight, axisFont ); // Axis title font std::vector axes = { QwtAxis::XBottom, QwtAxis::XTop, QwtAxis::YLeft, QwtAxis::YRight }; for ( QwtAxis::Position axis : axes ) { QwtText axisTitle = plot->axisTitle( axis ); QFont axisTitleFont = axisTitle.font(); axisTitleFont.setPixelSize( caf::FontTools::pointSizeToPixelSize( axisFontSize ) ); axisTitleFont.setBold( false ); axisTitle.setFont( axisTitleFont ); axisTitle.setRenderFlags( Qt::AlignRight ); plot->setAxisTitle( axis, axisTitle ); } // Set a focus policy to allow it taking key press events. // This is not strictly necessary since this widget inherit QwtPlot // which already has a focus policy. // However, for completeness we still do it here. plot->setFocusPolicy( Qt::WheelFocus ); // Enable mousetracking and event filter plot->canvas()->setMouseTracking( true ); plot->plotLayout()->setAlignCanvasToScales( true ); plot->setContentsMargins( 1, 1, 1, 1 ); // Store the pointer address as an object name. This way each plot can be identified uniquely for CSS-stylesheets QString objectName = QString( "%1" ).arg( reinterpret_cast( plot ) ); plot->setObjectName( objectName ); QString canvasName = QString( "%1" ).arg( reinterpret_cast( plot->canvas() ) ); plot->canvas()->setObjectName( canvasName ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RiuQwtPlotTools::setDefaultAxes( QwtPlot* plot ) { plot->setAxesCount( QwtAxis::XBottom, 1 ); plot->setAxesCount( QwtAxis::YLeft, 1 ); plot->axisWidget( QwtAxis::XBottom )->setMargin( 0 ); plot->axisWidget( QwtAxis::YLeft )->setMargin( 0 ); plot->axisWidget( QwtAxis::XTop )->setMargin( 0 ); plot->axisWidget( QwtAxis::YRight )->setMargin( 0 ); plot->setAxisMaxMinor( QwtAxis::XBottom, 2 ); plot->setAxisMaxMinor( QwtAxis::YLeft, 3 ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RiuQwtPlotTools::enableDateBasedBottomXAxis( QwtPlot* plot, const QString& dateFormat, const QString& timeFormat, RiaDefines::DateFormatComponents dateComponents, RiaDefines::TimeFormatComponents timeComponents ) { QwtDateScaleDraw* scaleDraw = new QwtDateScaleDraw( Qt::UTC ); std::set intervals = { QwtDate::Year, QwtDate::Month, QwtDate::Week, QwtDate::Day, QwtDate::Hour, QwtDate::Minute, QwtDate::Second, QwtDate::Millisecond }; for ( QwtDate::IntervalType interval : intervals ) { scaleDraw->setDateFormat( interval, dateTimeFormatForInterval( interval, dateFormat, timeFormat, dateComponents, timeComponents ) ); } QwtDateScaleEngine* scaleEngine = new QwtDateScaleEngine( Qt::UTC ); plot->setAxisScaleEngine( QwtAxis::XBottom, scaleEngine ); plot->setAxisScaleDraw( QwtAxis::XBottom, scaleDraw ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- QString RiuQwtPlotTools::dateTimeFormatForInterval( QwtDate::IntervalType interval, const QString& dateFormat, const QString& timeFormat, RiaDefines::DateFormatComponents dateComponents, RiaDefines::TimeFormatComponents timeComponents ) { if ( dateComponents != RiaDefines::DateFormatComponents::DATE_FORMAT_UNSPECIFIED && timeComponents != RiaDefines::TimeFormatComponents::TIME_FORMAT_UNSPECIFIED ) { return RiaQDateTimeTools::timeFormatString( timeFormat, timeComponents ) + "\n" + RiaQDateTimeTools::dateFormatString( dateFormat, dateComponents ); } else { switch ( interval ) { case QwtDate::Millisecond: return RiaQDateTimeTools::timeFormatString( timeFormat, RiaDefines::TimeFormatComponents::TIME_FORMAT_HOUR_MINUTE_SECOND_MILLISECOND ); case QwtDate::Second: return RiaQDateTimeTools::timeFormatString( timeFormat, RiaDefines::TimeFormatComponents::TIME_FORMAT_HOUR_MINUTE_SECOND ); case QwtDate::Minute: { QString fullFormat = RiaQDateTimeTools::timeFormatString( timeFormat, RiaDefines::TimeFormatComponents::TIME_FORMAT_HOUR_MINUTE ); fullFormat += "\n"; fullFormat += RiaQDateTimeTools::dateFormatString( dateFormat, RiaDefines::DateFormatComponents::DATE_FORMAT_YEAR_MONTH_DAY ); return fullFormat; } case QwtDate::Hour: { QString fullFormat = RiaQDateTimeTools::timeFormatString( timeFormat, RiaDefines::TimeFormatComponents::TIME_FORMAT_HOUR ); if ( !fullFormat.endsWith( "AP" ) ) { fullFormat += ":00"; } fullFormat += "\n"; fullFormat += RiaQDateTimeTools::dateFormatString( dateFormat, RiaDefines::DateFormatComponents::DATE_FORMAT_YEAR_MONTH_DAY ); return fullFormat; } case QwtDate::Day: return RiaQDateTimeTools::dateFormatString( dateFormat, RiaDefines::DateFormatComponents::DATE_FORMAT_YEAR_MONTH_DAY ); case QwtDate::Week: return RiaQDateTimeTools::dateFormatString( dateFormat, RiaDefines::DateFormatComponents::DATE_FORMAT_YEAR_MONTH ); case QwtDate::Month: return RiaQDateTimeTools::dateFormatString( dateFormat, RiaDefines::DateFormatComponents::DATE_FORMAT_YEAR_MONTH ); case QwtDate::Year: return RiaQDateTimeTools::dateFormatString( dateFormat, RiaDefines::DateFormatComponents::DATE_FORMAT_YEAR ); default: return RiaQDateTimeTools::dateFormatString( dateFormat, RiaDefines::DateFormatComponents::DATE_FORMAT_YEAR_MONTH_DAY ); } } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- QwtPlotShapeItem* RiuQwtPlotTools::createBoxShape( const QString& label, double startX, double endX, double startY, double endY, QColor color, Qt::BrushStyle brushStyle ) { return createBoxShapeT( label, startX, endX, startY, endY, color, brushStyle ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- QwtAxisId RiuQwtPlotTools::toQwtPlotAxis( RiuPlotAxis axis ) { QwtAxis::Position qwtPosition = toQwtPlotAxisEnum( axis.axis() ); return { qwtPosition, axis.index() }; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- QwtAxis::Position RiuQwtPlotTools::toQwtPlotAxisEnum( RiaDefines::PlotAxis riaPlotAxis ) { if ( riaPlotAxis == RiaDefines::PlotAxis::PLOT_AXIS_LEFT ) return QwtAxis::YLeft; else if ( riaPlotAxis == RiaDefines::PlotAxis::PLOT_AXIS_RIGHT ) return QwtAxis::YRight; else if ( riaPlotAxis == RiaDefines::PlotAxis::PLOT_AXIS_BOTTOM ) return QwtAxis::XBottom; else if ( riaPlotAxis == RiaDefines::PlotAxis::PLOT_AXIS_TOP ) return QwtAxis::XTop; return QwtAxis::YLeft; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RiaDefines::PlotAxis RiuQwtPlotTools::fromQwtPlotAxis( QwtAxis::Position axis ) { if ( axis == QwtAxis::YLeft ) return RiaDefines::PlotAxis::PLOT_AXIS_LEFT; else if ( axis == QwtAxis::YRight ) return RiaDefines::PlotAxis::PLOT_AXIS_RIGHT; else if ( axis == QwtAxis::XBottom ) return RiaDefines::PlotAxis::PLOT_AXIS_BOTTOM; else if ( axis == QwtAxis::XTop ) return RiaDefines::PlotAxis::PLOT_AXIS_TOP; return RiaDefines::PlotAxis::PLOT_AXIS_LEFT; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RiuQwtPlotTools::updateLegendData( RiuQwtPlotLegend* legend, const std::vector& curves ) { QList legendDataList = createLegendData( curves ); legend->updateLegend( QVariant(), legendDataList ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- QList RiuQwtPlotTools::createLegendData( const std::vector& curves ) { QList 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; }