mirror of
https://github.com/OPM/ResInsight.git
synced 2025-01-01 03:37:15 -06:00
3d663797b6
* Add docked depth result plot for eclipse data * Update dock layout defaults
348 lines
15 KiB
C++
348 lines
15 KiB
C++
/////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// 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 <http://www.gnu.org/licenses/gpl.html>
|
|
// 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 "RiuPlotCurveSymbolImageCreator.h"
|
|
#include "RiuQwtPlotLegend.h"
|
|
|
|
#include "qwt_axis.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 <vector>
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
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<QFrame*>( 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<QwtAxis::Position> 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<uint64_t>( plot ) );
|
|
plot->setObjectName( objectName );
|
|
|
|
QString canvasName = QString( "%1" ).arg( reinterpret_cast<uint64_t>( 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<QwtDate::IntervalType> 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<QwtPlotShapeItem>( label, startX, endX, startY, endY, color, brushStyle );
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
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<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() != RiuPlotCurveSymbol::SYMBOL_NONE )
|
|
{
|
|
auto image = RiuPlotCurveSymbolImageCreator::createSymbolImage( c->symbol(),
|
|
QSize( size.width() / 2, size.height() / 2 ),
|
|
RiaColorTools::toQColor( c->color() ) );
|
|
|
|
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;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
void RiuQwtPlotTools::enableGridLines( QwtPlot* plot, QwtAxis::Position axis, bool enableMajor, bool enableMinor )
|
|
{
|
|
QwtPlotItemList plotItems = plot->itemList( QwtPlotItem::Rtti_PlotGrid );
|
|
for ( QwtPlotItem* plotItem : plotItems )
|
|
{
|
|
auto* grid = static_cast<QwtPlotGrid*>( plotItem );
|
|
if ( axis == QwtAxis::XTop || axis == QwtAxis::XBottom )
|
|
{
|
|
grid->setXAxis( axis );
|
|
grid->enableX( enableMajor );
|
|
grid->enableXMin( enableMinor );
|
|
}
|
|
else
|
|
{
|
|
grid->setYAxis( axis );
|
|
grid->enableY( enableMajor );
|
|
grid->enableYMin( enableMinor );
|
|
}
|
|
grid->setMajorPen( Qt::lightGray, 1.0, Qt::SolidLine );
|
|
grid->setMinorPen( Qt::lightGray, 1.0, Qt::DashLine );
|
|
}
|
|
}
|