From b40973a3138439ba02d57e8d8a08eacce33e691b Mon Sep 17 00:00:00 2001 From: Murray Stevenson <50844517+murraystevenson@users.noreply.github.com> Date: Mon, 9 Dec 2024 19:53:05 -0800 Subject: [PATCH] RenderPassEditor : Display adaptor deleted render passes as disabled As render passes could have been deleted by a render adaptor, we build our RenderPassPaths from a PathMatcher generated with the render adaptors disabled and then later test to see whether the render pass still exists with adaptors enabled. From the end user's perspective, there's no functional difference between render passes deleted or disabled by a render adaptor, so we present both as automatically disabled. --- Changes.md | 2 +- python/GafferSceneUI/RenderPassEditor.py | 7 ++++- .../GafferSceneUITest/RenderPassEditorTest.py | 29 +++++++++++++++++++ .../RenderPassEditorBinding.cpp | 17 +++++++++-- 4 files changed, 51 insertions(+), 4 deletions(-) diff --git a/Changes.md b/Changes.md index 6239e20468a..12c4e74f63b 100644 --- a/Changes.md +++ b/Changes.md @@ -20,7 +20,7 @@ Improvements - PlugLayout : - A warning widget is now displayed when an invalid custom widget is registered. - `layout:customWidget::width` and `layout:customWidget::minimumWidth` metadata registrations are now supported for custom widgets. -- RenderPassEditor / RenderPassChooserWidget : Render passes disabled by render adaptors registered to `client = "RenderPassWedge"` are now shown as disabled. To differentiate these from user disabled render passes, an orange dot is shown in the corner of the disabled icon and the tooltip describes them as automatically disabled. +- RenderPassEditor / RenderPassChooserWidget : Render passes deleted or disabled by render adaptors registered to `client = "RenderPassWedge"` are now shown as disabled. To differentiate these from user disabled render passes, an orange dot is shown in the corner of the disabled icon and the tooltip describes them as automatically disabled. Fixes ----- diff --git a/python/GafferSceneUI/RenderPassEditor.py b/python/GafferSceneUI/RenderPassEditor.py index d7e96462705..edf5a4585ae 100644 --- a/python/GafferSceneUI/RenderPassEditor.py +++ b/python/GafferSceneUI/RenderPassEditor.py @@ -1036,11 +1036,16 @@ def _valuesForUpdate( plugs, auxiliaryPlugs ) : renderPasses = {} with Gaffer.Context( Gaffer.Context.current() ) as context : + adaptedRenderPassNames = globalsPlug.getValue().get( "option:renderPass:names", IECore.StringVectorData() ) + context["renderPassEditor:disableAdaptors"] = True for renderPass in globalsPlug.getValue().get( "option:renderPass:names", IECore.StringVectorData() ) : renderPasses.setdefault( "all", [] ).append( renderPass ) context["renderPass"] = renderPass context["renderPassEditor:disableAdaptors"] = False - if globalsPlug.getValue().get( "option:renderPass:enabled", IECore.BoolData( True ) ).value : + if renderPass not in adaptedRenderPassNames : + # The render pass has been deleted by a render adaptor so present it as disabled + renderPasses.setdefault( "adaptorDisabled", [] ).append( renderPass ) + elif globalsPlug.getValue().get( "option:renderPass:enabled", IECore.BoolData( True ) ).value : renderPasses.setdefault( "enabled", [] ).append( renderPass ) else : context["renderPassEditor:disableAdaptors"] = True diff --git a/python/GafferSceneUITest/RenderPassEditorTest.py b/python/GafferSceneUITest/RenderPassEditorTest.py index c72f7981bdf..3954c4b4c4d 100644 --- a/python/GafferSceneUITest/RenderPassEditorTest.py +++ b/python/GafferSceneUITest/RenderPassEditorTest.py @@ -208,6 +208,35 @@ def createAdaptor() : self.assertEqual( pathCopy.property( "renderPassPath:enabled" ), p in ( "/A", "/D" ) ) self.assertTrue( pathCopy.property( "renderPassPath:enabledWithoutAdaptors" ) ) + def testRenderPassPathAdaptorDeletingPasses( self ) : + + def createAdaptor() : + + node = GafferScene.DeleteRenderPasses() + node["names"].setValue( "B C" ) + return node + + GafferScene.SceneAlgo.registerRenderAdaptor( "RenderPassEditorTest", createAdaptor, client = "RenderPassWedge" ) + self.addCleanup( GafferScene.SceneAlgo.deregisterRenderAdaptor, "RenderPassEditorTest" ) + + renderPasses = GafferScene.RenderPasses() + renderPasses["names"].setValue( IECore.StringVectorData( [ "A", "B", "C", "D" ] ) ) + + adaptors = GafferSceneUI.RenderPassEditor._createRenderAdaptors() + adaptors["in"].setInput( renderPasses["out"] ) + + context = Gaffer.Context() + path = _GafferSceneUI._RenderPassEditor.RenderPassPath( adaptors["out"], context, "/" ) + + self.assertEqual( [ str( c ) for c in path.children() ], [ "/A", "/B", "/C", "/D" ] ) + + pathCopy = path.copy() + + for p in [ "/A", "/B", "/C", "/D" ] : + pathCopy.setFromString( p ) + self.assertEqual( pathCopy.property( "renderPassPath:enabled" ), p in ( "/A", "/D" ) ) + self.assertTrue( pathCopy.property( "renderPassPath:enabledWithoutAdaptors" ) ) + def testSearchFilter( self ) : renderPasses = GafferScene.RenderPasses() diff --git a/src/GafferSceneUIModule/RenderPassEditorBinding.cpp b/src/GafferSceneUIModule/RenderPassEditorBinding.cpp index 859ab499faf..c315b2d8022 100644 --- a/src/GafferSceneUIModule/RenderPassEditorBinding.cpp +++ b/src/GafferSceneUIModule/RenderPassEditorBinding.cpp @@ -192,7 +192,7 @@ PathMatcher pathMatcherCacheGetter( const PathMatcherCacheGetterKey &key, size_t } using PathMatcherCache = IECorePreview::LRUCache; -PathMatcherCache g_pathMatcherCache( pathMatcherCacheGetter, 25 ); +PathMatcherCache g_pathMatcherCache( pathMatcherCacheGetter, 50 ); const InternedString g_renderPassContextName( "renderPass" ); const InternedString g_disableAdaptorsContextName( "renderPassEditor:disableAdaptors" ); @@ -320,6 +320,15 @@ class RenderPassPath : public Gaffer::Path } else if( name == g_renderPassEnabledPropertyName || name == g_renderPassEnabledWithoutAdaptorsPropertyName ) { + if( + name == g_renderPassEnabledPropertyName && + !( pathMatcher( canceller, /* disableAdaptors = */ false ).match( names() ) & PathMatcher::ExactMatch ) + ) + { + // The render pass has been deleted by a render adaptor, so present it to the user as disabled. + return new BoolData( false ); + } + const PathMatcher p = pathMatcher( canceller ); if( p.match( names() ) & PathMatcher::ExactMatch ) { @@ -402,7 +411,7 @@ class RenderPassPath : public Gaffer::Path // practical as render pass names are used in output file paths where the included '/' characters would be // interpreted as subdirectories. Validation in the UI will prevent users from inserting invalid characters // such as '/' into render pass names. - const IECore::PathMatcher pathMatcher( const IECore::Canceller *canceller ) const + const IECore::PathMatcher pathMatcher( const IECore::Canceller *canceller, bool disableAdaptors = true ) const { Context::EditableScope scopedContext( m_context.get() ); if( canceller ) @@ -410,6 +419,10 @@ class RenderPassPath : public Gaffer::Path scopedContext.setCanceller( canceller ); } + if( disableAdaptors ) + { + scopedContext.set( g_disableAdaptorsContextName, &disableAdaptors ); + } if( ConstStringVectorDataPtr renderPassData = m_scene.get()->globals()->member( g_renderPassNamesOption ) ) { const PathMatcherCacheGetterKey key( renderPassData, m_grouped );