Parameter Policy ================ Introduction ------------ .. epigraph:: Parameter Policies in Katana are value policies that provide a layer in between parameters of nodes in the node graph document and widgets in the Parameters tab. Those widgets show values of parameters, and can be used to edit those parameter values. -- `Katana User Guide Glossary `_ This document explains the difference between Parameter and Parameter Policy accesses, the basics of how to use them through practical code examples, and existing policy types. .. warning:: Parameter Policies only support existing UI widgets and existing parameter types. Parameter vs Policy Value Access -------------------------------- While parameters serve as data storage, they do not necessarily return values as they appear in the UI. For example, when a parameter has a default value, the UI uses a parameter policy to display either the default value or the override value, depending on the state of the ``enable`` parameter that controls whether the override is active. Similarly, when you modify a value through the UI, it automatically updates the ``enable`` parameter. However, when you directly modify a parameter programmatically, the ``enable`` parameter is not automatically updated. Accessing parameters through parameter policies allows you to read and write values in a way that is consistent with UI behavior. Abstractly, the difference between Parameter and Parameter Policy access can be summarized as follows: Parameter: - Best for direct data reads/writes without UI condition. - Reads raw stored values from specific parameter paths. - For example, reading and writing many parameters in a batch process. Parameter Policy: - Best for UI-facing tools and editor workflows. - Reads and writes values in a way that follows policy/UI state handling. - For example, reading parameters as they appear in the UI using simple code. This section explains how to access Parameters correctly and compares two approaches for ``cameraName`` on a ``RenderSettings`` node: The examples show how each approach reads and writes values, and clarify when policy-based access is the safer choice for keeping UI-related parameter state consistent. 1) Set a value via Parameter ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ In this case, ``cameraName`` is represented as a parameter group with three child parameters: - ``value``: the current value - ``default``: the fallback/default value - ``enable``: whether the override is active Initially, ``default`` matches ``value``, and ``enable`` is ``0``. Setting only ``value`` does not automatically switch ``enable`` to ``1``. .. code-block:: python from Katana import NodegraphAPI rootNode = NodegraphAPI.GetRootNode() node = NodegraphAPI.CreateNode("RenderSettings", rootNode) camera_param_value = node.getParameter("args.renderSettings.cameraName.value") # Write to Parameter camera_param_value.setValue("/root/world/cam/mainCam", 0) The parameter is not enabled yet, so the UI still shows the default value, and the override value is not applied in the scene. This is because the ``enable`` parameter is still ``0``. .. image:: images/ParameterPolicy_parameter_setValue.png To apply the override, you need to set ``enable`` to ``1`` as well. .. code-block:: python camera_param_enable = node.getParameter("args.renderSettings.cameraName.enable") camera_param_enable.setValue(1, 0) 2) Set a value via Parameter Policy ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ With policy-based access, you do not need to handle ``enable`` manually. The policy handles the state transition and sets ``enable`` to ``1`` automatically when the value is updated. .. code-block:: python from Katana import NodegraphAPI, UI4 rootNode = NodegraphAPI.GetRootNode() node = NodegraphAPI.CreateNode("RenderSettings", rootNode) camera_param = node.getParameter("args.renderSettings.cameraName") policy = UI4.FormMaster.CreateParameterPolicy(None, camera_param) # Write through Policy policy.setValue("/root/world/cam/mainCam") The parameter is enabled and the override value is applied in the scene immediately after setting the value through the policy, without needing to set ``enable`` explicitly. .. image:: images/ParameterPolicy_policy_setValue.png 3) Get a value via Parameter and Parameter Policy ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Getting values can also produce different behavior between ``Parameter`` and ``ParameterPolicy``. When ``enable`` is ``False``: - The UI displays the ``default`` value. - The ``Parameter`` getter for ``.value`` returns the stored current value. - The ``ParameterPolicy`` getter returns the value that is currently displayed in the UI (the default value in this state). .. code-block:: python from Katana import NodegraphAPI, UI4 rootNode = NodegraphAPI.GetRootNode() node = NodegraphAPI.CreateNode("RenderSettings", rootNode) camera_group_param = node.getParameter("args.renderSettings.cameraName") camera_value_param = node.getParameter("args.renderSettings.cameraName.value") camera_enable_param = node.getParameter("args.renderSettings.cameraName.enable") # Prepare a state where UI should display default. camera_value_param.setValue("/root/world/cam/currentCam", 0) camera_enable_param.setValue(False, 0) # Raw parameter getter reads the stored current value. value_from_param = camera_value_param.getValue(0) # Policy getter reads the effective/displayed value. policy = UI4.FormMaster.CreateParameterPolicy(None, camera_group_param) value_from_policy = policy.getValue() # Expected result: # value_from_param == "/root/world/cam/currentCam" # value_from_policy == "/root/world/cam/camera" Using Parameter Policy ---------------------- Basic Parameter Policy Creation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Parameter policies are created through the ``FormMaster.CreateParameterPolicy`` function, which automatically selects the appropriate policy type based on the parameter type and node type. The system uses a delegate pattern where different node types can register custom policy delegates to override default behavior. .. code-block:: python from UI4.FormMaster import CreateParameterPolicy import NodegraphAPI # Get a parameter from a node node = NodegraphAPI.GetNode('myNode') param = node.getParameter('myParam') # Create a parameter policy policy = CreateParameterPolicy(None, param) # None = root policy if policy: # Policy created successfully print(f"Created {policy.getType()} policy for {param.getName()}") Hierarchical Policy Creation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ When creating policies in a hierarchy, a parent policy can be passed into ``CreateParameterPolicy(parentPolicy, param)``. This links the child policy to its parent and allows the parent policy to manage child policy behavior consistently. Some policy types require specific child parameters such as ``enable`` and ``value``. In most cases, these essential children are handled by the policy creation function, so you do not need to create them manually. .. code-block:: python # Create parent policy first parentParam = node.getParameter('parentGroup') parentPolicy = CreateParameterPolicy(None, parentParam) # Create child policies with parent reference childParam = parentParam.getChild('childParam') childPolicy = CreateParameterPolicy(parentPolicy, childParam) # Parent automatically manages child policies for groups children = parentPolicy.getChildren() Building a Widget from a Parameter Policy ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Use this workflow when you want to add existing parameter widgets to your own custom UI, such as a custom editor in a SuperTool, while keeping Katana's standard parameter UI behavior. Before creating a widget from a policy, you can also update the policy's widget hints. This lets you customize how the parameter appears in the UI, such as changing the displayed label. It is useful when building your own tools in Katana, for example a custom panel or SuperTool editor. The available hints depend on the parameters and the types of widgets. For more details, see :ref:`widgets-and-hints`. Implementation steps: 1. Resolve the target parameter from the node. 2. Create a policy with ``UI4.FormMaster.CreateParameterPolicy(parentPolicy, param)``. 3. Build the widget with ``UI4.FormMaster.ParameterWidgetFactory.buildWidget(parentWidget, policy)``. 4. Return the created widget to the caller. .. code-block:: python from Katana import NodegraphAPI, UI4 def create_parameter_widget(node_name, parameter_path, parent_widget=None): """Create and return a widget for a Katana parameter.""" node = NodegraphAPI.GetNode(node_name) param = node.getParameter(parameter_path) # Root policy creation: parentPolicy is None. policy = UI4.FormMaster.CreateParameterPolicy(None, param) # Update hints before creating the widget. hints = policy.getWidgetHints() hints["label"] = "Primary Camera" return UI4.FormMaster.ParameterWidgetFactory.buildWidget(parent_widget, policy) def build_editor(parent=None): return create_parameter_widget("myNode", "myGroup.myParam", parent) Developer notes: - For a root parameter, pass ``None`` as ``parentPolicy``. - If no widget appears, verify that the node and parameter path are valid and that policy creation did not return ``None``. Policy Delegate Registration ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Parameter policy delegates are registered using the RegisterPolicyDelegate function to provide custom policy behavior for specific node types. This allows you to define how policies are created for parameters of those nodes, enabling specialized handling of the UI and its behavior. For example, you can register ``EnableableScalarParameterPolicyDelegate`` for the example SuperTool ``ImageCoordinate`` node by uncommenting the relevant code within: ``$KATANA_ROOT/plugins/Src/Resources/Examples/SuperTools/ImageCoordinate/v1/__init__.py`` By default, the ``ImageCoordinate`` node does not display enable/disable buttons: .. image:: images/ParameterPolicy_default_ImageCoordinate.png After registering the ``EnableableScalarParameterPolicyDelegate``, the ``ImageCoordinate`` node displays enable/disable buttons to the left of each parameter: .. image:: images/ParameterPolicy_enableable_ImageCoordinate.png If you want to further customize the policy creation, you can create your own delegate class by inheriting from ``ParameterPolicy.ParameterPolicyDelegate`` and implementing the ``createPolicy`` method. Then, register your custom delegate for the target node type. .. code-block:: python from UI4.FormMaster import ParameterPolicy # Register a custom delegate for a specific node type ParameterPolicy.RegisterPolicyDelegate('MyNodeType', MyCustomDelegate()) Custom delegates must implement the createPolicy method: .. code-block:: python class MyCustomDelegate(ParameterPolicy.ParameterPolicyDelegate): def createPolicy(self, parentPolicy, param): # Custom policy creation logic if param.getType() == 'string' and param.getName() == 'customParam': return MyCustomParameterPolicy(param, parentPolicy) # Fall back to default behavior return ParameterPolicy.ParameterPolicyDelegate.createPolicy( self, parentPolicy, param) Parameter Policy Types ---------------------- Core Parameter Policy Types ~~~~~~~~~~~~~~~~~~~~~~~~~~~ The following table shows the built-in parameter policy types and their use cases: .. list-table:: :header-rows: 1 * - Policy Type - Parameter Types - Features * - ScalarParameterPolicy - ``number``, ``string`` - Expressions, curves, states, validation * - ArrayParameterPolicy - ``numberArray``, ``stringArray`` - Dynamic sizing, child management * - GroupParameterPolicy - ``group``, ``dynamicgroup`` - Child policy management, hierarchy * - CurveParameterPolicy - ``curve`` - Curve editing, keyframe management * - OpaqueParameterPolicy - ``opaque`` - Binary data handling Specialized Parameter Policy Types ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Beyond the core types, Katana provides several specialized parameter policy types for specific use cases. This list represents only some of the policies currently used in Katana. .. list-table:: :header-rows: 1 * - Policy Type - Purpose - Features - Example * - DefaultableParameterPolicy - Parameters with default value override - Defaultable and enableable - ``properties.size`` on ``UsdCubeCreate`` node * - EnableableScalarParameterPolicy - Parameters with enable/disable functionality - Enableable - ``projection`` on ``CameraCreate`` node * - EnableableGroupParameterPolicy - Groups with enable/disable functionality - Enableable and has child policy as group - Not used in current Katana version * - GraphStateVariableValuePolicy - Graph state variable handling - Defaultable and enableable - ``variables.var1`` on root node * - StageParameterPolicy - USD stage parameter handling - Enableable and return existing attribute value as a default value - ``properties.inputs.diffuse`` on ``UsdLight`` node DefaultableParameterPolicy ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Parameter XML structure: .. code-block:: xml EnableableScalarParameterPolicy ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Parameter XML structure: .. code-block:: xml GraphStateVariableValuePolicy ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Parameter XML structure: .. code-block:: xml StageParameterPolicy ^^^^^^^^^^^^^^^^^^^^ Parameter XML structure: .. code-block:: xml