Skip to content

Commit

Permalink
ScenePathPlugValueWidget : Improve search for ScenePlug
Browse files Browse the repository at this point in the history
We now accept a space-separated list of names of potential ScenePlugs, and use the first one with an input connection. We declare the ScenePlugs as auxiliary plugs, using the PlugValueWidget's existing mechanism for triggering an update when their connections change.

This allows us to fix the UI for the Constraint nodes to show locations from the `targetScene` if it has a connection.
  • Loading branch information
johnhaddon committed Sep 18, 2024
1 parent 5242530 commit 0f2b6dd
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 27 deletions.
8 changes: 8 additions & 0 deletions Changes.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
1.4.x.x (relative to 1.4.12.0)
=======

Fixes
-----

- Constraint : The `target` browser now shows locations from the `targetScene` if it has an input connection. Before it always showed locations from the main input.

API
---

- ScenePathPlugValueWidget : The `scenePathPlugValueWidget:scene` metadata now accepts a space-separated list of plugs, taking the first plug which has an input connection.

1.4.12.0 (relative to 1.4.11.0)
========
Expand Down
1 change: 1 addition & 0 deletions python/GafferSceneUI/ConstraintUI.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@
""",

"plugValueWidget:type", "GafferSceneUI.ScenePathPlugValueWidget",
"scenePathPlugValueWidget:scene", "targetScene in",

],

Expand Down
1 change: 1 addition & 0 deletions python/GafferSceneUI/FramingConstraintUI.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@
""",

"plugValueWidget:type", "GafferSceneUI.ScenePathPlugValueWidget",
"scenePathPlugValueWidget:scene", "targetScene in",

],

Expand Down
93 changes: 66 additions & 27 deletions python/GafferSceneUI/ScenePathPlugValueWidget.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,15 @@
import GafferImage
import GafferScene

# Supported metadata :
#
# - `scenePathPlugValueWidget:scene` : The name of a plug on the same node, used to
# provide a scene browser for path selection. Also accepts a space-separated list
# of names, taking the first plug with an input connection.
# - `scenePathPlugValueWidget:setNames` : Limits the scene browser to include only
# locations in the specified sets.
# - `scenePathPlugValueWidget:setsLabel` : A UI label for turning on and off the
# set filter.
class ScenePathPlugValueWidget( GafferUI.PathPlugValueWidget ) :

def __init__( self, plug, path = None, **kw ) :
Expand All @@ -54,15 +63,67 @@ def __init__( self, plug, path = None, **kw ) :
)

path = GafferScene.ScenePath(
self.__scenePlug( plug ),
None,
plug.node().scriptNode().context(),
"/",
filter = filter
)

GafferUI.PathPlugValueWidget.__init__( self, plug, path, **kw )

plug.ancestor( Gaffer.ScriptNode ).focusChangedSignal().connect( Gaffer.WeakMethod( self.__focusChanged ), scoped = False )
def _auxiliaryPlugs( self, plug ) :

scenePlugNames = Gaffer.Metadata.value( plug, "scenePathPlugValueWidget:scene" ) or "in"
return [
plug.node().descendant( n )
for n in scenePlugNames.split()
if isinstance( plug.node().descendant( n ), GafferScene.ScenePlug )
]

@staticmethod
def _valuesForUpdate( plugs, auxiliaryPlugs ) :

values = GafferUI.PathPlugValueWidget._valuesForUpdate( plugs, auxiliaryPlugs )

result = []
for value, scenePlugs in zip( values, auxiliaryPlugs ) :

# Find the first ScenePlug with an input, falling back to the last
# one in the list.
scenePlug = None
for scenePlug in scenePlugs :
if scenePlug.getInput() :
break

result.append( {
"value" : value,
"scenePlug" : scenePlug,
} )

return result

def _updateFromValues( self, values, exception ) :

GafferUI.PathPlugValueWidget._updateFromValues(
self, [ v["value"] for v in values ], exception
)

scenePlug = next( ( v["scenePlug"] for v in values if v["scenePlug"] is not None ), None )
if scenePlug is not None :
self.path().setScene( scenePlug )
self.__focusChangedConnection = None
else :
# The `_auxiliaryPlugs()` search doesn't work well for ShaderNodes,
# since they don't have ScenePlug inputs. We _could_ traverse outputs
# from the shader looking for a ShaderAssignment node to get a ScenePlug
# from. But this wouldn't be useful if the scene hierarchy was
# manipulated downstream of the ShaderAssignment as shaders need the
# final paths as seen by the renderer. So instead we use the focus node, as
# it is more likely to be pointed at the final render node.
self.path().setScene( self.__scenePlugFromFocus() )
self.__focusChangedConnection = self.getPlug().ancestor( Gaffer.ScriptNode ).focusChangedSignal().connect(
Gaffer.WeakMethod( self.__focusChanged ), scoped = True
)

def _pathChooserDialogue( self ) :

Expand All @@ -86,31 +147,9 @@ def _pathChooserDialogue( self ) :

return dialogue

def __scenePlug( self, plug ) :

# Search for a suitable ScenePlug input on the same node as this plug,
# or on the node of another plug being driven by this plug.

def predicate( plug ) :

scenePlugName = Gaffer.Metadata.value( plug, "scenePathPlugValueWidget:scene" ) or "in"
scenePlug = plug.node().descendant( scenePlugName )
if scenePlug and isinstance( scenePlug, GafferScene.ScenePlug ) :
return scenePlug

scenePlug = Gaffer.PlugAlgo.findDestination( plug, predicate )
if scenePlug is not None :
return scenePlug

# The above doesn't work well for ShaderNodes, since they don't have
# ScenePlug inputs. We _could_ traverse outputs from the shader looking
# for a ShaderAssignment node to get a ScenePlug from. But this wouldn't
# be useful if the scene hierarchy was manipulated downstream of the
# ShaderAssignment as shaders need the final paths as seen by the
# renderer. So instead use the focus node, as it is more likely to
# be pointed at the final render node.
def __scenePlugFromFocus( self ) :

focusNode = plug.ancestor( Gaffer.ScriptNode ).getFocus()
focusNode = self.getPlug().ancestor( Gaffer.ScriptNode ).getFocus()
if focusNode is not None :
outputScene = next( GafferScene.ScenePlug.RecursiveOutputRange( focusNode ), None )
if outputScene is not None :
Expand All @@ -121,6 +160,6 @@ def predicate( plug ) :

def __focusChanged( self, scriptNode, node ) :

scenePlug = self.__scenePlug( self.getPlug() )
scenePlug = self.__scenePlugFromFocus()
if scenePlug is not None :
self.path().setScene( scenePlug )

0 comments on commit 0f2b6dd

Please sign in to comment.