Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PathFilterUI : Allow Select Affected Objects on promoted Spreadsheets #6205

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