I scripted my custom "layout all nodes" which respects fixed positions of "pinned" nodes. 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:
pin () :
Function to pin(unpin) selected node(s) to their position. I pin just one node in a branch (or single node, camera, light, ropnet) … sometimes the last "OUT", sometimes the first "Object merge"
getConnectedNodes (node, got)
Finds all the nodes that are connected (any number of upstream / downstream nodes or connections).
node_prefixes ()
Returns a list of prefixes that should be aligned as pairs, even if they are not interconnected. For more, see section network_kwargs
lay ()
1) finds all the pinned nodes and remembers their positions
2) does classic layoutChildren(), which gives nice layout to the separate branches
3) repositions the branches to their previously stored pins
4) as a bonus, it places chopnets next to appropriate channelsop (naming convention applies)
source code
the following code is maintained also on my github
thank you, great people, I couldn't do this without you.
import hou import toolutils import wf_selection reload(wf_selection) def pin () : for node in hou.selectedNodes(): node.setGenericFlag(hou.nodeFlag.DisplayComment,False) if node.comment() == "`" : node.setComment("") else: node.setComment("`") 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 def node_prefixes () : node_prefixes = [] node_prefixes.append( 'mat' ) node_prefixes.append( 'MAT' ) node_prefixes.append( 'QQMAT' ) node_prefixes.append( 'chop' ) node_prefixes.append( 'CHOP' ) node_prefixes.append( 'QQCHOP' ) node_prefixes.append( 'ref' ) node_prefixes.append( 'REF' ) node_prefixes.append( 'QQREF' ) node_prefixes.append( 'pre' ) node_prefixes.append( 'PRE' ) node_prefixes.append( 'QQPRE' ) return node_prefixes def lay () : parm_pane = wf_selection.pane_linkGroup( hou.paneTabType.NetworkEditor ) containernode = parm_pane.currentNode().parent() containerpath = containernode.path() ################################ ######## the pins ######### ################################ 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("`") ################################ ####### dat to app ######## ################################ # define offset offsetx = 3 offsety = 0 prefixes = node_prefixes() for prefix in prefixes : name_dat = prefix + "dat_" name_app = prefix + "app_" dats = hou.node(containerpath).glob(name_dat+"*") # for all for dat in dats: xxx,task = dat.name().split("_") # appropriate channel node path_dat = containerpath + "/" + name_dat + task path_app = containerpath + "/" + name_app + task node_dat = hou.node(path_dat) node_app = hou.node(path_app) # get pos posx = node_app.position()[0] + offsetx posy = node_app.position()[1] + offsety # check collisions tolerance = 1.0; for check in containernode.children() : distance = hou.Vector2.length(check.position()-hou.Vector2([posx,posy])) # print distance if distance < tolerance : posx = posx - 2*offsetx break # set pos if node_dat.comment() != "`" : # typical dat node node_dat.setPosition( [posx,posy] ) else : # dat has custom pos, probably because it collided # so dont move it pass # shape node_dat.setUserData("nodeshape", "clipped_right") node_app.setUserData("nodeshape", "clipped_left")