Files
ResInsight/ApplicationLibCode/ProjectDataModel/Polygons/RimPolygonInView.cpp
T
Magne Sjaastad c66d29e6ea #13894 PolygonInView: Refresh owning picker editors when toggling picking
After migrating m_enablePicking from a PdmField<bool> to a PdmUiButton callback, the RimPolygonFilter parent was no longer notified via childFieldChangedByUi, so its 3D editor did not register or unregister the pick event handler and the button label did not refresh. Route the toggle through a helper that also calls updateEditorsAndVisualization on the owning RimPolylinePickerInterface.
2026-04-17 21:19:20 +02:00

523 lines
19 KiB
C++

/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2024 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 "RimPolygonInView.h"
#include "RiaColorTools.h"
#include "RigPolyLinesData.h"
#include "RigPolygonTools.h"
#include "Rim3dView.h"
#include "RimPolygon.h"
#include "RimPolygonInViewCollection.h"
#include "RimPolylineTarget.h"
#include "RimTools.h"
#include "WellPathCommands/PointTangentManipulator/RicPolyline3dEditor.h"
#include "WellPathCommands/RicPolylineTargetsPickEventHandler.h"
#include "Riu3DMainWindowTools.h"
#include "RiuGuiTheme.h"
#include "RivPolylinePartMgr.h"
#include "cafCmdFeatureMenuBuilder.h"
#include "cafDisplayCoordTransform.h"
#include "cafPdmUiButton.h"
#include "cafPdmUiTableViewEditor.h"
#include "cafPdmUiTreeAttributes.h"
#include "cvfModelBasicList.h"
CAF_PDM_SOURCE_INIT( RimPolygonInView, "RimPolygonInView" );
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimPolygonInView::RimPolygonInView()
: m_pickTargetsEventHandler( new RicPolylineTargetsPickEventHandler( this ) )
{
CAF_PDM_InitObject( "Polygon", ":/PolylinesFromFile16x16.png" );
CAF_PDM_InitFieldNoDefault( &m_polygon, "Polygon", "Polygon" );
m_polygon.uiCapability()->setUiReadOnly( true );
nameField()->uiCapability()->setUiReadOnly( true );
CAF_PDM_InitField( &m_showLabel, "ShowLabel", false, "Show Label" );
CAF_PDM_InitField( &m_handleScalingFactor, "HandleScalingFactor", 2.0, "Handle Scaling Factor" );
CAF_PDM_InitFieldNoDefault( &m_targets, "Targets", "Targets" );
m_targets.uiCapability()->setUiEditorTypeName( caf::PdmUiTableViewEditor::uiEditorTypeName() );
m_targets.uiCapability()->setUiTreeChildrenHidden( true );
m_targets.uiCapability()->setUiLabelPosition( caf::PdmUiItemInfo::LabelPosition::TOP );
m_targets.uiCapability()->setCustomContextMenuEnabled( true );
m_targets.xmlCapability()->disableIO();
setUi3dEditorTypeName( RicPolyline3dEditor::uiEditorTypeName() );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimPolygon* RimPolygonInView::polygon() const
{
return m_polygon();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimPolygonInView::setPolygon( RimPolygon* polygon )
{
m_polygon = polygon;
connectSignals();
updateTargetsFromPolygon();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimPolygonInView::appendPartsToModel( cvf::ModelBasicList* model,
const caf::DisplayCoordTransform* scaleTransform,
const cvf::BoundingBox& boundingBox )
{
auto view = firstAncestorOfType<Rim3dView>();
if ( m_polylinePartMgr.isNull() ) m_polylinePartMgr = new RivPolylinePartMgr( view, this, this );
m_polylinePartMgr->appendDynamicGeometryPartsToModel( model, scaleTransform, boundingBox );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimPolygonInView::enablePicking( bool enable )
{
m_enablePicking = enable;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimPolygonInView::insertTarget( const RimPolylineTarget* targetToInsertBefore, RimPolylineTarget* targetToInsert )
{
size_t index = m_targets.indexOf( targetToInsertBefore );
if ( index < m_targets.size() )
m_targets.insert( index, targetToInsert );
else
m_targets.push_back( targetToInsert );
updatePolygonFromTargets();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimPolygonInView::deleteTarget( RimPolylineTarget* targetToDelete )
{
m_targets.removeChild( targetToDelete );
delete targetToDelete;
updatePolygonFromTargets();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimPolygonInView::updateEditorsAndVisualization()
{
updateConnectedEditors();
updateVisualization();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimPolygonInView::updateVisualization()
{
auto view = firstAncestorOfType<Rim3dView>();
if ( view )
{
view->scheduleCreateDisplayModelAndRedraw();
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimPolygonInView::showLines() const
{
if ( auto poly = polygon() )
{
return poly->showLines() && isChecked();
}
return false;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<RimPolylineTarget*> RimPolygonInView::activeTargets() const
{
return m_targets.childrenByType();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimPolygonInView::pickingEnabled() const
{
return m_enablePicking;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
caf::PickEventHandler* RimPolygonInView::pickEventHandler() const
{
auto filterColl = firstAncestorOfType<RimPolygonInViewCollection>();
if ( filterColl && !filterColl->isChecked() ) return nullptr;
if ( !isChecked() ) return nullptr;
if ( m_polygon() && polygon()->isReadOnly() ) return nullptr;
return m_pickTargetsEventHandler.get();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimPolygonInView::onChildrenUpdated( caf::PdmChildArrayFieldHandle* childArray, std::vector<caf::PdmObjectHandle*>& updatedObjects )
{
if ( childArray == &m_targets )
{
updatePolygonFromTargets();
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
cvf::ref<RigPolyLinesData> RimPolygonInView::polyLinesData() const
{
if ( m_polygon )
{
return m_polygon->polyLinesData();
}
return nullptr;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimPolygonInView::updatePolygonFromTargets()
{
if ( m_polygon )
{
std::vector<cvf::Vec3d> points;
for ( const RimPolylineTarget* target : m_targets )
{
points.push_back( target->targetPointXYZ() );
}
m_polygon->setPointsInDomainCoords( points );
// update other pick editors, make sure we don't update ourselves
m_polygon->coordinatesChanged.block( this );
m_polygon->coordinatesChanged.send();
m_polygon->coordinatesChanged.unblock( this );
m_polygon->objectChanged.send();
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimPolygonInView::togglePicking()
{
m_enablePicking = !m_enablePicking;
updateConnectedEditors();
// When embedded in a RimPolygonFilter, the property panel and 3D editor are bound to the filter,
// not to this polygon-in-view. Ask the owning picker interface to refresh its editors so the
// button label updates and the pick event handler is (un)registered.
if ( auto owner = firstAncestorOfType<RimPolylinePickerInterface>() )
{
owner->updateEditorsAndVisualization();
}
updateVisualization();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimPolygonInView::connectSignals()
{
if ( m_polygon )
{
m_polygon->objectChanged.connect( this, &RimPolygonInView::onObjectChanged );
m_polygon->coordinatesChanged.connect( this, &RimPolygonInView::onCoordinatesChanged );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimPolygonInView::updateTargetsFromPolygon()
{
if ( m_polygon )
{
m_targets.deleteChildren();
for ( const auto& p : m_polygon->pointsInDomainCoords() )
{
auto target = new RimPolylineTarget();
target->setAsPointXYZ( p );
m_targets.push_back( target );
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimPolygonInView::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering )
{
updateNameField();
bool enableEdit = true;
if ( m_polygon() && m_polygon->isReadOnly() ) enableEdit = false;
uiOrdering.add( m_polygon );
if ( enableEdit )
{
uiOrdering.addNewButton( m_enablePicking ? "Stop Picking Points" : "Start Picking Points", [this]() { togglePicking(); } );
uiOrdering.add( &m_targets );
uiOrdering.add( &m_handleScalingFactor );
}
uiOrdering.add( &m_showLabel );
if ( m_polygon() )
{
uiOrdering.addNewButton( "Go to Polygon", [this]() { Riu3DMainWindowTools::selectAsCurrentItem( m_polygon() ); } );
}
uiOrdering.skipRemainingFields();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimPolygonInView::fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue )
{
updateVisualization();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QList<caf::PdmOptionItemInfo> RimPolygonInView::calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions )
{
QList<caf::PdmOptionItemInfo> options;
if ( fieldNeedingOptions == &m_polygon )
{
options.push_back( caf::PdmOptionItemInfo( "None", nullptr ) );
RimTools::polygonOptionItems( &options );
}
return options;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimPolygonInView::defineObjectEditorAttribute( QString uiConfigName, caf::PdmUiEditorAttribute* attribute )
{
if ( auto attrib = dynamic_cast<RicPolyline3dEditorAttribute*>( attribute ) )
{
attrib->pickEventHandler = m_pickTargetsEventHandler;
attrib->enablePicking = m_enablePicking;
}
if ( m_polygon() )
{
if ( auto* treeItemAttribute = dynamic_cast<caf::PdmUiTreeViewItemAttribute*>( attribute ) )
{
auto tag = caf::PdmUiTreeViewItemAttribute::createTag( RiaColorTools::toQColor( m_polygon->color() ),
RiuGuiTheme::getColorByVariableName( "backgroundColor1" ),
"---" );
tag->clicked.connect( m_polygon(), &RimPolygon::onColorTagClicked );
treeItemAttribute->tags.push_back( std::move( tag ) );
}
if ( m_polygon->isReadOnly() )
{
caf::PdmUiTreeViewItemAttribute::appendTagToTreeViewItemAttribute( attribute, ":/padlock.svg" );
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimPolygonInView::uiOrderingForLocalPolygon( QString uiConfigName, caf::PdmUiOrdering& uiOrdering )
{
uiOrdering.addNewButton( m_enablePicking ? "Stop Picking Points" : "Start Picking Points", [this]() { togglePicking(); } );
uiOrdering.add( &m_targets );
uiOrdering.add( &m_handleScalingFactor );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RimPolygonInView::label() const
{
if ( m_showLabel() && m_polygon() )
{
bool includeLastSegmentInfo = false;
QString label = m_polygon->name();
label += "\n" + RigPolygonTools::geometryDataAsText( m_polygon->pointsInDomainCoords(), includeLastSegmentInfo );
return label;
}
return {};
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimPolygonInView::appendMenuItems( caf::CmdFeatureMenuBuilder& menuBuilder ) const
{
RimPolygon::appendPolygonMenuItems( menuBuilder );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimPolygonInView::onObjectChanged( const caf::SignalEmitter* emitter )
{
// make sure name is in sync
if ( dynamic_cast<const RimPolygon*>( emitter ) )
{
setName( m_polygon->name() );
}
updateVisualization();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimPolygonInView::onCoordinatesChanged( const caf::SignalEmitter* emitter )
{
updateTargetsFromPolygon();
updateConnectedEditors();
updateVisualization();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimPolygonInView::initAfterRead()
{
connectSignals();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
double RimPolygonInView::scalingFactorForTarget() const
{
return m_handleScalingFactor();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimPolygonInView::defineEditorAttribute( const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute )
{
if ( field == &m_targets )
{
if ( auto tvAttribute = dynamic_cast<caf::PdmUiTableViewEditorAttribute*>( attribute ) )
{
tvAttribute->resizePolicy = caf::PdmUiTableViewEditorAttribute::RESIZE_TO_FIT_CONTENT;
if ( m_enablePicking )
{
tvAttribute->baseColor = RiuGuiTheme::getColorByVariableName( "externalInputColor" );
}
tvAttribute->alwaysEnforceResizePolicy = true;
tvAttribute->heightHint = 1000;
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimPolygonInView::defineCustomContextMenu( const caf::PdmFieldHandle* fieldNeedingMenu, QMenu* menu, QWidget* fieldEditorWidget )
{
if ( m_polygon() && m_polygon->isReadOnly() ) return;
caf::CmdFeatureMenuBuilder menuBuilder;
menuBuilder << "RicNewPolylineTargetFeature";
menuBuilder << "Separator";
menuBuilder << "RicDeletePolylineTargetFeature";
menuBuilder.appendToMenu( menu );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimPolygonInView::updateNameField()
{
QString name = "Undefined";
if ( m_polygon() )
{
name = m_polygon->name();
}
setName( name );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimPolygonInView::defineUiTreeOrdering( caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName /*= "" */ )
{
updateNameField();
}