forked from LeenkxTeam/LNXSDK
		
	
		
			
				
	
	
		
			219 lines
		
	
	
		
			8.6 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			219 lines
		
	
	
		
			8.6 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
import bpy
 | 
						|
 | 
						|
import lnx.utils
 | 
						|
import lnx.node_utils
 | 
						|
from lnx.logicnode.lnx_nodes import *
 | 
						|
import lnx.logicnode.miscellaneous.LN_call_group as LN_call_group
 | 
						|
 | 
						|
 | 
						|
class GroupOutputsNode(LnxLogicTreeNode):
 | 
						|
    """Output for a node group."""
 | 
						|
    bl_idname = 'LNGroupOutputsNode'
 | 
						|
    bl_label = 'Group Output Node'
 | 
						|
    lnx_section = 'group'
 | 
						|
    lnx_version = 3
 | 
						|
 | 
						|
    def __init__(self, *args, **kwargs):
 | 
						|
        super(GroupOutputsNode, self).__init__(*args, **kwargs)
 | 
						|
        self.register_id()
 | 
						|
 | 
						|
    # Active socket selected
 | 
						|
    active_input: IntProperty(name='active_input', description='', default=0)
 | 
						|
 | 
						|
    # Flag to store invalid links
 | 
						|
    invalid_link: BoolProperty(name='invalid_link', description='', default=False)
 | 
						|
 | 
						|
    # Override copy prevention in certain situations such as copying entire group
 | 
						|
    copy_override: BoolProperty(name='copy override', description='', default=False)
 | 
						|
 | 
						|
    def init(self, context):
 | 
						|
        tree = bpy.context.space_data.edit_tree
 | 
						|
        node_count = 0
 | 
						|
        for node in tree.nodes:
 | 
						|
            if node.bl_idname == 'LNGroupOutputsNode':
 | 
						|
                node_count += 1
 | 
						|
        if node_count > 1:
 | 
						|
            lnx.log.warn("Only one group output node per node tree is allowed")
 | 
						|
            self.mute = True
 | 
						|
        else:
 | 
						|
            super().init(context)
 | 
						|
 | 
						|
    # Prevent copying of group node
 | 
						|
    def copy(self, node):
 | 
						|
        if not self.copy_override:
 | 
						|
            self.mute = True
 | 
						|
            self.inputs.clear()
 | 
						|
        self.copy_override = False
 | 
						|
 | 
						|
    def lnx_init(self, context):
 | 
						|
        if not self.mute:
 | 
						|
            self.add_socket()
 | 
						|
 | 
						|
    # Called when link is created
 | 
						|
    def insert_link(self, link):
 | 
						|
        to_socket = link.to_socket
 | 
						|
        from_node = link.from_node
 | 
						|
        from_socket = None
 | 
						|
        # Recursively search for other socket in case of reroutes
 | 
						|
        if from_node.type == 'REROUTE':
 | 
						|
            _, from_socket = lnx.node_utils.input_get_connected_node(to_socket)
 | 
						|
        else:
 | 
						|
            from_socket = link.from_socket
 | 
						|
        if from_socket is not None:
 | 
						|
            index = self.get_socket_index(to_socket)
 | 
						|
            # If socket connected to LnxAnySocket, link is invalid
 | 
						|
            if from_socket.bl_idname == 'LnxAnySocket':
 | 
						|
                self.invalid_link = True
 | 
						|
            else:
 | 
						|
                call_group_nodes = self.get_call_group_nodes()
 | 
						|
                for node in call_group_nodes:
 | 
						|
                    # Change socket type according to the new link
 | 
						|
                    node.change_output_socket(from_socket.bl_idname, index, link.to_socket.display_label)
 | 
						|
 | 
						|
    # Use update method to remove invalid links
 | 
						|
    def update(self):
 | 
						|
        super().update()
 | 
						|
        if self.invalid_link:
 | 
						|
            self.remove_invalid_links()
 | 
						|
 | 
						|
    # Called when name of the socket is changed
 | 
						|
    def socket_name_update(self, socket):
 | 
						|
        index = self.get_socket_index(socket)
 | 
						|
        # Update socket names of the related call group nodes
 | 
						|
        call_node_groups = self.get_call_group_nodes()
 | 
						|
        for node in call_node_groups:
 | 
						|
            out_socket = node.outputs[index]
 | 
						|
            if out_socket.bl_idname == 'LnxAnySocket':
 | 
						|
                out_socket.display_label = socket.display_label
 | 
						|
            else:
 | 
						|
                out_socket.name = socket.display_label
 | 
						|
 | 
						|
    # Recursively search and remove invalid links
 | 
						|
    def remove_invalid_links(self):
 | 
						|
        for input in self.inputs:
 | 
						|
            for link in input.links:
 | 
						|
                if link.from_socket.bl_idname == 'LnxAnySocket':
 | 
						|
                    tree = self.get_tree()
 | 
						|
                    tree.links.remove(link)
 | 
						|
                    break
 | 
						|
        self.invalid_link = False
 | 
						|
 | 
						|
    # Function to move socket up and handle the same in related call group nodes
 | 
						|
    def move_socket_up(self):
 | 
						|
        if self.active_input > 0:
 | 
						|
            self.inputs.move(self.active_input, self.active_input - 1)
 | 
						|
            call_node_groups = self.get_call_group_nodes()
 | 
						|
            for nodes in call_node_groups:
 | 
						|
                nodes.outputs.move(self.active_input, self.active_input - 1)
 | 
						|
            self.active_input = self.active_input - 1
 | 
						|
 | 
						|
    # Function to move socket down and handle the same in related call group nodes
 | 
						|
    def move_socket_down(self):
 | 
						|
        if self.active_input < len(self.inputs) - 1:
 | 
						|
            self.inputs.move(self.active_input, self.active_input + 1)
 | 
						|
            call_node_groups = self.get_call_group_nodes()
 | 
						|
            for nodes in call_node_groups:
 | 
						|
                nodes.outputs.move(self.active_input, self.active_input + 1)
 | 
						|
            self.active_input = self.active_input + 1
 | 
						|
 | 
						|
    # Function to recursively get related call group nodes
 | 
						|
    def get_call_group_nodes(self):
 | 
						|
        call_group_nodes = []
 | 
						|
        # Return empty list if node is muted
 | 
						|
        if self.mute:
 | 
						|
            return call_group_nodes
 | 
						|
        for tree in bpy.data.node_groups:
 | 
						|
            if tree.bl_idname == "LnxLogicTreeType" or tree.bl_idname == "LnxGroupTree":
 | 
						|
                for node in tree.nodes:
 | 
						|
                    if node.bl_idname == 'LNCallGroupNode':
 | 
						|
                        if node.group_tree == self.get_tree():
 | 
						|
                            call_group_nodes.append(node)
 | 
						|
        return call_group_nodes
 | 
						|
 | 
						|
    # Function to add a socket and handle the same in the related call group nodes
 | 
						|
    def add_socket(self):
 | 
						|
        self.add_input('LnxAnySocket','',)
 | 
						|
        call_group_nodes = self.get_call_group_nodes()
 | 
						|
        for node in call_group_nodes:
 | 
						|
            node.add_output('LnxAnySocket','')
 | 
						|
 | 
						|
    # Function to remove a socket and handle the same in the related call group nodes
 | 
						|
    def remove_socket(self):
 | 
						|
        self.inputs.remove(self.inputs[-1])
 | 
						|
        call_group_nodes = self.get_call_group_nodes()
 | 
						|
        for node in call_group_nodes:
 | 
						|
            node.outputs.remove(node.outputs[-1])
 | 
						|
        if self.active_input > len(self.inputs) - 1:
 | 
						|
            self.active_input = self.active_input - 1
 | 
						|
 | 
						|
    # Function to add a socket at certain index and 
 | 
						|
    # handle the same in the related call group nodes
 | 
						|
    def add_socket_ext(self):
 | 
						|
        index = self.active_input + 1
 | 
						|
        self.insert_input('LnxAnySocket', index, '')
 | 
						|
        call_group_nodes = self.get_call_group_nodes()
 | 
						|
        for node in call_group_nodes:
 | 
						|
            node.insert_output('LnxAnySocket', index, '')
 | 
						|
 | 
						|
    # Function to remove a socket at certain index and 
 | 
						|
    # handle the same in the related call group nodes
 | 
						|
    def remove_socket_ext(self):
 | 
						|
        self.inputs.remove(self.inputs[self.active_input])
 | 
						|
        call_group_nodes = self.get_call_group_nodes()
 | 
						|
        for node in call_group_nodes:
 | 
						|
            node.outputs.remove(node.outputs[self.active_input])
 | 
						|
        if self.active_input > len(self.inputs) - 1:
 | 
						|
            self.active_input = len(self.inputs) - 1
 | 
						|
 | 
						|
    # Handle deletion of group input node
 | 
						|
    def free(self):
 | 
						|
        call_group_nodes = self.get_call_group_nodes()
 | 
						|
        for node in call_group_nodes:
 | 
						|
            node.outputs.clear()
 | 
						|
 | 
						|
    # Draw node UI
 | 
						|
    def draw_buttons(self, context, layout):
 | 
						|
        if self.mute:
 | 
						|
            layout.enabled = False
 | 
						|
        row = layout.row(align=True)
 | 
						|
        op = row.operator('lnx.node_call_func', text='New', icon='PLUS', emboss=True)
 | 
						|
        op.node_index = self.get_id_str()
 | 
						|
        op.callback_name = 'add_socket'
 | 
						|
        if len(self.inputs) > 1:
 | 
						|
            op2 = row.operator('lnx.node_call_func', text='', icon='X', emboss=True)
 | 
						|
            op2.node_index = self.get_id_str()
 | 
						|
            op2.callback_name = 'remove_socket'
 | 
						|
 | 
						|
    # Draw side panel UI
 | 
						|
    def draw_buttons_ext(self, context, layout):
 | 
						|
        if self.mute:
 | 
						|
            layout.enabled = False
 | 
						|
        node = context.active_node
 | 
						|
        split = layout.row()
 | 
						|
        split.template_list('LNX_UL_InterfaceSockets', 'IN', node, 'inputs', node, 'active_input')
 | 
						|
        ops_col = split.column()
 | 
						|
        add_remove_col = ops_col.column(align=True)
 | 
						|
        props = add_remove_col.operator('lnx.node_call_func', icon='ADD', text="")
 | 
						|
        props.node_index = self.get_id_str()
 | 
						|
        props.callback_name = 'add_socket_ext'
 | 
						|
        if len(self.inputs) > 1:
 | 
						|
            props = add_remove_col.operator('lnx.node_call_func', icon='REMOVE', text="")
 | 
						|
            props.node_index = self.get_id_str()
 | 
						|
            props.callback_name = 'remove_socket_ext'
 | 
						|
 | 
						|
        ops_col.separator()
 | 
						|
 | 
						|
        up_down_col = ops_col.column(align=True)
 | 
						|
        props = up_down_col.operator('lnx.node_call_func', icon='TRIA_UP', text="")
 | 
						|
        props.node_index = self.get_id_str()
 | 
						|
        props.callback_name = 'move_socket_up'
 | 
						|
        props = up_down_col.operator('lnx.node_call_func', icon='TRIA_DOWN', text="")
 | 
						|
        props.node_index = self.get_id_str()
 | 
						|
        props.callback_name = 'move_socket_down'
 | 
						|
 | 
						|
    def get_replacement_node(self, node_tree: bpy.types.NodeTree):
 | 
						|
        if self.lnx_version not in (0, 1, 2):
 | 
						|
            raise LookupError()
 | 
						|
 | 
						|
        return node_tree.nodes.new('LNGroupOutputsNode')
 |