| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227 | #Mantis Nodes Baseimport bpyfrom bpy.props import BoolProperty, StringProperty, EnumProperty, CollectionProperty, IntPropertyfrom . import ops_nodegroupfrom bpy.types import NodeTree, Node, PropertyGroup, Operator, UIList, Panelfrom mantis.utilities import (prRed, prGreen, prPurple, prWhite,                              prOrange,                              wrapRed, wrapGreen, wrapPurple, wrapWhite,                              wrapOrange,)from bpy.app.handlers import persistentdef TellClasses():    #Why use a function to do this? Because I don't need every class to register.    return [MantisNodeGroup, MantisTree, ]class MantisTree(NodeTree):    '''A custom node tree type that will show up in the editor type list'''    bl_idname = 'MantisTree'    bl_label = "Rigging Nodes"    bl_icon = 'OUTLINER_OB_ARMATURE'        tree_valid:BoolProperty(default=False)    do_live_update:BoolProperty(default=True)    # use this to disable updates for e.g. scripts    locked:BoolProperty(default=True)        num_links:IntProperty(default=-1)        parsed_tree={}        def interface_update(self, context):        # no idea what this does        print ("Update Interface function in MantisTree class")               def interface_update(self, context):        prGreen("interface_update")            if bpy.app.version >= (3, 2):  # in 3.1 this can lead to a crash        @classmethod        def valid_socket_type(cls, socket_type: str):            # https://docs.blender.org/api/master/bpy.types.NodeTree.html#bpy.types.NodeTree.valid_socket_type            from mantis.socket_definitions import Tell_bl_idnames            return socket_type in Tell_bl_idnames()            # thank you, Sverchok                def update_tree(self, context):        if self.do_live_update == False:            return        from mantis import readtree        prGreen("Validating Tree: %s" % self.name)        parsed_tree = readtree.parse_tree(self)        self.parsed_tree=parsed_tree        current_tree = bpy.context.space_data.path[-1].node_tree        self.tree_valid = True        prWhite("Number of Nodes: %s" % (len(self.parsed_tree)))        self.display_update(context)        def display_update(self, context):        if self.do_live_update == False:            return        current_tree = bpy.context.space_data.path[-1].node_tree        for node in current_tree.nodes:            if hasattr(node, "display_update"):                try:                    node.display_update(self.parsed_tree, context)                except Exception as e:                    print("Node \"%s\" failed to update display with error: %s" %(wrapGreen(node.name), wrapRed(e)))                    # raise e                def execute_tree(self,context):        prGreen("Executing Tree: %s" % self.name)        from mantis import readtree        readtree.execute_tree(self.parsed_tree, self, context)    def update_handler(scene):    context=bpy.context    if context.space_data:        node_tree = context.space_data.path[0].node_tree        if node_tree.do_live_update:            prev_links = node_tree.num_links            node_tree.num_links = len(node_tree.links)            if (prev_links == -1):                return            if prev_links != node_tree.num_links:                node_tree.tree_valid = False            if node_tree.tree_valid == False:                from mantis import readtree                node_tree.update_tree(context)def execute_handler(scene):    context = bpy.context    if context.space_data:        node_tree = context.space_data.path[0].node_tree        if node_tree.tree_valid and node_tree.do_live_update:            node_tree.execute_tree(context)            self.tree_valid = False# bpy.app.handlers.load_post.append(set_tree_invalid)bpy.app.handlers.depsgraph_update_pre.append(update_handler)bpy.app.handlers.depsgraph_update_post.append(execute_handler)    class MantisNode:    num_links:IntProperty(default=-1)    # do_display_update:BoolProperty(default=False)    @classmethod    def poll(cls, ntree):        return (ntree.bl_idname == 'MantisTree')                    def insert_link(self, link):        context = bpy.context        if context.space_data:            node_tree = context.space_data.path[0].node_tree            from mantis import readtree            prOrange("Updating from insert_link callback")            node_tree.update_tree(context)            if (link.to_socket.is_linked == False):                node_tree.num_links+=1            elif (link.to_socket.is_multi_input and                   link.to_socket.links < link.to_socket.link_limit ):                node_tree.num_links+=1                            class LinkNode(MantisNode):    useTarget : BoolProperty(default=False)    @classmethod    def poll(cls, ntree):        return (ntree.bl_idname == 'MantisTree')class xFormNode(MantisNode):    @classmethod    def poll(cls, ntree):        return (ntree.bl_idname == 'MantisTree')class DeformerNode(MantisNode):    @classmethod    def poll(cls, ntree):        return (ntree.bl_idname == 'MantisTree')from bpy.types import NodeCustomGroup# TODO: make this one's traverse() function actually workclass MantisNodeGroup(NodeCustomGroup, MantisNode):    bl_idname = "MantisNodeGroup"    bl_label = "Node Group"        # def poll_node_tree(self, object):        # if object.bl_idname not in "MantisTree":            # return False        # context=bpy.context        # context = bpy.context        # if context.space_data:            # used_trees = [ pathitem.node_tree for pathitem in context.space_data.path]            # if object in used_trees:                # return False    # node_tree:bpy.props.PointerProperty(type=bpy.types.NodeTree, poll=poll_node_tree)        def init(self, context):        pass        def draw_buttons(self, context, layout):        row = layout.row(align=True)        row.prop(self, "node_tree", text="")        row.operator("mantis.edit_group", text="", icon='NODETREE', emboss=True)        # I don't remember why I need this?class GroupOutputDummySocket:    # a dummy class for acting like a socket that is coming from every    #  group output node    def __init__(self, tree, identifier, is_input=True):        #        # So, we need to go through the node tree and find all         #   the Group Input sockets that match this        #   socket's identifier        #        sockets = []        s = None        for node in tree.nodes:            if (is_input):                if node.bl_idname == 'NodeGroupInput':                    # Group Inputs have outputs... confusing.                    for s in node.outputs:                        if (s.identifier == identifier):                            sockets.append(s)            else:                if node.bl_idname == 'NodeGroupOutput':                    for s in node.inputs:                        if (s.identifier == identifier):                            sockets.append(s)        sock = sockets[-1]        # whatever the last socket is should be OK for most of this stuff        self.bl_idname=sock.bl_idname        self.identifier = identifier        self.name = sock.name        is_linked = False        for s in sockets:            if s.is_linked:                is_linked = True; break        self.is_linked = is_linked        self.is_output = not is_input        # hopefully this doesn't matter, since it is a group node...        self.node = sock.node        self.links = []        for s in sockets:            self.links.extend(s.links)        # seems to werkclass CircularDependencyError(Exception):    passclass GraphError(Exception):    passdef get_signature_from_edited_tree(self, context):    sig_path=[None,]    for item in context.space_data.path[:-1]:        sig_path.append(item.node_tree.nodes.active.name)    return tuple(sig_path+[self.name])
 |