Skip to content

Commit

Permalink
SpreadsheetUI : Forward metadata from connected plugs
Browse files Browse the repository at this point in the history
  • Loading branch information
murraystevenson committed May 28, 2024
1 parent 585ea96 commit 6fd4548
Show file tree
Hide file tree
Showing 3 changed files with 176 additions and 12 deletions.
1 change: 1 addition & 0 deletions Changes.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ Improvements
- CodeWidget : Added highlighting of braces and operators.
- RenderPassEditor : Added preset menu for choosing a render pass type from the list of available registered types. An "auto" type is included in the list when an auto type function has been registered.
- OptionTweaks : Tweak `value` plugs can now access metadata registered globally to `option:{tweakName}`, where `{tweakName}` is the value of the tweak's `name` plug.
- Spreadsheet : Added support for metadata to be automatically forwarded from plugs downstream of a column's `out` plug to the column's default row.

Fixes
-----
Expand Down
78 changes: 66 additions & 12 deletions python/GafferUI/SpreadsheetUI/_Metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -249,10 +249,26 @@ def __correspondingDefaultPlug( plug ) :
rowsPlug = rowPlug.parent()
return rowsPlug.defaultRow().descendant( plug.relativeName( rowPlug ) )

def __correspondingOutPlug( plug ) :

return Gaffer.PlugAlgo.findDestination(
plug,
lambda p : p if isinstance( p.node(), Gaffer.Spreadsheet ) and p.node()["out"].isAncestorOf( p ) else None
)

def __defaultCellMetadata( plug, key ) :

return Gaffer.Metadata.value( __correspondingDefaultPlug( plug ), key )

def __forwardedMetadata( plug, key ) :

source = Gaffer.PlugAlgo.findDestination(
__correspondingOutPlug( plug ),
lambda p : p if Gaffer.Metadata.value( p, key ) else None
)

return Gaffer.Metadata.value( source, key ) if source else None

for key in [
"description",
"spreadsheet:columnLabel",
Expand All @@ -263,6 +279,10 @@ def __defaultCellMetadata( plug, key ) :
"tweakPlugValueWidget:allowCreate",
] :

Gaffer.Metadata.registerValue(
Gaffer.Spreadsheet.RowsPlug, "default.*...", key,
functools.partial( __forwardedMetadata, key = key ),
)
Gaffer.Metadata.registerValue(
Gaffer.Spreadsheet.RowsPlug, "row*.*...", key,
functools.partial( __defaultCellMetadata, key = key ),
Expand All @@ -286,36 +306,70 @@ def __defaultCellMetadata( plug, key ) :

}

def __presetSourcePlug( plug ) :

def predicate( p ) :

if (
( Gaffer.Metadata.value( p, "presetNames" ) and Gaffer.Metadata.value( p, "presetValues" ) )
or any( v.startswith( "preset:" ) for v in Gaffer.Metadata.registeredValues( p ) )
) :
return p

source = Gaffer.PlugAlgo.findDestination(
__correspondingOutPlug( plug ),
lambda p : predicate( p )
)

return source

def __presetNamesMetadata( plug ) :

if plug.__class__ not in __plugPresetTypes :
if not plug or plug.__class__ not in __plugPresetTypes :
return None

source = __correspondingDefaultPlug( plug )

result = IECore.StringVectorData()
for n in Gaffer.Metadata.registeredValues( source ) :
for n in Gaffer.Metadata.registeredValues( plug ) :
if n.startswith( "preset:" ) :
result.append( n[7:] )

result.extend( Gaffer.Metadata.value( source, "presetNames" ) or [] )
result.extend( Gaffer.Metadata.value( plug, "presetNames" ) or [] )
return result

def __presetValuesMetadata( plug ) :

if not plug :
return None

dataType = __plugPresetTypes.get( plug.__class__ )
if dataType is None :
return None

source = __correspondingDefaultPlug( plug )

result = dataType()
for n in Gaffer.Metadata.registeredValues( source ) :
for n in Gaffer.Metadata.registeredValues( plug ) :
if n.startswith( "preset:" ) :
result.append( Gaffer.Metadata.value( source, n ) )
result.append( Gaffer.Metadata.value( plug, n ) )

result.extend( Gaffer.Metadata.value( source, "presetValues" ) or [] )
result.extend( Gaffer.Metadata.value( plug, "presetValues" ) or [] )
return result

Gaffer.Metadata.registerValue( Gaffer.Spreadsheet.RowsPlug, "row*.*...", "presetNames", __presetNamesMetadata )
Gaffer.Metadata.registerValue( Gaffer.Spreadsheet.RowsPlug, "row*.*...", "presetValues", __presetValuesMetadata )
def __defaultPlugPresetNamesMetadata( plug ) :

return __presetNamesMetadata( __correspondingDefaultPlug( plug ) )

def __defaultPlugPresetValuesMetadata( plug ) :

return __presetValuesMetadata( __correspondingDefaultPlug( plug ) )

def __forwardedPresetNamesMetadata( plug ) :

return __presetNamesMetadata( __presetSourcePlug( plug ) )

def __forwardedPresetValuesMetadata( plug ) :

return __presetValuesMetadata( __presetSourcePlug( plug ) )

Gaffer.Metadata.registerValue( Gaffer.Spreadsheet.RowsPlug, "default.*...", "presetNames", __forwardedPresetNamesMetadata )
Gaffer.Metadata.registerValue( Gaffer.Spreadsheet.RowsPlug, "default.*...", "presetValues", __forwardedPresetValuesMetadata )
Gaffer.Metadata.registerValue( Gaffer.Spreadsheet.RowsPlug, "row*.*...", "presetNames", __defaultPlugPresetNamesMetadata )
Gaffer.Metadata.registerValue( Gaffer.Spreadsheet.RowsPlug, "row*.*...", "presetValues", __defaultPlugPresetValuesMetadata )
109 changes: 109 additions & 0 deletions python/GafferUITest/SpreadsheetUITest.py
Original file line number Diff line number Diff line change
Expand Up @@ -914,5 +914,114 @@ def testMetadataAlgoRemovesNonDefaultRowMetadata( self ) :
[]
)

def testMetadataForwarding( self ) :

s = Gaffer.Spreadsheet()
s["rows"].addColumn( Gaffer.StringPlug( "a" ) )
s["rows"].addColumn( Gaffer.StringPlug( "b" ) )
s["rows"].addRows( 1 )

n = Gaffer.Node()
n.addChild( Gaffer.StringPlug( "a" ) )

n["a"].setInput( s["out"]["a"] )

self.assertEqual( Gaffer.Metadata.value( s["rows"][1]["cells"]["a"]["value"], "plugValueWidget:type" ), None )
self.assertEqual( Gaffer.Metadata.value( s["rows"][1]["cells"]["b"]["value"], "plugValueWidget:type" ), None )

Gaffer.Metadata.registerValue( n["a"], "plugValueWidget:type", "Test" )

self.assertEqual( Gaffer.Metadata.value( s["rows"][1]["cells"]["a"]["value"], "plugValueWidget:type" ), "Test" )
self.assertEqual( Gaffer.Metadata.value( s["rows"][1]["cells"]["b"]["value"], "plugValueWidget:type" ), None )

Gaffer.Metadata.registerValue( s["rows"].defaultRow()["cells"]["b"]["value"], "plugValueWidget:type", "Test2" )

self.assertEqual( Gaffer.Metadata.value( s["rows"][1]["cells"]["a"]["value"], "plugValueWidget:type" ), "Test" )
self.assertEqual( Gaffer.Metadata.value( s["rows"][1]["cells"]["b"]["value"], "plugValueWidget:type" ), "Test2" )

Gaffer.Metadata.registerValue( s["rows"].defaultRow()["cells"]["a"]["value"], "plugValueWidget:type", "Test2" )

self.assertEqual( Gaffer.Metadata.value( s["rows"][1]["cells"]["a"]["value"], "plugValueWidget:type" ), "Test2" )
self.assertEqual( Gaffer.Metadata.value( s["rows"][1]["cells"]["b"]["value"], "plugValueWidget:type" ), "Test2" )

def testPresetForwarding( self ) :

s = Gaffer.Spreadsheet()
s["rows"].addColumn( Gaffer.StringPlug( "a" ) )
s["rows"].addColumn( Gaffer.StringPlug( "b" ) )
s["rows"].addRows( 1 )

n = Gaffer.Node()
n.addChild( Gaffer.StringPlug( "a" ) )
n.addChild( Gaffer.StringPlug( "b" ) )

n["a"].setInput( s["out"]["a"] )
n["b"].setInput( s["out"]["b"] )

self.assertEqual( Gaffer.Metadata.value( s["rows"][1]["cells"]["a"]["value"], "presetNames" ), IECore.StringVectorData( [] ) )
self.assertEqual( Gaffer.Metadata.value( s["rows"][1]["cells"]["a"]["value"], "presetValues" ), IECore.StringVectorData( [] ) )
self.assertEqual( Gaffer.Metadata.value( s["rows"][1]["cells"]["b"]["value"], "presetNames" ), IECore.StringVectorData( [] ) )
self.assertEqual( Gaffer.Metadata.value( s["rows"][1]["cells"]["b"]["value"], "presetValues" ), IECore.StringVectorData( [] ) )

self.assertEqual( Gaffer.Metadata.value( s["rows"].defaultRow()["cells"]["a"]["value"], "presetNames" ), None )
self.assertEqual( Gaffer.Metadata.value( s["rows"].defaultRow()["cells"]["a"]["value"], "presetValues" ), None )
self.assertEqual( Gaffer.Metadata.value( s["rows"].defaultRow()["cells"]["b"]["value"], "presetNames" ), None )
self.assertEqual( Gaffer.Metadata.value( s["rows"].defaultRow()["cells"]["b"]["value"], "presetValues" ), None )

# Registering only "presetNames" on the destination plug doesn't forward to the cell.
Gaffer.Metadata.registerValue( n["a"], "presetNames", IECore.StringVectorData( [ "Test", "Test2" ] ) )

self.assertEqual( Gaffer.Metadata.value( s["rows"][1]["cells"]["a"]["value"], "presetNames" ), IECore.StringVectorData( [] ) )
self.assertEqual( Gaffer.Metadata.value( s["rows"][1]["cells"]["a"]["value"], "presetValues" ), IECore.StringVectorData( [] ) )
self.assertEqual( Gaffer.Metadata.value( s["rows"][1]["cells"]["b"]["value"], "presetNames" ), IECore.StringVectorData( [] ) )
self.assertEqual( Gaffer.Metadata.value( s["rows"][1]["cells"]["b"]["value"], "presetValues" ), IECore.StringVectorData( [] ) )

self.assertEqual( Gaffer.Metadata.value( s["rows"].defaultRow()["cells"]["a"]["value"], "presetNames" ), None )
self.assertEqual( Gaffer.Metadata.value( s["rows"].defaultRow()["cells"]["a"]["value"], "presetValues" ), None )
self.assertEqual( Gaffer.Metadata.value( s["rows"].defaultRow()["cells"]["b"]["value"], "presetNames" ), None )
self.assertEqual( Gaffer.Metadata.value( s["rows"].defaultRow()["cells"]["b"]["value"], "presetValues" ), None )

# Registering "presetValues" alongside "presetNames" will forward.
Gaffer.Metadata.registerValue( n["a"], "presetValues", IECore.StringVectorData( [ "test", "test2" ] ) )

self.assertEqual( Gaffer.Metadata.value( s["rows"].defaultRow()["cells"]["a"]["value"], "presetNames" ), IECore.StringVectorData( [ "Test", "Test2" ] ) )
self.assertEqual( Gaffer.Metadata.value( s["rows"].defaultRow()["cells"]["a"]["value"], "presetValues" ), IECore.StringVectorData( [ "test", "test2" ] ) )
self.assertEqual( Gaffer.Metadata.value( s["rows"].defaultRow()["cells"]["b"]["value"], "presetNames" ), None )
self.assertEqual( Gaffer.Metadata.value( s["rows"].defaultRow()["cells"]["b"]["value"], "presetValues" ), None )

self.assertEqual( Gaffer.Metadata.value( s["rows"][1]["cells"]["a"]["value"], "presetNames" ), IECore.StringVectorData( [ "Test", "Test2" ] ) )
self.assertEqual( Gaffer.Metadata.value( s["rows"][1]["cells"]["a"]["value"], "presetValues" ), IECore.StringVectorData( [ "test", "test2" ] ) )
self.assertEqual( Gaffer.Metadata.value( s["rows"][1]["cells"]["b"]["value"], "presetNames" ), IECore.StringVectorData( [] ) )
self.assertEqual( Gaffer.Metadata.value( s["rows"][1]["cells"]["b"]["value"], "presetValues" ), IECore.StringVectorData( [] ) )

# Registering "preset:" metadata also forwards, and combines with "presetNames" & "presetValues"
Gaffer.Metadata.registerValue( n["a"], "preset:Test3", "test3" )
Gaffer.Metadata.registerValue( n["b"], "preset:Test", "test" )

self.assertEqual( Gaffer.Metadata.value( s["rows"][1]["cells"]["a"]["value"], "presetNames" ), IECore.StringVectorData( [ "Test3", "Test", "Test2" ] ) )
self.assertEqual( Gaffer.Metadata.value( s["rows"][1]["cells"]["a"]["value"], "presetValues" ), IECore.StringVectorData( [ "test3", "test", "test2" ] ) )
self.assertEqual( Gaffer.Metadata.value( s["rows"][1]["cells"]["b"]["value"], "presetNames" ), IECore.StringVectorData( [ "Test" ] ) )
self.assertEqual( Gaffer.Metadata.value( s["rows"][1]["cells"]["b"]["value"], "presetValues" ), IECore.StringVectorData( [ "test" ] ) )

self.assertEqual( Gaffer.Metadata.value( s["rows"].defaultRow()["cells"]["a"]["value"], "presetNames" ), IECore.StringVectorData( [ "Test3", "Test", "Test2" ] ) )
self.assertEqual( Gaffer.Metadata.value( s["rows"].defaultRow()["cells"]["a"]["value"], "presetValues" ), IECore.StringVectorData( [ "test3", "test", "test2" ] ) )
self.assertEqual( Gaffer.Metadata.value( s["rows"].defaultRow()["cells"]["b"]["value"], "presetNames" ), IECore.StringVectorData( [ "Test" ] ) )
self.assertEqual( Gaffer.Metadata.value( s["rows"].defaultRow()["cells"]["b"]["value"], "presetValues" ), IECore.StringVectorData( [ "test" ] ) )

# Registering either metadata on the default row will override the metadata from the destination.
Gaffer.Metadata.registerValue( s["rows"].defaultRow()["cells"]["b"]["value"], "preset:TestDefault", "testDefault" )
Gaffer.Metadata.registerValue( s["rows"].defaultRow()["cells"]["b"]["value"], "presetNames", IECore.StringVectorData( [ "TestDefault2", "TestDefault3" ] ) )
Gaffer.Metadata.registerValue( s["rows"].defaultRow()["cells"]["b"]["value"], "presetValues", IECore.StringVectorData( [ "testDefault2", "testDefault3" ] ) )

self.assertEqual( Gaffer.Metadata.value( s["rows"][1]["cells"]["b"]["value"], "presetNames" ), IECore.StringVectorData( [ "TestDefault", "TestDefault2", "TestDefault3" ] ) )
self.assertEqual( Gaffer.Metadata.value( s["rows"][1]["cells"]["b"]["value"], "presetValues" ), IECore.StringVectorData( [ "testDefault", "testDefault2", "testDefault3" ] ) )

# Registering "presetNames" and "presetValues" on the default row will override the destination presets.
Gaffer.Metadata.registerValue( s["rows"].defaultRow()["cells"]["a"]["value"], "presetNames", IECore.StringVectorData( [ "TestDefault2", "TestDefault3" ] ) )
Gaffer.Metadata.registerValue( s["rows"].defaultRow()["cells"]["a"]["value"], "presetValues", IECore.StringVectorData( [ "testDefault2", "testDefault3" ] ) )

self.assertEqual( Gaffer.Metadata.value( s["rows"][1]["cells"]["a"]["value"], "presetNames" ), IECore.StringVectorData( [ "TestDefault2", "TestDefault3" ] ) )
self.assertEqual( Gaffer.Metadata.value( s["rows"][1]["cells"]["a"]["value"], "presetValues" ), IECore.StringVectorData( [ "testDefault2", "testDefault3" ] ) )

if __name__ == "__main__":
unittest.main()

0 comments on commit 6fd4548

Please sign in to comment.