BUTTONS_gearParm Utilities interface module

This module provides functions for working with parameters. These include copying and linking parms from one node to another, copying spare parms, finding external references and promoting parms to parent nodes.

Info
Date 01/12/2011
Compatibility Houdini 11.0
Change Log Added the Parm Utilities module.
#
# Produced by:
#	Graham Thompson
#	captainhammy@gmail.com
#	www.captainhammy.com
#
# Name:         parmutils.py
#
# Comments:     Functions dealing with parameters.
#
# Version:      1.0
#
# Compatibility: Houdini 11.0
#
 
import hou
 
import os
import re
 
 
def copyParmValues(source_node, target_node):
    """ Copy parameter values of the source node to those of the target node 
        if a parameter with the same name exists.
    """
    for parm_to_copy in source_node.parms():
        parm_template = parm_to_copy.parmTemplate()
        # Skip folder parms.
        if isinstance(parm_template, hou.FolderSetParmTemplate):
            continue
 
        parm_to_copy_to = target_node.parm(parm_to_copy.name())
        # If the parameter on the target node does not exist, skip this parm.
        if parm_to_copy_to is None:
            continue
 
        # If we have keys/expressions we need to copy them all.
        if parm_to_copy.keyframes():
            # Copy all hou.Keyframe objects.
            for key in parm_to_copy.keyframes():
                parm_to_copy_to.setKeyframe(key)
        else:
            # If the parameter is a string copy the raw string.
            if isinstance(parm_template, hou.StringParmTemplate):
                parm_to_copy_to.set(parm_to_copy.unexpandedString())
            # Copy the raw value.
            else:
                parm_to_copy_to.set(parm_to_copy.eval())
 
 
def linkParmsTo(source_node, target_node):
    """ Link the parms of the source node to those of the target node if 
        a parameter with the same name exists.
    """
    for parm_to_link in source_node.parms():
        # Skip folder parms.
        if isinstance(parm_to_link.parmTemplate(), hou.FolderSetParmTemplate):
            continue
 
        parm_to_link_to = target_node.parm(parm_to_link.name())
 
        # If the target parm exists
        if parm_to_link_to is not None:
            parm_to_link.set(parm_to_link_to)
 
 
def copySpareParms(source_node, target_node):
    """ Copy spare parameters from the source node to the target node. """
    spare_parms = [parm_tuple for parm_tuple in source_node.parms()
                   if parm_tuple.isSpare()]
 
    for parm_tuple in spare_parms:
        template = parm_tuple.parmTemplate()
 
        if isinstance(template, hou.FolderSetParmTemplate):
            continue
 
        folders = parm_tuple[0].containingFolders()
 
        target_node.addSpareParmTuple(template, folders, True)
 
def copyParameterLayout(source_node, target_node):
    """ Copy the entire parameter layout from the source node to the target_node. """
    parm_template_group = source_node.parmTemplateGroup()
    target_node.setParmTemplateGroup(parm_template_group)
 
 
def hardenAssetParameters(node):
    """ Convert any spare parameters on an asset node to asset parameters. """
 
    # Get the node type definition.  It will be None if the node is
    # not an asset.
    asset_definition = node.type().definition()
 
    # Make sure the node is a digital asset.
    if asset_definition is None:
        raise hou.OperationFailed("Node must be a digital asset.")
 
    # Get the parameter template group from the node.
    parm_template_group = node.parmTemplateGroup()
    # Set the parameter template on the asset to be the one from
    # the node.  This converts all spare parameters to normal
    # asset parameters.
    asset_definition.setParmTemplateGroup(parm_template_group)
 
 
def copyAndReplace(source_node):
    """ Replace a node with a new instance and copy the parameters."""
 
    # Create a new instance of the node.
    new_node = source_node.parent().createNode(source_node.type().name())
 
    # If the node is selected, set the new one selected.
    if source_node.isSelected():
        new_node.setSelected(True, False)
 
    # Copy the parms.
    parm_template_group = source_node.parmTemplateGroup()
    new_node.setParmTemplateGroup(parm_template_group)
 
    # Match the position and color.
    new_node.setPosition(source_node.position())
    new_node.setColor(source_node.color())
 
    # Process inputs.
    input_connections = source_node.inputConnections()
 
    for connection in input_connections:
        in_idx = connection.inputIndex()
        out_idx = connection.outputIndex()
        input_node = connection.inputNode()
 
        new_node.setInput(in_idx, input_node, out_idx)
 
    # Process outputs.
    output_connections = source_node.outputConnections()
 
    for connection in output_connections:
        in_idx = connection.inputIndex()
        out_idx = connection.outputIndex()
        output_node = connection.outputNode()
 
        output_node.setInput(in_idx, new_node, out_idx)
 
    #TODO: Per context flag handling.
 
 
    # If this is a Sop, look at setting the Render flag.
    if isinstance(new_node, hou.SopNode):
        new_node.setRenderFlag(source_node.isRenderFlagSet())
 
    new_node.setDisplayFlag(source_node.isDisplayFlagSet())
 
    name = source_node.name()
 
    source_node.destroy()
 
    new_node.setName(name)
 
 
def parmValueDictionary(node):
    """ Get a dictionary of all the parameters and corresponding
        values.
    """
    parm_dict = {}
    for parm in node.parms():
        if not parm.keyframes():
            parm_dict[parm.name()] = parm.eval()
 
    return parm_dict
 
 
def parmExpressionDictionary(node):
    """ Get a dictionary of all the parameters with expressions
        and their corresponding values.
    """
    parm_dict = {}
    for parm in node.parms():
        if parm.keyframes():
            parm_dict[parm.name()] = parm.keyframes()[0].expression()
 
    return parm_dict
 
 
def displayParmInDialog(parm_or_parm_tuple):
    """ Force the parameter dialog to display this parameter. """
    if isinstance(parm_or_parm_tuple, hou.ParmTuple):
        parm_or_parm_tuple = parm_or_parm_tuple[0]
 
    for tpl, idx in zip(parm_or_parm_tuple.containingFolderSetParmTuples(),
                        parm_or_parm_tuple.containingFolderIndices()):
        tpl[0].set(idx)
 
 
def defaultValue(parm_or_parm_tuple):
    """ Get the default value of a parameter. """
    # Handle a hou.Parm object.
    if isinstance(parm_or_parm_tuple, hou.Parm):
        # Get the parm tuple so we can access the names of all 
        # the parms in the group.
        parm_tuple = parm_or_parm_tuple.tuple()
        # Get a list of the parm names.
        parm_names = [parm.name() for parm in parm_tuple]
        # Find the index of our parm in the tuple.
        idx = parm_names.index(parm_or_parm_tuple.name())
        # Use the index to get the correct default value and return it.
        return parm_tuple.parmTemplate().defaultValue()[idx]
 
    else:
        return parm_or_parm_tuple.parmTemplate().defaultValue()
 
 
def isDefaultValue(parm_or_parm_tuple):
    """ Determine if the parameter is currently set to the default value. """
    default = defaultValue(parm_or_parm_tuple)
    return parm_or_parm_tuple.eval() == default
 
 
def applyFunctionToParms(parm_list, function, args=()):
    """ Apply a function with specific args to each parameter in the list.
 
        The hou.Parm object is inserted into the beginning of the args list.
    """
    for parm in parm_list:
        function.__call__((parm,) + args)
 
 
def linkParmToParent(parm):
    """ Link a parameter to a parameter of the same name on the parent node
        if the parameter exists.
    """
    parent = parm.node().parent()
 
    parm_node = parm.node()
 
    parent_parm = parent.parm("%s_%s" % (parm_node.name(), parm.name()))
    if parent_parm is None:
        parent_parm = parent.parm(parm.name())
    if parent_parm:
        parm.set(parent_parm)
 
 
def promoteToParent(parm_tuple):
    """ Promote a parameter to the parent node. """
    parent = parm_tuple.node().parent()
    promoteToNode(parm_tuple, parent)
 
 
def promoteToNode(source_tuple, target_node=None):
    """ Promote a parameter to a specific node as a spare parameter.
 
       A new parameter is created with the name nodename_parmname.
       Promoting the "t" parameter from a node called "xform1" will
       create a new parameter "xform1_t".
 
    """
    # Get the source node.
    source_node = source_tuple.node()
    source_node_name = source_node.name()
 
    if target_node is None:
        # If the ui module isn't available then we can't choose a
        # node so we will throw an exception.
        if not hou.isUIAvailable():
            raise hou.OperationFailed("Please specify a target node.")
 
        # Try to select a node.
        target_node_path = hou.ui.selectNode()
        if target_node_path is None:
            return
        target_node = hou.node(target_node_path)
 
    # Get the parameter template and change the name and label.
    template = source_tuple.parmTemplate()
 
    # Change the parm name and label to include the source node name.
    parm_name = "%s_%s" % (source_node_name, source_tuple.name())
    parm_label = "%s %s" % (source_node_name, template.label())
 
    template.setName(parm_name)
    template.setLabel(parm_label)
 
    # Get the current value.
    parm_value = source_tuple.eval()
 
    target_tuple = target_node.addSpareParmTuple(template)
 
    # Link the parms.
    for parm, target in zip(source_tuple, target_tuple):
        parm.set(target)
    # Restore the parm value.
    target_tuple.set(parm_value)
 
    # Clean up the spare parameter if the linked node is destroyed.
    def cleanParm(**kwargs):
        try:
            target_node.removeSpareParmTuple(target_tuple)
        except hou.ObjectWasDeleted:
            pass
 
    # Clean up the channel reference if the control node is destroyed.
    def cleanRefs(**kwargs):
        try:
            value = target_tuple.eval()
            source_tuple.revertToDefaults()
            source_tuple.set(value)
        except hou.ObjectWasDeleted:
            pass
 
    # Add event callbacks.
    source_node.addEventCallback((hou.nodeEventType.BeingDeleted,), cleanParm)
    target_node.addEventCallback((hou.nodeEventType.BeingDeleted,), cleanRefs)
 
 
def isParmDriven(parm):
    """ Test to see if a parameter is driven by an animation
        channel, expression or CHOP override.
    """
    if parm.keyframes() or parm.overrideTrack():
        return True
    else:
        return False
 
def getMultiParmInstanceNumber(parm):
    """ Get the instance number from a multi parm parameter. """
    # Parameter needs to be a multi parm instance.
    if not parm.isMultiParmInstance():
        raise hou.OperationFailed("Parameter is not a multi parm parameter.")
    # Use a regular expression to extract the number from the parameter.
    result = re.search("[0-9]*$", parm.name())
    # Convert the result to an integer and return it.
    return int(result.group())
 
 
def getCurrentMenuLabel(parm):
    """ Returns the label of the current menu item. """    
    # Get the template for the parameter.
    parm_template = parm.parmTemplate()
 
    # If this is a regular menu parameter then we just use the value
    # of the parameter to index into the list of menu labels.
    if isinstance(parm_template, hou.MenuParmTemplate):
        return parm_template.menuLabels()[parm.eval()]
    # If this parameter at is a string parm then we can't just use 
    # the value as the index.
    elif isinstance(parm_template, hou.StringParmTemplate):
        # Get the possible string values.
        menu_items = parm_template.menuItems()
        # Get the current string value.
        value = parm.evalAsString()
        # Use the index of the current value in the possible values
        # to index into the labels.
        return parm_template.menuLabels()[menu_items.index(value)]
    # Not a valid parameter type so we throw an exception.
    else:
        raise hou.OperationFailed("Parmeter is not a menu type.")
 
 
def driveByRamp(scriptargs, driver_expr="$F/$RFEND"):
    """ Drive a parameter's value(s) using a ramp.
 
        Single parameters are driven by a Float ramp while multiple valued
        parameters are driven by a Color ramp.
 
        Only Float and Integer parameters can be driven by a ramp by default
        but more types can be added.
 
        scriptargs: The kwargs dictionary generated for a parameter interaction
                    by the PARMmenu.xml file.
 
        driver_expr: The default expression to drive the ramp position.
    """
 
    # Parameter types that can be driven by a ramp.
    allowable_types = (hou.parmTemplateType.Float,
                       hou.parmTemplateType.Int,
                      )
 
    # Get the parameters.
    parms = scriptargs['parms']
 
    # If there are more then 3 parms, ie Vector4 then we need to clamp the number to
    # 3 since the most parameters we can drive is 3 with the Color ramp.
    num_parms = len(parms)
    if num_parms > 3:
        num_parms = 3
 
    # Get the parameter or tuple and the correct ramp type.
    if num_parms == 1:
        parm = parms[0]
        ramp_type = hou.rampParmType.Float
    else:
        parm = parms[0].tuple()
        ramp_type = hou.rampParmType.Color
 
    # Get the parameter type.
    parm_template_type = parm.parmTemplate().type()
 
    # If the parameter isn't in the allowable types we display a message and abort.
    if parm_template_type not in allowable_types:
        hou.ui.displayMessage("Cannot drive %s parameter type using a ramp." 
                                % parm_template_type.name(),
                              severity=hou.severityType.Error)
        return
 
    # Get the node we are working on.
    node = parm.node()
 
    # Create the parameter template for the ramp parm.
    ramp_name = "%s_ramp" % parm.name()
    ramp_label = "%s Ramp" % parm.description()
    ramp_template = hou.RampParmTemplate(ramp_name, ramp_label, ramp_type)
 
    # Create the parameter template for the ramp position.
    position_name = "%s_position" % ramp_name
    position_label = "%s Position" % ramp_label
    position_template = hou.FloatParmTemplate(position_name, position_label,
                                              1, default_value=([0]), min=0, max=1,
                                              min_is_strict=True, max_is_strict=True)
 
    # Add the parms to the node.
    position_parm = node.addSpareParmTuple(position_template)
    ramp_parm = node.addSpareParmTuple(ramp_template)
 
    # Set an expression for the position driver.
    position_parm[0].setExpression(driver_expr)
 
    # If it is just a single parm then set an expression to point to the ramp.
    if isinstance(parm, hou.Parm):
        parm.setExpression('chramp("%s", ch("%s"), 0)' % (ramp_name, position_name))
    # If there are multiple parameters then set expressions to the correct indices 
    # of the ramp.
    else:
        for p, idx in zip(parm, range(num_parms)):
            p.setExpression('chramp("%s", ch("%s"), %s)' % (ramp_parm.name(), 
                                                            position_name, idx))
 
 
 
def removeRampDriver(scriptargs):
    """ Remove the ramp that is driving a parameter. """
 
    # Get the parameters.
    parms = scriptargs['parms']
 
    # If there are more then 3 parms, ie Vector4 then we need to clamp the 
    # number to 3 since the most parameters we could have drove is 3 with 
    # the Color ramp.  This ensures that if we have 4 parms that we don't 
    # delete any expression in the last parm.
    num_parms = len(parms)
    if num_parms > 3:
        num_parms = 3
 
    # Get the parameter or tuple and the correct ramp type.
    if num_parms == 1:
        parm = parms[0]
    else:
        parm = parms[0].tuple()
 
    parm_name = parm.name()
    node = parm.node()
 
    # Get the names of the parms to remove.
    ramp_name = "%s_ramp" % parm.name()
    position_name = "%s_position" % ramp_name
 
    # Get the parameters to remove.
    ramp_parm = node.parmTuple(ramp_name)
    ramp_position_parm = node.parmTuple(position_name)
 
    # Delete all the expressions.
    if isinstance(parm, hou.Parm):
        parm.deleteAllKeyframes()
    else:
        for p, idx in zip(parm, range(num_parms)):
            p.deleteAllKeyframes()
 
    # Remove the parameters.
    node.removeSpareParmTuple(ramp_parm)
    node.removeSpareParmTuple(ramp_position_parm)
 
 

Valid XHTML 1.0 Strict