Custom onClick handler for HDA

   1437   6   0
User Avatar
Member
61 posts
Joined: Feb. 2020
Offline
I'd like one of my HDA's to execute some custom code whenever it is clicked/double clicked.

In Type Properties>Scripts, I see we can handle events like "On Created" or "On Deleted", as pictured in my screen cap.

But can we handle events like clicking/dragging?

Attachments:
HDA_EVENT_HANDLING.png (169.5 KB)

User Avatar
Member
61 posts
Joined: Feb. 2020
Offline
After more investigation I see several additional event types are covered for nodes via the hou.nodeEventType [www.sidefx.com] class...while several events not covered in the Event Handler drop down I posted earlier are covered here, I still don't see anything for custom handling of click or double click events...

Suprisingly, nothing in hou.NetworkMoveableItem [www.sidefx.com] either regarding handling clicks.

I'm imaging that there must be some code somewhere which defines click behavior for different network items. Say, when a sticky note is clicked vs when a subnetwork is clicked.
Any thoughts on where I might find that code?
Edited by wyhinton1 - Sept. 26, 2022 20:02:31
User Avatar
Member
8525 posts
Joined: July 2007
Online
https://www.sidefx.com/docs/houdini/hom/network.html [www.sidefx.com]
Tomas Slancik
FX Supervisor
Method Studios, NY
User Avatar
Member
61 posts
Joined: Feb. 2020
Offline
tamte
https://www.sidefx.com/docs/houdini/hom/network.html [www.sidefx.com]

Thanks, that's exactly what I needed!

User Avatar
Member
61 posts
Joined: Feb. 2020
Offline
I think the docs [www.sidefx.com] are outdated?

The example in "Extending the Node Editor" says to add the example code to $HOUDINI_USER_PREF_DIR/python2.7libs/nodegraphhooks.py.

I assume they mean $HOUDINI_USER_PREF_DIR/python3.7libs/nodegraphhooks.py.

I tried editing nodegraphhooks.pyto do a simple print statement:

# inside nodegraphhooks.py
def createEventHandler(uievent, pending_actions):
    print(uievent)
    return None, False

Saving the file and restarting Houdini, and I'm not getting anything to print. I tried copy-pasting the "Ctrl+Shift+H" example from the docs as as well, and it doesn't seem to work either.

Am I doing something wrong here? It seems like these new event handlers are not being correctly registered?
Edited by wyhinton1 - Sept. 29, 2022 16:47:16
User Avatar
Member
61 posts
Joined: Feb. 2020
Offline
Looking at an example from the Marking Menue's nodegraphhooks.py helped me figure it out. Here's what I ended up with:


def buildObjectMergeClickHandler(uievent, pending_actions):
    import nodegraph # to avoid circular imports
    class ObjectMergeClickHandler(nodegraph.NodeMouseHandler):
        def handleEvent(self, uievent, pending_actions):    
            if isinstance(uievent, MouseEvent):
                obj_merge_node = uievent.selected.item
                obj_parm = obj_merge_node.parm("objpath1")
                rel_path = obj_parm.eval()
                referenced_node = obj_merge_node.node(rel_path)
                if referenced_node is not None:
                    center_node(referenced_node)
                return None
            return nodegraph.NodeMouseHandler.handleEvent(
                self, uievent, pending_actions)
    return ObjectMergeClickHandler(uievent)

def createEventHandler(uievent, pending_actions):
    if isinstance(uievent, MouseEvent) and uievent.eventtype == 'mousedown' and  \
    uievent.mousestate.mmb and \
    isinstance(uievent.selected.item, hou.Node) and \
    uievent.selected.item.type().name() == "object_merge" :
        if uievent.selected.item is not None:
            b = buildObjectMergeClickHandler(uievent, pending_actions)
            return b, True
        else:
            return None, False

Note that I thought that there was a type for a "doubleclick" for uievent.eventtype...however I could never seem to get this event to trigger? I just ended up checking for a middle mouse down on the object merge node instead of a doubleclick.
User Avatar
Member
4495 posts
Joined: Feb. 2012
Offline
wyhinton1
Looking at an example from the Marking Menue's nodegraphhooks.py helped me figure it out. Here's what I ended up with:


def buildObjectMergeClickHandler(uievent, pending_actions):
    import nodegraph # to avoid circular imports
    class ObjectMergeClickHandler(nodegraph.NodeMouseHandler):
        def handleEvent(self, uievent, pending_actions):    
            if isinstance(uievent, MouseEvent):
                obj_merge_node = uievent.selected.item
                obj_parm = obj_merge_node.parm("objpath1")
                rel_path = obj_parm.eval()
                referenced_node = obj_merge_node.node(rel_path)
                if referenced_node is not None:
                    center_node(referenced_node)
                return None
            return nodegraph.NodeMouseHandler.handleEvent(
                self, uievent, pending_actions)
    return ObjectMergeClickHandler(uievent)
[quote=wyhinton1]Looking at an example from the Marking Menue's nodegraphhooks.py helped me figure it out. Here's what I ended up with:


[code python]
def buildObjectMergeClickHandler(uievent, pending_actions):
    import nodegraph # to avoid circular imports
    class ObjectMergeClickHandler(nodegraph.NodeMouseHandler):
        def handleEvent(self, uievent, pending_actions):    
            if isinstance(uievent, MouseEvent):
                obj_merge_node = uievent.selected.item
                obj_parm = obj_merge_node.parm("objpath1")
                rel_path = obj_parm.eval()
                referenced_node = obj_merge_node.node(rel_path)
                if referenced_node is not None:
                    center_node(referenced_node)
                return None
            return nodegraph.NodeMouseHandler.handleEvent(
                self, uievent, pending_actions)
    return ObjectMergeClickHandler(uievent)

def createEventHandler(uievent, pending_actions):
    if isinstance(uievent, MouseEvent) and uievent.eventtype == 'mousedown' and  \
    uievent.mousestate.mmb and \
    isinstance(uievent.selected.item, hou.Node) and \
    uievent.selected.item.type().name() == "object_merge" :
        if uievent.selected.item is not None:
            b = buildObjectMergeClickHandler(uievent, pending_actions)
            return b, True
        else:
            return None, False

[/code]

Note that I thought that there was a type for a "doubleclick" for uievent.eventtype...however I could never seem to get this event to trigger? I just ended up checking for a middle mouse down on the object merge node instead of a doubleclick.[/quote]

def createEventHandler(uievent, pending_actions):
    if isinstance(uievent, MouseEvent) and uievent.eventtype == 'mousedown' and  \
    uievent.mousestate.mmb and \
    isinstance(uievent.selected.item, hou.Node) and \
    uievent.selected.item.type().name() == "object_merge" :
        if uievent.selected.item is not None:
            b = buildObjectMergeClickHandler(uievent, pending_actions)
            return b, True
        else:
            return None, False

Note that I thought that there was a type for a "doubleclick" for uievent.eventtype...however I could never seem to get this event to trigger? I just ended up checking for a middle mouse down on the object merge node instead of a doubleclick.

I also had some issues with double click I think, it was long ago, have to double check.

I customize this module extensively also. You can also use modifier keys to further customize behaviour:


def createEventHandler(uievent, pending_actions):
    if not isinstance(uievent.editor, hou.NetworkEditor):
        return None, False


    if uievent.eventtype == 'mousedown' and uievent.selected.item is None:
        hou.session.networkEditorVisibleBounds = uievent.editor.visibleBounds()
        hou.session.mouseDownEventTime = uievent.time
        return CustomBackgroundMouseHandler(uievent), True

    if getSessionVariable("useRMBToSelectDisplayNodes") and uievent.eventtype == 'mousedown' and uievent.mousestate.rmb:
        node = uievent.selected.item

        category = node.type().category().name()
        if category in hou.nodeTypeCategories().keys() and category != "Vop":
            if uievent.modifierstate.ctrl:
                if uievent.modifierstate.shift:
                    utility_generic.selectableTemplateNearestNodeInEditor(nearestNode=node)
                if uievent.modifierstate.alt:
                    utility_generic.bypassNearestNodeInEditor(nearestNode=node)
                else:
                    utility_generic.templateNearestNodeInEditor(nearestNode=node)
            elif uievent.modifierstate.shift:
                utility_generic.displayNearestNodeInEditor(nearestNode=node)
            elif uievent.modifierstate.alt:
                utility_generic.showNodeMenuNearestNodeInEditor()
            else:
                utility_generic.selectDisplayNearestNodeInEditor(nearestNode=node)


            return None, True



    if isinstance(uievent, KeyboardEvent):
        key = utility_generic.getUnshiftedKey(uievent.key, uievent.modifierstate)
        
        hou.session.spaceKeyIsDown = uievent.editor.isVolatileKeyDown('Space')
        
        if uievent.eventtype == 'keyhit':
            return utility_hotkey_system.invokeActionFromKey(uievent)

    return None, False
Senior FX TD @ Industrial Light & Magic
Get to the NEXT level in Houdini & VEX with Pragmatic VEX! [www.pragmatic-vfx.com]

youtube.com/@pragmaticvfx | patreon.com/animatrix | animatrix2k7.gumroad.com
  • Quick Links