paste script.

   3152   5   1
User Avatar
Member
239 posts
Joined: Dec. 2016
Offline
Hello, I've been working on a paste script that's a bit more advanced than the one circulating on the internet right now.


It that checks the context you are pasting in and the type of node you are trying to paste in some cases.

For example, it will paste copied nodes in geo level as sop imports when pasting in lops and it wil paste cop networks as an image node when working in a materialXSubnet.

I bind it to ctrl + shift + v


Below is the code. It's not optimized, but it works.




#should refactor with only the node being created in the a forloop



import hou

network = hou.ui.curDesktop().paneTabUnderCursor()
networkpath = network.pwd().path()
pos = network.cursorPosition()

clipboard = hou.ui.getTextFromClipboard()

context = hou.node(networkpath)

n = 0

shader = 0

# shader types
#     0 = null error
#     1 = mtlx



print("context       : " +context.type().name())
print("contextparent : " +context.parent().type().name())

if clipboard:
    list = clipboard.split()
    print("____")
    for item in list:
        n += 1
        print(n)
    n=0
    #for using cops in shaders
    entry = hou.node(list[0])
    print(hou.node(list[0]).type().name())
    print(entry.parent().type().name())
    
    #check if cop node
    if entry.parent().type().name() == 'cop2net' or entry.parent().type().name() == 'img' and hou.node(list[0]) != None:
        
    #check if in shading context
        if context.parent().type().name() == 'materiallibrary' or context.parent().type().name() == 'mat':
            for item in list:
                if hou.node(item) != None:
                    
                    #check chader type
                    
                    for child in context.children():
                        #print (child)
                        name = str(child)
                        #print (name)
                        if hou.patternMatch("*tlx*", name):
                            shader = 1
                    
                    
                    #create node
                    
                    if shader == 1:
                        if hou.node(item) != None:
                                node = hou.node(networkpath).createNode('mtlximage','merge_'+item.split('/')[-1])
                                node.parm('file').set('op:'+str(item))
                                node.setPosition(pos)
                                node.move([n*1,-0.9*n])
                                if n == 0:
                                    node.setSelected(True,True)
                                else:
                                    node.setSelected(True,False)
                                n = n + 1

                            
                            
                            
                            
                            
    #for geo context
    elif context.type().name() == 'geo' or context.type().name() == 'sopnet' or context.type().name() == 'sopsolver::2.0':
        for item in list:
            if hou.node(item) != None:
                merge = hou.node(networkpath).createNode('object_merge','merge_'+item.split('/')[-1])
                merge.parm('objpath1').set(str(item))
                merge.setPosition(pos)
                merge.move([n*1,-0.9*n])
                if n == 0:
                    merge.setSelected(True,True)
                else:
                    merge.setSelected(True,False)
                n = n + 1


    #for lop context
    elif context.type().name() == 'stage':
        print('in stage')
        for item in list:
            if hou.node(item) != None:
                sopimport = hou.node(networkpath).createNode('sopimport','merge_'+item.split('/')[-1])
                sopimport.parm('soppath').set(str(item))
                sopimport.setPosition(pos)
                sopimport.move([n*1,-0.9*n])
                if n == 0:
                    sopimport.setSelected(True,True)
                else:
                    sopimport.setSelected(True,False)
                n = n + 1
    else:
        print('no logic setup')
n = 0


print("__________________________________________________")
Edited by NicTanghe - Dec. 16, 2022 16:50:22
User Avatar
Member
782 posts
Joined: Feb. 2017
Offline
Hey NicTanghe,

Thank you for sharing. Could you explain where and when to use it?
Excuse my ignorance!

Cheers
CYTE
User Avatar
Member
239 posts
Joined: Dec. 2016
Offline
Updated the discription
User Avatar
Member
44 posts
Joined: March 2023
Offline
here is paste script
User Avatar
Member
44 posts
Joined: March 2023
Offline
Updated the script so it actualy works in subnets now.
Stil needs updating for pasting lop nodes in sop context.
as wel as cleaning up the naming

#should refactor with only the node being created in the a forloop



import hou

pane = hou.ui.curDesktop().paneTabUnderCursor()
network = pane.pwd()
networkpath = network.path()
pos = pane.cursorPosition()

clipboard = hou.ui.getTextFromClipboard()

context = hou.node(networkpath)
type = network.type()

stype = 0

print("type : " + str(type.name()))
if network:
    if str(type.name())=="subnet":
        for child_node in network.children():
            if isinstance(child_node, hou.SopNode):
                print("This is a SOP subnet.")
                stype = 1
                break
            elif isinstance(child_node, hou.LopNode):
                stype = 2
                print("This is a LOP subnet.")
                break
            elif isinstance(child_node, hou.Cop2Node):
                print("This is a COP subnet.")
                stype = 3
                break
        else:
            print("This subnet does not contain a SOP, LOP, or COP network.")
    else:         
        print("This is not a subnet.")
else:
    print("Node not found.")


n = 0
shader = 0

if clipboard:
    list = clipboard.split()
    print("____")
    for item in list:
        n += 1
        print(n)
    n=0
    if hou.node(list[0]) is not None:
        #for using cops in shaders
        entry = hou.node(list[0])
        
        #check if cop node
        if entry.parent().type().name() == 'cop2net' or entry.parent().type().name() == 'img' and hou.node(list[0]) != None:
            
        #check if in shading context
            if context.parent().type().name() == 'materiallibrary' or context.parent().type().name() == 'mat' or stype == 3:
                for item in list:
                    if hou.node(item) != None:
                        
                        #check chader type
                        
                        for child in context.children():
                            #print (child)
                            name = str(child)
                            #print (name)
                            if hou.patternMatch("*tlx*", name):
                                shader = 1
                        
                        
                        #create node
                        
                        if shader == 1:
                            if hou.node(item) != None:
                                    node = hou.node(networkpath).createNode('mtlximage','merge_'+item.split('/')[-1])
                                    node.parm('file').set('op:'+str(item))
                                    node.setPosition(pos)
                                    node.move([n*1,-0.9*n])
                                    if n == 0:
                                        node.setSelected(True,True)
                                    else:
                                        node.setSelected(True,False)
                                    n = n + 1
    
                                
                                
                                
                                
                                
        #for sop context
        elif context.type().name() == 'geo' or context.type().name() == 'sopnet' or context.type().name() == 'sopsolver::2.0' or stype == 1:
            for item in list:
                if hou.node(item) != None:
                    merge = hou.node(networkpath).createNode('object_merge','merge_'+item.split('/')[-1])
                    merge.parm('objpath1').set(str(item))
                    merge.setPosition(pos)
                    merge.move([n*1,-0.9*n])
                    if n == 0:
                        merge.setSelected(True,True)
                    else:
                        merge.setSelected(True,False)
                    n = n + 1
    
    
        #for lop context
        elif context.type().name() == 'stage' or stype == 2:
            print('in stage')
            for item in list:
                if hou.node(item) != None:
                    sopimport = hou.node(networkpath).createNode('sopimport','merge_'+item.split('/')[-1])
                    sopimport.parm('soppath').set(str(item))
                    sopimport.setPosition(pos)
                    sopimport.move([n*1,-0.9*n])
                    if n == 0:
                        sopimport.setSelected(True,True)
                    else:
                        sopimport.setSelected(True,False)
                    n = n + 1
        else:
            print('no logic setup')
    n = 0
    
    
    print("__________________________________________________")
Edited by nicolaas.tanghe - April 6, 2023 15:33:02
User Avatar
Member
239 posts
Joined: Dec. 2016
Offline
now it does evrything
import hou
import sys
import os

def debug_log(message):
    """Ensures messages are printed and flushed to console."""
    print(message)
    sys.stdout.flush()

def validate_clipboard_nodes(clipboard):
    """Validate clipboard content and ensure it contains valid Houdini node paths."""
    valid_nodes = []
    paths = clipboard.split()

    debug_log(f"Clipboard split: {paths}")

    for path in paths:
        if not path.startswith("/"):
            continue
        try:
            node = hou.node(path)
            if node:
                valid_nodes.append(node)
        except hou.ObjectWasDeleted:
            debug_log(f"Node deleted: {path}")
        except Exception as e:
            debug_log(f"Error accessing {path}: {e}")
    return valid_nodes

def get_context_type(network):
    """Determine context type, treating OBJ/geo as SOP context."""
    category = network.childTypeCategory().name().lower()
    if category == "object":
        if network.type().name() == "geo":
            return "sop"
        else:
            return "object"
    return category

def offset_positions(base_pos, count, dx=2.0, dy=0.0):
    """Return offset positions for laying out new nodes."""
    return [hou.Vector2(base_pos[0] + i * dx, base_pos[1] + i * dy) for i in range(count)]

def layout_new_nodes(network, new_nodes):
    """Layout only the newly created nodes."""
    try:
        network.layoutChildren(items=new_nodes)
    except Exception as e:
        debug_log(f"Layout failed: {e}")

# --- SOP ---
def create_object_merges(network, nodes, pos):
    created = []
    positions = offset_positions(pos, len(nodes))
    for i, src in enumerate(nodes):
        om = network.createNode("object_merge", f"copied_object_merge{i+1}")
        om.setPosition(positions[i])
        om.parm("objpath1").set(src.path())
        created.append(om)
    return created

def create_font(network, pos, clipboard_text):
    font = network.createNode("font", "clipboard_text")
    font.setPosition(pos)
    if font.parm("text"):
        font.parm("text").set(clipboard_text)
    return [font]

# --- OBJ ---
def create_geos(network, nodes, pos):
    created = []
    positions = offset_positions(pos, len(nodes))
    for i, src in enumerate(nodes):
        geo = network.createNode("geo", f"copied_geo{i+1}")
        geo.setPosition(positions[i])
        om = geo.createNode("object_merge", "inside_merge")
        om.parm("objpath1").set(src.path())
        created.append(geo)
    return created

def create_geo_with_font(network, pos, clipboard_text):
    geo = network.createNode("geo", "clipboard_geo_text")
    geo.setPosition(pos)
    font = geo.createNode("font", "clipboard_text")
    font.parm("text").set(clipboard_text)
    return [geo]

# --- LOP / COP ---
def create_sopimports(network, nodes, pos, prefix="copied_sopimport"):
    created = []
    positions = offset_positions(pos, len(nodes))
    for i, src in enumerate(nodes):
        si = network.createNode("sopimport", f"{prefix}{i+1}")
        si.setPosition(positions[i])
        if si.parm("usesoppath"):
            si.parm("usesoppath").set(1)
        if si.parm("soppath"):
            si.parm("soppath").set(src.path())
        created.append(si)
    return created

def create_sopcreate_with_font(network, pos, clipboard_text):
    sc = network.createNode("sopcreate", "clipboard_sopcreate")
    sc.setPosition(pos)
    font = sc.createNode("font", "clipboard_text")
    font.parm("text").set(clipboard_text)
    return [sc]

# --- COP special rules ---
def create_in_cop_context(network, valid_nodes, pos, clipboard):
    """Handle COP paste rules: node paths → sopimport, text → font."""
    if valid_nodes:
        return create_sopimports(network, valid_nodes, pos, prefix="copied_sopimport")
    else:
        # Heuristic: if clipboard looks like a file path to an image, drop a file COP
        if os.path.splitext(clipboard)[1].lower() in (".jpg", ".jpeg", ".png", ".exr", ".tif", ".tiff"):
            file_cop = network.createNode("file", "clipboard_file")
            file_cop.setPosition(pos)
            file_cop.parm("filename1").set(clipboard)
            return [file_cop]
        else:
            # Plain text → font COP
            font_cop = network.createNode("font", "clipboard_text")
            font_cop.setPosition(pos)
            font_cop.parm("text").set(clipboard)
            return [font_cop]

# --- Main ---
def main():
    pane = hou.ui.curDesktop().paneTabUnderCursor()
    if not pane:
        hou.ui.displayMessage("No active network pane found")
        return

    network = pane.pwd()
    pos = pane.cursorPosition()
    clipboard = hou.ui.getTextFromClipboard().strip()
    context_type = get_context_type(network)
    valid_nodes = validate_clipboard_nodes(clipboard)

    created_nodes = []
    if context_type == "sop":
        created_nodes = create_object_merges(network, valid_nodes, pos) if valid_nodes else create_font(network, pos, clipboard)
    elif context_type == "object":
        created_nodes = create_geos(network, valid_nodes, pos) if valid_nodes else create_geo_with_font(network, pos, clipboard)
    elif context_type == "lop":
        created_nodes = create_sopimports(network, valid_nodes, pos) if valid_nodes else create_sopcreate_with_font(network, pos, clipboard)
    elif context_type in ("cop2", "cop"):
        created_nodes = create_in_cop_context(network, valid_nodes, pos, clipboard)
    else:
        hou.ui.displayMessage(f"Unsupported context: {context_type}")
        return

    if created_nodes:
        for i, node in enumerate(created_nodes):
            node.setSelected(i == 0, clear_all_selected=True) if i == 0 else node.setSelected(True)
        layout_new_nodes(network, created_nodes)
    else:
        hou.ui.displayMessage("No valid nodes or text in clipboard")

main()
  • Quick Links