#13997 3dView: Show active filter name(s) below Z-scale indicator

Adds a new HUD label in the upper-left of the 3D view that reads
"Filter : <name(s)>" whenever a cell, property, or per-view data
filter is active. The label is hidden when nothing is enabled.

Names are joined per the source collection's AND/OR combine mode, and
contributions from different collections are concatenated with ", ".
On Eclipse views the unified RimFilterInViewCollection is used as the
single anchor; GeoMech views aggregate cell and GeoMech property
filters directly.
This commit is contained in:
Kristian Bendiksen
2026-05-20 14:16:04 +02:00
parent af5c133736
commit 20087c6dd9
15 changed files with 238 additions and 0 deletions
@@ -18,6 +18,7 @@ set(SOURCE_GROUP_HEADER_FILES
${CMAKE_CURRENT_LIST_DIR}/RimCellIndexFilter.h
${CMAKE_CURRENT_LIST_DIR}/RimUserDefinedIndexFilter.h
${CMAKE_CURRENT_LIST_DIR}/RimFilterInViewCollection.h
${CMAKE_CURRENT_LIST_DIR}/RimFilterDisplayUtil.h
)
set(SOURCE_GROUP_SOURCE_FILES
@@ -40,6 +41,7 @@ set(SOURCE_GROUP_SOURCE_FILES
${CMAKE_CURRENT_LIST_DIR}/RimCellIndexFilter.cpp
${CMAKE_CURRENT_LIST_DIR}/RimUserDefinedIndexFilter.cpp
${CMAKE_CURRENT_LIST_DIR}/RimFilterInViewCollection.cpp
${CMAKE_CURRENT_LIST_DIR}/RimFilterDisplayUtil.cpp
)
list(APPEND CODE_HEADER_FILES ${SOURCE_GROUP_HEADER_FILES})
@@ -0,0 +1,36 @@
/////////////////////////////////////////////////////////////////////////////////
//
// 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 "RimFilterDisplayUtil.h"
#include "RimCellFilter.h"
#include <QStringList>
QString RimFilterDisplayUtil::filterNamesJoined( const std::vector<RimCellFilter*>& filters, bool useAndOperation )
{
QStringList names;
for ( auto* f : filters )
{
if ( f && f->isFilterEnabled() ) names << f->name();
}
if ( names.isEmpty() ) return {};
const QString sep = useAndOperation ? QStringLiteral( " AND " ) : QStringLiteral( " OR " );
return names.join( sep );
}
@@ -0,0 +1,30 @@
/////////////////////////////////////////////////////////////////////////////////
//
// 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 <QString>
#include <vector>
class RimCellFilter;
namespace RimFilterDisplayUtil
{
QString filterNamesJoined( const std::vector<RimCellFilter*>& filters, bool useAndOperation );
}
@@ -25,12 +25,14 @@
#include "RimDataFilterInView.h"
#include "RimDataFilterInViewCollection.h"
#include "RimEclipsePropertyFilterCollection.h"
#include "RimFilterDisplayUtil.h"
#include "RimTools.h"
#include "cafCmdFeatureMenuBuilder.h"
#include "cafPdmUiTreeOrdering.h"
#include <QIcon>
#include <QStringList>
#include <QVariant>
CAF_PDM_SOURCE_INIT( RimFilterInViewCollection, "FilterInViewCollection" );
@@ -105,6 +107,43 @@ RimDataFilterInViewCollection* RimFilterInViewCollection::dataFiltersInView() co
return m_dataFiltersInView();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RimFilterInViewCollection::activeFiltersDisplayText() const
{
if ( !isChecked() ) return {};
QStringList parts;
if ( auto* cf = m_cellFilters(); cf && cf->isActive() && cf->hasActiveFilters() )
{
const QString cellPart = RimFilterDisplayUtil::filterNamesJoined( cf->filters(), cf->useAndOperation() );
if ( !cellPart.isEmpty() ) parts << cellPart;
}
const bool useAndOperation = true;
if ( auto* pf = m_propertyFilters(); pf && pf->isActive && pf->hasActiveFilters() )
{
const QString propPart = RimFilterDisplayUtil::filterNamesJoined( pf->filtersForEvaluation(), useAndOperation );
if ( !propPart.isEmpty() ) parts << propPart;
}
if ( auto* df = m_dataFiltersInView(); df && df->isChecked() && df->hasActiveFilters() )
{
std::vector<RimCellFilter*> sourceFilters;
for ( auto* w : df->activeWrappers() )
{
if ( w && w->sourceFilter() ) sourceFilters.push_back( w->sourceFilter() );
}
const QString dataPart = RimFilterDisplayUtil::filterNamesJoined( sourceFilters, useAndOperation );
if ( !dataPart.isEmpty() ) parts << dataPart;
}
return parts.join( QStringLiteral( ", " ) );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@@ -54,6 +54,8 @@ public:
RimEclipsePropertyFilterCollection* propertyFilters() const;
RimDataFilterInViewCollection* dataFiltersInView() const;
QString activeFiltersDisplayText() const;
protected:
void defineUiTreeOrdering( caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName = "" ) override;
void fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) override;
@@ -38,11 +38,13 @@
#include "RimCellFilterCollection.h"
#include "RimEclipseResultDefinition.h"
#include "RimEclipseView.h"
#include "RimFilterDisplayUtil.h"
#include "RimGeoMechCase.h"
#include "RimGeoMechCellColors.h"
#include "RimGeoMechFaultReactivationResult.h"
#include "RimGeoMechPart.h"
#include "RimGeoMechPartCollection.h"
#include "RimGeoMechPropertyFilter.h"
#include "RimGeoMechPropertyFilterCollection.h"
#include "RimGridCollection.h"
#include "RimIntersectionCollection.h"
@@ -1075,6 +1077,30 @@ const RimPropertyFilterCollection* RimGeoMechView::propertyFilterCollection() co
return geoMechPropertyFilterCollection();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RimGeoMechView::activeFiltersDisplayText() const
{
QStringList parts;
const QString cellPart = RimGridView::activeFiltersDisplayText();
if ( !cellPart.isEmpty() ) parts << cellPart;
if ( const auto* pfc = geoMechPropertyFilterCollection(); pfc && pfc->isActive && pfc->hasActiveFilters() )
{
std::vector<RimCellFilter*> asCellFilters;
for ( size_t i = 0; i < pfc->propertyFilters.size(); i++ )
{
if ( RimGeoMechPropertyFilter* p = pfc->propertyFilters[i] ) asCellFilters.push_back( p );
}
const QString propPart = RimFilterDisplayUtil::filterNamesJoined( asCellFilters, /*useAnd*/ true );
if ( !propPart.isEmpty() ) parts << propPart;
}
return parts.join( QStringLiteral( ", " ) );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@@ -93,6 +93,8 @@ public:
bool isUsingFormationNames() const override;
QString activeFiltersDisplayText() const override;
void calculateCurrentTotalCellVisibility( cvf::UByteArray* totalVisibility, int viewerTimeStep ) override;
void updateLegendTextAndRanges( RimRegularLegendConfig* legendConfig, int viewerTimeStep );
@@ -335,6 +335,7 @@ QWidget* Rim3dView::createViewWidget( QWidget* mainWindowParent )
m_viewer->setAxisLabels( xLabel, yLabel, zLabel );
updateZScaleLabel();
updateFilterLabel();
return m_viewer->layoutWidget();
}
@@ -717,6 +718,7 @@ void Rim3dView::createDisplayModelAndRedraw()
onCreateDisplayModel();
createHighlightAndGridBoxDisplayModel();
updateDisplayModelVisibility();
updateFilterLabel();
if ( m_cameraPosition().isIdentity() )
{
@@ -1281,6 +1283,33 @@ void Rim3dView::updateZScaleLabel()
if ( viewer() ) viewer()->setZScale( m_scaleZ() );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString Rim3dView::activeFiltersDisplayText() const
{
return {};
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void Rim3dView::updateFilterLabel()
{
if ( !viewer() ) return;
const QString text = activeFiltersDisplayText();
if ( text.isEmpty() )
{
viewer()->showFilterLabel( false );
}
else
{
viewer()->setFilterText( QStringLiteral( "Filter : %1" ).arg( text ) );
viewer()->showFilterLabel( true );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@@ -185,6 +185,9 @@ public:
bool isScaleZEditable();
double scaleZ() const;
virtual QString activeFiltersDisplayText() const;
void updateFilterLabel();
bool isMasterView() const;
Rim3dView* activeComparisonView() const;
void setComparisonView( Rim3dView* compView );
@@ -2597,6 +2597,16 @@ const RimPropertyFilterCollection* RimEclipseView::propertyFilterCollection() co
return eclipsePropertyFilterCollection();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RimEclipseView::activeFiltersDisplayText() const
{
if ( m_filterInViewCollection() ) return m_filterInViewCollection()->activeFiltersDisplayText();
return RimGridView::activeFiltersDisplayText();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@@ -176,6 +176,8 @@ public:
bool isUsingFormationNames() const override;
QString activeFiltersDisplayText() const override;
void calculateCurrentTotalCellVisibility( cvf::UByteArray* totalVisibility, int timeStep ) override;
void calculateCellVisibility( cvf::UByteArray* visibility, std::vector<RivCellSetEnum> geomTypes, int timeStep = 0 ) override;
@@ -19,9 +19,11 @@
#include "RimGridView.h"
#include "Rim3dOverlayInfoConfig.h"
#include "RimCellFilter.h"
#include "RimCellFilterCollection.h"
#include "RimEclipseCase.h"
#include "RimEclipseResultDefinition.h"
#include "RimFilterDisplayUtil.h"
#include "RimGeoMechPartCollection.h"
#include "RimGeoMechResultDefinition.h"
#include "RimGeoMechView.h"
@@ -243,6 +245,17 @@ const RimCellFilterCollection* RimGridView::cellFilterCollection() const
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RimGridView::activeFiltersDisplayText() const
{
const auto* coll = cellFilterCollection();
if ( !coll || !coll->isActive() || !coll->hasActiveFilters() ) return {};
return RimFilterDisplayUtil::filterNamesJoined( coll->filters(), coll->useAndOperation() );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@@ -69,6 +69,8 @@ public:
bool isGridVisualizationMode() const override;
QString activeFiltersDisplayText() const override;
void updateWellMeasurements();
void updateViewTreeItems( RiaDefines::ItemIn3dView itemType ) override;
@@ -148,6 +148,14 @@ RiuViewer::RiuViewer( QWidget* parent )
m_showZScaleLabel = true;
m_hideZScaleCheckbox = false;
// Filter label
m_filterLabel = new QLabel();
m_filterLabel->setFrameShape( QFrame::NoFrame );
m_filterLabel->setAlignment( Qt::AlignLeft );
m_filterLabel->setObjectName( "FilterLabel" );
m_filterLabel->setFont( font );
m_showFilterLabel = false;
// Animation progress bar
m_animationProgress = new caf::QStyledProgressBar( "AnimationProgress" );
m_animationProgress->setFormat( "Time Step: %v/%m" );
@@ -183,6 +191,7 @@ RiuViewer::RiuViewer( QWidget* parent )
m_animationProgress->setFont( regTestFont );
m_histogramWidget->setFont( regTestFont );
m_zScaleLabel->setFont( regTestFont );
m_filterLabel->setFont( regTestFont );
}
// When a context menu is created in the viewer is, and the action triggered is displaying a dialog,
@@ -543,6 +552,15 @@ void RiuViewer::paintOverlayItems( QPainter* painter )
m_zScaleLabel->render( painter, pos );
}
if ( m_showFilterLabel ) // Filter label, drawn just below the Z scale label
{
QSize size( m_filterLabel->sizeHint().width(), m_filterLabel->sizeHint().height() );
int yTop = margin + edgeAxisFrameBorderHeight + ( m_showZScaleLabel ? m_zScaleLabel->height() : 0 );
QPoint pos( margin + edgeAxisFrameBorderWidth, yTop );
m_filterLabel->resize( size.width(), size.height() );
m_filterLabel->render( painter, pos );
}
if ( !m_cursorPositionDomainCoords.isUndefined() )
{
if ( mainCamera() )
@@ -615,6 +633,22 @@ void RiuViewer::setZScale( double scale )
if ( isScaleChanged ) m_selectionVisualizerManager->updateVisibleEditors();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiuViewer::showFilterLabel( bool enable )
{
m_showFilterLabel = enable;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiuViewer::setFilterText( const QString& text )
{
m_filterLabel->setText( text );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@@ -1459,6 +1493,8 @@ void RiuViewer::updateOverlayItemsStyle()
caf::StyleSheetTools::createFrameStyleSheet( "QLabel", "VersionInfo", contrastColor, backgroundColor, backgroundColor ) );
m_zScaleLabel->setStyleSheet(
caf::StyleSheetTools::createFrameStyleSheet( "QLabel", "ZScaleLabel", contrastColor, backgroundColor, backgroundColor ) );
m_filterLabel->setStyleSheet(
caf::StyleSheetTools::createFrameStyleSheet( "QLabel", "FilterLabel", contrastColor, backgroundColor, backgroundColor ) );
m_histogramWidget->setStyleSheet(
caf::StyleSheetTools::createFrameStyleSheet( "QWidget", "HistogramWidget", contrastColor, backgroundColor, backgroundFrameColor ) );
@@ -89,6 +89,9 @@ public:
void showZScaleLabel( bool enable );
void setZScale( double scale );
void showFilterLabel( bool enable );
void setFilterText( const QString& text );
void showHistogram( bool enable );
void setHistogram( double min, double max, const std::vector<size_t>& histogram );
void setHistogramPercentiles( double pmin, double pmax, double mean );
@@ -179,6 +182,9 @@ private:
double m_zScale;
int m_fontSize;
QLabel* m_filterLabel;
bool m_showFilterLabel;
caf::QStyledProgressBar* m_animationProgress;
caf::QStyledProgressBar* m_animationProgressCompView;
bool m_showAnimProgress;