Skip to content

Commit

Permalink
Merge pull request #6205 from murraystevenson/spreadsheetSelectAffect…
Browse files Browse the repository at this point in the history
…edFix

PathFilterUI : Allow Select Affected Objects on promoted Spreadsheets
  • Loading branch information
johnhaddon authored Jan 17, 2025
2 parents 04f38a7 + fc1ee4d commit 9508c0e
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 49 deletions.
4 changes: 4 additions & 0 deletions Changes.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ Fixes
- USDLayerWriter :
- Fixed silent failures when unable to create the output file (#6197).
- Fixed leak of `usdLayerWriter:fileName` context variable.
- PathFilter :
- Fixed bug preventing display of "Select Affected Objects" menu item in the row name column of promoted Spreadsheets.
- Fixed bug preventing use of "Select Affected Objects" menu item in the row name column of Spreadsheets with `enabledRowNames` connected to the `paths` plug of a PathFilter.
- Fixed error when using "Select Affected Objects" on Spreadsheet cells connected to the `paths` plug of a PathFilter.

1.4.15.3 (relative to 1.4.15.2)
========
Expand Down
104 changes: 55 additions & 49 deletions python/GafferSceneUI/PathFilterUI.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,45 +123,36 @@
# VectorDataPlugValueWidget customisation
###########################################################################

def __targetFilterPlug( plug ) :
# Searches for a PathFilter whose `paths` plug is eventually driven by `plug`,
# and returns it.
def _destinationPathFilter( plug ) :

return Gaffer.PlugAlgo.findDestination(
plug,
lambda plug : plug if isinstance( plug.parent(), GafferScene.PathFilter ) and plug.getName() == "paths" else None
lambda plug : plug.parent() if isinstance( plug.parent(), GafferScene.PathFilter ) and plug.getName() == "paths" else None
)

def _selectAffected( plug, selection ) :
def _filteredScenes( filter ) :

inPlugs = []
result = set()
for node in GafferScene.SceneAlgo.filteredNodes( filter ) :
if isinstance( node["in"], Gaffer.ArrayPlug ) :
result.add( node["in"][0] )
else :
result.add( node["in"] )

rowPlug = plug.ancestor( Gaffer.Spreadsheet.RowPlug )

targetPlug = __targetFilterPlug( plug )

if targetPlug is not None :
inPlugs = [ n["in"] for n in GafferScene.SceneAlgo.filteredNodes( targetPlug.node() ) ]
elif rowPlug is not None :
for output in rowPlug.node()["out"] :
targetPlug = Gaffer.PlugAlgo.findDestination(
output,
lambda plug : plug.node()["out"] if isinstance( plug.node(), GafferScene.SceneNode ) else None
)
if targetPlug is not None :
inPlugs = [ targetPlug ]
break
return list( result )

if targetPlug is None :
return

scenes = [ s[0] if isinstance( s, Gaffer.ArrayPlug ) else s for s in inPlugs ]
def _selectAffected( pathMatcher, scenes ) :

result = IECore.PathMatcher()
context = targetPlug.ancestor( Gaffer.ScriptNode ).context()
with context :
for scene in scenes :
GafferScene.SceneAlgo.matchingPaths( selection, scene, result )
for scene in scenes :
with scene.ancestor( Gaffer.ScriptNode ).context() :
GafferScene.SceneAlgo.matchingPaths(
pathMatcher, scene, result
)

GafferSceneUI.ContextAlgo.setSelectedPaths( context, result )
GafferSceneUI.ScriptNodeAlgo.setSelectedPaths( scenes[0].ancestor( Gaffer.ScriptNode ), result )

class _PathsPlugValueWidget( GafferUI.VectorDataPlugValueWidget ) :

Expand All @@ -176,14 +167,15 @@ def __dataMenu( self, vectorDataWidget, menuDefinition ) :
selectedIndices = vectorDataWidget.selectedIndices()

filterData = vectorDataWidget.getData()[0]
selection = IECore.PathMatcher( [ filterData[row] for column, row in selectedIndices ] )
pathMatcher = IECore.PathMatcher( [ filterData[row] for column, row in selectedIndices ] )
scenes = _filteredScenes( _destinationPathFilter( self.getPlug() ) )

menuDefinition.append( "/selectDivider", { "divider" : True } )
menuDefinition.append(
"/Select Affected Objects",
{
"command" : functools.partial( _selectAffected, self.getPlug(), selection ),
"active" : len( selectedIndices ) > 0,
"command" : functools.partial( _selectAffected, pathMatcher, scenes ),
"active" : len( selectedIndices ) > 0 and len( scenes ) > 0,
}
)

Expand All @@ -193,36 +185,50 @@ def __dataMenu( self, vectorDataWidget, menuDefinition ) :

def __popupMenu( menuDefinition, plugValueWidget ) :

selection = None

plug = plugValueWidget.getPlug()
if plug is None:
return

node = plug.node()

if isinstance( node, Gaffer.Spreadsheet ) :
rowPlug = plug.ancestor( Gaffer.Spreadsheet.RowPlug )

with plugValueWidget.getContext() :
if __targetFilterPlug( plug ) is not None :
cellPlug = plug.ancestor( Gaffer.Spreadsheet.CellPlug )
if cellPlug is None :
return

selection = IECore.PathMatcher( plugValueWidget.vectorDataWidget().getData()[0] )
rowPlug = plug.ancestor( Gaffer.Spreadsheet.RowPlug )
if rowPlug is None :
return

elif rowPlug and plug == rowPlug["name"] and node["selector"].getValue() == "${scene:path}" :
selection = IECore.PathMatcher( [ plugValueWidget.getPlug().getValue() ] )
spreadsheet = Gaffer.PlugAlgo.findDestination(
rowPlug,
lambda plug : plug.node() if isinstance( plug.node(), Gaffer.Spreadsheet ) else None
)
if spreadsheet is None :
return

if selection is None :
scenes = []
pathMatcher = None
with plugValueWidget.getContext() :
pathFilter = _destinationPathFilter( plug )
if pathFilter is not None :
pathMatcher = IECore.PathMatcher( plug.getValue() )
scenes = _filteredScenes( pathFilter )
elif plug == rowPlug["name"] and spreadsheet["selector"].getValue() == "${scene:path}" :
pathMatcher = IECore.PathMatcher( [ plug.getValue() ] )
pathFilter = _destinationPathFilter( spreadsheet["enabledRowNames"] )
if pathFilter is not None :
scenes = _filteredScenes( pathFilter )
else :
for output in spreadsheet["out"] :
scene = Gaffer.PlugAlgo.findDestination(
output,
lambda plug : plug.node()["out"] if isinstance( plug.node(), GafferScene.SceneNode ) else None
)
if scene is not None :
scenes = [ scene ]

if pathMatcher is None or len( scenes ) == 0 :
return

menuDefinition.prepend( "/selectAffectedDivider", { "divider" : True } )
menuDefinition.prepend(
"/Select Affected Objects",
{
"command" : functools.partial( _selectAffected, plug, selection )
"command" : functools.partial( _selectAffected, pathMatcher, scenes )
}
)

Expand Down

0 comments on commit 9508c0e

Please sign in to comment.