mirror of
https://github.com/OPM/ResInsight.git
synced 2026-10-25 22:50:25 -05:00
#12925: Add global curve style settings and per-item rules
This commit is contained in:
1 parent
635c49bb3b
commit
e21da59dbb
19 files changed
+2215
-8
No files matched your search
@@ -68,6 +68,47 @@ std::vector<RimSummaryCase*> RiaSummaryTools::singleTopLevelSummaryCases()
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
std::set<std::string> RiaSummaryTools::allSummaryCaseNames()
|
||||||
|
{
|
||||||
|
std::set<std::string> summaryCaseFilenames;
|
||||||
|
|
||||||
|
for ( RimSummaryCase* rimCase : RimProject::current()->allSummaryCases() )
|
||||||
|
{
|
||||||
|
summaryCaseFilenames.insert( rimCase->summaryHeaderFilename().toUtf8().constData() );
|
||||||
|
}
|
||||||
|
|
||||||
|
return summaryCaseFilenames;
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
std::set<std::string> RiaSummaryTools::allSummaryWellNames()
|
||||||
|
{
|
||||||
|
std::set<std::string> summaryWellNames;
|
||||||
|
|
||||||
|
for ( RimSummaryCase* rimCase : RimProject::current()->allSummaryCases() )
|
||||||
|
{
|
||||||
|
if ( !rimCase ) continue;
|
||||||
|
|
||||||
|
RifSummaryReaderInterface* reader = rimCase->summaryReader();
|
||||||
|
if ( !reader ) continue;
|
||||||
|
|
||||||
|
for ( const auto& address : reader->allResultAddresses() )
|
||||||
|
{
|
||||||
|
if ( address.category() == RifEclipseSummaryAddressDefines::SummaryCategory::SUMMARY_WELL )
|
||||||
|
{
|
||||||
|
summaryWellNames.insert( address.wellName() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return summaryWellNames;
|
||||||
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
///
|
///
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -27,6 +27,8 @@
|
|||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
|
|
||||||
|
#include <set>
|
||||||
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
class RifEclipseSummaryAddress;
|
class RifEclipseSummaryAddress;
|
||||||
@@ -60,7 +62,9 @@ public:
|
|||||||
|
|
||||||
static std::vector<RimSummaryCase*> singleTopLevelSummaryCases();
|
static std::vector<RimSummaryCase*> singleTopLevelSummaryCases();
|
||||||
|
|
||||||
static void notifyCalculatedCurveNameHasChanged( int calculationId, const QString& currentCurveName );
|
static std::set<std::string> allSummaryCaseNames();
|
||||||
|
static std::set<std::string> allSummaryWellNames();
|
||||||
|
static void notifyCalculatedCurveNameHasChanged( int calculationId, const QString& currentCurveName );
|
||||||
|
|
||||||
static RimSummaryPlot* parentSummaryPlot( caf::PdmObject* object );
|
static RimSummaryPlot* parentSummaryPlot( caf::PdmObject* object );
|
||||||
static RimSummaryMultiPlot* parentSummaryMultiPlot( caf::PdmObject* object );
|
static RimSummaryMultiPlot* parentSummaryMultiPlot( caf::PdmObject* object );
|
||||||
|
|||||||
@@ -75,11 +75,13 @@ public:
|
|||||||
void setSymbolSize( int sizeInPixels );
|
void setSymbolSize( int sizeInPixels );
|
||||||
void setLineThickness( int thickness );
|
void setLineThickness( int thickness );
|
||||||
void resetAppearance();
|
void resetAppearance();
|
||||||
virtual Qt::BrushStyle fillStyle() const;
|
|
||||||
void setFillStyle( Qt::BrushStyle brushStyle );
|
RimPlotCurveAppearance* curveAppearance() const { return m_curveAppearance(); }
|
||||||
void setFillColor( const cvf::Color3f& fillColor );
|
virtual Qt::BrushStyle fillStyle() const;
|
||||||
void setFillColorOpacity( float opacity );
|
void setFillStyle( Qt::BrushStyle brushStyle );
|
||||||
void setCurveColorOpacity( float opacity );
|
void setFillColor( const cvf::Color3f& fillColor );
|
||||||
|
void setFillColorOpacity( float opacity );
|
||||||
|
void setCurveColorOpacity( float opacity );
|
||||||
|
|
||||||
bool isChecked() const;
|
bool isChecked() const;
|
||||||
void setCheckState( bool isChecked );
|
void setCheckState( bool isChecked );
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
#include "cafPdmUiCommandSystemProxy.h"
|
#include "cafPdmUiCommandSystemProxy.h"
|
||||||
#include "cafPdmUiDoubleSliderEditor.h"
|
#include "cafPdmUiDoubleSliderEditor.h"
|
||||||
|
|
||||||
CAF_PDM_XML_ABSTRACT_SOURCE_INIT( RimPlotCurveAppearance, "PlotCurveAppearance" );
|
CAF_PDM_XML_SOURCE_INIT( RimPlotCurveAppearance, "PlotCurveAppearance" );
|
||||||
|
|
||||||
namespace caf
|
namespace caf
|
||||||
{
|
{
|
||||||
@@ -236,9 +236,43 @@ void RimPlotCurveAppearance::defineUiOrdering( QString uiConfigName, caf::PdmUiO
|
|||||||
uiOrdering.add( &m_curveInterpolation );
|
uiOrdering.add( &m_curveInterpolation );
|
||||||
m_curveInterpolation.uiCapability()->setUiHidden( !m_interpolationVisible );
|
m_curveInterpolation.uiCapability()->setUiHidden( !m_interpolationVisible );
|
||||||
|
|
||||||
|
for ( auto field : std::vector<caf::PdmFieldHandle*>{ &m_curveColor,
|
||||||
|
&m_curveColorOpacity,
|
||||||
|
&m_pointSymbol,
|
||||||
|
&m_symbolEdgeColor,
|
||||||
|
&m_symbolSize,
|
||||||
|
&m_symbolSkipPixelDistance,
|
||||||
|
&m_lineStyle,
|
||||||
|
&m_curveThickness,
|
||||||
|
&m_fillStyle,
|
||||||
|
&m_fillColor,
|
||||||
|
&m_fillColorOpacity,
|
||||||
|
&m_curveInterpolation } )
|
||||||
|
{
|
||||||
|
field->uiCapability()->setUiReadOnly( m_uiLocked );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Keep the fields that are irrelevant for the current symbol and line style read-only
|
||||||
|
const bool noSymbol = m_pointSymbol() == RiuPlotCurveSymbol::SYMBOL_NONE;
|
||||||
|
const bool noLine = m_lineStyle() == RiuQwtPlotCurveDefines::LineStyleEnum::STYLE_NONE;
|
||||||
|
m_symbolSize.uiCapability()->setUiReadOnly( m_uiLocked || noSymbol );
|
||||||
|
m_symbolSkipPixelDistance.uiCapability()->setUiReadOnly( m_uiLocked || noSymbol );
|
||||||
|
m_curveThickness.uiCapability()->setUiReadOnly( m_uiLocked || noLine );
|
||||||
|
m_curveInterpolation.uiCapability()->setUiReadOnly( m_uiLocked || noLine );
|
||||||
|
|
||||||
|
if ( m_curveFittingToleranceVisible && m_uiLocked ) m_curveFittingTolerance.uiCapability()->setUiReadOnly( true );
|
||||||
|
|
||||||
uiOrdering.skipRemainingFields();
|
uiOrdering.skipRemainingFields();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
void RimPlotCurveAppearance::setUiLocked( bool isLocked )
|
||||||
|
{
|
||||||
|
m_uiLocked = isLocked;
|
||||||
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
///
|
///
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
@@ -401,6 +435,30 @@ int RimPlotCurveAppearance::lineThickness() const
|
|||||||
return m_curveThickness;
|
return m_curveThickness;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
void RimPlotCurveAppearance::copyFrom( const RimPlotCurveAppearance& other )
|
||||||
|
{
|
||||||
|
// Fields are assigned directly, as this runs per curve on every restyle. XML based copies like copyObject() or
|
||||||
|
// readObjectFromXmlString( other.writeObjectToXmlString() ) are too slow for many curves. New fields must be added here.
|
||||||
|
m_symbolLabel = other.m_symbolLabel();
|
||||||
|
m_symbolSize = other.m_symbolSize();
|
||||||
|
m_curveColor = other.m_curveColor();
|
||||||
|
m_curveColorOpacity = other.m_curveColorOpacity();
|
||||||
|
m_curveThickness = other.m_curveThickness();
|
||||||
|
m_symbolSkipPixelDistance = other.m_symbolSkipPixelDistance();
|
||||||
|
m_curveFittingTolerance = other.m_curveFittingTolerance();
|
||||||
|
m_pointSymbol = other.m_pointSymbol();
|
||||||
|
m_lineStyle = other.m_lineStyle();
|
||||||
|
m_fillStyle = other.m_fillStyle();
|
||||||
|
m_fillColor = other.m_fillColor();
|
||||||
|
m_fillColorOpacity = other.m_fillColorOpacity();
|
||||||
|
m_curveInterpolation = other.m_curveInterpolation();
|
||||||
|
m_symbolLabelPosition = other.m_symbolLabelPosition();
|
||||||
|
m_symbolEdgeColor = other.m_symbolEdgeColor();
|
||||||
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
///
|
///
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -79,7 +79,10 @@ public:
|
|||||||
void setSymbolLabelPosition( RiuPlotCurveSymbol::LabelPosition labelPosition );
|
void setSymbolLabelPosition( RiuPlotCurveSymbol::LabelPosition labelPosition );
|
||||||
RiuPlotCurveSymbol::LabelPosition symbolLabelPosition() const;
|
RiuPlotCurveSymbol::LabelPosition symbolLabelPosition() const;
|
||||||
|
|
||||||
void resetAppearance();
|
void resetAppearance();
|
||||||
|
|
||||||
|
// Copies the visual settings from another appearance without emitting signals
|
||||||
|
void copyFrom( const RimPlotCurveAppearance& other );
|
||||||
Qt::BrushStyle fillStyle() const;
|
Qt::BrushStyle fillStyle() const;
|
||||||
void setFillStyle( Qt::BrushStyle brushStyle );
|
void setFillStyle( Qt::BrushStyle brushStyle );
|
||||||
|
|
||||||
@@ -102,6 +105,9 @@ public:
|
|||||||
void setFillOptionsVisible( bool isVisible );
|
void setFillOptionsVisible( bool isVisible );
|
||||||
void setCurveFittingToleranceVisible( bool isVisible );
|
void setCurveFittingToleranceVisible( bool isVisible );
|
||||||
|
|
||||||
|
// Shows all fields as read-only, used when the appearance is controlled elsewhere
|
||||||
|
void setUiLocked( bool isLocked );
|
||||||
|
|
||||||
void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override;
|
void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@@ -135,4 +141,5 @@ protected:
|
|||||||
bool m_interpolationVisible;
|
bool m_interpolationVisible;
|
||||||
bool m_fillOptionsVisible;
|
bool m_fillOptionsVisible;
|
||||||
bool m_curveFittingToleranceVisible;
|
bool m_curveFittingToleranceVisible;
|
||||||
|
bool m_uiLocked = false;
|
||||||
};
|
};
|
||||||
@@ -101,6 +101,7 @@
|
|||||||
#include "RimWellPath.h"
|
#include "RimWellPath.h"
|
||||||
#include "RimWellPathCollection.h"
|
#include "RimWellPathCollection.h"
|
||||||
#include "RimWellTargetMapping.h"
|
#include "RimWellTargetMapping.h"
|
||||||
|
#include "Summary/RimCurveStyleRules.h"
|
||||||
#include "Tools/RimAutomationSettings.h"
|
#include "Tools/RimAutomationSettings.h"
|
||||||
#include "VerticalFlowPerformance/RimVfpDataCollection.h"
|
#include "VerticalFlowPerformance/RimVfpDataCollection.h"
|
||||||
#include "VerticalFlowPerformance/RimVfpPlotCollection.h"
|
#include "VerticalFlowPerformance/RimVfpPlotCollection.h"
|
||||||
@@ -148,6 +149,9 @@ RimProject::RimProject()
|
|||||||
CAF_PDM_InitFieldNoDefault( &m_mainPlotCollection, "MainPlotCollection", "Plots" );
|
CAF_PDM_InitFieldNoDefault( &m_mainPlotCollection, "MainPlotCollection", "Plots" );
|
||||||
CAF_PDM_InitFieldNoDefault( &m_pinnedFieldCollection, "PinnedFieldCollection", "PinnedFieldCollection" );
|
CAF_PDM_InitFieldNoDefault( &m_pinnedFieldCollection, "PinnedFieldCollection", "PinnedFieldCollection" );
|
||||||
|
|
||||||
|
CAF_PDM_InitFieldNoDefault( &m_curveStyleRules, "CurveStyleRules", "Curve Style Rules" );
|
||||||
|
m_curveStyleRules = new RimCurveStyleRules;
|
||||||
|
|
||||||
CAF_PDM_InitFieldNoDefault( &viewLinkerCollection, "LinkedViews", "Linked Views", ":/LinkView.svg" );
|
CAF_PDM_InitFieldNoDefault( &viewLinkerCollection, "LinkedViews", "Linked Views", ":/LinkView.svg" );
|
||||||
viewLinkerCollection = new RimViewLinkerCollection;
|
viewLinkerCollection = new RimViewLinkerCollection;
|
||||||
|
|
||||||
@@ -346,6 +350,14 @@ RimQuickAccessCollection* RimProject::pinnedFieldCollection() const
|
|||||||
return m_pinnedFieldCollection();
|
return m_pinnedFieldCollection();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
RimCurveStyleRules* RimProject::curveStyleRules() const
|
||||||
|
{
|
||||||
|
return m_curveStyleRules();
|
||||||
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
///
|
///
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -71,6 +71,7 @@ class RimCompletionTemplateCollection;
|
|||||||
class RimPlotTemplateFolderItem;
|
class RimPlotTemplateFolderItem;
|
||||||
class RimGridCalculationCollection;
|
class RimGridCalculationCollection;
|
||||||
class RimQuickAccessCollection;
|
class RimQuickAccessCollection;
|
||||||
|
class RimCurveStyleRules;
|
||||||
class RimAutomationSettings;
|
class RimAutomationSettings;
|
||||||
class RimJobCollection;
|
class RimJobCollection;
|
||||||
class RimEnsembleFileSetCollection;
|
class RimEnsembleFileSetCollection;
|
||||||
@@ -194,6 +195,7 @@ public:
|
|||||||
void updatesAfterProjectFileIsRead();
|
void updatesAfterProjectFileIsRead();
|
||||||
|
|
||||||
RimQuickAccessCollection* pinnedFieldCollection() const;
|
RimQuickAccessCollection* pinnedFieldCollection() const;
|
||||||
|
RimCurveStyleRules* curveStyleRules() const;
|
||||||
RimAutomationSettings* automationSettings() const;
|
RimAutomationSettings* automationSettings() const;
|
||||||
RimEnsembleFileSetCollection* ensembleFileSetCollection() const;
|
RimEnsembleFileSetCollection* ensembleFileSetCollection() const;
|
||||||
RimJobCollection* jobCollection() const;
|
RimJobCollection* jobCollection() const;
|
||||||
@@ -208,6 +210,7 @@ protected:
|
|||||||
private:
|
private:
|
||||||
caf::PdmChildField<RimMainPlotCollection*> m_mainPlotCollection;
|
caf::PdmChildField<RimMainPlotCollection*> m_mainPlotCollection;
|
||||||
caf::PdmChildField<RimQuickAccessCollection*> m_pinnedFieldCollection;
|
caf::PdmChildField<RimQuickAccessCollection*> m_pinnedFieldCollection;
|
||||||
|
caf::PdmChildField<RimCurveStyleRules*> m_curveStyleRules;
|
||||||
caf::PdmChildField<RimAutomationSettings*> m_automationSettings;
|
caf::PdmChildField<RimAutomationSettings*> m_automationSettings;
|
||||||
caf::PdmChildField<RimEnsembleFileSetCollection*> m_ensembleFileSetCollection;
|
caf::PdmChildField<RimEnsembleFileSetCollection*> m_ensembleFileSetCollection;
|
||||||
caf::PdmChildField<RimJobCollection*> m_jobCollection;
|
caf::PdmChildField<RimJobCollection*> m_jobCollection;
|
||||||
|
|||||||
@@ -8,6 +8,10 @@ set(SOURCE_GROUP_SOURCE_FILES
|
|||||||
${CMAKE_CURRENT_LIST_DIR}/RimSummaryCurve.cpp
|
${CMAKE_CURRENT_LIST_DIR}/RimSummaryCurve.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/RimSummaryCurvesData.cpp
|
${CMAKE_CURRENT_LIST_DIR}/RimSummaryCurvesData.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/RimSummaryCurveAppearanceCalculator.cpp
|
${CMAKE_CURRENT_LIST_DIR}/RimSummaryCurveAppearanceCalculator.cpp
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/RimCurveStyleSettings.cpp
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/RimCurveStyleRule.cpp
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/RimCurveStyleRules.cpp
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/RimSavedCurveAppearance.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/RimSummaryCurveAutoName.cpp
|
${CMAKE_CURRENT_LIST_DIR}/RimSummaryCurveAutoName.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/RimSummaryPlotAxisFormatter.cpp
|
${CMAKE_CURRENT_LIST_DIR}/RimSummaryPlotAxisFormatter.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/RimSummaryCurveCollection.cpp
|
${CMAKE_CURRENT_LIST_DIR}/RimSummaryCurveCollection.cpp
|
||||||
|
|||||||
@@ -0,0 +1,575 @@
|
|||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Copyright (C) 2026- 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 "RimCurveStyleRule.h"
|
||||||
|
|
||||||
|
#include "RiaColorTools.h"
|
||||||
|
#include "Summary/RiaSummaryTools.h"
|
||||||
|
|
||||||
|
#include "RimCurveStyleRules.h"
|
||||||
|
#include "RimEnsembleCurveSet.h"
|
||||||
|
#include "RimEnsembleCurveSetCollection.h"
|
||||||
|
#include "RimPlotCurve.h"
|
||||||
|
#include "RimProject.h"
|
||||||
|
#include "RimSummaryCase.h"
|
||||||
|
#include "RimSummaryCurve.h"
|
||||||
|
#include "RimSummaryEnsemble.h"
|
||||||
|
#include "RimSummaryPlot.h"
|
||||||
|
|
||||||
|
#include "RiuPlotCurveSymbolImageCreator.h"
|
||||||
|
|
||||||
|
#include <QColor>
|
||||||
|
#include <QLinearGradient>
|
||||||
|
#include <QPainter>
|
||||||
|
#include <QPixmap>
|
||||||
|
|
||||||
|
#include <set>
|
||||||
|
|
||||||
|
namespace caf
|
||||||
|
{
|
||||||
|
template <>
|
||||||
|
void caf::AppEnum<RimCurveStyleRule::Mode>::setUp()
|
||||||
|
{
|
||||||
|
addItem( RimCurveStyleRule::Mode::AUTO, "AUTO", "Auto" );
|
||||||
|
addItem( RimCurveStyleRule::Mode::CUSTOM, "CUSTOM", "Custom" );
|
||||||
|
setDefault( RimCurveStyleRule::Mode::AUTO );
|
||||||
|
}
|
||||||
|
} // namespace caf
|
||||||
|
|
||||||
|
CAF_PDM_SOURCE_INIT( RimCurveStyleRule, "RimCurveStyleRule" );
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
RimCurveStyleRule::RimCurveStyleRule()
|
||||||
|
{
|
||||||
|
CAF_PDM_InitObject( "Curve Style Rule" );
|
||||||
|
|
||||||
|
CAF_PDM_InitFieldNoDefault( &m_dimension, "Dimension", "Dimension" );
|
||||||
|
CAF_PDM_InitFieldNoDefault( &m_itemName, "ItemName", "Item Name" );
|
||||||
|
CAF_PDM_InitFieldNoDefault( &m_mode, "Mode", "Mode" );
|
||||||
|
|
||||||
|
CAF_PDM_InitFieldNoDefault( &m_curveAppearance, "CurveAppearance", "Curve Appearance" );
|
||||||
|
m_curveAppearance = new RimPlotCurveAppearance;
|
||||||
|
m_curveAppearance.uiCapability()->setUiTreeChildrenHidden( true );
|
||||||
|
connectAppearanceSignal();
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
void RimCurveStyleRule::connectAppearanceSignal()
|
||||||
|
{
|
||||||
|
if ( m_curveAppearance() ) m_curveAppearance->appearanceChanged.connect( this, &RimCurveStyleRule::onAppearanceChanged );
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
void RimCurveStyleRule::initAfterRead()
|
||||||
|
{
|
||||||
|
connectAppearanceSignal();
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
/// Editing any appearance value turns the item into a custom item
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
void RimCurveStyleRule::onAppearanceChanged( const caf::SignalEmitter* emitter )
|
||||||
|
{
|
||||||
|
m_mode = Mode::CUSTOM;
|
||||||
|
|
||||||
|
if ( auto collection = firstAncestorOrThisOfType<RimCurveStyleRules>() ) collection->ruleChanged( this );
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
void RimCurveStyleRule::applyToCurve( RimPlotCurve* curve, bool applyColor, bool applySymbol ) const
|
||||||
|
{
|
||||||
|
if ( m_mode() != Mode::CUSTOM ) return;
|
||||||
|
|
||||||
|
auto curveAppearance = curve->curveAppearance();
|
||||||
|
const auto color = curveAppearance->color();
|
||||||
|
const auto symbol = curveAppearance->symbol();
|
||||||
|
const auto label = curveAppearance->symbolLabel();
|
||||||
|
const auto labelPosition = curveAppearance->symbolLabelPosition();
|
||||||
|
|
||||||
|
curveAppearance->copyFrom( *m_curveAppearance );
|
||||||
|
|
||||||
|
// Color and symbol are only controlled by the rule when its dimension is the one selected for them
|
||||||
|
if ( !applyColor ) curveAppearance->setColor( color );
|
||||||
|
if ( !applySymbol ) curveAppearance->setSymbol( symbol );
|
||||||
|
|
||||||
|
// Labels are specific to each curve
|
||||||
|
curveAppearance->setSymbolLabel( label );
|
||||||
|
curveAppearance->setSymbolLabelPosition( labelPosition );
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
std::optional<cvf::Color3f> RimCurveStyleRule::overriddenColor() const
|
||||||
|
{
|
||||||
|
if ( m_mode() != Mode::CUSTOM ) return std::nullopt;
|
||||||
|
return m_curveAppearance->color();
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
bool matchesItem( RimCurveStyleRule::Dimension dimension, const QString& itemName, const RifEclipseSummaryAddress& address, const std::string& caseName )
|
||||||
|
{
|
||||||
|
return QString::fromStdString( RimCurveStyleSettings::dimensionValue( dimension, address, caseName ) ) == itemName;
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
std::string ensembleCaseName( RimEnsembleCurveSet* curveSet )
|
||||||
|
{
|
||||||
|
return curveSet->summaryEnsemble() ? curveSet->summaryEnsemble()->name().toStdString() : std::string();
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
/// Shows what the global appearance gives for the item. The assigned color and symbol are used even if no
|
||||||
|
/// plot has a matching curve.
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
void RimCurveStyleRule::updateAppearanceFromCurves()
|
||||||
|
{
|
||||||
|
copyAppearanceFromCurves();
|
||||||
|
if ( m_autoColor ) m_curveAppearance->setColor( *m_autoColor );
|
||||||
|
if ( m_autoSymbol ) m_curveAppearance->setSymbol( *m_autoSymbol );
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
void RimCurveStyleRule::setAutoAssigned( const std::optional<cvf::Color3f>& color,
|
||||||
|
const std::optional<RiuPlotCurveSymbol::PointSymbolEnum>& symbol )
|
||||||
|
{
|
||||||
|
m_autoColor = color;
|
||||||
|
m_autoSymbol = symbol;
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
/// Copies the appearance of the first matching curve
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
void RimCurveStyleRule::copyAppearanceFromCurves()
|
||||||
|
{
|
||||||
|
auto project = RimProject::current();
|
||||||
|
if ( !project ) return;
|
||||||
|
|
||||||
|
for ( auto plot : project->descendantsIncludingThisOfType<RimSummaryPlot>() )
|
||||||
|
{
|
||||||
|
if ( !plot->useGlobalCurveAppearance() ) continue;
|
||||||
|
|
||||||
|
for ( auto curve : plot->summaryCurves() )
|
||||||
|
{
|
||||||
|
if ( matchesItem( m_dimension(), m_itemName(), curve->summaryAddressY(), RimCurveStyleSettings::caseName( curve->summaryCaseY() ) ) )
|
||||||
|
{
|
||||||
|
m_curveAppearance->copyFrom( *curve->curveAppearance() );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( auto curveSet : plot->ensembleCurveSetCollection()->curveSets() )
|
||||||
|
{
|
||||||
|
if ( matchesItem( m_dimension(), m_itemName(), curveSet->summaryAddressY(), ensembleCaseName( curveSet ) ) )
|
||||||
|
{
|
||||||
|
m_curveAppearance->setColor( curveSet->color() );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
RimCurveStyleRule::Dimension RimCurveStyleRule::dimension() const
|
||||||
|
{
|
||||||
|
return m_dimension();
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
QString RimCurveStyleRule::itemName() const
|
||||||
|
{
|
||||||
|
return m_itemName();
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
void RimCurveStyleRule::setDimension( Dimension dimension )
|
||||||
|
{
|
||||||
|
m_dimension = dimension;
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
void RimCurveStyleRule::setItemName( const QString& itemName )
|
||||||
|
{
|
||||||
|
m_itemName = itemName;
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
void RimCurveStyleRule::setCustom( bool isCustom )
|
||||||
|
{
|
||||||
|
m_mode = isCustom ? Mode::CUSTOM : Mode::AUTO;
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
void RimCurveStyleRule::copySettingsFrom( const RimCurveStyleRule& other )
|
||||||
|
{
|
||||||
|
m_mode = other.m_mode();
|
||||||
|
m_curveAppearance->copyFrom( *other.m_curveAppearance() );
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
std::optional<std::map<RimCurveStyleRule::Dimension, QStringList>> availableNamesCache;
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
RimCurveStyleRule::AvailableNamesCache::AvailableNamesCache()
|
||||||
|
: m_isOwner( !availableNamesCache )
|
||||||
|
{
|
||||||
|
if ( m_isOwner ) availableNamesCache.emplace();
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
RimCurveStyleRule::AvailableNamesCache::~AvailableNamesCache()
|
||||||
|
{
|
||||||
|
if ( m_isOwner ) availableNamesCache.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
QStringList RimCurveStyleRule::availableNames( Dimension dimension )
|
||||||
|
{
|
||||||
|
if ( availableNamesCache )
|
||||||
|
{
|
||||||
|
auto it = availableNamesCache->find( dimension );
|
||||||
|
if ( it != availableNamesCache->end() ) return it->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( dimension == Dimension::NONE || !RimProject::current() ) return {};
|
||||||
|
|
||||||
|
std::set<QString> names;
|
||||||
|
if ( dimension == Dimension::WELL )
|
||||||
|
{
|
||||||
|
for ( const auto& wellName : RiaSummaryTools::allSummaryWellNames() )
|
||||||
|
{
|
||||||
|
names.insert( QString::fromStdString( wellName ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ( dimension == Dimension::CASE )
|
||||||
|
{
|
||||||
|
if ( auto project = RimProject::current() )
|
||||||
|
{
|
||||||
|
for ( auto ensemble : project->summaryEnsembles() )
|
||||||
|
{
|
||||||
|
names.insert( ensemble->name() );
|
||||||
|
}
|
||||||
|
for ( auto summaryCase : project->allSummaryCases() )
|
||||||
|
{
|
||||||
|
if ( !summaryCase->ensemble() ) names.insert( summaryCase->displayCaseName() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ( auto project = RimProject::current() )
|
||||||
|
{
|
||||||
|
for ( auto summaryCase : project->allSummaryCases() )
|
||||||
|
{
|
||||||
|
auto reader = summaryCase->summaryReader();
|
||||||
|
if ( !reader ) continue;
|
||||||
|
|
||||||
|
for ( const auto& address : reader->allResultAddresses() )
|
||||||
|
{
|
||||||
|
const auto value = RimCurveStyleSettings::dimensionValue( dimension, address, {} );
|
||||||
|
if ( !value.empty() ) names.insert( QString::fromStdString( value ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList result;
|
||||||
|
for ( const auto& name : names )
|
||||||
|
{
|
||||||
|
result.push_back( name );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( availableNamesCache ) ( *availableNamesCache )[dimension] = result;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
std::map<QString, RimCurveStyleRule::PlotAppearance> RimCurveStyleRule::appearancesFromPlots( Dimension dimension )
|
||||||
|
{
|
||||||
|
std::map<QString, PlotAppearance> appearances;
|
||||||
|
|
||||||
|
auto project = RimProject::current();
|
||||||
|
if ( !project ) return appearances;
|
||||||
|
|
||||||
|
for ( auto plot : project->descendantsIncludingThisOfType<RimSummaryPlot>() )
|
||||||
|
{
|
||||||
|
if ( !plot->useGlobalCurveAppearance() ) continue;
|
||||||
|
|
||||||
|
for ( auto curve : plot->summaryCurves() )
|
||||||
|
{
|
||||||
|
const auto value = RimCurveStyleSettings::dimensionValue( dimension,
|
||||||
|
curve->summaryAddressY(),
|
||||||
|
RimCurveStyleSettings::caseName( curve->summaryCaseY() ) );
|
||||||
|
|
||||||
|
auto& appearance = appearances[QString::fromStdString( value )];
|
||||||
|
if ( !appearance.color ) appearance.color = curve->color();
|
||||||
|
if ( !appearance.symbol ) appearance.symbol = curve->symbol();
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( auto curveSet : plot->ensembleCurveSetCollection()->curveSets() )
|
||||||
|
{
|
||||||
|
const auto value = RimCurveStyleSettings::dimensionValue( dimension, curveSet->summaryAddressY(), ensembleCaseName( curveSet ) );
|
||||||
|
|
||||||
|
auto& appearance = appearances[QString::fromStdString( value )];
|
||||||
|
if ( !appearance.color ) appearance.color = curveSet->color();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return appearances;
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
bool RimCurveStyleRule::isCustom() const
|
||||||
|
{
|
||||||
|
return m_mode() == Mode::CUSTOM;
|
||||||
|
}
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
void RimCurveStyleRule::fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue )
|
||||||
|
{
|
||||||
|
// The available names depend on the type
|
||||||
|
if ( changedField == &m_dimension ) m_itemName = QString();
|
||||||
|
if ( changedField == &m_mode && m_mode() == Mode::AUTO ) updateAppearanceFromCurves();
|
||||||
|
|
||||||
|
if ( auto collection = firstAncestorOrThisOfType<RimCurveStyleRules>() ) collection->ruleChanged( this );
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
void RimCurveStyleRule::appendFieldsToUiOrdering( const QString& uiConfigName, caf::PdmUiOrdering& uiOrdering )
|
||||||
|
{
|
||||||
|
uiOrdering.add( &m_mode );
|
||||||
|
|
||||||
|
auto appearanceGroup = uiOrdering.addNewGroup( "Curve Style" );
|
||||||
|
m_curveAppearance->uiOrdering( "AppearanceOrdering", *appearanceGroup );
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
void RimCurveStyleRule::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering )
|
||||||
|
{
|
||||||
|
uiOrdering.add( &m_dimension );
|
||||||
|
uiOrdering.add( &m_itemName );
|
||||||
|
uiOrdering.skipRemainingFields();
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
caf::IconProvider RimCurveStyleRule::swatchIcon( const cvf::Color3f& color )
|
||||||
|
{
|
||||||
|
QPixmap pixmap( 16, 16 );
|
||||||
|
pixmap.fill( Qt::transparent );
|
||||||
|
|
||||||
|
QPainter painter( &pixmap );
|
||||||
|
painter.setPen( Qt::darkGray );
|
||||||
|
painter.setBrush( RiaColorTools::toQColor( color ) );
|
||||||
|
painter.drawRect( 1, 1, 13, 13 );
|
||||||
|
|
||||||
|
return caf::IconProvider( pixmap );
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
caf::IconProvider RimCurveStyleRule::paletteIcon()
|
||||||
|
{
|
||||||
|
QPixmap pixmap( 16, 16 );
|
||||||
|
pixmap.fill( Qt::transparent );
|
||||||
|
|
||||||
|
QLinearGradient gradient( 0, 0, 16, 0 );
|
||||||
|
gradient.setColorAt( 0.0, Qt::red );
|
||||||
|
gradient.setColorAt( 0.5, Qt::green );
|
||||||
|
gradient.setColorAt( 1.0, Qt::blue );
|
||||||
|
|
||||||
|
QPainter painter( &pixmap );
|
||||||
|
painter.setPen( Qt::darkGray );
|
||||||
|
painter.setBrush( gradient );
|
||||||
|
painter.drawRect( 1, 1, 13, 13 );
|
||||||
|
|
||||||
|
return caf::IconProvider( pixmap );
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
caf::IconProvider RimCurveStyleRule::symbolIcon()
|
||||||
|
{
|
||||||
|
QPixmap pixmap( 16, 16 );
|
||||||
|
pixmap.fill( Qt::transparent );
|
||||||
|
|
||||||
|
QPainter painter( &pixmap );
|
||||||
|
painter.setRenderHint( QPainter::Antialiasing );
|
||||||
|
painter.setPen( Qt::black );
|
||||||
|
painter.setBrush( Qt::NoBrush );
|
||||||
|
painter.drawEllipse( 2, 2, 5, 5 );
|
||||||
|
painter.drawRect( 9, 2, 5, 5 );
|
||||||
|
painter.drawLine( 2, 14, 8, 9 );
|
||||||
|
painter.drawLine( 8, 9, 14, 14 );
|
||||||
|
painter.drawLine( 2, 14, 14, 14 );
|
||||||
|
|
||||||
|
return caf::IconProvider( pixmap );
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
QString dimensionIconPath( RimCurveStyleRule::Dimension dimension )
|
||||||
|
{
|
||||||
|
using D = RimCurveStyleRule::Dimension;
|
||||||
|
switch ( dimension )
|
||||||
|
{
|
||||||
|
case D::CASE:
|
||||||
|
return ":/SummaryCase.svg";
|
||||||
|
case D::VECTOR:
|
||||||
|
return ":/summary/components/images/misc.svg";
|
||||||
|
case D::WELL:
|
||||||
|
return ":/summary/components/images/well.svg";
|
||||||
|
case D::LGR:
|
||||||
|
return ":/LGR16x16.png";
|
||||||
|
case D::GROUP:
|
||||||
|
return ":/summary/components/images/group.svg";
|
||||||
|
case D::NETWORK:
|
||||||
|
return ":/summary/components/images/network.svg";
|
||||||
|
case D::REGION:
|
||||||
|
return ":/summary/components/images/region.svg";
|
||||||
|
case D::REGION_2_REGION:
|
||||||
|
return ":/summary/components/images/region-region.svg";
|
||||||
|
case D::AQUIFER:
|
||||||
|
return ":/summary/components/images/aquifer.svg";
|
||||||
|
case D::BLOCK:
|
||||||
|
case D::CONNECTION:
|
||||||
|
return ":/summary/components/images/block.svg";
|
||||||
|
case D::SEGMENT:
|
||||||
|
return ":/summary/components/images/segment.svg";
|
||||||
|
default:
|
||||||
|
return ":/DataVector.svg";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
caf::IconProvider RimCurveStyleRule::dimensionColorIcon( Dimension dimension,
|
||||||
|
const std::optional<cvf::Color3f>& color,
|
||||||
|
const std::optional<RiuPlotCurveSymbol::PointSymbolEnum>& symbol )
|
||||||
|
{
|
||||||
|
QPixmap pixmap( 52, 16 );
|
||||||
|
pixmap.fill( Qt::transparent );
|
||||||
|
|
||||||
|
QPainter painter( &pixmap );
|
||||||
|
painter.drawPixmap( 0, 0, QIcon( dimensionIconPath( dimension ) ).pixmap( 16, 16 ) );
|
||||||
|
|
||||||
|
const QColor qColor = color ? RiaColorTools::toQColor( *color ) : QColor( Qt::black );
|
||||||
|
|
||||||
|
int x = 19;
|
||||||
|
if ( color )
|
||||||
|
{
|
||||||
|
painter.setPen( Qt::darkGray );
|
||||||
|
painter.setBrush( qColor );
|
||||||
|
painter.drawRect( x, 1, 13, 13 );
|
||||||
|
x += 17;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( symbol && *symbol != RiuPlotCurveSymbol::SYMBOL_NONE )
|
||||||
|
{
|
||||||
|
painter.drawImage( x, 1, RiuPlotCurveSymbolImageCreator::createSymbolImage( *symbol, QSize( 14, 14 ), qColor ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
return caf::IconProvider( pixmap );
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
std::optional<RiuPlotCurveSymbol::PointSymbolEnum> RimCurveStyleRule::overriddenSymbol() const
|
||||||
|
{
|
||||||
|
if ( m_mode() != Mode::CUSTOM ) return std::nullopt;
|
||||||
|
return m_curveAppearance->symbol();
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
caf::IconProvider RimCurveStyleRule::dimensionIcon( Dimension dimension )
|
||||||
|
{
|
||||||
|
return caf::IconProvider( dimensionIconPath( dimension ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
QList<caf::PdmOptionItemInfo> RimCurveStyleRule::calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions )
|
||||||
|
{
|
||||||
|
QList<caf::PdmOptionItemInfo> options;
|
||||||
|
|
||||||
|
if ( fieldNeedingOptions == &m_mode )
|
||||||
|
{
|
||||||
|
options.push_back( caf::PdmOptionItemInfo( "Auto", Mode::AUTO, false, caf::IconProvider( ":/Refresh.svg" ) ) );
|
||||||
|
options.push_back( caf::PdmOptionItemInfo( "Custom", Mode::CUSTOM, false, caf::IconProvider( ":/edit.svg" ) ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
return options;
|
||||||
|
}
|
||||||
@@ -0,0 +1,142 @@
|
|||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Copyright (C) 2026- 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.
|
||||||
|
//
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "RimCurveStyleSettings.h"
|
||||||
|
#include "RimPlotCurveAppearance.h"
|
||||||
|
|
||||||
|
#include "RiuPlotCurveSymbol.h"
|
||||||
|
|
||||||
|
#include "cafAppEnum.h"
|
||||||
|
#include "cafIconProvider.h"
|
||||||
|
#include "cafPdmField.h"
|
||||||
|
#include "cafPdmFieldCvfColor.h"
|
||||||
|
#include "cafPdmObject.h"
|
||||||
|
|
||||||
|
#include "cvfColor3.h"
|
||||||
|
|
||||||
|
#include <QString>
|
||||||
|
#include <QStringList>
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
|
class RimPlotCurve;
|
||||||
|
|
||||||
|
//==================================================================================================
|
||||||
|
/// Project-stored curve appearance for one specific summary case, ensemble or well. The values are
|
||||||
|
/// edited in the curve appearance dock window.
|
||||||
|
//==================================================================================================
|
||||||
|
class RimCurveStyleRule : public caf::PdmObject
|
||||||
|
{
|
||||||
|
CAF_PDM_HEADER_INIT;
|
||||||
|
|
||||||
|
public:
|
||||||
|
using Dimension = RimCurveStyleSettings::Dimension;
|
||||||
|
|
||||||
|
enum class Mode
|
||||||
|
{
|
||||||
|
AUTO,
|
||||||
|
CUSTOM
|
||||||
|
};
|
||||||
|
|
||||||
|
RimCurveStyleRule();
|
||||||
|
|
||||||
|
Dimension dimension() const;
|
||||||
|
QString itemName() const;
|
||||||
|
|
||||||
|
void setDimension( Dimension dimension );
|
||||||
|
void setItemName( const QString& itemName );
|
||||||
|
void setCustom( bool isCustom );
|
||||||
|
|
||||||
|
// Copies the mode and appearance, not the item the rule applies to
|
||||||
|
void copySettingsFrom( const RimCurveStyleRule& other );
|
||||||
|
|
||||||
|
// Applies the rule to the curve if it is custom. Color and symbol are only applied when requested
|
||||||
|
void applyToCurve( RimPlotCurve* curve, bool applyColor, bool applySymbol ) const;
|
||||||
|
|
||||||
|
static QStringList availableNames( Dimension dimension );
|
||||||
|
|
||||||
|
// Caches availableNames() while in scope, as finding them can require scanning all summary addresses
|
||||||
|
class AvailableNamesCache
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AvailableNamesCache();
|
||||||
|
~AvailableNamesCache();
|
||||||
|
AvailableNamesCache( const AvailableNamesCache& ) = delete;
|
||||||
|
AvailableNamesCache& operator=( const AvailableNamesCache& ) = delete;
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool m_isOwner;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PlotAppearance
|
||||||
|
{
|
||||||
|
std::optional<cvf::Color3f> color;
|
||||||
|
std::optional<RiuPlotCurveSymbol::PointSymbolEnum> symbol;
|
||||||
|
};
|
||||||
|
|
||||||
|
// The appearance of the first curve for each item in plots using the global appearance
|
||||||
|
static std::map<QString, PlotAppearance> appearancesFromPlots( Dimension dimension );
|
||||||
|
|
||||||
|
static caf::IconProvider swatchIcon( const cvf::Color3f& color );
|
||||||
|
static caf::IconProvider paletteIcon();
|
||||||
|
static caf::IconProvider symbolIcon();
|
||||||
|
static caf::IconProvider dimensionIcon( Dimension dimension );
|
||||||
|
|
||||||
|
// Dimension icon followed by color and/or symbol swatches, when given. The symbol is drawn with the color if present.
|
||||||
|
static caf::IconProvider dimensionColorIcon( Dimension dimension,
|
||||||
|
const std::optional<cvf::Color3f>& color,
|
||||||
|
const std::optional<RiuPlotCurveSymbol::PointSymbolEnum>& symbol = std::nullopt );
|
||||||
|
bool isCustom() const;
|
||||||
|
|
||||||
|
// The custom symbol, if the rule is custom
|
||||||
|
std::optional<RiuPlotCurveSymbol::PointSymbolEnum> overriddenSymbol() const;
|
||||||
|
|
||||||
|
// Adds the mode, color and symbol fields, to be edited for the object selected in the collection
|
||||||
|
void appendFieldsToUiOrdering( const QString& uiConfigName, caf::PdmUiOrdering& uiOrdering );
|
||||||
|
|
||||||
|
// The properties currently assigned automatically by the global appearance, shown while the item is Auto
|
||||||
|
void setAutoAssigned( const std::optional<cvf::Color3f>& color, const std::optional<RiuPlotCurveSymbol::PointSymbolEnum>& symbol );
|
||||||
|
void updateAppearanceFromCurves();
|
||||||
|
|
||||||
|
// The custom color, if the rule is custom
|
||||||
|
std::optional<cvf::Color3f> overriddenColor() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) override;
|
||||||
|
QList<caf::PdmOptionItemInfo> calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions ) override;
|
||||||
|
void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override;
|
||||||
|
void initAfterRead() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void copyAppearanceFromCurves();
|
||||||
|
void connectAppearanceSignal();
|
||||||
|
void onAppearanceChanged( const caf::SignalEmitter* emitter );
|
||||||
|
|
||||||
|
private:
|
||||||
|
caf::PdmField<caf::AppEnum<Dimension>> m_dimension;
|
||||||
|
caf::PdmField<QString> m_itemName;
|
||||||
|
caf::PdmField<caf::AppEnum<Mode>> m_mode;
|
||||||
|
|
||||||
|
// Color, symbol, line and fill settings that can be overridden
|
||||||
|
caf::PdmChildField<RimPlotCurveAppearance*> m_curveAppearance;
|
||||||
|
|
||||||
|
std::optional<cvf::Color3f> m_autoColor;
|
||||||
|
std::optional<RiuPlotCurveSymbol::PointSymbolEnum> m_autoSymbol;
|
||||||
|
};
|
||||||
@@ -0,0 +1,659 @@
|
|||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Copyright (C) 2026- 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 "RimCurveStyleRules.h"
|
||||||
|
|
||||||
|
#include "RiaGuiApplication.h"
|
||||||
|
|
||||||
|
#include "RimColorLegend.h"
|
||||||
|
#include "RimColorLegendCollection.h"
|
||||||
|
#include "RimColorLegendItem.h"
|
||||||
|
#include "RimCurveStyleRule.h"
|
||||||
|
#include "RimCurveStyleSettings.h"
|
||||||
|
#include "RimEnsembleCurveSet.h"
|
||||||
|
#include "RimEnsembleCurveSetCollection.h"
|
||||||
|
#include "RimProject.h"
|
||||||
|
#include "RimSummaryCurve.h"
|
||||||
|
#include "RimSummaryCurveAppearanceCalculator.h"
|
||||||
|
#include "RimSummaryPlot.h"
|
||||||
|
|
||||||
|
#include "RiuPlotCurveSymbolImageCreator.h"
|
||||||
|
#include "RiuPlotMainWindow.h"
|
||||||
|
|
||||||
|
#include "cafPdmUiLabel.h"
|
||||||
|
#include "cafPdmUiListEditor.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <map>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
|
CAF_PDM_SOURCE_INIT( RimCurveStyleRules, "RimCurveStyleRules" );
|
||||||
|
|
||||||
|
namespace caf
|
||||||
|
{
|
||||||
|
template <>
|
||||||
|
void caf::AppEnum<RimCurveStyleRules::AppearanceType>::setUp()
|
||||||
|
{
|
||||||
|
using T = RimCurveStyleRules::AppearanceType;
|
||||||
|
addItem( T::COLOR, "COLOR", "Color" );
|
||||||
|
addItem( T::SYMBOL, "SYMBOL", "Symbol" );
|
||||||
|
setDefault( T::COLOR );
|
||||||
|
}
|
||||||
|
} // namespace caf
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
RimCurveStyleRules::RimCurveStyleRules()
|
||||||
|
{
|
||||||
|
CAF_PDM_InitObject( "Curve Style Rules" );
|
||||||
|
|
||||||
|
CAF_PDM_InitField( &m_useGlobalAppearance,
|
||||||
|
"UseGlobalAppearance",
|
||||||
|
false,
|
||||||
|
"Use Global Curve Appearance",
|
||||||
|
"",
|
||||||
|
"Assign curve appearance in all summary plots from the global curve appearance definition" );
|
||||||
|
|
||||||
|
CAF_PDM_InitFieldNoDefault( &m_settings, "Settings", "Settings" );
|
||||||
|
m_settings.uiCapability()->setUiTreeChildrenHidden( true );
|
||||||
|
m_settings.uiCapability()->setUiHidden( true );
|
||||||
|
m_settings = new RimCurveStyleSettings;
|
||||||
|
|
||||||
|
CAF_PDM_InitFieldNoDefault( &m_savedAppearances, "SavedAppearances", "Saved Appearances" );
|
||||||
|
m_savedAppearances.uiCapability()->setUiTreeChildrenHidden( true );
|
||||||
|
m_savedAppearances.uiCapability()->setUiHidden( true );
|
||||||
|
|
||||||
|
CAF_PDM_InitFieldNoDefault( &m_rules, "Rules", "Rules" );
|
||||||
|
m_rules.uiCapability()->setUiTreeChildrenHidden( true );
|
||||||
|
m_rules.uiCapability()->setUiHidden( true );
|
||||||
|
|
||||||
|
CAF_PDM_InitFieldNoDefault( &m_caseOrder, "CaseOrder", "Case Order" );
|
||||||
|
m_caseOrder.uiCapability()->setUiHidden( true );
|
||||||
|
CAF_PDM_InitFieldNoDefault( &m_wellOrder, "WellOrder", "Well Order" );
|
||||||
|
m_wellOrder.uiCapability()->setUiHidden( true );
|
||||||
|
|
||||||
|
CAF_PDM_InitFieldNoDefault( &m_selectedItem, "SelectedItem", "Selected Item" );
|
||||||
|
m_selectedItem.uiCapability()->setUiTreeChildrenHidden( true );
|
||||||
|
m_selectedItem.uiCapability()->setUiHidden( true );
|
||||||
|
m_selectedItem.xmlCapability()->disableIO();
|
||||||
|
m_selectedItem = new RimCurveStyleRule;
|
||||||
|
|
||||||
|
CAF_PDM_InitFieldNoDefault( &m_appearanceType, "AppearanceType", "Appearance Property" );
|
||||||
|
m_appearanceType.xmlCapability()->disableIO();
|
||||||
|
|
||||||
|
CAF_PDM_InitFieldNoDefault( &m_autoColorLegend, "AutoColorLegend", "Color Palette" );
|
||||||
|
|
||||||
|
CAF_PDM_InitField( &m_symbolLegend, "SymbolLegend", 0, "Symbol Sequence" );
|
||||||
|
m_symbolLegend.uiCapability()->setUiEditorTypeName( caf::PdmUiListEditor::uiEditorTypeName() );
|
||||||
|
m_symbolLegend.uiCapability()->setUiLabelPosition( caf::PdmUiItemInfo::LabelPosition::TOP );
|
||||||
|
m_symbolLegend.uiCapability()->setUiReadOnly( true );
|
||||||
|
m_symbolLegend.uiCapability()->setAttribute( caf::PdmUiListEditor::Keys::HEIGHT_HINT, 120 );
|
||||||
|
m_symbolLegend.xmlCapability()->disableIO();
|
||||||
|
|
||||||
|
CAF_PDM_InitFieldNoDefault( &m_currentType, "CurrentType", "Differentiate By" );
|
||||||
|
m_currentType.registerGetMethod( this, &RimCurveStyleRules::currentDimension );
|
||||||
|
m_currentType.registerSetMethod( this, &RimCurveStyleRules::setCurrentDimension );
|
||||||
|
m_currentType.xmlCapability()->disableIO();
|
||||||
|
|
||||||
|
CAF_PDM_InitField( &m_currentItemIndex, "CurrentItemIndex", 0, "Items" );
|
||||||
|
m_currentItemIndex.uiCapability()->setUiEditorTypeName( caf::PdmUiListEditor::uiEditorTypeName() );
|
||||||
|
m_currentItemIndex.uiCapability()->setUiLabelPosition( caf::PdmUiItemInfo::LabelPosition::TOP );
|
||||||
|
m_currentItemIndex.uiCapability()->setAttribute( caf::PdmUiListEditor::Keys::HEIGHT_HINT, 200 );
|
||||||
|
m_currentItemIndex.uiCapability()->setAttribute( caf::PdmUiListEditor::Keys::ICON_SIZE, QSize( 52, 16 ) );
|
||||||
|
m_currentItemIndex.xmlCapability()->disableIO();
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
RimCurveStyleSettings* RimCurveStyleRules::settings() const
|
||||||
|
{
|
||||||
|
return m_settings();
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
std::vector<RimCurveStyleRule*> RimCurveStyleRules::rules() const
|
||||||
|
{
|
||||||
|
return m_rules.childrenByType();
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
RimCurveStyleRule* RimCurveStyleRules::findOrCreateRule( RimCurveStyleRule::Dimension dimension, const QString& name )
|
||||||
|
{
|
||||||
|
if ( auto rule = findRule( dimension, name ) ) return rule;
|
||||||
|
|
||||||
|
auto rule = new RimCurveStyleRule;
|
||||||
|
rule->setDimension( dimension );
|
||||||
|
rule->setItemName( name );
|
||||||
|
m_rules.push_back( rule );
|
||||||
|
|
||||||
|
return rule;
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
std::vector<const RimCurveStyleRule*> RimCurveStyleRules::rulesFor( const RifEclipseSummaryAddress& address, const std::string& caseName ) const
|
||||||
|
{
|
||||||
|
const auto colorDimension = m_settings->colorDimension();
|
||||||
|
const auto symbolDimension = m_settings->symbolDimension();
|
||||||
|
|
||||||
|
std::vector<const RimCurveStyleRule*> result;
|
||||||
|
for ( auto rule : m_rules )
|
||||||
|
{
|
||||||
|
if ( !rule->isCustom() ) continue;
|
||||||
|
|
||||||
|
const auto dimension = rule->dimension();
|
||||||
|
if ( dimension != colorDimension && dimension != symbolDimension ) continue;
|
||||||
|
|
||||||
|
const auto value = RimCurveStyleSettings::dimensionValue( dimension, address, caseName );
|
||||||
|
if ( !value.empty() && QString::fromStdString( value ) == rule->itemName() ) result.push_back( rule );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fixed precedence by dimension, so the result does not depend on the order the rules were created in
|
||||||
|
std::stable_sort( result.begin(),
|
||||||
|
result.end(),
|
||||||
|
[]( const RimCurveStyleRule* a, const RimCurveStyleRule* b ) { return a->dimension() < b->dimension(); } );
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
void RimCurveStyleRules::rulesChanged()
|
||||||
|
{
|
||||||
|
auto project = RimProject::current();
|
||||||
|
if ( !project ) return;
|
||||||
|
|
||||||
|
RimCurveStyleRule::AvailableNamesCache namesCache;
|
||||||
|
for ( auto plot : project->descendantsIncludingThisOfType<RimSummaryPlot>() )
|
||||||
|
{
|
||||||
|
plot->updateCurveAppearanceFromGlobalSettings();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
void RimCurveStyleRules::ruleChanged( RimCurveStyleRule* rule )
|
||||||
|
{
|
||||||
|
if ( rule == m_selectedItem() )
|
||||||
|
{
|
||||||
|
// Rules are only stored for items that have been made custom
|
||||||
|
auto stored = rule->isCustom() ? findOrCreateRule( rule->dimension(), rule->itemName() )
|
||||||
|
: findRule( rule->dimension(), rule->itemName() );
|
||||||
|
if ( stored ) stored->copySettingsFrom( *rule );
|
||||||
|
}
|
||||||
|
|
||||||
|
rulesChanged();
|
||||||
|
updateConnectedEditors();
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
bool RimCurveStyleRules::controlsColor( const RifEclipseSummaryAddress& address, const std::string& caseName ) const
|
||||||
|
{
|
||||||
|
const auto dimension = m_settings->colorDimension();
|
||||||
|
if ( !m_useGlobalAppearance() || dimension == RimCurveStyleRule::Dimension::NONE ) return false;
|
||||||
|
|
||||||
|
return !RimCurveStyleSettings::dimensionValue( dimension, address, caseName ).empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
bool RimCurveStyleRules::controlsSymbol( const RifEclipseSummaryAddress& address, const std::string& caseName ) const
|
||||||
|
{
|
||||||
|
const auto dimension = m_settings->symbolDimension();
|
||||||
|
if ( !m_useGlobalAppearance() || dimension == RimCurveStyleRule::Dimension::NONE ) return false;
|
||||||
|
|
||||||
|
return !RimCurveStyleSettings::dimensionValue( dimension, address, caseName ).empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
void RimCurveStyleRules::registerItemNames( RimCurveStyleRule::Dimension dimension, const QStringList& names )
|
||||||
|
{
|
||||||
|
auto order = itemOrder( dimension );
|
||||||
|
if ( !order ) return;
|
||||||
|
|
||||||
|
auto values = ( *order )();
|
||||||
|
const std::set<QString> registered( values.begin(), values.end() );
|
||||||
|
for ( const auto& name : names )
|
||||||
|
{
|
||||||
|
if ( !registered.contains( name ) ) values.push_back( name );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( values.size() != ( *order )().size() ) order->setValue( values );
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
std::map<QString, int> RimCurveStyleRules::itemIndices( RimCurveStyleRule::Dimension dimension ) const
|
||||||
|
{
|
||||||
|
auto order = itemOrder( dimension );
|
||||||
|
if ( !order ) return {};
|
||||||
|
|
||||||
|
std::map<QString, int> indices;
|
||||||
|
|
||||||
|
int index = 0;
|
||||||
|
for ( const auto& name : ( *order )() )
|
||||||
|
{
|
||||||
|
if ( indices.emplace( name, index ).second ) index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( const auto& name : RimCurveStyleRule::availableNames( dimension ) )
|
||||||
|
{
|
||||||
|
if ( indices.emplace( name, index ).second ) index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return indices;
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
caf::PdmField<std::vector<QString>>* RimCurveStyleRules::itemOrder( RimCurveStyleRule::Dimension dimension )
|
||||||
|
{
|
||||||
|
if ( dimension == RimCurveStyleRule::Dimension::CASE ) return &m_caseOrder;
|
||||||
|
if ( dimension == RimCurveStyleRule::Dimension::WELL ) return &m_wellOrder;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
const caf::PdmField<std::vector<QString>>* RimCurveStyleRules::itemOrder( RimCurveStyleRule::Dimension dimension ) const
|
||||||
|
{
|
||||||
|
return const_cast<RimCurveStyleRules*>( this )->itemOrder( dimension );
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
void RimCurveStyleRules::addGlobalAppearanceLink( caf::PdmUiOrdering& uiOrdering, const QString& text )
|
||||||
|
{
|
||||||
|
auto label = uiOrdering.addNewLabel( text );
|
||||||
|
label->setLinkActivatedCallback(
|
||||||
|
[]( const QString& )
|
||||||
|
{
|
||||||
|
if ( auto window = RiaGuiApplication::instance()->mainPlotWindow() ) window->showCurveAppearance();
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
bool RimCurveStyleRules::useGlobalAppearance() const
|
||||||
|
{
|
||||||
|
return m_useGlobalAppearance();
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
void RimCurveStyleRules::setUseGlobalAppearance( bool enable )
|
||||||
|
{
|
||||||
|
if ( m_useGlobalAppearance() == enable ) return;
|
||||||
|
|
||||||
|
m_useGlobalAppearance = enable;
|
||||||
|
applyGlobalAppearanceMode();
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
/// Applies the global appearance to all plots when enabled, and restores the original appearance when disabled
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
void RimCurveStyleRules::applyGlobalAppearanceMode()
|
||||||
|
{
|
||||||
|
auto project = RimProject::current();
|
||||||
|
if ( !project ) return;
|
||||||
|
|
||||||
|
if ( m_useGlobalAppearance() )
|
||||||
|
{
|
||||||
|
RimCurveStyleRule::AvailableNamesCache namesCache;
|
||||||
|
|
||||||
|
m_savedAppearances.deleteChildren();
|
||||||
|
for ( auto plot : project->descendantsIncludingThisOfType<RimSummaryPlot>() )
|
||||||
|
{
|
||||||
|
saveAppearance( plot );
|
||||||
|
plot->updateCurveAppearanceFromGlobalSettings();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
restoreAppearances();
|
||||||
|
m_savedAppearances.deleteChildren();
|
||||||
|
}
|
||||||
|
|
||||||
|
updateConnectedEditors();
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
void RimCurveStyleRules::saveAppearance( RimSummaryPlot* plot )
|
||||||
|
{
|
||||||
|
for ( auto curve : plot->summaryCurves() )
|
||||||
|
{
|
||||||
|
auto saved = new RimSavedCurveAppearance;
|
||||||
|
saved->setCurve( curve );
|
||||||
|
m_savedAppearances.push_back( saved );
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( auto curveSet : plot->ensembleCurveSetCollection()->curveSets() )
|
||||||
|
{
|
||||||
|
auto saved = new RimSavedCurveAppearance;
|
||||||
|
saved->setEnsembleCurveSet( curveSet );
|
||||||
|
m_savedAppearances.push_back( saved );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
/// Curves without a saved appearance, typically created while the global appearance was enabled, get the
|
||||||
|
/// calculated default appearance
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
void RimCurveStyleRules::restoreAppearances()
|
||||||
|
{
|
||||||
|
auto project = RimProject::current();
|
||||||
|
if ( !project ) return;
|
||||||
|
|
||||||
|
std::set<caf::PdmObject*> restored;
|
||||||
|
for ( auto saved : m_savedAppearances )
|
||||||
|
{
|
||||||
|
if ( auto object = saved->restore() ) restored.insert( object );
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( auto plot : project->descendantsIncludingThisOfType<RimSummaryPlot>() )
|
||||||
|
{
|
||||||
|
std::vector<RimSummaryCurve*> curves;
|
||||||
|
for ( auto curve : plot->summaryCurves() )
|
||||||
|
{
|
||||||
|
if ( !restored.contains( curve ) ) curves.push_back( curve );
|
||||||
|
}
|
||||||
|
if ( !curves.empty() ) plot->applyDefaultCurveAppearances( curves );
|
||||||
|
|
||||||
|
std::vector<RimEnsembleCurveSet*> curveSets;
|
||||||
|
for ( auto curveSet : plot->ensembleCurveSetCollection()->curveSets() )
|
||||||
|
{
|
||||||
|
if ( !restored.contains( curveSet ) ) curveSets.push_back( curveSet );
|
||||||
|
}
|
||||||
|
if ( !curveSets.empty() ) plot->applyDefaultCurveAppearances( curveSets );
|
||||||
|
|
||||||
|
plot->updateConnectedEditors();
|
||||||
|
plot->loadDataAndUpdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
std::optional<cvf::Color3f> RimCurveStyleRules::autoLegendColor( int index ) const
|
||||||
|
{
|
||||||
|
if ( !m_autoColorLegend() || index < 0 ) return std::nullopt;
|
||||||
|
|
||||||
|
const auto items = m_autoColorLegend()->colorLegendItems();
|
||||||
|
if ( items.empty() ) return std::nullopt;
|
||||||
|
|
||||||
|
return items[index % items.size()]->color();
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
QList<caf::PdmOptionItemInfo> RimCurveStyleRules::calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions )
|
||||||
|
{
|
||||||
|
QList<caf::PdmOptionItemInfo> options;
|
||||||
|
|
||||||
|
if ( fieldNeedingOptions == &m_autoColorLegend )
|
||||||
|
{
|
||||||
|
options.push_back( caf::PdmOptionItemInfo( "Default Palette", nullptr ) );
|
||||||
|
if ( auto project = RimProject::current() )
|
||||||
|
{
|
||||||
|
for ( auto legend : project->colorLegendCollection()->allColorLegends() )
|
||||||
|
{
|
||||||
|
options.push_back( caf::PdmOptionItemInfo( legend->colorLegendName(), legend, false, legend->paletteIconProvider() ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ( fieldNeedingOptions == &m_symbolLegend )
|
||||||
|
{
|
||||||
|
const int count = static_cast<int>( caf::AppEnum<RiuPlotCurveSymbol::PointSymbolEnum>::size() ) - 1;
|
||||||
|
for ( int i = 0; i < count; i++ )
|
||||||
|
{
|
||||||
|
const auto symbol = RimSummaryCurveAppearanceCalculator::cycledSymbol( i );
|
||||||
|
const auto image = RiuPlotCurveSymbolImageCreator::createSymbolImage( symbol, QSize( 14, 14 ), QColor( Qt::black ) );
|
||||||
|
options.push_back( caf::PdmOptionItemInfo( caf::AppEnum<RiuPlotCurveSymbol::PointSymbolEnum>::uiText( symbol ),
|
||||||
|
i,
|
||||||
|
false,
|
||||||
|
caf::IconProvider( QPixmap::fromImage( image ) ) ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ( fieldNeedingOptions == &m_currentType )
|
||||||
|
{
|
||||||
|
using D = RimCurveStyleRule::Dimension;
|
||||||
|
for ( size_t i = 0; i < caf::AppEnum<D>::size(); i++ )
|
||||||
|
{
|
||||||
|
const auto dimension = caf::AppEnum<D>::fromIndex( i );
|
||||||
|
options.push_back( caf::PdmOptionItemInfo( caf::AppEnum<D>::uiText( dimension ), static_cast<int>( dimension ) ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ( fieldNeedingOptions == &m_currentItemIndex )
|
||||||
|
{
|
||||||
|
RimCurveStyleRule::AvailableNamesCache namesCache;
|
||||||
|
|
||||||
|
const bool isColorDim = m_appearanceType() == AppearanceType::COLOR;
|
||||||
|
const bool isSymbolDim = m_appearanceType() == AppearanceType::SYMBOL;
|
||||||
|
const auto plotAppearances = RimCurveStyleRule::appearancesFromPlots( m_currentType() );
|
||||||
|
const auto indices = itemIndices( m_currentType() );
|
||||||
|
for ( const auto& name : RimCurveStyleRule::availableNames( m_currentType() ) )
|
||||||
|
{
|
||||||
|
const auto customRule = findRule( m_currentType(), name );
|
||||||
|
const bool isCustom = customRule && customRule->isCustom();
|
||||||
|
const auto indexIt = indices.find( name );
|
||||||
|
const int index = indexIt != indices.end() ? indexIt->second : static_cast<int>( options.size() );
|
||||||
|
|
||||||
|
std::optional<cvf::Color3f> autoColor;
|
||||||
|
std::optional<RiuPlotCurveSymbol::PointSymbolEnum> autoSymbol;
|
||||||
|
assignedAppearance( name, index, plotAppearances, autoColor, autoSymbol );
|
||||||
|
|
||||||
|
std::optional<cvf::Color3f> color;
|
||||||
|
if ( isColorDim && autoColor ) color = isCustom ? customRule->overriddenColor().value_or( *autoColor ) : autoColor;
|
||||||
|
|
||||||
|
std::optional<RiuPlotCurveSymbol::PointSymbolEnum> symbol;
|
||||||
|
if ( isSymbolDim && autoSymbol ) symbol = isCustom ? customRule->overriddenSymbol().value_or( *autoSymbol ) : autoSymbol;
|
||||||
|
const auto icon = RimCurveStyleRule::dimensionColorIcon( m_currentType(), color, symbol );
|
||||||
|
options.push_back(
|
||||||
|
caf::PdmOptionItemInfo( isCustom ? name + " [Custom]" : name + " [Auto]", static_cast<int>( options.size() ), false, icon ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
/// The color and symbol the global appearance assigns to the item at the given position
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
void RimCurveStyleRules::assignedAppearance( const QString& name,
|
||||||
|
int index,
|
||||||
|
const std::map<QString, RimCurveStyleRule::PlotAppearance>& plotAppearances,
|
||||||
|
std::optional<cvf::Color3f>& color,
|
||||||
|
std::optional<RiuPlotCurveSymbol::PointSymbolEnum>& symbol ) const
|
||||||
|
{
|
||||||
|
const bool projectWide = m_currentType() == RimCurveStyleRule::Dimension::CASE || m_currentType() == RimCurveStyleRule::Dimension::WELL;
|
||||||
|
|
||||||
|
const auto fromPlots = plotAppearances.find( name );
|
||||||
|
const bool inPlots = fromPlots != plotAppearances.end();
|
||||||
|
|
||||||
|
if ( projectWide ) color = RimSummaryCurveAppearanceCalculator::cycledPaletteColor( index );
|
||||||
|
if ( !color && inPlots ) color = fromPlots->second.color;
|
||||||
|
if ( !color ) color = RimSummaryCurveAppearanceCalculator::cycledPaletteColor( index );
|
||||||
|
|
||||||
|
if ( projectWide ) symbol = RimSummaryCurveAppearanceCalculator::cycledSymbol( index );
|
||||||
|
if ( !symbol && inPlots ) symbol = fromPlots->second.symbol;
|
||||||
|
if ( !symbol ) symbol = RimSummaryCurveAppearanceCalculator::cycledSymbol( index );
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
RimCurveStyleRule* RimCurveStyleRules::findRule( RimCurveStyleRule::Dimension dimension, const QString& name ) const
|
||||||
|
{
|
||||||
|
for ( auto item : m_rules )
|
||||||
|
{
|
||||||
|
if ( item->dimension() == dimension && item->itemName() == name ) return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
void RimCurveStyleRules::fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue )
|
||||||
|
{
|
||||||
|
RimCurveStyleRule::AvailableNamesCache namesCache;
|
||||||
|
|
||||||
|
if ( changedField == &m_useGlobalAppearance )
|
||||||
|
{
|
||||||
|
applyGlobalAppearanceMode();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( changedField == &m_autoColorLegend )
|
||||||
|
{
|
||||||
|
rulesChanged();
|
||||||
|
}
|
||||||
|
else if ( changedField == &m_appearanceType )
|
||||||
|
{
|
||||||
|
m_currentItemIndex = 0;
|
||||||
|
}
|
||||||
|
else if ( changedField == &m_currentType )
|
||||||
|
{
|
||||||
|
m_currentItemIndex = 0;
|
||||||
|
rulesChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
updateConnectedEditors();
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
QString RimCurveStyleRules::currentItemName() const
|
||||||
|
{
|
||||||
|
const auto names = RimCurveStyleRule::availableNames( m_currentType() );
|
||||||
|
const int index = m_currentItemIndex();
|
||||||
|
return index >= 0 && index < names.size() ? names[index] : QString();
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
caf::AppEnum<RimCurveStyleRule::Dimension> RimCurveStyleRules::currentDimension() const
|
||||||
|
{
|
||||||
|
auto settings = m_settings();
|
||||||
|
if ( !settings ) return RimCurveStyleRule::Dimension::NONE;
|
||||||
|
|
||||||
|
return m_appearanceType() == AppearanceType::COLOR ? settings->colorDimension() : settings->symbolDimension();
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
void RimCurveStyleRules::setCurrentDimension( const caf::AppEnum<RimCurveStyleRule::Dimension>& dimension )
|
||||||
|
{
|
||||||
|
auto settings = m_settings();
|
||||||
|
if ( !settings ) return;
|
||||||
|
|
||||||
|
if ( m_appearanceType() == AppearanceType::COLOR )
|
||||||
|
settings->setColorDimension( dimension );
|
||||||
|
else
|
||||||
|
settings->setSymbolDimension( dimension );
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
/// Shows the stored custom settings of the selected item, or the appearance assigned automatically. Only the
|
||||||
|
/// selected item object is changed, it is not stored in the project.
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
bool RimCurveStyleRules::updateSelectedItem()
|
||||||
|
{
|
||||||
|
const QString itemName = currentItemName();
|
||||||
|
if ( itemName.isEmpty() ) return false;
|
||||||
|
|
||||||
|
auto selected = m_selectedItem();
|
||||||
|
selected->setDimension( m_currentType() );
|
||||||
|
selected->setItemName( itemName );
|
||||||
|
|
||||||
|
auto stored = findRule( m_currentType(), itemName );
|
||||||
|
if ( stored && stored->isCustom() )
|
||||||
|
{
|
||||||
|
selected->copySettingsFrom( *stored );
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto indices = itemIndices( m_currentType() );
|
||||||
|
const auto indexIt = indices.find( itemName );
|
||||||
|
const int index = indexIt != indices.end() ? indexIt->second : m_currentItemIndex();
|
||||||
|
|
||||||
|
std::optional<cvf::Color3f> autoColor;
|
||||||
|
std::optional<RiuPlotCurveSymbol::PointSymbolEnum> autoSymbol;
|
||||||
|
assignedAppearance( itemName, index, RimCurveStyleRule::appearancesFromPlots( m_currentType() ), autoColor, autoSymbol );
|
||||||
|
|
||||||
|
selected->setCustom( false );
|
||||||
|
selected->setAutoAssigned( m_appearanceType() == AppearanceType::COLOR ? autoColor : std::nullopt,
|
||||||
|
m_appearanceType() == AppearanceType::SYMBOL ? autoSymbol : std::nullopt );
|
||||||
|
selected->updateAppearanceFromCurves();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
void RimCurveStyleRules::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering )
|
||||||
|
{
|
||||||
|
RimCurveStyleRule::AvailableNamesCache namesCache;
|
||||||
|
|
||||||
|
uiOrdering.add( &m_useGlobalAppearance );
|
||||||
|
uiOrdering.add( &m_appearanceType );
|
||||||
|
uiOrdering.add( &m_currentType );
|
||||||
|
|
||||||
|
auto rulesGroup = uiOrdering.addNewGroup( "Assigned Appearance" );
|
||||||
|
if ( m_appearanceType() == AppearanceType::COLOR )
|
||||||
|
rulesGroup->add( &m_autoColorLegend );
|
||||||
|
else
|
||||||
|
rulesGroup->add( &m_symbolLegend );
|
||||||
|
rulesGroup->add( &m_currentItemIndex );
|
||||||
|
|
||||||
|
if ( updateSelectedItem() )
|
||||||
|
{
|
||||||
|
auto appearanceGroup = uiOrdering.addNewGroup( "Selected Item" );
|
||||||
|
m_selectedItem->appendFieldsToUiOrdering( uiConfigName, *appearanceGroup );
|
||||||
|
}
|
||||||
|
|
||||||
|
uiOrdering.skipRemainingFields();
|
||||||
|
}
|
||||||
@@ -0,0 +1,137 @@
|
|||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Copyright (C) 2026- 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.
|
||||||
|
//
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "RimCurveStyleRule.h"
|
||||||
|
#include "RimPlotCurveAppearance.h"
|
||||||
|
#include "RimSavedCurveAppearance.h"
|
||||||
|
|
||||||
|
#include "cafPdmChildArrayField.h"
|
||||||
|
#include "cafPdmChildField.h"
|
||||||
|
#include "cafPdmField.h"
|
||||||
|
#include "cafPdmObject.h"
|
||||||
|
#include "cafPdmProxyValueField.h"
|
||||||
|
#include "cafPdmPtrField.h"
|
||||||
|
|
||||||
|
#include "cvfColor3.h"
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <optional>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
class RimColorLegend;
|
||||||
|
class RimEnsembleCurveSet;
|
||||||
|
class RimPlotCurve;
|
||||||
|
class RimSummaryPlot;
|
||||||
|
class RifEclipseSummaryAddress;
|
||||||
|
|
||||||
|
//==================================================================================================
|
||||||
|
/// Project-stored list of per-item style rules for the global curve appearance.
|
||||||
|
//==================================================================================================
|
||||||
|
class RimCurveStyleRules : public caf::PdmObject
|
||||||
|
{
|
||||||
|
CAF_PDM_HEADER_INIT;
|
||||||
|
|
||||||
|
public:
|
||||||
|
RimCurveStyleRules();
|
||||||
|
|
||||||
|
std::vector<RimCurveStyleRule*> rules() const;
|
||||||
|
RimCurveStyleRule* findOrCreateRule( RimCurveStyleRule::Dimension dimension, const QString& name );
|
||||||
|
|
||||||
|
// Custom rules for the dimensions selected for color or symbol, ordered so that later entries win: by dimension
|
||||||
|
std::vector<const RimCurveStyleRule*> rulesFor( const RifEclipseSummaryAddress& address, const std::string& caseName ) const;
|
||||||
|
|
||||||
|
RimCurveStyleSettings* settings() const;
|
||||||
|
|
||||||
|
// Re-applies the global appearance to all plots using it
|
||||||
|
void rulesChanged();
|
||||||
|
|
||||||
|
// Stores custom settings edited for the selected item, and re-applies the global appearance
|
||||||
|
void ruleChanged( RimCurveStyleRule* rule );
|
||||||
|
|
||||||
|
// Whether the global appearance assigns the color or symbol of a curve with the given address and case
|
||||||
|
bool controlsColor( const RifEclipseSummaryAddress& address, const std::string& caseName ) const;
|
||||||
|
bool controlsSymbol( const RifEclipseSummaryAddress& address, const std::string& caseName ) const;
|
||||||
|
|
||||||
|
// Index used to pick the palette color and symbol for a case or well name. Indices are kept in the project so that
|
||||||
|
// existing items keep their appearance when new cases or wells are added.
|
||||||
|
// Names not yet registered get the indices they would get if registered now.
|
||||||
|
void registerItemNames( RimCurveStyleRule::Dimension dimension, const QStringList& names );
|
||||||
|
std::map<QString, int> itemIndices( RimCurveStyleRule::Dimension dimension ) const;
|
||||||
|
|
||||||
|
// Color from the project color legend used for auto colors, if one is selected
|
||||||
|
std::optional<cvf::Color3f> autoLegendColor( int index ) const;
|
||||||
|
|
||||||
|
// Configures a field as a label with a link that shows the global curve appearance
|
||||||
|
static void addGlobalAppearanceLink( caf::PdmUiOrdering& uiOrdering, const QString& text );
|
||||||
|
|
||||||
|
// The global appearance applies to all summary plots in the project
|
||||||
|
bool useGlobalAppearance() const;
|
||||||
|
void setUseGlobalAppearance( bool enable );
|
||||||
|
|
||||||
|
protected:
|
||||||
|
QList<caf::PdmOptionItemInfo> calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions ) override;
|
||||||
|
void fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) override;
|
||||||
|
void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override;
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum class AppearanceType
|
||||||
|
{
|
||||||
|
COLOR,
|
||||||
|
SYMBOL
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
void assignedAppearance( const QString& name,
|
||||||
|
int index,
|
||||||
|
const std::map<QString, RimCurveStyleRule::PlotAppearance>& plotAppearances,
|
||||||
|
std::optional<cvf::Color3f>& color,
|
||||||
|
std::optional<RiuPlotCurveSymbol::PointSymbolEnum>& symbol ) const;
|
||||||
|
RimCurveStyleRule* findRule( RimCurveStyleRule::Dimension dimension, const QString& name ) const;
|
||||||
|
QString currentItemName() const;
|
||||||
|
bool updateSelectedItem();
|
||||||
|
|
||||||
|
// The dimension controlling the selected appearance type, as stored in the global settings
|
||||||
|
caf::AppEnum<RimCurveStyleRule::Dimension> currentDimension() const;
|
||||||
|
void setCurrentDimension( const caf::AppEnum<RimCurveStyleRule::Dimension>& dimension );
|
||||||
|
|
||||||
|
caf::PdmField<std::vector<QString>>* itemOrder( RimCurveStyleRule::Dimension dimension );
|
||||||
|
const caf::PdmField<std::vector<QString>>* itemOrder( RimCurveStyleRule::Dimension dimension ) const;
|
||||||
|
|
||||||
|
void applyGlobalAppearanceMode();
|
||||||
|
void saveAppearance( RimSummaryPlot* plot );
|
||||||
|
void restoreAppearances();
|
||||||
|
|
||||||
|
// The curve appearance before the global appearance was enabled, restored when disabled
|
||||||
|
caf::PdmChildArrayField<RimSavedCurveAppearance*> m_savedAppearances;
|
||||||
|
caf::PdmField<bool> m_useGlobalAppearance;
|
||||||
|
|
||||||
|
caf::PdmChildField<RimCurveStyleSettings*> m_settings;
|
||||||
|
caf::PdmChildArrayField<RimCurveStyleRule*> m_rules;
|
||||||
|
caf::PdmField<std::vector<QString>> m_caseOrder;
|
||||||
|
caf::PdmField<std::vector<QString>> m_wellOrder;
|
||||||
|
caf::PdmField<caf::AppEnum<AppearanceType>> m_appearanceType;
|
||||||
|
caf::PdmProxyValueField<caf::AppEnum<RimCurveStyleRule::Dimension>> m_currentType;
|
||||||
|
caf::PdmPtrField<RimColorLegend*> m_autoColorLegend;
|
||||||
|
caf::PdmField<int> m_symbolLegend;
|
||||||
|
caf::PdmField<int> m_currentItemIndex;
|
||||||
|
|
||||||
|
// Edited in the dock window for the selected item. Not stored, custom settings are copied to a rule in m_rules.
|
||||||
|
caf::PdmChildField<RimCurveStyleRule*> m_selectedItem;
|
||||||
|
};
|
||||||
@@ -0,0 +1,197 @@
|
|||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Copyright (C) 2026- 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 "RimCurveStyleSettings.h"
|
||||||
|
|
||||||
|
#include "RifEclipseSummaryAddress.h"
|
||||||
|
|
||||||
|
#include "RimCurveStyleRules.h"
|
||||||
|
#include "RimSummaryCase.h"
|
||||||
|
#include "RimSummaryEnsemble.h"
|
||||||
|
|
||||||
|
namespace caf
|
||||||
|
{
|
||||||
|
template <>
|
||||||
|
void caf::AppEnum<RimCurveStyleSettings::Dimension>::setUp()
|
||||||
|
{
|
||||||
|
using D = RimCurveStyleSettings::Dimension;
|
||||||
|
addItem( D::NONE, "NONE", "None" );
|
||||||
|
addItem( D::CASE, "CASE", "Summary Case" );
|
||||||
|
addItem( D::VECTOR, "VECTOR", "Vector" );
|
||||||
|
addItem( D::WELL, "WELL", "Well" );
|
||||||
|
addItem( D::GROUP, "GROUP", "Group" );
|
||||||
|
addItem( D::NETWORK, "NETWORK", "Network" );
|
||||||
|
addItem( D::REGION, "REGION", "Region" );
|
||||||
|
addItem( D::REGION_2_REGION, "REGION_2_REGION", "Region-Region" );
|
||||||
|
addItem( D::AQUIFER, "AQUIFER", "Aquifer" );
|
||||||
|
addItem( D::LGR, "LGR", "LGR" );
|
||||||
|
addItem( D::BLOCK, "BLOCK", "Block" );
|
||||||
|
addItem( D::CONNECTION, "CONNECTION", "Connection" );
|
||||||
|
addItem( D::SEGMENT, "SEGMENT", "Segment" );
|
||||||
|
setDefault( D::NONE );
|
||||||
|
}
|
||||||
|
} // namespace caf
|
||||||
|
|
||||||
|
CAF_PDM_SOURCE_INIT( RimCurveStyleSettings, "RimCurveStyleSettings" );
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
RimCurveStyleSettings::RimCurveStyleSettings()
|
||||||
|
{
|
||||||
|
CAF_PDM_InitObject( "Global Curve Appearance" );
|
||||||
|
|
||||||
|
CAF_PDM_InitField( &m_colorDimension, "ColorDimension", DimensionEnum( Dimension::CASE ), "Color", "", "Data dimension controlling the curve color" );
|
||||||
|
CAF_PDM_InitField( &m_symbolDimension,
|
||||||
|
"SymbolDimension",
|
||||||
|
DimensionEnum( Dimension::NONE ),
|
||||||
|
"Symbol",
|
||||||
|
"",
|
||||||
|
"Data dimension controlling the curve symbol" );
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
RimCurveStyleSettings::Dimension RimCurveStyleSettings::colorDimension() const
|
||||||
|
{
|
||||||
|
return m_colorDimension();
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
RimCurveStyleSettings::Dimension RimCurveStyleSettings::symbolDimension() const
|
||||||
|
{
|
||||||
|
return m_symbolDimension();
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
void RimCurveStyleSettings::setColorDimension( Dimension dimension )
|
||||||
|
{
|
||||||
|
m_colorDimension = dimension;
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
void RimCurveStyleSettings::setSymbolDimension( Dimension dimension )
|
||||||
|
{
|
||||||
|
m_symbolDimension = dimension;
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
std::string RimCurveStyleSettings::caseName( const RimSummaryCase* summaryCase )
|
||||||
|
{
|
||||||
|
if ( !summaryCase ) return {};
|
||||||
|
if ( summaryCase->ensemble() ) return summaryCase->ensemble()->name().toStdString();
|
||||||
|
return summaryCase->displayCaseName().toStdString();
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
std::string RimCurveStyleSettings::dimensionValue( Dimension dimension, const RifEclipseSummaryAddress& address, const std::string& caseName )
|
||||||
|
{
|
||||||
|
using Category = RifEclipseSummaryAddressDefines::SummaryCategory;
|
||||||
|
|
||||||
|
switch ( dimension )
|
||||||
|
{
|
||||||
|
case Dimension::CASE:
|
||||||
|
return caseName;
|
||||||
|
|
||||||
|
case Dimension::VECTOR:
|
||||||
|
{
|
||||||
|
std::string name = address.vectorName();
|
||||||
|
if ( address.isHistoryVector() && !name.empty() ) name.pop_back();
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
case Dimension::WELL:
|
||||||
|
return address.wellName();
|
||||||
|
|
||||||
|
case Dimension::GROUP:
|
||||||
|
return address.groupName();
|
||||||
|
|
||||||
|
case Dimension::NETWORK:
|
||||||
|
return address.networkName();
|
||||||
|
|
||||||
|
case Dimension::REGION:
|
||||||
|
return address.category() == Category::SUMMARY_REGION ? address.itemUiText() : std::string();
|
||||||
|
|
||||||
|
case Dimension::REGION_2_REGION:
|
||||||
|
return address.category() == Category::SUMMARY_REGION_2_REGION ? address.itemUiText() : std::string();
|
||||||
|
|
||||||
|
case Dimension::AQUIFER:
|
||||||
|
return address.category() == Category::SUMMARY_AQUIFER ? address.itemUiText() : std::string();
|
||||||
|
|
||||||
|
case Dimension::LGR:
|
||||||
|
return address.lgrName();
|
||||||
|
|
||||||
|
case Dimension::BLOCK:
|
||||||
|
return address.category() == Category::SUMMARY_BLOCK || address.category() == Category::SUMMARY_BLOCK_LGR ? address.itemUiText()
|
||||||
|
: std::string();
|
||||||
|
|
||||||
|
case Dimension::CONNECTION:
|
||||||
|
return address.category() == Category::SUMMARY_WELL_COMPLETION || address.category() == Category::SUMMARY_WELL_CONNECTION ||
|
||||||
|
address.category() == Category::SUMMARY_WELL_CONNECTION_LGR
|
||||||
|
? address.itemUiText()
|
||||||
|
: std::string();
|
||||||
|
|
||||||
|
case Dimension::SEGMENT:
|
||||||
|
return address.category() == Category::SUMMARY_WELL_SEGMENT ? address.itemUiText() : std::string();
|
||||||
|
|
||||||
|
default:
|
||||||
|
return std::string();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
void RimCurveStyleSettings::fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue )
|
||||||
|
{
|
||||||
|
// The collection list shows colors that depend on the global appearance
|
||||||
|
if ( auto collection = firstAncestorOrThisOfType<RimCurveStyleRules>() )
|
||||||
|
{
|
||||||
|
collection->rulesChanged();
|
||||||
|
collection->updateConnectedEditors();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
void RimCurveStyleSettings::appendFieldsToUiOrdering( caf::PdmUiOrdering& uiOrdering )
|
||||||
|
{
|
||||||
|
uiOrdering.add( &m_colorDimension );
|
||||||
|
uiOrdering.add( &m_symbolDimension );
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
void RimCurveStyleSettings::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering )
|
||||||
|
{
|
||||||
|
appendFieldsToUiOrdering( uiOrdering );
|
||||||
|
uiOrdering.skipRemainingFields();
|
||||||
|
}
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Copyright (C) 2026- 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.
|
||||||
|
//
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "cafAppEnum.h"
|
||||||
|
#include "cafPdmField.h"
|
||||||
|
#include "cafPdmObject.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class RifEclipseSummaryAddress;
|
||||||
|
class RimSummaryCase;
|
||||||
|
|
||||||
|
//==================================================================================================
|
||||||
|
/// Global definition of which data dimension controls the curve color and the curve symbol.
|
||||||
|
/// Used by summary plots that have "Use Global Curve Appearance" enabled.
|
||||||
|
//==================================================================================================
|
||||||
|
class RimCurveStyleSettings : public caf::PdmObject
|
||||||
|
{
|
||||||
|
CAF_PDM_HEADER_INIT;
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum class Dimension
|
||||||
|
{
|
||||||
|
NONE,
|
||||||
|
CASE,
|
||||||
|
VECTOR,
|
||||||
|
WELL,
|
||||||
|
GROUP,
|
||||||
|
NETWORK,
|
||||||
|
REGION,
|
||||||
|
REGION_2_REGION,
|
||||||
|
AQUIFER,
|
||||||
|
LGR,
|
||||||
|
BLOCK,
|
||||||
|
CONNECTION,
|
||||||
|
SEGMENT
|
||||||
|
};
|
||||||
|
using DimensionEnum = caf::AppEnum<Dimension>;
|
||||||
|
|
||||||
|
RimCurveStyleSettings();
|
||||||
|
|
||||||
|
Dimension colorDimension() const;
|
||||||
|
Dimension symbolDimension() const;
|
||||||
|
void setColorDimension( Dimension dimension );
|
||||||
|
void setSymbolDimension( Dimension dimension );
|
||||||
|
|
||||||
|
// The value of the dimension for the address, empty if the address has no value for the dimension
|
||||||
|
static std::string dimensionValue( Dimension dimension, const RifEclipseSummaryAddress& address, const std::string& caseName );
|
||||||
|
|
||||||
|
// The case name used by dimensionValue: ensemble name for ensemble members, otherwise the display name
|
||||||
|
static std::string caseName( const RimSummaryCase* summaryCase );
|
||||||
|
|
||||||
|
// Adds the color and symbol fields, used both here and when shown together with other items
|
||||||
|
void appendFieldsToUiOrdering( caf::PdmUiOrdering& uiOrdering );
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override;
|
||||||
|
void fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
caf::PdmField<DimensionEnum> m_colorDimension;
|
||||||
|
caf::PdmField<DimensionEnum> m_symbolDimension;
|
||||||
|
};
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Copyright (C) 2026- 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 "RimSavedCurveAppearance.h"
|
||||||
|
|
||||||
|
#include "RimEnsembleCurveSet.h"
|
||||||
|
#include "RimPlotCurve.h"
|
||||||
|
#include "RimPlotCurveAppearance.h"
|
||||||
|
|
||||||
|
CAF_PDM_SOURCE_INIT( RimSavedCurveAppearance, "RimSavedCurveAppearance" );
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
RimSavedCurveAppearance::RimSavedCurveAppearance()
|
||||||
|
{
|
||||||
|
CAF_PDM_InitObject( "Saved Curve Appearance" );
|
||||||
|
|
||||||
|
CAF_PDM_InitFieldNoDefault( &m_curve, "Curve", "Curve" );
|
||||||
|
CAF_PDM_InitFieldNoDefault( &m_appearance, "CurveAppearance", "Curve Appearance" );
|
||||||
|
CAF_PDM_InitFieldNoDefault( &m_ensembleCurveSet, "EnsembleCurveSet", "Ensemble Curve Set" );
|
||||||
|
CAF_PDM_InitFieldNoDefault( &m_ensembleColor, "EnsembleColor", "Ensemble Color" );
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
void RimSavedCurveAppearance::setCurve( RimPlotCurve* curve )
|
||||||
|
{
|
||||||
|
m_curve = curve;
|
||||||
|
m_appearance = curve->curveAppearance()->copyObject<RimPlotCurveAppearance>();
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
void RimSavedCurveAppearance::setEnsembleCurveSet( RimEnsembleCurveSet* curveSet )
|
||||||
|
{
|
||||||
|
m_ensembleCurveSet = curveSet;
|
||||||
|
m_ensembleColor = curveSet->color();
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
caf::PdmObject* RimSavedCurveAppearance::restore() const
|
||||||
|
{
|
||||||
|
if ( m_curve() && m_appearance() )
|
||||||
|
{
|
||||||
|
m_curve()->curveAppearance()->copyFrom( *m_appearance() );
|
||||||
|
return m_curve();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( m_ensembleCurveSet() )
|
||||||
|
{
|
||||||
|
m_ensembleCurveSet()->setColorAndUpdateCurves( m_ensembleColor() );
|
||||||
|
return m_ensembleCurveSet();
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Copyright (C) 2026- 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.
|
||||||
|
//
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "cafPdmChildField.h"
|
||||||
|
#include "cafPdmField.h"
|
||||||
|
#include "cafPdmFieldCvfColor.h"
|
||||||
|
#include "cafPdmObject.h"
|
||||||
|
#include "cafPdmPtrField.h"
|
||||||
|
|
||||||
|
class RimEnsembleCurveSet;
|
||||||
|
class RimPlotCurve;
|
||||||
|
class RimPlotCurveAppearance;
|
||||||
|
|
||||||
|
//==================================================================================================
|
||||||
|
/// The appearance of a curve or ensemble curve set before the global curve appearance was enabled. Stored in the
|
||||||
|
/// project so it can be restored after a reload, and referenced by PDM pointers so deleted objects are not matched.
|
||||||
|
//==================================================================================================
|
||||||
|
class RimSavedCurveAppearance : public caf::PdmObject
|
||||||
|
{
|
||||||
|
CAF_PDM_HEADER_INIT;
|
||||||
|
|
||||||
|
public:
|
||||||
|
RimSavedCurveAppearance();
|
||||||
|
|
||||||
|
void setCurve( RimPlotCurve* curve );
|
||||||
|
void setEnsembleCurveSet( RimEnsembleCurveSet* curveSet );
|
||||||
|
|
||||||
|
// Restores the saved appearance and returns the curve or curve set, nullptr if it no longer exists
|
||||||
|
caf::PdmObject* restore() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
caf::PdmPtrField<RimPlotCurve*> m_curve;
|
||||||
|
caf::PdmChildField<RimPlotCurveAppearance*> m_appearance;
|
||||||
|
|
||||||
|
caf::PdmPtrField<RimEnsembleCurveSet*> m_ensembleCurveSet;
|
||||||
|
caf::PdmField<cvf::Color3f> m_ensembleColor;
|
||||||
|
};
|
||||||
@@ -147,6 +147,8 @@ set(SOURCE_UNITTEST_FILES
|
|||||||
${CMAKE_CURRENT_LIST_DIR}/opm-summary-Test.cpp
|
${CMAKE_CURRENT_LIST_DIR}/opm-summary-Test.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/RifEclipseTextFileReader-Test.cpp
|
${CMAKE_CURRENT_LIST_DIR}/RifEclipseTextFileReader-Test.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/RiaSummaryStringTools-Test.cpp
|
${CMAKE_CURRENT_LIST_DIR}/RiaSummaryStringTools-Test.cpp
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/RimCurveStyleSettings-Test.cpp
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/RimCurveStyleRules-Test.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/RiaVariableMapper-Test.cpp
|
${CMAKE_CURRENT_LIST_DIR}/RiaVariableMapper-Test.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/RifPressureDepthTextFileReader-Test.cpp
|
${CMAKE_CURRENT_LIST_DIR}/RifPressureDepthTextFileReader-Test.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/RifRevealCsvSectionSummaryReader-Test.cpp
|
${CMAKE_CURRENT_LIST_DIR}/RifRevealCsvSectionSummaryReader-Test.cpp
|
||||||
|
|||||||
@@ -0,0 +1,124 @@
|
|||||||
|
#include "gtest/gtest.h"
|
||||||
|
|
||||||
|
#include "RifEclipseSummaryAddress.h"
|
||||||
|
|
||||||
|
#include "RimCurveStyleRule.h"
|
||||||
|
#include "RimCurveStyleRules.h"
|
||||||
|
#include "RimCurveStyleSettings.h"
|
||||||
|
#include "RimPlotCurveAppearance.h"
|
||||||
|
#include "RimSavedCurveAppearance.h"
|
||||||
|
#include "RimSummaryCurve.h"
|
||||||
|
|
||||||
|
using D = RimCurveStyleSettings::Dimension;
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
/// Rules for the selected dimensions are returned ordered by dimension, independent of creation order
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
TEST( RimCurveStyleRulesTest, RulesForOrderedByDimension )
|
||||||
|
{
|
||||||
|
RimCurveStyleRules rules;
|
||||||
|
rules.settings()->setColorDimension( D::WELL );
|
||||||
|
rules.settings()->setSymbolDimension( D::CASE );
|
||||||
|
|
||||||
|
auto wellRule = rules.findOrCreateRule( D::WELL, "A-1" );
|
||||||
|
wellRule->setCustom( true );
|
||||||
|
rules.findOrCreateRule( D::WELL, "B-2" )->setCustom( true );
|
||||||
|
rules.findOrCreateRule( D::VECTOR, "WOPR" )->setCustom( true );
|
||||||
|
rules.findOrCreateRule( D::CASE, "auto case" );
|
||||||
|
auto caseRule = rules.findOrCreateRule( D::CASE, "case" );
|
||||||
|
caseRule->setCustom( true );
|
||||||
|
|
||||||
|
EXPECT_EQ( wellRule, rules.findOrCreateRule( D::WELL, "A-1" ) );
|
||||||
|
|
||||||
|
const auto matching = rules.rulesFor( RifEclipseSummaryAddress::wellAddress( "WOPR", "A-1" ), "case" );
|
||||||
|
|
||||||
|
ASSERT_EQ( 2u, matching.size() );
|
||||||
|
EXPECT_EQ( caseRule, matching[0] );
|
||||||
|
EXPECT_EQ( wellRule, matching[1] );
|
||||||
|
|
||||||
|
EXPECT_TRUE( rules.rulesFor( RifEclipseSummaryAddress::wellAddress( "WOPR", "A-1" ), "auto case" ).size() == 1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
/// Registered names keep their index when new names are added
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
TEST( RimCurveStyleRulesTest, ItemIndicesStableWhenNamesAdded )
|
||||||
|
{
|
||||||
|
RimCurveStyleRules rules;
|
||||||
|
|
||||||
|
rules.registerItemNames( D::CASE, { "B", "D" } );
|
||||||
|
auto indices = rules.itemIndices( D::CASE );
|
||||||
|
EXPECT_EQ( 0, indices["B"] );
|
||||||
|
EXPECT_EQ( 1, indices["D"] );
|
||||||
|
|
||||||
|
rules.registerItemNames( D::CASE, { "A", "B", "C", "D" } );
|
||||||
|
indices = rules.itemIndices( D::CASE );
|
||||||
|
ASSERT_EQ( 4u, indices.size() );
|
||||||
|
EXPECT_EQ( 0, indices["B"] );
|
||||||
|
EXPECT_EQ( 1, indices["D"] );
|
||||||
|
EXPECT_EQ( 2, indices["A"] );
|
||||||
|
EXPECT_EQ( 3, indices["C"] );
|
||||||
|
|
||||||
|
EXPECT_TRUE( rules.itemIndices( D::WELL ).empty() );
|
||||||
|
EXPECT_TRUE( rules.itemIndices( D::VECTOR ).empty() );
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
TEST( RimCurveStyleRulesTest, ControlsOnlyCurvesWithValueForDimension )
|
||||||
|
{
|
||||||
|
RimCurveStyleRules rules;
|
||||||
|
rules.settings()->setColorDimension( D::WELL );
|
||||||
|
rules.settings()->setSymbolDimension( D::NONE );
|
||||||
|
|
||||||
|
const auto wellAddress = RifEclipseSummaryAddress::wellAddress( "WOPR", "A-1" );
|
||||||
|
const auto fieldAddress = RifEclipseSummaryAddress::fieldAddress( "FOPT" );
|
||||||
|
|
||||||
|
EXPECT_FALSE( rules.controlsColor( wellAddress, "case" ) );
|
||||||
|
|
||||||
|
rules.setUseGlobalAppearance( true );
|
||||||
|
|
||||||
|
EXPECT_TRUE( rules.controlsColor( wellAddress, "case" ) );
|
||||||
|
EXPECT_FALSE( rules.controlsColor( fieldAddress, "case" ) );
|
||||||
|
EXPECT_FALSE( rules.controlsSymbol( wellAddress, "case" ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
TEST( RimCurveStyleRulesTest, CopyAppearance )
|
||||||
|
{
|
||||||
|
RimPlotCurveAppearance source;
|
||||||
|
source.setColor( cvf::Color3f::RED );
|
||||||
|
source.setSymbol( RiuPlotCurveSymbol::SYMBOL_DIAMOND );
|
||||||
|
source.setLineThickness( 4 );
|
||||||
|
source.setSymbolLabel( "label" );
|
||||||
|
|
||||||
|
RimPlotCurveAppearance target;
|
||||||
|
target.copyFrom( source );
|
||||||
|
|
||||||
|
EXPECT_TRUE( target.color() == cvf::Color3f::RED );
|
||||||
|
EXPECT_EQ( RiuPlotCurveSymbol::SYMBOL_DIAMOND, target.symbol() );
|
||||||
|
EXPECT_EQ( 4, target.lineThickness() );
|
||||||
|
EXPECT_EQ( "label", target.symbolLabel() );
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
/// The saved appearance is restored, and not applied after the curve is deleted
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
TEST( RimCurveStyleRulesTest, SavedAppearanceRestore )
|
||||||
|
{
|
||||||
|
auto curve = new RimSummaryCurve;
|
||||||
|
curve->setColor( cvf::Color3f::RED );
|
||||||
|
|
||||||
|
RimSavedCurveAppearance saved;
|
||||||
|
saved.setCurve( curve );
|
||||||
|
|
||||||
|
curve->setColor( cvf::Color3f::BLUE );
|
||||||
|
EXPECT_EQ( curve, saved.restore() );
|
||||||
|
EXPECT_TRUE( curve->color() == cvf::Color3f::RED );
|
||||||
|
|
||||||
|
delete curve;
|
||||||
|
EXPECT_EQ( nullptr, saved.restore() );
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
#include "gtest/gtest.h"
|
||||||
|
|
||||||
|
#include "RifEclipseSummaryAddress.h"
|
||||||
|
#include "RimCurveStyleSettings.h"
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
TEST( RimCurveStyleSettingsTest, DefaultsControlColorByCase )
|
||||||
|
{
|
||||||
|
RimCurveStyleSettings settings;
|
||||||
|
|
||||||
|
EXPECT_EQ( RimCurveStyleSettings::Dimension::CASE, settings.colorDimension() );
|
||||||
|
EXPECT_EQ( RimCurveStyleSettings::Dimension::NONE, settings.symbolDimension() );
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
TEST( RimCurveStyleSettingsTest, DimensionValues )
|
||||||
|
{
|
||||||
|
using D = RimCurveStyleSettings::Dimension;
|
||||||
|
|
||||||
|
const auto well = RifEclipseSummaryAddress::wellAddress( "WOPR", "A-1" );
|
||||||
|
const auto region = RifEclipseSummaryAddress::regionAddress( "ROPR", 3 );
|
||||||
|
|
||||||
|
EXPECT_EQ( "A-1", RimCurveStyleSettings::dimensionValue( D::WELL, well, "case" ) );
|
||||||
|
EXPECT_EQ( "case", RimCurveStyleSettings::dimensionValue( D::CASE, well, "case" ) );
|
||||||
|
EXPECT_EQ( "WOPR", RimCurveStyleSettings::dimensionValue( D::VECTOR, well, "case" ) );
|
||||||
|
EXPECT_TRUE( RimCurveStyleSettings::dimensionValue( D::REGION, well, "case" ).empty() );
|
||||||
|
EXPECT_EQ( "3", RimCurveStyleSettings::dimensionValue( D::REGION, region, "case" ) );
|
||||||
|
}
|
||||||
Reference in new issue
Block a user