Is there a shortcut to "insert node between two nodes"?

   Views 930   Replies 6   Subscribers 1
User Avatar
Member
607 posts
Joined: Aug. 2019
Offline
In Houdini, when the Tab menu is open, we can press Shift+Enter to insert the node and it'll be automatically connected to the current seleted node. Which is great.

But my question is: how to insert it between the current node and the next node?

For example, I have this setup:




Now I want a Normal SOP between Subdivide and the Null:




But if I press Shift+Enter, Houdini adds the new node like this:




It looks fine at first glance... but it's not! The Normal SOP is NOT connect to Null!



I know I can just drag and drop it, but this kinda defeats the whole point of using Shift+Enter in the first place...

Is there a hidden shortcut that I'm unaware of? Like Shift+Enter but insert the new node between two existing ones?
Edited by raincole - Feb. 16, 2025 07:47:49

Attachments:
Screenshot 2025-02-16 204525.jpg (78.5 KB)
Screenshot 2025-02-16 204201.jpg (93.5 KB)
Screenshot 2025-02-16 204323.jpg (134.6 KB)
Screenshot 2025-02-16 204428.jpg (83.1 KB)

User Avatar
Member
1764 posts
Joined: March 2009
Online
The only way I know how to do this specific thing (disclaimer: I sometimes do not know things) is to not select the node you want it inserted after, but to right click on its output, which opens the tab-menu, select or type subdivide, and then press enter twice.

So no keyboard only method.
Martin Winkler
money man at Alarmstart Germany
User Avatar
Member
65 posts
Joined: April 2018
Offline
Another way is to select the wire, then add the node with Tab > (node) > Shift+Enter.
User Avatar
Member
607 posts
Joined: Aug. 2019
Offline
Thank you guys. I didn't even know the wire is selectable I always use Y to delete wires.
User Avatar
Member
4843 posts
Joined: Feb. 2012
Online
You can also implement your own logic to insert nodes between wires if the new node is close enough to any wire(s) or if there are any wires selected, then use all of them regardless of distance.



def dropNodeOnWire(newNode, nodeConnections, pos, editor, nearbyOnly=True):
    newNodeType = newNode.type()
    ninputs = newNodeType.maxNumInputs()
    noutputs = newNodeType.maxNumOutputs()

    if ((len(nodeConnections) == ninputs and len(nodeConnections) == noutputs) or not nearbyOnly):
        sortedwires = sorted(nodeConnections, key=lambda c: c.outputItem().position().x())
        sortedwires = sorted(sortedwires, key=lambda c: c.outputIndex())
    else:
        sortedwires = sorted(nodeConnections, key=lambda c: pointLineProjection(pos, c.inputItem().position(), c.outputItem().position()).distanceTo(pos))

    uniquewires = []
    uniquenames = []

    if nearbyOnly:
        nearestwires = []
        for c in sortedwires:
            dist = pointLineProjection(pos, c.inputItem().position(), c.outputItem().position()).distanceTo(pos)
            # hard coded distance to wire connections
            if dist <= 0.42:
                nearestwires.append(c)

        sortedwires = nearestwires

    for w in sortedwires:
        uniquename = w.inputItem().name() + ":" + str(w.inputIndex())
        if uniquename not in uniquenames:
            uniquenames.append(uniquename)
            uniquewires.append(w)

    nwires = len(uniquewires)
    
    for i in range(min(ninputs, nwires)):
        c = uniquewires[i]
        newNode.setInput(i, c.inputItem(), c.outputIndex())


    for i in range(min(noutputs, nwires)):
        outputIndex = i
        if i >= noutputs - 1:
            outputIndex = noutputs - 1

        c = sortedwires[i]
        c.outputItem().setInput(c.inputIndex(), newNode, outputIndex)



def createNewNode(uievent, nodetypename, parms=None, name=None, pressbuttons=None, mousepos=None):
    import nodegraphutils as utils
    
    pwd = uievent.editor.pwd()
    path = pwd.path()
    context = pwd.childTypeCategory().name()
    if pwd and path and context:
        #nodetype = hou.nodeType(pwd.childTypeCategory(), nodetypename)
        #if nodetype:
        if True:
            selectedNodes = list(hou.selectedNodes())
            selectedConnections = hou.selectedConnections()
            selectedSubnetInputs = [item for item in hou.selectedItems() if type(item) == hou.OpSubnetIndirectInput]
            selectedNetworkDots= [item for item in hou.selectedItems() if type(item) == hou.OpNetworkDot]
            selectedNodes.extend(selectedSubnetInputs)
            selectedNodes.extend(selectedNetworkDots)

            selectedNodes = sorted(selectedNodes, key=lambda n: n.position().x())
                
            #with hou.undos.group("Create New Node: " + nodetype.description()):
            with hou.undos.group("Create New Node: " + nodetypename):
                pos = uievent.editor.cursorPosition()
                if mousepos:
                    pos = mousepos
                    
                newNode = pwd.createNode(nodetypename)

                radius = utils.getConnectorSnapRadius(uievent.editor)
                targets = utils.getPossibleDropTargets(uievent, radius)
                nodewires = [target.item for target in targets if target.name == "wire"]

                size = utils.getNewNodeHalfSize()
                #print ("size", size)
                pos[0] -= size.x()
                pos[1] -= size.y()

                setdisplayflag = False
                connectInputs = False

                if selectedConnections and len(hou.selectedNodes()) == 0:
                    dropNodeOnWire(newNode, selectedConnections, pos, uievent.editor, nearbyOnly=False)
                elif nodewires and len(selectedNodes) <= 1:
                    dropNodeOnWire(newNode, nodewires, pos, uievent.editor)
                elif selectedNodes and context != "Apex":
                    connectInputs = True
                    setdisplayflag = True

                if pressbuttons:
                    for button in pressbuttons:
                        newNode.parm(button).pressButton()
                        
                if name:
                    newNode.setName(name, unique_name=True)
                newNode.setPosition(pos)
                newNode.setSelected(True, clear_all_selected=True)

                nodecount = len(selectedNodes)
                if setdisplayflag and nodecount != 0:
                    toggleNodeDisplayFlag(newNode, context)
                    toggleNodeRenderFlag(newNode, context)


                if parms:
                    if isinstance(parms, dict):
                        for i, (key, value) in enumerate(parms.items()):
                            newNode.parm(key).set(value)

                    elif isinstance(parms, str):

                        if parms.startswith("de:"):
                            # Split parms into opcode and opfunc
                            opcode, opfunc = parms.split(":", 1)
                            hou.data.applyDecorationRecipe(opfunc, newNode)
                        else:
                            # Search inside legacy presets that has the same name
                            presets = hou.hscript("oppresetls " + newNode.path())
                            presets = [item.strip() for item in presets[0].splitlines() if item.strip()]

                            isrecipe = parms in presets
                            if isrecipe:
                                hou.hscript("oppresetload " + newNode.path() + " '{0}'".format(parms))
                            else:
                                hou.data.applyNodePresetRecipe(parms.strip("'"), newNode)


                if connectInputs:
                    connectNodesToNewNode(newNode, selectedNodes)


                return newNode
Senior FX TD @ Industrial Light & Magic
Get to the NEXT level in Houdini & VEX with Pragmatic VEX! [www.pragmatic-vfx.com] https://lnk.bio/animatrix [lnk.bio]
User Avatar
Member
607 posts
Joined: Aug. 2019
Offline
animatrix_
createNewNode

That's dope, but I'm not sure where I should call createNewNode. In a shelf tool? Or there is a callback that Houdini will call when a new node is created (but if so how to register this createNewNode as callback?)
User Avatar
Member
4843 posts
Joined: Feb. 2012
Online
raincole
animatrix_
createNewNode

That's dope, but I'm not sure where I should call createNewNode. In a shelf tool? Or there is a callback that Houdini will call when a new node is created (but if so how to register this createNewNode as callback?)

It's part of a larger set of tools I use daily in my workflow which basically calls this function in nodegraphhooks.py when I press a specific key to create a specific node type based on the current key modifiers and the current network editor context. They work outside of the default Houdini hotkey system.

Because this is really involved, you can use the same function in a shelf to create a specific node by calling the function directly. You might need to modify it to make sure you pass the correct parameters like the current network editor, node type, etc.

Once you have a shelf tool, you can assign hotkeys, etc. I didn't want to do that because then it will result in 1000s of shelf tools and it's harder to change these each time but rather use a hot swappable CSV file that has all the hotkeys per context.

Another method is to use the OnCreated.py script to implement your logic to use wires, etc. I use it to connect new nodes to the currently selected nodes so even if a node is created using the TAB menu, it will be subject to my own custom rules.
Senior FX TD @ Industrial Light & Magic
Get to the NEXT level in Houdini & VEX with Pragmatic VEX! [www.pragmatic-vfx.com] https://lnk.bio/animatrix [lnk.bio]
  • Quick Links