tldr; I scripted my custom “layout all nodes” which respects fixed positions of “pinned” nodes. The code is below.
I was still struggling with the Network Editor’s “layout all” nodes. I liked it most of the times but sometimes I wanted some nodes (or branches) to stay where they were. The best solution I came with was this:
- hotkey to pin(unpin) selected node(s) to their position … I do this by setComment
- I pin just one node in a branch (or single node, camera, light, ropnet) … sometimes the last “OUT”, sometimes the first “Object merge” …
- I have replaced the L hotkey to run “my layout tool” which goes through these python steps:
- 1) find all the pinned nodes and remember their positions
- 2) classic layoutChildren(), which gives nice layout to the branches
- 3) reposition the branches to their previously stored pins
- 4) as a bonus, it places chopnets next to appropriate channelsop (naming convention applies)
- Michael Goldfarb filed two RFEs (thanks again) and if you like this idea, you may refer to them:
- RFE – #87728 – pin nodes
- RFE – #87729 – link node positions
This script pins/unpins the selected node(s)
I use the Ctrl-L hotkey
### swap pinned / unpinned state for node in hou.selectedNodes(): node.setGenericFlag(hou.nodeFlag.DisplayComment,True) if node.comment() == "`" : node.setComment("") else: node.setComment("`")
This script layouts all the nodes
I use the L hotkey
import hou import toolutils def getConnectedNodes(node,got): iteration = [] inout = [] try: inout += node.inputs() except: has_no_inputs = 1 try: inout += node.outputs() except: has_no_outputs = 1 for n in inout: if n not in got: got.append(n) iteration.append(n) iteration += getConnectedNodes(n,got) return iteration ################################ ######## the pins ######### ################################ parm_pane = hou.ui.curDesktop().paneTabOfType(hou.paneTabType.Parm) containernode = parm_pane.currentNode().parent() childrenArr = containernode.children() pinStatesArr = [] pinNodesArr = [] positionsArr = [] # store all positions for child in childrenArr: pinned = 0 if child.comment() == "`" : pinned = 1 pinNodesArr.append( child ) pinStatesArr.append( pinned ) positionsArr.append( child.position() ) # store pinned positions for pinNode in pinNodesArr: pos = pinNode.position() comment = str(pos[0]) + "," + str(pos[1]) pinNode.setComment(comment) # classic layoutChildren() containernode.layoutChildren() # reposition the branches for pinNode in pinNodesArr: pinpos = pinNode.comment() pinpos = pinpos.split(",") pinpos = [ float(pinpos[0]) , float(pinpos[1]) ] allConnected = [] allConnected = getConnectedNodes(pinNode,allConnected) pos = pinNode.position() move = [ pinpos[0] - pos[0] , pinpos[1] - pos[1] ] for connected in allConnected: try: connected.move(move) except: no_connected = 1 # cleanup pinNode.setPosition(pinpos) pinNode.setComment("`") ################################ ######## chop to chan ######## ################################ # define offset offsetx = 3 offsety = 0 containerpath = containernode.path() # find all chopnets chopnets = hou.node(containerpath).glob("chopnet_*") # for all for ch in chopnets: xxx,task = ch.name().split("_") # appropriate channel node path_channel = containerpath + "/channel_" + task path_chopnet = containerpath + "/chopnet_" + task node_channel = hou.node(path_channel) node_chopnet = hou.node(path_chopnet) # get posx = node_channel.position()[0] + offsetx posy = node_channel.position()[1] + offsety # set node_chopnet.setPosition( [posx,posy] )