On this page |
Overview ¶
You can use the hou.ViewerStateMenu object to build a custom context menu that appears when the user presses while your state is active.
Optionally, you can manage the UI states of the custom context menu with the onMenuPreOpen
handler.
Building and binding the menu ¶
Responding to menu actions ¶
Reading menu settings ¶
Whenever you include checkbox menu items (using hou.ViewerStateMenu.addToggleItem) or radio button items (using hou.ViewerStateMenu.addRadioStrip) in the context menu, Houdini passes the current state of those items in every kwargs
dictionary passed to every event handler method.
This makes it easy to check a menu setting to change how you handle a certain event. In the following example, the onMouseEvent
code checks menu settings to change how it interprets mouse clicks.
from __future__ import print_function # Class implementing the state behavior class MyState(object): def __init__(self, state_name, scene_viewer): self.state_name = state_name self.scene_viewer = scene_viewer def onMouseEvent(self, kwargs): ui_event = kwargs["ui_event"] if ui_event.device().isLeftButton(): # Check if the "Bend" checkbox item in the menu is on if kwargs["bend"]: option = kwargs["bend_parm_option"] # ... else: # ... # Function to generate the state's context menu def create_menu(): menu = hou.ViewerStateMenu('bend_menu', 'Bend') menu.addToggleItem( 'bend', 'Bend', True ) menu.addSeparator() select_parm_menu = hou.ViewerStateMenu( 'select_parm_menu', 'Select Parm...' ) select_parm_menu.addRadioStrip( 'bend_parm_option', 'Bend Parm', 0 ) select_parm_menu.addRadioStripItem( 'bend_parm_option', 'bend', 'Bend' ) select_parm_menu.addRadioStripItem( 'bend_parm_option', 'twist', 'Twist' ) select_parm_menu.addRadioStripItem( 'bend_parm_option', 'lengthscale', 'Length Scale' ) select_parm_menu.addRadioStripItem( 'bend_parm_option', 'taper', 'Taper' ) select_parm_menu.addRadioStripItem( 'bend_parm_option', 'squish', 'Squish' ) menu.addMenu(select_parm_menu) return menu # Function to generate the state template, which describes the state and any # menus, handles, selectors, etc. bound to it def createViewerStateTemplate(): # Create the template object template = hou.ViewerStateTemplate( "mystate", "My State", hou.sopNodeTypeCategory() ) # Bind the implementation class template.bindFactory(MyState) # Bind handles, selectors, menus... template.bindMenu(create_menu()) return template
Menu hotkeys ¶
Note
Under the new hotkey system introduced in Houdini 20.5, key assignments are explicitly managed in contexts rather than an attribute of the action.
-
Houdini uses symbols (such as
h.pane.gview.world.selectall
) to represent hotkey-able actions instead of the key itself (such asshift+p
) so users can edit them using the hotkey editor.When you build the state menu, you can create your own custom hotkey symbol, and assign it to menu items in the state context menu. This will allow users to assign a hotkey to the menu item.
You’ll also want to create a custom hotkey context to store key assignments to these actions.
-
The hou.ViewerStateMenu.addActionItem, hou.ViewerStateMenu.addToggleItem, and hou.ViewerStateMenu.addRadioStripItem methods accept Houdini hotkey symbol strings as an optional argument.
-
Hotkey symbols have a dotted prefix that specifies the category to which the symbol belongs. This is not to be confused with the context in which keys are assigned to a hotkey symbol, despite both having the same dotted format. Under the new hotkey system introduced in 20.5, the context and category are separate concepts. The same key can be assigned to different actions in different contexts.
For a SOP viewer state, the prefix for your hotkeys will be:
h.pane.gview.state.sop.‹state_name›.
where ‹state_name› is the internal name for the state you specify when you create the state template.
The same symbol is also typically used as the primary context for your state’s key assignments.
-
You will add a name for the specific action to the end of the category to make a hotkey symbol. So, for example, if you want to specify a Delete hotkey, you could use the symbol:
h.pane.gview.state.sop.‹state_name›.delete
import hou # Create hotkey symbols. This should be done through a definitons object that # is later attached to the viewer state template. definitions = hou.PluginHotkeyDefinitions() # Need to create the hotkey context with addContext key_context = "h.pane.gview.state.sop.mystate" definitions.addContext( key_context, "mystate Operation", "These keys apply to the mystate operation." ) # Need to create the hotkey category for our commands with addCommandCategory key_category = "h.pane.gview.state.sop.mystate" definitions.addCommandCategory( key_category, "mystate Operation", "These commands apply to the mystate operation." ) # Call addCommand with the symbol, a name, and a description del_key = key_category + ".delete" definitions.addCommand(del_key, "Delete", "Delete the current change") dup_key = key_category + ".duplicate" definitions.addCommand( dup_key, "Duplicate", "Copies the current change into a new change" ) end_key = key_category + ".finish" definitions.addCommand(end_key, "Finish", "Saves the current change") # Call addDefaultBinding to assign default keys in your context. definitions.addDefaultBinding(key_context, del_key, ["Del"]) definitions.addDefaultBinding(key_context, dup_key, ["Ctrl+D"]) definitions.addDefaultBinding(key_context, end_key, []) # Build the menu menu = hou.ViewerStateMenu('bend_menu', 'Bend') # Call add*Item methods with the hotkey symbol as an extra argument menu.addActionItem("delete", "Delete", del_key) menu.addActionItem("dup", "Duplicate", dup_key) menu.addActionItem("done", "Finish", end_key)