node_global ()
Returns the "/obj/global" address. If the node does not exist, creates it.
node_parent (node)
Returns the address node.parent()
opmultiparm_ramp (node_channel, node_source, ramp_name, color)
Creates a script for hscript opmultiparm. To reference promoted ramp.
parm_ref_parm_ramp (node_channel, node_source, ramp_name)
Creates a reference from one ramp to another ramp.
I mostly use it for an automated parameter promotion.
parm_ref_parm (node_channel, node_source, parm_name, parm_type)
Creates a reference from one parameter to another parameter.
I mostly use it for an automated parameter promotion.
parm_create (node, type, name, label)
Creates a new parameter in the node interface.
parm_update (node, type, name, default, min, max, hidden, join, ramplib)
Modifies parameter properties (default value, min, max, etc.)
line_parse (node, line, linenum)
It parses a single line of the Attribute Wrangle Snippet. Every line is evaluated to:
- create new parameters
- update parameter properties
- automatically promote the parameter (to parent node, to global node)
qq_expand ()
This function replaces "code shortcuts" into "code snippets" and also updates the parm interface (default values, channel ranges from comments, ramps are generated from custom library). You can build your own libraries of snippets with specific channel ranges and defaults.
parm_generate ()
Parses whole snippet (current wrangle node) and executes line_parse() on each line.
parm_clean ()
Removes all spare parm templates from the selected node.
qq_parse_uberfile ()
Reads qqvex uberfile and writes four files to disk:
1) qq.vfl - library of functions, to be #included
2) uber_qq_shortcuts.vfl - library of shortcuts
3) uber_qq_snippets.vfl - library of snippets
4) uber_qq_helpcard.vfl - just a helpcard
names_counts_in (node, ptg)
Auxiliary function for browsing interface folders.
folders_trygo (node, name, count, dir)
Auxiliary function for browsing interface folders.
folders_tab_go (dir)
Goes to next/previous folder in parameter interface, using a keyboard shortcut.
source code
the following code is maintained also on my github
thank you, great people, I couldn't do this without you.
import re import hou import wf_network_ui_ramp_lib import wf_selection import wf_midi reload (wf_midi) # def node_snippet (node) : # parm_ # no_snippet = 1 # try : # snippet = node.parm("snippet") # except : # nosnippet = 1 # actualcode = snippet.unexpandedString() # return snippet def node_global () : color = hou.Color(0.0, 0.0, 0.0) path = "/obj/global" name = "global" if hou.node(path) : existed = 1 return hou.node(path) else : existed = 0 node_global = hou.node("/obj").createNode('null',name) node_global.moveToGoodPosition() node_global.setUserData("nodeshape", "circle") node_global.setColor(color) return node_global def node_parent (node) : return node.parent() def opmultiparm_ramp (node_channel, node_source, ramp_name, color) : rel_path = node_channel.relativePathTo(node_source) hscript = 'opmultiparm ' hscript += node_channel.path() hscript += ' "' + ramp_name + '#pos" "' + rel_path + '/' + ramp_name + '#pos" ' hscript += ' "' + ramp_name + '#interp" "' + rel_path + '/' + ramp_name + '#interp" ' if not color: hscript += ' "' + ramp_name + '#value" "' + rel_path + '/' + ramp_name + '#value" ' else: hscript += ' "' + ramp_name + '#cr" "' + rel_path + '/' + ramp_name + '#cr" ' hscript += ' "' + ramp_name + '#cg" "' + rel_path + '/' + ramp_name + '#cg" ' hscript += ' "' + ramp_name + '#cb" "' + rel_path + '/' + ramp_name + '#cb" ' hou.hscript(hscript) def parm_ref_parm_ramp (node_channel, node_source, ramp_name) : ramp_source = node_source.parm(ramp_name) ramp_channel = node_channel.parm(ramp_name) ramp_channel.set(ramp_source, None, False) template = ramp_source.parmTemplate().parmType() color = template == hou.rampParmType.Color keys = ramp_source.eval().keys() if color : parms = ["pos","interp","cr","cg","cb"] else : parms = ["pos","interp","value"] for i in xrange(len(keys)) : for parm in parms : parm_source = node_source.parm(ramp_name + str(i + 1) + parm) parm_channel = node_channel.parm(ramp_name + str(i + 1) + parm) parm_channel.set(parm_source, None, False) opmultiparm_ramp (node_channel, node_source, ramp_name, color) def parm_ref_parm (node_channel, node_source, parm_name, parm_type) : if parm_type == "rampfloat" or parm_type == "rampcolor" : parm_ref_parm_ramp(node_channel, node_source, parm_name) elif parm_type == "vector" : for dim in ["x","y","z"] : parm_source = node_source.parm(parm_name + dim) parm_channel = node_channel.parm(parm_name + dim) parm_channel.set(parm_source, None, False) elif parm_type == "color" : for dim in ["r","g","b"] : parm_source = node_source.parm(parm_name + dim) parm_channel = node_channel.parm(parm_name + dim) parm_channel.set(parm_source, None, False) else : parm_source = node_source.parm(parm_name) parm_channel = node_channel.parm(parm_name) parm_channel.set(parm_source, None, False) def parm_create (node, type, name, label) : if type == "integer" : new_template = hou.IntParmTemplate(name, name, 1) if type == "toggle" : new_template = hou.ToggleParmTemplate(name, name) if type == "float" : new_template = hou.FloatParmTemplate(name, name, 1) if type == "vector" : new_template = hou.FloatParmTemplate(name, name, 3) new_template.setLook(hou.parmLook.Regular) if type == "color" : new_template = hou.FloatParmTemplate(name, name, 3) new_template.setNamingScheme(hou.parmNamingScheme.RGBA) new_template.setLook(hou.parmLook.ColorSquare) if type == "string" : new_template = hou.StringParmTemplate(name, label, 1) new_template.setStringType(hou.stringParmType.Regular) if type == "file" : new_template = hou.StringParmTemplate(name, name, 1) new_template .setStringType(hou.stringParmType.FileReference) if type == "node" : new_template = hou.StringParmTemplate(name, name, 1) new_template.setStringType(hou.stringParmType.NodeReference) if type == "separator" : new_template = hou.SeparatorParmTemplate(name) if type == "label" : new_template = hou.LabelParmTemplate(name, label, [label], False, True) if type == "rampfloat" : new_template = hou.RampParmTemplate(name, name, hou.rampParmType.Float) new_template.setShowsControls(False) if type == "rampcolor" : new_template = hou.RampParmTemplate(name, name, hou.rampParmType.Color) new_template.setShowsControls(False) try : ptg = node.parmTemplateGroup() ptg.addParmTemplate(new_template) node.setParmTemplateGroup( ptg ) existed = 0 except: existed = 1 def parm_update (node, type, name, default="", min="", max="", hidden="", join="", ramplib="") : ptg = node.parmTemplateGroup() parmedit = ptg.find( name ) if type == "integer" : try: parmedit.setDefaultValue( [int(default)] ) parmedit.setMinValue ( int(min) ) parmedit.setMaxValue ( int(max) ) except: pass if type == "toggle" : try: parmedit.setDefaultValue( int(default) ) except: pass if type == "float" : try: parmedit.setDefaultValue( [float(default)] ) parmedit.setMinValue ( float(min) ) parmedit.setMaxValue ( float(max) ) except: pass if type == "string" : try: parmedit.setDefaultValue( [default] ) except: pass if hidden : parmedit.hide(True) if join : parmedit.setJoinWithNext( True ) if ramplib : ramp_preset, ramp_basis, ramp_keys, ramp_values = wf_network_ui_ramp_lib.ramp_lib() try: i = ramp_preset.index(ramplib) newRamp = hou.Ramp(ramp_basis[i], ramp_keys[i], ramp_values[i]) node.setParms({name:newRamp}) except: # comment is "color" or "glob" or anything else pass ptg.replace( name, parmedit ) node.setParmTemplateGroup( ptg ) def line_parse (node, line, linenum) : name = None label = None type = None default = None min = None max = None hidden = None join = None ramplib = None ################## ###### type ###### ################## chi = re.findall('chi(["'](w+)['"]',line) chf = re.findall('chf(["'](w+)['"]',line) chv = re.findall('chv(["'](w+)['"]',line) chs = re.findall('chs(["'](w+)['"]',line) chramp = re.findall('chramp("(w+)"', line) chlabel = re.findall('//# *(.+)', line) chseparator = re.findall("//---", line) chcolor = re.findall('//.*color',line) chtoggle = re.findall('//.*toggle',line) chfile = re.findall('//.*file',line) chnode = re.findall('//.*node',line) if chi : type = "integer" ; name = chi[0] ; label = name if chi and chtoggle : type = "toggle" ; name = chi[0] ; label = name if chf : type = "float" ; name = chf[0] ; label = name if chv : type = "vector" ; name = chv[0] ; label = name if chv and chcolor : type = "color" ; name = chv[0] ; label = name if chs : type = "string" ; name = chs[0] ; label = name if chs and chfile : type = "file" ; name = chs[0] ; label = name if chs and chnode : type = "node" ; name = chs[0] ; label = name if chseparator : type = "separator" ; name = "separ" + str(linenum) ; label = name if chlabel : type = "label" ; name = "label" + str(linenum) ; label = re.sub("[^0-9a-zA-Z. ]+", "_", chlabel[0]) if chramp : type = "rampfloat" ; name = chramp[0] ; label = name if chramp and chcolor : type = "rampcolor" ; name = chramp[0] ; label = name if name : # check if already referenced if name.startswith( "../" ) or name.startswith( "/obj/" ) : name == None if name : parm_create (node, type, name, label) ################## ###### spec ###### ################## parm_join = re.findall('//.*join',line) parm_hide = re.findall('//.*hide',line) ramplib = re.findall('chramp(.*//.*?(w+)',line) defminmax = re.findall("// *([+-]?d+.?d*?|.d+) +in +([+-]?d+.?d*?|.d+) +to +([+-]?d+.?d*|.d+)",line) if parm_join : join = True if parm_hide : hidden = True if ramplib : ramplib = ramplib[0] if defminmax : default = defminmax[0][0] min = defminmax[0][1] max = defminmax[0][2] if name : parm_update (node, type, name, default, min, max, hidden, join, ramplib) ################### ### reference ### ################### ref_parent = re.findall('//.*parent',line) ref_global = re.findall('//.*global',line) if ref_parent and name : node_channel = node node_source = node_parent(node) parm_create (node_source, type, name, label) parm_update (node_source, type, name, default, min, max, hidden, join, ramplib) parm_ref_parm (node_channel, node_source, name, type) node.setUserData("nodeshape", "chevron_down") node.setColor(hou.Color(0.95, 0.27, 0.27)) line = line.replace('"' + name + '"', '"../' + name + '"') if ref_global and name : node_channel = node node_source = node_global() parm_create (node_source, type, name, label) parm_update (node_source, type, name, default, min, max, hidden, join, ramplib) parm_ref_parm (node_channel, node_source, name, type) node.setUserData("nodeshape", "chevron_down") node.setColor(hou.Color(0.95, 0.27, 0.27)) line = line.replace('"' + name + '"', '"/obj/global/' + name + '"') return line def qq_expand (node,parm_code) : ################################################### ####### qqr qqi qqf // + interface ####### ################################################### actualcode = parm_code.unexpandedString() lines = actualcode.split('n') for line in lines: found = 0 if line.startswith("qqf."): qq,var = line.split('.') newline = 'float ' + var + ' = chf("' + var + '"); // 0.5 in 0.0 to 1.0' found = 1 if line.startswith("qqi."): qq,var = line.split('.') newline = 'int ' + var + ' = chi("' + var + '"); // 1 in 0 to 10' found = 1 if line.startswith("qqr."): qq,var = line.split('.') newline = var + ' = chramp("' + var + '",' + var + '); //' + var found = 1 if line.startswith("qqs."): qq,var = line.split('.') newline = 'string ' + var + ' = chs("' + var + '"); // file node' found = 1 if line.startswith("qqv."): qq,var = line.split('.') newline = 'vector ' + var + ' = chv("' + var + '"); // color' found = 1 if line.startswith("qq@f."): qq,var = line.split('.') newline = 'f@' + var + ' = chf("' + var + '"); // 0.5 in 0.0 to 1.0' found = 1 if line.startswith("qq@i."): qq,var = line.split('.') newline = 'i@' + var + ' = chi("' + var + '"); // 1 in 0 to 10' found = 1 if line.startswith("qq01."): qq,var = line.split('.') newline = 'float new_min = chf("new_min"); // -1 in -10 to 10n'; newline += 'float new_max = chf("new_max"); // 1 in -10 to 10n'; newline += var + ' = fit01(' + var + ', new_min, new_max);'; found = 1 if line.startswith("qqx."): qq,var = line.split('.') if var.find("//") > 0 : # comment is defined var,comment = var.split('//') comment = " //"+comment else: comment = "" var = var.strip(" ") newline = '//----n' newline += 'float ' + var + '_x = chf("' + var + '_x");' + comment + 'n' newline += 'float ' + var + '_y = chf("' + var + '_y");' + comment + 'n' newline += 'float ' + var + '_z = chf("' + var + '_z");' + comment + 'n' newline += 'vector ' + var + ' = set(' + var + '_x, ' + var + '_y, ' + var + '_z);' found = 1 if line.startswith("qqxx."): qq,var = line.split('.') if var.find("//") > 0 : # comment is defined var,comment = var.split('//') comment = " //"+comment else: comment = "" var = var.strip(" ") newline = '#include "qq.vfl"n' newline += '//----n' newline += 'float ' + var + '_x_min = chf("' + var + '_x_min");' + comment + 'n' newline += 'float ' + var + '_x_max = chf("' + var + '_x_max");' + comment + 'n' newline += '//----n' newline += 'float ' + var + '_y_min = chf("' + var + '_y_min");' + comment + 'n' newline += 'float ' + var + '_y_max = chf("' + var + '_y_max");' + comment + 'n' newline += '//----n' newline += 'float ' + var + '_z_min = chf("' + var + '_z_min");' + comment + 'n' newline += 'float ' + var + '_z_max = chf("' + var + '_z_max");' + comment + 'n' newline += 'vec_len_fit01( '+ var + '_noise, ' + var + '_x_min, ' + var + '_x_max, ' + var + '_y_min, ' + var + '_y_max, ' + var + '_z_min, ' + var + '_z_max);' found = 1 if found: actualcode = actualcode.replace(line,newline,1) # only the first occurrence parm_code.set(actualcode) ############################################## ####### read library ######### ############################################## import pickle path_shortcuts = hou.getenv("HOUDINI_USER_PREF_DIR") + "/vex/include/triggers.db" path_snippets = hou.getenv("HOUDINI_USER_PREF_DIR") + "/vex/include/snippets.db" with open(path_shortcuts, 'r') as f: src = pickle.load(f) with open(path_snippets, 'r') as f: rep = pickle.load(f) ############################################## ####### replace library ######## ############################################## index = 0 for src_item in src: rep_item = rep[index] if src_item in actualcode: newcode = actualcode.replace(src_item,rep_item) parm_code.set(newcode) actualcode = newcode index = index+1 def parm_generate (node,parm_code) : snippet = parm_code.unexpandedString() snippet_updated = '' lines = snippet.split('n') for (linenum, line) in enumerate(lines): wf_midi.check_midi(node, line, linenum) for (linenum, line) in enumerate(lines): line_updated = line_parse (node, line, linenum) snippet_updated += line_updated if linenum < len(lines)-1 : snippet_updated += 'n' parm_code.set(snippet_updated) def parm_clean () : node = wf_selection.parmnode() ptg = node.parmTemplateGroup() ptg.clear() node.setParmTemplateGroup(ptg) def qq_parse_uberfile () : import pickle path_VEX = hou.getenv("HOUDINI_USER_PREF_DIR") + "/vex/include/" path_uber = path_VEX + "uber.vfl" file_uber = open( path_uber ) uber_data = file_uber.read() snippets = [] shortcuts = [] includes = "" helplines = "" blocks = uber_data.split('///------------------------------------------------------------------') for block in blocks: block = block.strip("-") lines = block.split('n') line_num = len(lines) line_with_shortcut = -1 for i, line in enumerate(lines) : if line.startswith("--") : line_with_shortcut = i if line_with_shortcut == -1 : # block is a headline # ------------------- helplines += "----------------n" else : # block is a definition # --------------------- snippet = "" shortcut = "" include = "" helpline = "" # snippet for i in range( 0 , line_with_shortcut ) : snippet += lines[i].lstrip("-") snippet += "n" snippet = snippet.strip("n") # include if lines[line_with_shortcut].startswith("--dont") : #this definition is just a shortcut without function to be included pass else: include += "//DON'T EDIT THIS FILE, IT GETS OVERWRITTEN BY A SCRIPTn" for i in range( line_with_shortcut , len(lines) ) : include += lines[i].lstrip("-") include += "n" # helpline helpline = lines[line_with_shortcut] helpline = helpline.lstrip("-") helpline = helpline.split(" ")[1] helpline = helpline.replace(" ", "") helpline = helpline.split("(")[0] # shortcut shortcut = "qq" + helpline snippets.append(snippet) shortcuts.append(shortcut) includes += include + "n" helplines += helpline + "n" # write to disk # paths path_includes = path_VEX + "qq.vfl" path_shortcuts = path_VEX + "triggers.db" path_snippets = path_VEX + "snippets.db" path_helpcard = path_VEX + "helpcard.txt" # files file_includes = open( path_includes, 'w') file_shortcuts = open( path_shortcuts, 'w') file_snippets = open( path_snippets, 'w') file_helpcard = open( path_helpcard, 'w') # write pickle.dump(shortcuts, file_shortcuts) pickle.dump(snippets, file_snippets ) file_helpcard.write(helplines) file_includes.write(includes) def names_counts_in (node, ptg) : names = [] counts = [] index = -1 for pt in ptg.parmTemplates() : if pt.type() == hou.parmTemplateType.Folder : if pt.folderType() == hou.folderType.Tabs : try: name = pt.name() + "1" parm = node.parm(name).eval() names.append(pt.name()) counts.append(0) index = index+1 except: pass counts[index] = counts[index] + 1 return names, counts def folders_trygo (node, name, count, dir) : went = 0 parm = node.parm(name+"1") actual = parm.eval() if dir > 0 : if actual < count-1: parm.set(actual+1) went = 1 if dir < 0 : if actual > 0: parm.set(actual-1) went = 1 return went def folders_tab_go (dir) : node = wf_selection.parmnode() A = node.parmTemplateGroup() A_names, A_counts = names_counts_in (node, A) for (iA,A_name) in enumerate(A_names) : A_went = 0 B_went = 0 C_went = 0 A_actual = node.parm(A_name+"1").eval() A_count = A_counts[iA] pt_name = A_name if A_actual > 0: pt_name += "_" + str(A_actual) B = node.parmTemplateGroup().find(pt_name) B_names, B_counts = names_counts_in (node, B) for (iB,B_name) in enumerate(B_names) : B_actual = node.parm(B_name+"1").eval() B_count = B_counts[iB] pt_name = B_name if B_actual > 0: pt_name += "_" + str(B_actual) C = node.parmTemplateGroup().find(pt_name) C_names, C_counts = names_counts_in (node, C) for (iC,C_name) in enumerate(C_names): C_count = C_counts[iC] C_went = folders_trygo(node, C_name, C_count , dir) if C_went == 0: B_went = folders_trygo(node, B_name, B_count , dir) if B_went == 0 and C_went == 0: A_went = folders_trygo(node, A_name, A_count , dir)