Houdini 21.0 Python scripting

Python state handles

How to bind handles to your state and react to user interaction with the handles.

On this page

Overview

The standard way to let users interactively edit parameters in a node’s viewer state is by binding handles to node parameters.

While it’s possible to interpret lower-level input events, handles remain the primary method for enabling user interaction within a state. They offer a powerful and flexible interface for parameter configurations and are backed by a large library of predefined handle types.

Viewer states make use of handles by binding a node’s parameters to the handle’s parameters. Handle bindings typically occur during the state’s registration via its state template. However, it is also possible to bind and unbind viewer handles dynamically using hou.SceneViewer. Viewer states can manipulate handles at runtime through hou.Handle.

Bindings

Viewer states can bind to viewer handles either programmatically using the hou.ViewerStateTemplate API, or interactively using the Digital Asset Handle Bindings dialog. The hou.ViewerStateTemplate API is described in the following sections.

The Digital Asset dialog allows you to select a handle from a list of available handles that match the state context. Once selected, you can bind the handle parameters to the asset parameters you want to control with the handle.

Note

Binding a Python handle using the Digital Asset Handle Bindings dialog requires that a viewer state be added to your digital asset for the bindings to take effect. If your asset doesn’t already have a state, you can generate a blank default state using the Viewer Handle Code Generator, available from the Digital Asset New… button.

Static handles

A static handle binding supports a straightforward 1:1 mapping between handle parameters and node parameters. This is often sufficient, as handle parameters such as translate, rotate, scale, length, and others typically correspond directly to parameters on your node.

To add a static handle to your state, call hou.ViewerStateTemplate.bindHandleStatic with the handle type name, a unique internal name for the handle (unique among all handles in the tool), and a list of (“node_parm_name”, “handle_parm_name”) tuples that map node parameters to handle parameters.

You can run the example below in the Python Source Editor for a quick test:

import hou

class PythonMeasureState():
    def __init__(self, state_name, scene_viewer):
        self.state_name = state_name
        self.scene_viewer = scene_viewer


template = hou.ViewerStateTemplate(
    "pythonmeasure",
    "Python Measure",
    hou.sopNodeTypeCategory()
)
template.bindFactory(PythonMeasureState)

# Assume the asset this state is for has two translate
# parameters, "start" and "end"
template.bindHandleStatic(
    "xform", "start_handle",
    [("startx", "tx"), ("starty", "ty"), ("startz", "tz")]
)
template.bindHandleStatic(
    "xform", "end_handle",
    [("endx", "tx"), ("endy", "ty"), ("endz", "tz")]
)

hou.ui.registerViewerState(template)

Dynamic handles

Dynamic handle bindings let you decide (using a callback) how changes to a handle affect parameters on the node, and how changes to the node’s parameters affect the handle.

To add a dynamic handle to your state, call hou.ViewerStateTemplate.bindHandle with the handle type name and a unique internal name for the handle (each handle name must be unique among all handles in the tool).

NOTE: hou.ViewerStateTemplate.bindHandle takes a cache_previous_parms boolean argument:

  • If you pass cache_previous_parms=True, Houdini keeps track of the handle values and provides both the previous and new values in the handle callback. This is useful for tracking deltas, for example, to determine how fast the user is moving the handle.

  • If you pass False (the default), Houdini does not include the previous values in the handle callback.

You can run the example below in the Python Source Editor for a quick test:

import hou

class PythonTwistState():
    def __init__(self, state_name, scene_viewer):
        self.state_name = state_name
        self.scene_viewer = scene_viewer

    def onHandleToState(self, kwargs):
        # Called when the user manipulates a handle

        handle_name = kwargs["handle"]
        parms = kwargs["parms"]
        prev_parms = kwargs["prev_parms"]

        print("User edited handle:", handle_name)
        for parm_name in kwargs["mod_parms"]:
            old_value = prev_parms[parm_name]
            new_value = parms[parm_name]
            print("%s was: %s now: %s" % (parm_name, old_value, new_value))

    def onStateToHandle(self, kwargs):
        # Called when the user changes parameter(s), so you can update
        # dynamic handles if necessary

        parms = kwargs["parms"]
        print("Parameters are now:", parms)
        for p in parms:
            print(p)


template = hou.ViewerStateTemplate(
    "pythontwist",
    "Python Twist",
    hou.sopNodeTypeCategory()
)
template.bindFactory(PythonTwistState)
template.bindHandle("xform", "twist_handle", cache_previous_parms=True)

hou.ui.registerViewerState(template)

The dictionary passed to the dynamic handle event methods contains the following standard items:

node

Contains a hou.OpNode instance representing the node being operated on by the current state.

state_parms

Contains the names representing the state parameters tied to the current state. This dictionary is used for modifying the parameter states. See the details here.

state_flags

A dictionary containing various flags associated to the state. State flags can be set by all state handlers via their kwargs argument.

Flag

Notes

mouse_drag

Controls whether a mouse drag event (with the up) is generated or not. Mouse drag events are generated by default (True).

When mouse_drag is False, no mouse drag event is generated. If a selector is active, the selectable elements will not be highlighted.

If mouse drag events are not required by your state, consider setting mouse_drag to False to reduce the overhead.

class MyState(object):
    def __init__(self, state_name, scene_viewer):
        self.state_name = state_name
        self.scene_viewer = scene_viewer

    def onEnter( self, kwargs):
        kwargs['state_flags']['mouse_drag'] = False
        ...                

redraw

The flag triggers a redraw of the viewport on a mouse move or mouse wheel event when it’s set to True.

By default the viewport always redraw. To reduce performance issues with large scenes, redraw should be set to False when your state doesn’t require a redraw of the viewport.

class MyState(object):
    def __init__(self, state_name, scene_viewer):
        self.state_name = state_name
        self.scene_viewer = scene_viewer

    def onMouseEvent( self, kwargs):
        kwargs['state_flags']['redraw'] = False
        if __some_redraw_test__:
            kwargs['state_flags']['redraw'] = True
        ...                

indirect_handle_drag

When set to True (the default), this flag enables the handle indirect dragging from the viewport (with down). When the flag is set to False, indirect handle dragging is disabled which allows the state to process events.

Note

The state can also handle events if the following conditions are met:

  • Indirect mouse dragging is allowed in the viewport.

  • The current state allows indirect handle drags.

  • All active handles do not support indirect mouse handling.

class MyState(object):
    def __init__(self, state_name, scene_viewer):
        self.state_name = state_name
        self.scene_viewer = scene_viewer

    def onEnter( self, kwargs):
        # Disable indirect handle dragging. Handle parms can 
        # no longer be modified by dragging the MMB in the
        # viewport.
        kwargs['state_flags']['indirect_handle_drag'] = False
        ...                

exit_on_node_select

This flag determines whether the state is exited or remains active when a different node is selected. If set to True (which is the default behavior), the state exits when a different node is selected. If set to False, the state remains active even when a different node is selected. The exit_on_node_select flag can be used with both node-less and node-aware states.

class MyState(object):
    def __init__(self, state_name, scene_viewer):
        self.state_name = state_name
        self.scene_viewer = scene_viewer

    def onGenerate( self, kwargs):
        # Set this node-less state to remains active when 
        # a node selection occurs.
        kwargs['state_flags']['exit_on_node_select'] = False
        ...                

interrupt_state

The name of the state that is interrupting the python state when a volatile state is activated, or an empty string.

onHandleToState

This lets you update node parameters (and/or the state/display) when a handle changes.

The dictionary passed to this method contains the following extra items:

handle

The string ID of the handle.

parms

A dictionary containing the new handle parameter values.

mod_parms

A list of of the names of parameters that changed.

prev_parms

This key is only present if you passed cache_previous_parms=True to the hou.ViewerStateTemplate.bindHandle method.

This is a dictionary containing the previous handle parameter values. This can be useful for computing deltas.

ui_event

A hou.UIEvent object to access the handle status. For instance, you can use the hou.uiEventReason value returned by hou.UIEvent.reason to know if the user has started or finished dragging the handle.

These hou.uiEventReason values have different meanings for onHandleToState:

  • uiEventReason.Active: User is dragging the handle.

  • uiEventReason.Changed: User has finished dragging the handle. prev_parms should contain the most recent handle values at this point.

  • uiEventReason.Start: User has started dragging the handle.

  • uiEventReason.Picked: Handle menu action, hotkey or mouse click. For instance, a Picked value is generated when clicking on a HUD slider.

onStateToHandle

This method is called separately for each dynamic handle bound to your state whenever a parameter on the node changes. It lets you update handle parameters to match changed node parameters.

The dictionary passed to this method contains the following extra items:

handle

The name of the handle.

parms

A dictionary mapping the handle’s parameter names to values. You can change the values in this dictionary to edit the handle parameters.

In this method you would read parameters from the node’s parameters, and do whatever dynamic updates of the handle’s parameters in kwargs["parms"] you want:

def onStateToHandle(self, kwargs):
    node = kwargs["node"]
    handle_parms = kwargs["parms"]
    if kwargs["handle"] == "my_angle":
        node_tx = node.parm("tx").evalAsFloat()
        handle_parms["tx"] = node_tx * 2

Extra notifications

Houdini provides special callbacks to notify the state when the user has started or ended the manipulation of dynamic handles.

onBeginHandleToState is called right before the onHandleToState callback. onBeginHandleToState could be used, for example, to open an undo block and perform undoable operations while the user manipulate the handle.

onEndHandleToState is called after onHandleToState has been called. The callback can then be used to close the undo block that may have been opened in onBeginHandleToState.

Handle types

Name

Description

Parameters

angle

A position and rotation handle.

input, onoff, px, py, pz, rx, ry, rz, scale, trs_order, tx, ty, tz, xyz_order

bboxvector

Bounding Box Vector

input, onoff, scale, twist, tx, ty, tz, vx, vy, vz

boundingbox

Bounding Box

centerx, centery, centerz, constant_scale, onoff, rx, ry, rz, sizex, sizey, sizez, uniform_scale

boundingrect

Bounding Rectangle

centerx, centery, centerz, constant_scale, onoff, orient, rx, ry, rz, sizex, sizey, sizez, uniform_scale

boundboundingbox

Bounder Bounding Box

bound_type, centerx, centery, centerz, constant_scale, onoff, orient, rx, ry, rz, sizex, sizey, sizez, uniform_scale

circle

Circle Transform

onoff, orient, rx, ry, rz, sx, sy, tx, ty, tz

clayxlate

Clay Translate

input, onoff, tx, ty, tz, u, v

curvepoint

Curve Point Options

keepingeo, pointlist

distance

Distance

dist, input, onoff, px, py, pz, vx, vy, vz

domain

Domain

input, onoff, u0, u1, v0, v1

edit

Edit

brushswitcher, dist, handle_group_pivot, input, inputtype, localspace, onoff, pivot_comp_rx, pivot_comp_ry, pivot_comp_rz, pivot_comp_shear_xy, pivot_comp_shear_xz, pivot_comp_shear_yz, pivot_comp_sx, pivot_comp_sy, pivot_comp_sz, pivot_comp_trs_order, pivot_comp_tx, pivot_comp_ty, pivot_comp_tz, pivot_comp_xyz_order, pivot_rx, pivot_ry, pivot_rz, px, py, pz, rx, ry, rz, shear_xy, shear_xz, shear_yz, switcher, sx, sy, sz, trs_order, tx, ty, tz, upx, upy, upz, xyz_order

extrude

Extrude

roup_pivot, grst_order , grx , gry , grz , gshear_xy , gshear_xz , gshear_yz , gsx , gsy , gsz , gtx , gty , gtz , gxyz_order , input, onoff, pivot_comp_in_obj_prexform, pivot_comp_rx, pivot_comp_ry, pivot_comp_rz, pivot_comp_shear_xy, pivot_comp_shear_xz, pivot_comp_shear_yz, pivot_comp_sx, pivot_comp_sy, pivot_comp_sz, pivot_comp_trs_order, pivot_comp_tx, pivot_comp_ty, pivot_comp_tz, pivot_comp_xyz_order, pivot_rx, pivot_ry, pivot_rz, px, py, pz, roffsetx, roffsety, roffsetz, rpivotx, rpivoty, rpivotz, rpostx, rposty, rpostz, rprex, rprey, rprez, rx, ry, rz, shear_xy, shear_xz, shear_yz, soffsetx, soffsety, soffsetz, spivotx, spivoty, spivotz, sx, sy, sz, trs_order, tx, ty, tz, uniform_scale, xyz_order

extrude2

Extrude v2

input, onoff, pivot_comp_in_obj_prexform, pivot_comp_rx, pivot_comp_ry, pivot_comp_rz, pivot_comp_shear_xy, pivot_comp_shear_xz, pivot_comp_shear_yz, pivot_comp_sx, pivot_comp_sy, pivot_comp_sz, pivot_comp_trs_order, pivot_comp_tx, pivot_comp_ty, pivot_comp_tz, pivot_comp_xyz_order, pivot_rx, pivot_ry, pivot_rz, px, py, pz, roffsetx, roffsety, roffsetz, rpivotx, rpivoty, rpivotz, rpostx, rposty, rpostz, rprex, rprey, rprez, rx, ry, rz, shear_xy, shear_xz, shear_yz, soffsetx, soffsety, soffsetz, spivotx, spivoty, spivotz, sx, sy, sz, trs_order, tx, ty, tz, uniform_scale, xform_front, xyz_order

fallbackvector

Vector with Fallback

onoff, scale, useval, vx, vy, vz

hudintslider

HUD Int Slider

value, onoff

settings

hudslider

HUD Slider

value, onoff

settings

isosegment0

Isoparm Segment

input , knotu, knotv, onoff, scale, useu, width

isosegment1

Isoparm Segment

input, onoff, knotu, knotv, scale, useu, width

mousewheelbump

Mouse Wheel Bump

onoff, value

mousewheelradius

Mouse Wheel Radius

radius

pasterange

Paste Range

input1, input2, onoff, u0, u1, v0, v1

peak

Peak

dist, input, onoff, radius, px, py, pz, vx, vy, vz

pill

Pill

botheight, botrx, botry, botrz, cbotheight, cbotrx, cbotry, cbotrz, colorb, colorg, colorr, corient, crx, cry, crz, csx, csy, csz, ctopheight, ctoprx, ctopry, ctoprz, ctx, cty, ctz, czfactor, orient, onoff, rigadjrx, rigadjry, rigadjrz, rigadjsx, rigadjsy, rigadjsz, rigadjtx, rigadjty, rigadjtz, rigadjzfactor, rx, ry, rz, topheight, toprx, topry, toprz, tx, ty, tz, x, y, z, zfactor

pivot

Pivot

input, onoff, tx, ty, tz

project

Project

axis, input, onoff, scale, twist, vx, vy, vz

sidefx_tangentpivot

Tangent Pivot

tx, ty, tt1x, tt1y, tt2x, tt2y

sidefx_transform2d

Transform2d

tx, ty, rz, sx, sy, scale

softxform

Soft Transformer

input, localspace, onoff, pivot_comp_in_obj_prexform, pivot_comp_rx, pivot_comp_ry, pivot_comp_rz, pivot_comp_shear_xy, pivot_comp_shear_xz, pivot_comp_shear_yz, pivot_comp_sx, pivot_comp_sy, pivot_comp_sz, pivot_comp_trs_order, pivot_comp_tx, pivot_comp_ty, pivot_comp_tz, pivot_comp_xyz_order, pivot_rx, pivot_ry, pivot_rz, px, py, pz, roffsetx, roffsety, roffsetz, rpivotx, rpivoty, rpivotz, rpostx, rposty, rpostz, rprex, rprey, rprez, rx, ry, rz, shear_xy, shear_xz, shear_yz, soffsetx, soffsety, soffsetz, spivotx, spivoty, spivotz, sx, sy, sz, trs_order, tx, ty, tz, uniform_scale, upx, upy, upz, xyz_order

sphere

Sphere Transformer

onoff, orient, rx, ry, rz, sx, sy, sz, tx, ty, tz

translate

Translate

input, onoff, tx, ty, tz

torus

Torus Transformer

onoff, orient, rx, ry, rz, sx, sy, tx, ty, tz

tube

Tube Transformer

onoff, orient, rx, ry, rz, sx, sy, sz, tx, ty, tz

uisoparm

U Isoparm

input, k, onoff

uvedit

UV Edit Manipulator

input, onoff, px, py, rz, shear_xy, sx, sy, trs_order, tx, ty, xyz_order

uvedit_reversez

Texture Transformer

input, onoff, rz, sx, sy, tx, ty

uvpoint

UV Point

input, onoff, px, py, pz, rx, ry, rz, sx, sy, sz, u, v

uvproject

UV Project Manipulator

onoff, projtype, px, py, pz, rx, ry, rz, sx, sy, sz, torrad, trs_order, tx, ty, tz, xyz_order

uvrange

UV Range Manipulator

onoff, projtype, px, py, pz, rx, ry, rz, sx, sy, sz, torrad, trs_order, tx, ty, tz, u0, u1, v0, v1, xyz_order

uvxform

UV Transform Manipulator

group_pivot, input, onoff, px, py, rz, shear_xy, sx, sy, trs_order, tx, ty, xyz_order

uvunwrap

UV Unwrap Manipulator

input, onoff, projplanes, px, py, pz, ref_input, rx, ry, rz, trs_order, tx, ty, tz, xyz_order

vector

Vector

input, onoff, scale, twist, tx, ty, tz, vx, vy, vz

visoparm

V Isoparm

input, k, onoff

xform

Transformer

input, onoff, pivot_comp_in_obj_prexform, pivot_comp_rx, pivot_comp_ry, pivot_comp_rz, pivot_comp_shear_xy, pivot_comp_shear_xz, pivot_comp_shear_yz, pivot_comp_sx, pivot_comp_sy, pivot_comp_sz, pivot_comp_trs_order, pivot_comp_tx, pivot_comp_ty, pivot_comp_tz, pivot_comp_xyz_order, pivot_rx, pivot_ry, pivot_rz, px, py, pz, roffsetx, roffsety, roffsetz, rpivotx, rpivoty, rpivotz, rpostx, rposty, rpostz, rprex, rprey, rprez, rx, ry, rz, shear_xy, shear_xz, shear_yz, soffsetx, soffsety, soffsetz, spivotx, spivoty, spivotz, sx, sy, sz, trs_order, tx, ty, tz, uniform_scale, xyz_order

Handle settings

Settings are attributes for changing the handle behavior.

See also:

HUD integer slider settings

hudharbourname('name') Assigns the slider to a group. Sliders in the same group will dock together.

hudharbourx(int) Slider group X position.

hudharboury(int) Slider group Y position.

hudnameside(int) Label position: top(1), left(2), right(3), bottom(4)

hudrangehigh(int) Slider range high value.

hudrangelow(int) Slider range low value.

hudlockhigh(int) When set to 1, the slider’s high limit is set to hudrangehigh and cannot move beyond this value.

hudlocklow(int) When set to 1, the slider’s low limit is set to hudrangelow and cannot move below this value.

hudvalueside(int) Value position: top(1), left(2), right(3), bottom(4)

hudx(int) X position in the viewer pane.

hudy(int) Y position in the viewer pane.

hudw(int) Width

hudh(int) Height

HUD slider settings

hudharbourname('name') Assigns the slider to a group. Sliders in the same group will dock together.

hudharbourx(int) Slider group X position.

hudharboury(int) Slider group Y position.

hudnameside(int) Label position: top(1), left(2), right(3), bottom(4)

hudrangehigh(float) Slider range high value.

hudrangelow(float) Slider range low value.

hudlockhigh(int) When set to 1, the slider’s high limit is set to hudrangehigh and cannot move beyond this value.

hudlocklow(int) When set to 1, the slider’s low limit is set to hudrangelow and cannot move below this value.

hudvalueside(int) Value position: top(1), left(2), right(3), bottom(4)

hudx(int) X position in the viewer pane.

hudy(int) Y position in the viewer pane.

hudw(int) Width

hudh(int) Height

sidefx_transform2d settings

The sidefx_transform2d handle provides control over bound parameters for translation, rotation, and scaling. This section lists the available settings for the handle. These settings allow for customization of the handle’s behavior, including its pivot coordinates.

The handle pivot settings (handlepivotx, handlepivoty, handlepivotrz) store the coordinates and rotation of the handle’s pivot point. These settings are useful for tracking the pivot’s position, for example, to update the placement of drawables that are dependent on the handle’s pivot.

sidefx_transform2d supports a detachable mode. When enabled, the handle pivot can be manipulated independently, without updating the bound parameters. By default, the handle detachable mode is OFF and follows the values of its bound parameters. Once the handle has been detached and the pivot modified, it no longer responds to changes in the bound parameters.

Setting

Description

Values

handledetachable(int)

Enable or disable the handle’s detached mode capability

0: The handle is not detachable (default).

1: The handle is detachable.

handlemode(int)

Set the handle mode

0: Rotate

1: Translate (default)

2: Scale

handlepivotx(float)

Stores the X-coordinate of the handle’s pivot point.

Value is typically overridden by the bound parameter upon handle creation.

handlepivoty(float)

Stores the Y-coordinate of the handle’s pivot point.

Value is typically overridden by the bound parameter upon handle creation.

handlepivotrz(float)

Stores the Z-axis rotation (in degrees) of the handle’s pivot point.

Value is typically overridden by the bound parameter upon handle creation.

rotateringstyle(int)

Controls the rotate ring style

0: 4 arcs (default)

1: the first quadrant’s arc

rotatestep(int)

Specifies the rotation step angle (in degrees). The parameter corresponds to an index to a predefined list of step sizes

1, 2, 3, 4, 5, 5.625, 10, 11.25, 12, 15, 20, 22.5, 30, 45, 60, 90

scalestep(float)

Specifies the step size for the scale parameters

Default to 0.1

translateaxes(int)

Toggles visibility of the translate axes

0: Disables both axes

1: Enables both axes (default)

translatepivotcolor(int)

Controls the translate pivot color

0: White

1: Pivot color

2: Point color

translatepivotstyle(int)

Controls the translate pivot style

0: Cross

1: Diamond

2: Dot

3: HollowDiamond

4: HollowDot

5: HollowSquare

6: Square

7: SquareCross

8: XShape

translatestep(float)

Specifies the step size for the translate parameters

Default to 0.1

xform settings

translate(int) Enable (1) or disable (0) the xform translate mode.

scale(int) Enable (1) or disable (0) the xform scale mode.

rotate(int) Enable (1) or disable (0) the xform rotate mode.

snap_to_selection(int) Allow snapping to selected geometry components if set to 1. See details here.

boundingbox settings

translate(int) Enable (1) or disable (0) the boundingbox translate mode.

rotate(int) Enable (1) or disable (0) the boundingbox rotate mode.

snap_to_selection(int) Allows snapping to selected geometry components if set to 1. See details here.

Handle snapping

Most handles (e.g. xform, pivot, distance, boundingbox, etc…) want to avoid snapping to selected components. The assumption is that these handles will be moving the selected geometry, so snapping the handle to that same geometry will result in a bad feedback loop. In most situations, the selection we're talking about here is the cook selection generated by the node.

Houdini can only distinguish between selected and unselected geometry components when there is a selection present. When there is no selection present, Houdini treats the entire geometry generated by a node bound to that handle as selected, preventing the handle from snapping to it. The snap_to_selection setting is used to control whether the handle should snap to selected components and can be applied to handles with the usual APIs:

Python scripting

Getting started

Next steps

Reference

  • hou

    Module containing all the sub-modules, classes, and functions to access Houdini.

Guru level

Python viewer states

Python viewer handles

Plugin types