Adding Presets to Global Context Variables: Difference between revisions

From Gaffer Wiki
Jump to navigation Jump to search
No edit summary
No edit summary
Line 17: Line 17:
The second method sets all of the preset names and all of the values in one step each. This can be done by setting the <code>presetNames</code> metadata entry to a Cortex string vector (<code>IECore.StringVectorData</code>)holding all of the preset names. Setting <code>presetValues</code> to a Cortex vector of some type, such as <code>IECoreStringVectorData</code> or <code>IECoreFloatVectorData</code>.
The second method sets all of the preset names and all of the values in one step each. This can be done by setting the <code>presetNames</code> metadata entry to a Cortex string vector (<code>IECore.StringVectorData</code>)holding all of the preset names. Setting <code>presetValues</code> to a Cortex vector of some type, such as <code>IECoreStringVectorData</code> or <code>IECoreFloatVectorData</code>.


Note that the <code>Settings</code> UI is built once and then reused for subsequent showings. This means after adding presets, you need to force Gaffer to refresh the <code>Settings</code> dialog. The last four lines of the following script show how to do that.
Note that the <code>Settings</code> UI is built once and then reused for subsequent showings. This means after adding presets, you need to force Gaffer to refresh the <code>Settings</code> dialog. You can force Gaffer to rebuild the <code>Settings</code> dialog by running the following code in the Python editor :<pre>
sw = GafferUI.ScriptWindow.acquire(root)
for window in sw.childWindows():
if hasattr( window, "_settingsEditor" ) :
sw.removeChild(window)
</pre>


The following script is an example of all of the above steps condensed into a reusable function for adding presets for a global context variable.<pre>
The following script is an example of all of the above steps condensed into a reusable function for adding presets for a global context variable.<pre>
#test
# Sets the preset names and values for a global context variable.
# `scriptNode` is the script node which you want to set global context variables for.
# `variableName` is the name of the variable to set presets for.
# `presetNames` is a list of strings to set the preset names to.
# `presetValues` is an `IECore.*VectorData` holding a list of preset values
# for each corresponding item in `presetNames`
def globalContextPresets( scriptNode, variableName, presetNames, presetValues ) :
if len( presetNames ) != len( presetValues ) :
raise ValueError( "`presetNames` and `presetValues` must be the same length" )
# Find the value plug for `variableName` global context variable.
variablePlug = None
for p in scriptNode["variables"] :
if p["name"].getValue() == variableName :
variablePlug = p["value"]
break
 
if variablePlug is None :
raise RuntimeError( "\"{}\" not found in global context variables".format( variableName ) )
# Set the widget to a presets dropdown.
Gaffer.Metadata.registerValue( variablePlug, "plugValueWidget:type", "GafferUI.PresetsPlugValueWidget" )
 
# Register the names and values.
Gaffer.Metadata.registerValue( variablePlug, "presetNames", IECore.StringVectorData( presetNames ) )
Gaffer.Metadata.registerValue( variablePlug, "presetValues", presetValues )
 
# Set the value to the first preset.
variablePlug.setValue( presetValues[0] )
 
# Tell Gaffer to rebuild the `Settings` dialog.
sw = GafferUI.ScriptWindow.acquire( scriptNode )
for window in sw.childWindows():
if hasattr( window, "_settingsEditor" ) :
sw.removeChild(window)
</pre>For example, to set a few presets for a global context variable named <code>shot</code> run the script above in the Python editor, followed by the line below.<pre>
globalContextPresets( root, "shot", ["shot A", "shot B", "shot C"], IECore.StringVectorData( [ "shotA", "shotB", "shotC" ] ) )
</pre>
</pre>

Revision as of 13:19, 19 July 2024

Global context variables can be useful for ensuring a context variable is always accessible and set for the entire script. Unless it is overridden by a ContextVariables or ContextVariablesTweaks node in the node graph, all nodes will have access to the same global context variable. There are some global context variables added by Gaffer by default when creating a new script. You can see these, and add your own, from the Variables tab in the Settings dialog accessed from the File.Settingsmenu item.

The default user interface for a global context variable can be useful for many situations, but like all plugs in Gaffer, it is possible to customize how the plugs for global context variables are presented to the user. One such customization is adding presets for the user to choose from. This ensures only valid values can be assigned to the context variable. This guide will describe how to add presets to the widget controlling a global context variable.

Adding Presets to the Settings Dialog

One way of controlling global context variables is through the Settings dialog as described above. Presets can be added here by assigning metadata to the value plug for a global context variable. Before we assign metadata, we need to identify which plug represents the context variable you want to add presets to. Global context variables are stored in the variables child of the script root. In the Python editor, these are accessed by root["variables"].

The entries in root["variables"] are of the type NameValuePlug. These plugs themselves have three child plugs : name, enabled and value. The name plug sets the name of the context variable and the value sets the value of the variable. The enabled plug is used to enable or disable the variable. Note that the value of name may be different from the name of the actual NameValuePlug. When adding plugs in using the + button in the Settings dialog, the NameValuePlug added will start with member and be followed by the next available number to keep the child names of root["variables"] unique.

To determine which child of root["variables"] you want to add metadata to, loop through all the children of root["variables"] checking the value of the name plug until you find the variable. The corresponding value child plug will be the plug we add metadata to.

The first metadata entry will tell Gaffer to use a presets dropdown as the plug widget. That is done by setting plugValueWidget:type to "GafferUI.PresetsPlugValueWidget".

Now we can add the presets themselves. That can be done in one of two ways. You can add a metadata entry starting with preset: followed by the display string of your preset, the value of which is the preset value. For example, Gaffer.Metadata.registerValue( root["variables"]["member1"]["value"], "preset:Shot 1004", "shot1004")will create a preset on the member1 plug's value plug called Shot 1004. When the user chooses that preset, the actual value of the context variable will be shot1004.

The second method sets all of the preset names and all of the values in one step each. This can be done by setting the presetNames metadata entry to a Cortex string vector (IECore.StringVectorData)holding all of the preset names. Setting presetValues to a Cortex vector of some type, such as IECoreStringVectorData or IECoreFloatVectorData.

Note that the Settings UI is built once and then reused for subsequent showings. This means after adding presets, you need to force Gaffer to refresh the Settings dialog. You can force Gaffer to rebuild the Settings dialog by running the following code in the Python editor :

sw = GafferUI.ScriptWindow.acquire(root)
for window in sw.childWindows():
	if hasattr( window, "_settingsEditor" ) :
		sw.removeChild(window)

The following script is an example of all of the above steps condensed into a reusable function for adding presets for a global context variable.

# Sets the preset names and values for a global context variable.
# `scriptNode` is the script node which you want to set global context variables for.
# `variableName` is the name of the variable to set presets for.
# `presetNames` is a list of strings to set the preset names to.
# `presetValues` is an `IECore.*VectorData` holding a list of preset values
# for each corresponding item in `presetNames`
def globalContextPresets( scriptNode, variableName, presetNames, presetValues ) :
	if len( presetNames ) != len( presetValues ) :
		raise ValueError( "`presetNames` and `presetValues` must be the same length" )
	
	# Find the value plug for `variableName` global context variable.
	variablePlug = None
	for p in scriptNode["variables"] :
		if p["name"].getValue() == variableName :
			variablePlug = p["value"]
			break

	if variablePlug is None :
		raise RuntimeError( "\"{}\" not found in global context variables".format( variableName ) )
	
	# Set the widget to a presets dropdown.
	Gaffer.Metadata.registerValue( variablePlug, "plugValueWidget:type", "GafferUI.PresetsPlugValueWidget" )

	# Register the names and values.
	Gaffer.Metadata.registerValue( variablePlug, "presetNames", IECore.StringVectorData( presetNames ) )
	Gaffer.Metadata.registerValue( variablePlug, "presetValues", presetValues )

	# Set the value to the first preset.
	variablePlug.setValue( presetValues[0] )

	# Tell Gaffer to rebuild the `Settings` dialog.
	sw = GafferUI.ScriptWindow.acquire( scriptNode )
	for window in sw.childWindows():
		if hasattr( window, "_settingsEditor" ) :
			sw.removeChild(window)

For example, to set a few presets for a global context variable named shot run the script above in the Python editor, followed by the line below.

globalContextPresets( root, "shot", ["shot A", "shot B", "shot C"], IECore.StringVectorData( [ "shotA", "shotB", "shotC" ] ) )