Houdini 18.5 Basics

Radial menus

Radial menus give you quick access to commonly used features in the viewer.

On this page

Overview

Radial menus pop up when you press or hold a hotkey. You can assign commonly used items to the menu. You can also assign sub-menus to certain positions, creating a hierarchy of radial menus. This gives you access to a large number of tools at your fingertips as you work in the viewer.

Radial menus appear at the mouse pointer, feature large hit targets, and put all options equidistant from the pointer, requiring less mouse movement. Using the radial menu trains you on the "directions" to get to a tool, so you can eventually get to the tool quickly without reading labels.

Houdini comes with default radial menus you can use to work in the 3D viewer. You can also create your own radial menus in the Radial Menu Editor and assign a radial menu to a hotkey in the 3D viewer or the network editor.

Currently radial menus are supported in the 3D viewer and the Network editor.

Using radial menus

You can interact with the menus in three different ways. Different people may be more comfortable with one interaction style than the others, and different styles may be more appropriate for different input devices.

  • Hold the key to show the menu, then move the mouse to choose a menu item and release the key.

  • Tap the key to show the menu, then move the mouse to choose a menu item and click.

  • Press the key and start dragging the mouse, then move the mouse to choose a menu item and release the mouse button.

    This style may work best if you're used to marking menus, or if you're using a tablet.

  • Click inside the circle or press ⎋ Esc to cancel the menu.

  • When the menu is open you can use the number pad keys (1-9) to "select" different directions on the current menu rather than using the mouse.

    The menu author can also specify "shortcut" keys for each item. Pressing the key when the menu is visible allows you to choose that item from the menu.

Default menus

Houdini comes with several pre-defined radial menus.

You can access pre-made radial menus in the 3D viewer using the following keys:

Key

Menu type

X

Snapping controls

C

The "Current" menu. You can choose the menu on this key using the Radial switching menu at the top of the main interface.

V

View controls

You can access a pre-made radial menu in the network editor using the following key:

Key

Menu type

N

Navigation controls

You can assign radial menus to other hotkeys in the hotkey editor.

The "current" menu

By default, the C key in the 3D viewer shows the "current" radial menu.

  • To set the current menu on the C key, click the Radial switching menu at the top of the main interface.

    There are specialized pre-built menus for curve modeling, polygonal modeling, UV Editing, and other workflows.

  • Houdini usually has a separate "current" menu with each desktop.

    For example, if you switch to the Modeling desktop, the C key will show a menu with modeling tools. The generic Build desktop has a menu with lots of generally useful tools.

  • Normally when you switch desktops, Houdini switches the C key to the custom radial menu associated with that desktop. You can "pin" the current radial menu so it doesn’t change with the desktop by opening the Radial switching menu and turning on Pin current menu at the bottom.

Managing radial menus

To...Do this

Open the radial menu editor

  • In the main menus, choose Edit ▸ Radial Menus.

Create a new custom menu

  1. Open the radial menu editor.

  2. On the left side, under Panes, click the pane type you want to edit radial menus for.

  3. Below the list of menus, click the Add button and choose Regular Menu or Script Menu.

    • If you want to design the top-level menu (not generate it with a script), click Regular Menu. See editing a radial menu below.

    • You want to generate the radial menu dynamically using a script, click Script menu. See generating scripted menus below.

  4. On the right side, set the Name to a short internal name for the menu. This string cannot have spaces. This name is used for scripting and to build the filename when the menu is saved.

  5. Set the Label to the "human readable" name for the menu. This label will appear in the user interface, such as the radial switcher menu.

  6. Click Apply to update the menu, or Accept to update the menu and close the editor.

Assign a radial menu to a hotkey

See how to assign a radial menu to a hotkey.

Edit an existing menu

  1. Open the radial menu editor.

  2. On the left side, under Panes, click the pane type you want to edit radial menus for.

  3. Under Menus, click the menu you want to edit.

  4. Use the editing interface to edit the items in the menu.

  5. Click Apply to update the menu, or Accept to update the menu and close the editor.

Tip

To quickly open the "current" menu in the editor, open the Radial switching menu at the top of the main interface, then click Edit Current.

Editing a radial menu

To...Do this

Create a menu item that invokes a shelf tool

  1. Click the Shelf tools tab and navigate through the shelves tree to find the shelf tool you want to add to the menu.

  2. Drag the tool from the left pane onto one of the eight positions around the radial menu on the right.

Create a menu item that creates a node

  1. Click the Nodes tab and navigate through the node type and category tree to find the node you want to add to the menu.

  2. Drag the node from the left pane onto one of the eight positions around the radial menu on the right.

Create a menu item that runs an arbitrary Python script

  1. Click the Utilities tab and drag the "Script" item onto one of the eight positions around the radial menu on the right.

  2. Set the Label to the text that should appear in the menu slot.

  3. You can specify an Icon. If you leave the icon field blank, the menu will use a small dot.

  4. Enter the script to run when the user selects the menu item in the Script tab.

    The script can access a global dictionary called access. Currently the only item in the dictionary is kwargs["pane"] which returns a hou.SceneViewer object representing the viewer pane in which the user opened the menu.

    You can get an object representing viewport (split view) the mouse is over using hou.SceneViewer.curViewport().

If you want the menu item to be an on/off toggle, click the Check on/off tab and enter a Python expression that returns True when the menu item is on.

For example, if you have a global boolean variable in the session module called hou.session.mytoggle, you could set the Script tab to:

# When the user invokes this menu item,
# flip the toggle state
hou.session.mytoggle = not hou.session.mytoggle

…and set the Check on/off tab to:

hou.session.mytoggle is True

or just

hou.session.mytoggle

See scripting Houdini with Python for more on Python scripting.

Create a submenu

  1. Click the Utilities tab and drag the "Submenu" item onto one of the eight positions around the radial menu on the right.

  2. Double-click the submenu item to jump to the submenu.

  3. Edit the submenu.

    In a submenu, the menu slot opposite the submenu item slot on the parent menu is dedicated as a "go back" item (marked with a "rewind" icon) to allow the user to back out of the submenu. You can’t edit this slot.

  4. To go back "up" to the parent menu, double-click the "go back" item, or click in the path above the menu.

Create a scripted submenu

  1. Click the Utilities tab and drag the "Script Submenu" item onto one of the eight positions around the radial menu on the right.

  2. Set the item’s Label.

  3. On the Script tab, enter a script to generate the submenu’s contents.

Generating a radial menu with a script

Scripted menus/submenus let you write a Python script that generates the contents of the menu "on-the-fly" at the moment the user opens the menu. This lets you create a radial menu that dynamically changes with the current conditions.

  • The script can access a dict object called kwargs. Currently the dictionary has one item:

    • kwargs["pane"] a hou.PaneTab object representing the pane in which the user opened the radial menu.

      The 3D scene viewer is a hou.SceneViewer object. The viewer pane is divided into one or more viewports. You can get the current viewport using hou.SceneViewer.curViewport().

  • The script generates a JSON-like structure representing the menu to display (see below).

  • The script can also automatically access the radialmenu module. The script calls radialmenu.setRadialMenu() with the menu data to set it as the menu contents.

  • Alternatively, instead of building a menu structure, you can call setRadialMenu() with the name of an existing radial menu to show that menu’s contents. This lets you choose dynamically whether to show an existing menu. For example:

    if someCondition:
        radialmenu.setRadialMenu("cloth")
    else:
        radialmenu.setRadialMenu("polymodel")
    
  • The basic menu structure is a dictionary, where the keys indicate the radial direction, and the values are dictionaries describing the item or submenu in that direction.

    def openAnimationEditor(**kwargs):
        desk = hou.ui.curDesktop()
        desk.createFloatingPaneTab(hou.paneTabType.ChannelEditor)
    
    
    def openParmEditor(**kwargs):
        desk = hou.ui.curDesktop()
        desk.createFloatingPaneTab(hou.paneTabType.Parm)
    
    
    def makeSubMenu(**kwargs):
        menu = {
            "se": {"type": "script_action",
                   "script": "hou.ui.displayMessage('Hi!')"}
        }
        radialmenu.setRadialMenu(menu)
    
    
    menu = {
        "n": {
            "type": "script_action",
            "label": "Animation Editor",
            "script": openAnimationEditor,
        },
        "s": {
            "type": "script_action",
            "label": "Parameters",
            "script": openParmEditor,
        },
        "e": {
            "type": "link",
            "label": "Cloth",
            "name": "cloth",
        }
        "se": {
            "type": "script_submenu",
            "label": "Go To",
            "script": makeSubMenu,
        }
    }
    
    radialmenu.setRadialMenu(menu)
    

    (The above example is meant to demonstrate the dictionary structure, but since the point of a scripted menu is to change the contents based on some conditions, you would usually build up the dictionary in the script, rather than as a literal dictionary as shown above. See the example below.)

  • The location keys can be specified in different ways:

    • As a number from 0 to 7, where 0 is the top (north) item, and the numbers increase clockwise.

    • As a string n, ne, e, se, s, sw, w, or nw.

    • As a string north, northeast, east, southeast, south, southwest, west, or northwest.

  • Each item dictionary contains the following keys:

    type

    The type can be script_action, script_submenu, or link. See below.

    label

    The human-readable label for the item/submenu, displayed in the radial menu.

    icon (optional)

    The name or file path of an icon to display next to this item in the radial menu.

    shortcut (optional)

    Specifies a key that triggers this item when the radial menu is visible.

  • A script_action type item runs a script when the user chooses the item in the radial menu. It has the following extra keys:

    script

    A callable function, or a string containing Python code, to run when the user chooses this item in the menu.

    Currently the script is called with one keyword argument (pane, the hou.PaneTab object). You probably want to write your function to accept **kwargs (any additional keyword arguments) to the function won’t break if we add more keyword arguments later.

    check

    If this key is present, the item can be toggled on or off.

    This should be a callable function. The function should return True if the item is currently checked, or False if it is not checked. This controls whether the item is displayed as "on" or "off" in the radial menu.

    For a clear user interface, the script changes the state, so choosing the menu item toggles it on or off.

  • A script_submenu type item generates a scripted submenu when the user chooses it in the radial menu. It has the following extra key:

    script

    A callable function, or a string containing Python code. It generates the contents of the scripted submenu.

    Currently the script is called with one keyword argument (pane, the hou.PaneTab object). You probably want to write your function to accept **kwargs (any additional keyword arguments) to the function won’t break if we add more keyword arguments later.

  • A link type item shows an existing radial menu as a submenu when the user chooses it in the radial menu. It has the following extra key:

    name

    A string containing the internal name of the menu to show when this is chosen.

    Tip

    If you don’t specify a label key in a link item, it will use the linked menu’s label. If you do specify a label key, that label will be displayed instead.

Scripted menu example

This script generates a menu that shows the eight most-recently edited Light LOPs. Choosing one of the lights selects it.

# Fill the cardinal directions (N, S, E, W) first, then the diagonals
slots = ("n", "s", "e", "w", "ne", "se", "nw", "sw")
light_types = ("light", "distantlight", "domelight")
lop_category = hou.nodeTypeCategories()["Lop"]

lights = []
for light_type in light_types:
    # Get the node type object
    nodetype = hou.nodeType(lop_category, light_type)
    # Find the instances of this node type and add them to the list
    lights.extend(nodetype.instances())

# Sort the list of light nodes by their last modified times (reversed so
# the most recently modified nodes are at the front)
lights.sort(key=lambda n: n.modificationTime(), reverse=True)

# Build a menu from the most recent lights
menu = {}
for slot, light in zip(slots, lights[:8]):
    menu[slot] = {
        "type": "script_action",
        "label": light.name(),
        "icon": light.type().icon(),
        "script": lambda n=light, **kwargs: n.setCurrent(True, clear_all_selected=True)
    }

radialmenu.setRadialMenu(menu)

Tip

It’s an unfortunate "gotcha" in Python that if you try to capture the value of a looping variable in a lambda or local function, you won’t get what you expect. For example:

for i, light in enumerate(lights):
    menu[slot] = {"script": lambda **kwargs: light.setCurrent(True)}

What you would expect is each lambda defined by the loop to have the reference to light that was current in that iteration of the loop. However, that is not what Python does.

Instead, the lambda captures the lexical reference to light, which always points to the current value of the variable in the local context. This means that at the end of the loop, all references to light in the generated lambdas point to the same, final value of light (the last value in the list). In terms of the example script, it would mean all items would select the exact same node (the last one in the list).

A quick workaround, as shown in the example above, is to pass the variables you want to capture as keyword arguments to the lambda:

for i, light in enumerate(lights):
    menu[slot] = {"script": lambda n=light, **kwargs: n.setCurrent(True)}

Alternatively, you can call a separate "wrapper" function that captures the variable in its own context, which is separate from the caller’s loop:

def makeSelectFn(light):
    # Returns a function that when called, selects the given light
    def wrapper(**kwargs):
        light.setCurrent(True)
    return wrapper

for i, light in enumerate(lights):
    menu[slot] = {"script": makeSelectFn(light)}

Tips and notes

  • You can use radial menu shortcuts to assign scripts to hotkey sequences.

    For example, you could create a radial menu

  • If you have fewer than eight items on a menu, the "hit area" of the items next to the "gaps" get bigger to fill in. This means in menus with fewer items, the items are easier to hit.

  • You can script showing a menu in the Viewer pane using hou.SceneViewer.displayRadialMenu(). Note that the menu will open under the mouse pointer.

Basics

Getting started

Next steps

Customization

Guru-level