Skip to content
Snippets Groups Projects
node_efficiency_tools.py 72 KiB
Newer Older
  • Learn to ignore specific revisions
  •                         locy += parent.location.y
                            parent = parent.parent
                    width = abs((zero_x - locx) * 2.0)
                    height = abs((zero_y - locy) * 2.0)
                    selected[j].append(width)  # complete selected's entry for nodes[i]
                    selected[j].append(height)  # complete selected's entry for nodes[i]
                    total_w += width  # add nodes[i] width to total width of all nodes
                    total_h += height  # add nodes[i] height to total height of all nodes
                selected_sorted_x = sorted(selected, key=lambda k: (k[1], -k[2]))
                selected_sorted_y = sorted(selected, key=lambda k: (-k[2], k[1]))
                min_x = selected_sorted_x[0][1]  # min loc.x
                min_x_loc_y = selected_sorted_x[0][2]  # loc y of node with min loc x
                min_x_w = selected_sorted_x[0][3]  # width of node with max loc x
                max_x = selected_sorted_x[count - 1][1]  # max loc.x
                max_x_loc_y = selected_sorted_x[count - 1][2]  # loc y of node with max loc.x
                max_x_w = selected_sorted_x[count - 1][3]  # width of node with max loc.x
                min_y = selected_sorted_y[0][2]  # min loc.y
                min_y_loc_x = selected_sorted_y[0][1]  # loc.x of node with min loc.y
                min_y_h = selected_sorted_y[0][4]  # height of node with min loc.y
                min_y_w = selected_sorted_y[0][3]  # width of node with min loc.y
                max_y = selected_sorted_y[count - 1][2]  # max loc.y
                max_y_loc_x = selected_sorted_y[count - 1][1]  # loc x of node with max loc.y
                max_y_w = selected_sorted_y[count - 1][3]  # width of node with max loc.y
                max_y_h = selected_sorted_y[count - 1][4]  # height of node with max loc.y
    
    
                if self.option == 'AXIS_Y':  # Horizontally. Equivelent of s -> x -> 0 with even spacing.
    
                    loc_x = min_x
                    #loc_y = (max_x_loc_y + min_x_loc_y) / 2.0
                    loc_y = (max_y - max_y_h / 2.0 + min_y - min_y_h / 2.0) / 2.0
                    offset_x = (max_x - min_x - total_w + max_x_w) / (count - 1)
                    for i, x, y, w, h in selected_sorted_x:
                        nodes[i].location.x = loc_x
                        nodes[i].location.y = loc_y + h / 2.0
                        parent = nodes[i].parent
                        while parent is not None:
                            nodes[i].location.x -= parent.location.x
                            nodes[i].location.y -= parent.location.y
                            parent = parent.parent
                        loc_x += offset_x + w
                else:  # if self.option == 'AXIS_Y'
                    #loc_x = (max_y_loc_x + max_y_w / 2.0 + min_y_loc_x + min_y_w / 2.0) / 2.0
                    loc_x = (max_x + max_x_w / 2.0 + min_x + min_x_w / 2.0) / 2.0
                    loc_y = min_y
                    offset_y = (max_y - min_y + total_h - min_y_h) / (count - 1)
                    for i, x, y, w, h in selected_sorted_y:
                        nodes[i].location.x = loc_x - w / 2.0
                        nodes[i].location.y = loc_y
                        parent = nodes[i].parent
                        while parent is not None:
                            nodes[i].location.x -= parent.location.x
                            nodes[i].location.y -= parent.location.y
                            parent = parent.parent
                        loc_y += offset_y - h
    
                # reselect selected frames
                for i in frames_reselect:
                    nodes[i].select = True
                # restore active node
                nodes.active = active
    
            return {'FINISHED'}
    
    
    class SelectParentChildren(Operator, NodeToolBase):
        bl_idname = "node.select_parent_child"
        bl_label = "Select Parent or Children"
        bl_options = {'REGISTER', 'UNDO'}
    
        option = EnumProperty(
                name="option",
                items=(
                    ('PARENT', 'Select Parent', 'Select Parent Frame'),
                    ('CHILD', 'Select Children', 'Select members of selected frame'),
                    )
                )
    
        def execute(self, context):
            nodes, links = get_nodes_links(context)
            option = self.option
            selected = [node for node in nodes if node.select]
            if option == 'PARENT':
                for sel in selected:
                    parent = sel.parent
                    if parent:
                        parent.select = True
            else:  # option == 'CHILD'
                for sel in selected:
                    children = [node for node in nodes if node.parent == sel]
                    for kid in children:
                        kid.select = True
    
            return {'FINISHED'}
    
    
    
    Bartek Skorupa's avatar
    Bartek Skorupa committed
    class DetachOutputs(Operator, NodeToolBase):
        bl_idname = "node.detach_outputs"
    
        bl_label = "Detach Outputs"
    
    Bartek Skorupa's avatar
    Bartek Skorupa committed
        bl_options = {'REGISTER', 'UNDO'}
        
        def execute(self, context):
            nodes, links = get_nodes_links(context)
            selected = context.selected_nodes
            bpy.ops.node.duplicate_move_keep_inputs()
            new_nodes = context.selected_nodes
            bpy.ops.node.select_all(action="DESELECT")
            for node in selected:
                node.select = True
            bpy.ops.node.delete_reconnect()
            for new_node in new_nodes:
                new_node.select = True
    
    Bartek Skorupa's avatar
    Bartek Skorupa committed
            return {'FINISHED'}
    
    
    Bartek Skorupa's avatar
    Bartek Skorupa committed
    class LinkToOutputNode(Operator, NodeToolBase):
        bl_idname = "node.link_to_output_node"
        bl_label = "Link to Output Node"
        bl_options = {'REGISTER', 'UNDO'}
        
        @classmethod
        def poll(cls, context):
    
            space = context.space_data
            valid = False
            if (space.type == 'NODE_EDITOR' and
                    space.node_tree is not None and
                    context.active_node is not None
                    ):
                valid = True
            return valid
    
    Bartek Skorupa's avatar
    Bartek Skorupa committed
        
        def execute(self, context):
            nodes, links = get_nodes_links(context)
            active = nodes.active
            output_node = None
            for node in nodes:
                if (node.type == 'OUTPUT_MATERIAL' or\
                        node.type == 'OUTPUT_WORLD' or\
                        node.type == 'OUTPUT_LAMP' or\
                        node.type == 'COMPOSITE'):
                    output_node = node
                    break
            if not output_node:
                bpy.ops.node.select_all(action="DESELECT")
                type = context.space_data.tree_type
                if type == 'ShaderNodeTree':
                    output_node = nodes.new('ShaderNodeOutputMaterial')
                elif type == 'CompositorNodeTree':
                    output_node = nodes.new('CompositorNodeComposite')
                output_node.location = active.location + Vector((300.0, 0.0))
                nodes.active = output_node
            if (output_node and active.outputs):
                output_index = 0
                for i, output in enumerate(active.outputs):
                    if output.type == output_node.inputs[0].type:
                        output_index = i
                        break
                links.new(active.outputs[output_index], output_node.inputs[0])
    
            return {'FINISHED'}
    
    
    
    #############################################################
    #  P A N E L S
    #############################################################
    
    class EfficiencyToolsPanel(Panel, NodeToolBase):
        bl_idname = "NODE_PT_efficiency_tools"
        bl_space_type = 'NODE_EDITOR'
        bl_region_type = 'UI'
        bl_label = "Efficiency Tools (Ctrl-SPACE)"
    
        def draw(self, context):
            type = context.space_data.tree_type
            layout = self.layout
    
            box = layout.box()
            box.menu(MergeNodesMenu.bl_idname)
            if type == 'ShaderNodeTree':
                box.operator(NodesAddTextureSetup.bl_idname, text="Add Image Texture (Ctrl T)")
            box.menu(BatchChangeNodesMenu.bl_idname, text="Batch Change...")
            box.menu(NodeAlignMenu.bl_idname, text="Align Nodes (Shift =)")
            box.menu(CopyToSelectedMenu.bl_idname, text="Copy to Selected (Shift-C)")
            box.operator(NodesClearLabel.bl_idname).option = True
    
    Bartek Skorupa's avatar
    Bartek Skorupa committed
            box.operator(DetachOutputs.bl_idname)
    
            box.menu(AddReroutesMenu.bl_idname, text="Add Reroutes ( / )")
            box.menu(NodesSwapMenu.bl_idname, text="Swap Nodes (Shift-S)")
            box.menu(LinkActiveToSelectedMenu.bl_idname, text="Link Active To Selected ( \\ )")
    
    Bartek Skorupa's avatar
    Bartek Skorupa committed
            box.operator(LinkToOutputNode.bl_idname)
    
    
    
    #############################################################
    #  M E N U S
    #############################################################
    
    class EfficiencyToolsMenu(Menu, NodeToolBase):
        bl_idname = "NODE_MT_node_tools_menu"
        bl_label = "Efficiency Tools"
    
        def draw(self, context):
            type = context.space_data.tree_type
            layout = self.layout
            layout.menu(MergeNodesMenu.bl_idname, text="Merge Selected Nodes")
            if type == 'ShaderNodeTree':
                layout.operator(NodesAddTextureSetup.bl_idname, text="Add Image Texture with coordinates")
            layout.menu(BatchChangeNodesMenu.bl_idname, text="Batch Change")
            layout.menu(NodeAlignMenu.bl_idname, text="Align Nodes")
            layout.menu(CopyToSelectedMenu.bl_idname, text="Copy to Selected")
            layout.operator(NodesClearLabel.bl_idname).option = True
    
    Bartek Skorupa's avatar
    Bartek Skorupa committed
            layout.operator(DetachOutputs.bl_idname)
    
            layout.menu(AddReroutesMenu.bl_idname, text="Add Reroutes")
            layout.menu(NodesSwapMenu.bl_idname, text="Swap Nodes")
            layout.menu(LinkActiveToSelectedMenu.bl_idname, text="Link Active To Selected")
    
    Bartek Skorupa's avatar
    Bartek Skorupa committed
            layout.operator(LinkToOutputNode.bl_idname)
    
    
    
    class MergeNodesMenu(Menu, NodeToolBase):
        bl_idname = "NODE_MT_merge_nodes_menu"
        bl_label = "Merge Selected Nodes"
    
        def draw(self, context):
            type = context.space_data.tree_type
            layout = self.layout
            if type == 'ShaderNodeTree':
                layout.menu(MergeShadersMenu.bl_idname, text="Use Shaders")
            layout.menu(MergeMixMenu.bl_idname, text="Use Mix Nodes")
            layout.menu(MergeMathMenu.bl_idname, text="Use Math Nodes")
    
    
    class MergeShadersMenu(Menu, NodeToolBase):
        bl_idname = "NODE_MT_merge_shaders_menu"
        bl_label = "Merge Selected Nodes using Shaders"
    
        def draw(self, context):
            layout = self.layout
    
                props = layout.operator(MergeNodes.bl_idname, text=type)
                props.mode = type
                props.merge_type = 'SHADER'
    
    
    class MergeMixMenu(Menu, NodeToolBase):
        bl_idname = "NODE_MT_merge_mix_menu"
        bl_label = "Merge Selected Nodes using Mix"
    
        def draw(self, context):
            layout = self.layout
            for type, name, description in blend_types:
                props = layout.operator(MergeNodes.bl_idname, text=name)
                props.mode = type
                props.merge_type = 'MIX'
    
    
    class MergeMathMenu(Menu, NodeToolBase):
        bl_idname = "NODE_MT_merge_math_menu"
        bl_label = "Merge Selected Nodes using Math"
    
        def draw(self, context):
            layout = self.layout
            for type, name, description in operations:
                props = layout.operator(MergeNodes.bl_idname, text=name)
                props.mode = type
                props.merge_type = 'MATH'
    
    
    class BatchChangeNodesMenu(Menu, NodeToolBase):
        bl_idname = "NODE_MT_batch_change_nodes_menu"
        bl_label = "Batch Change Selected Nodes"
    
        def draw(self, context):
            layout = self.layout
            layout.menu(BatchChangeBlendTypeMenu.bl_idname)
            layout.menu(BatchChangeOperationMenu.bl_idname)
    
    
    class BatchChangeBlendTypeMenu(Menu, NodeToolBase):
        bl_idname = "NODE_MT_batch_change_blend_type_menu"
        bl_label = "Batch Change Blend Type"
    
        def draw(self, context):
            layout = self.layout
            for type, name, description in blend_types:
                props = layout.operator(BatchChangeNodes.bl_idname, text=name)
                props.blend_type = type
                props.operation = 'CURRENT'
    
    
    class BatchChangeOperationMenu(Menu, NodeToolBase):
        bl_idname = "NODE_MT_batch_change_operation_menu"
        bl_label = "Batch Change Math Operation"
    
        def draw(self, context):
            layout = self.layout
            for type, name, description in operations:
                props = layout.operator(BatchChangeNodes.bl_idname, text=name)
                props.blend_type = 'CURRENT'
                props.operation = type
    
    
    class CopyToSelectedMenu(Menu, NodeToolBase):
        bl_idname = "NODE_MT_copy_node_properties_menu"
        bl_label = "Copy to Selected"
    
        def draw(self, context):
            layout = self.layout
            layout.operator(NodesCopySettings.bl_idname, text="Settings from Active")
            layout.menu(CopyLabelMenu.bl_idname)
    
    
    class CopyLabelMenu(Menu, NodeToolBase):
        bl_idname = "NODE_MT_copy_label_menu"
        bl_label = "Copy Label"
    
        def draw(self, context):
            layout = self.layout
            layout.operator(NodesCopyLabel.bl_idname, text="from Active Node's Label").option = 'FROM_ACTIVE'
            layout.operator(NodesCopyLabel.bl_idname, text="from Linked Node's Label").option = 'FROM_NODE'
            layout.operator(NodesCopyLabel.bl_idname, text="from Linked Output's Name").option = 'FROM_SOCKET'
    
    
    class AddReroutesMenu(Menu, NodeToolBase):
        bl_idname = "NODE_MT_add_reroutes_menu"
        bl_label = "Add Reroutes"
        bl_description = "Add Reroute Nodes to Selected Nodes' Outputs"
    
        def draw(self, context):
            layout = self.layout
            layout.operator(NodesAddReroutes.bl_idname, text="to All Outputs").option = 'ALL'
            layout.operator(NodesAddReroutes.bl_idname, text="to Loose Outputs").option = 'LOOSE'
            layout.operator(NodesAddReroutes.bl_idname, text="to Linked Outputs").option = 'LINKED'
    
    
    class NodesSwapMenu(Menu, NodeToolBase):
        bl_idname = "NODE_MT_swap_menu"
        bl_label = "Swap Nodes"
    
        def draw(self, context):
            type = context.space_data.tree_type
            layout = self.layout
            if type == 'ShaderNodeTree':
                layout.menu(ShadersSwapMenu.bl_idname, text="Swap Shaders")
            layout.operator(NodesSwap.bl_idname, text="Change to Mix Nodes").option = 'NodeMixRGB'
            layout.operator(NodesSwap.bl_idname, text="Change to Math Nodes").option = 'NodeMath'
            if type == 'CompositorNodeTree':
                layout.operator(NodesSwap.bl_idname, text="Change to Alpha Over").option = 'CompositorNodeAlphaOver'
            if type == 'CompositorNodeTree':
                layout.operator(NodesSwap.bl_idname, text="Change to Switches").option = 'CompositorNodeSwitch'
                layout.operator(NodesSwap.bl_idname, text="Change to Reroutes").option = 'NodeReroute'
    
    
    class ShadersSwapMenu(Menu):
        bl_idname = "NODE_MT_shaders_swap_menu"
        bl_label = "Swap Shaders"
    
        @classmethod
        def poll(cls, context):
            space = context.space_data
            valid = False
            if space.type == 'NODE_EDITOR':
                if space.tree_type == 'ShaderNodeTree' and space.node_tree is not None:
                    valid = True
            return valid
    
        def draw(self, context):
            layout = self.layout
    
            shaders = regular_shaders + merge_shaders
            for opt, type, txt in shaders:
    
                layout.operator(NodesSwap.bl_idname, text=txt).option = opt
    
    
    class LinkActiveToSelectedMenu(Menu, NodeToolBase):
        bl_idname = "NODE_MT_link_active_to_selected_menu"
        bl_label = "Link Active to Selected"
    
        def draw(self, context):
            layout = self.layout
            layout.menu(LinkStandardMenu.bl_idname)
    
            layout.menu(LinkUseNodeNameMenu.bl_idname)
            layout.menu(LinkUseOutputsNamesMenu.bl_idname)
    
    
    
    class LinkStandardMenu(Menu, NodeToolBase):
        bl_idname = "NODE_MT_link_standard_menu"
        bl_label = "To All Selected"
    
        def draw(self, context):
            layout = self.layout
    
            props = layout.operator(NodesLinkActiveToSelected.bl_idname, text="Don't Replace Links")
    
            props.replace = False
            props.use_node_name = False
            props.use_outputs_names = False
    
            props = layout.operator(NodesLinkActiveToSelected.bl_idname, text="Replace Links")
    
            props.replace = True
            props.use_node_name = False
            props.use_outputs_names = False
    
    
    class LinkUseNodeNameMenu(Menu, NodeToolBase):
        bl_idname = "NODE_MT_link_use_node_name_menu"
        bl_label = "Use Node Name/Label"
    
        def draw(self, context):
            layout = self.layout
            props = layout.operator(NodesLinkActiveToSelected.bl_idname, text="Don't Replace Links")
            props.replace = False
            props.use_node_name = True
            props.use_outputs_names = False
    
            props = layout.operator(NodesLinkActiveToSelected.bl_idname, text="Replace Links")
            props.replace = True
            props.use_node_name = True
            props.use_outputs_names = False
    
    
    
    class LinkUseOutputsNamesMenu(Menu, NodeToolBase):
        bl_idname = "NODE_MT_link_use_outputs_names_menu"
        bl_label = "Use Outputs Names"
    
        def draw(self, context):
            layout = self.layout
            props = layout.operator(NodesLinkActiveToSelected.bl_idname, text="Don't Replace Links")
            props.replace = False
            props.use_node_name = False
            props.use_outputs_names = True
    
            props = layout.operator(NodesLinkActiveToSelected.bl_idname, text="Replace Links")
            props.replace = True
            props.use_node_name = False
            props.use_outputs_names = True
    
    
    
    class NodeAlignMenu(Menu, NodeToolBase):
        bl_idname = "NODE_MT_node_align_menu"
        bl_label = "Align Nodes"
    
        def draw(self, context):
            layout = self.layout
            layout.operator(AlignNodes.bl_idname, text="Horizontally").option = 'AXIS_X'
            layout.operator(AlignNodes.bl_idname, text="Vertically").option = 'AXIS_Y'
    
    
    #############################################################
    #  MENU ITEMS
    #############################################################
    
    def select_parent_children_buttons(self, context):
        layout = self.layout
        layout.operator(SelectParentChildren.bl_idname, text="Select frame's members (children)").option = 'CHILD'
        layout.operator(SelectParentChildren.bl_idname, text="Select parent frame").option = 'PARENT'
    
    #############################################################
    #  REGISTER/UNREGISTER CLASSES AND KEYMAP ITEMS
    #############################################################
    
    addon_keymaps = []
    # kmi_defs entry: (identifier, key, CTRL, SHIFT, ALT, props)
    # props entry: (property name, property value)
    kmi_defs = (
        # MERGE NODES
        # MergeNodes with Ctrl (AUTO).
        (MergeNodes.bl_idname, 'NUMPAD_0', True, False, False,
            (('mode', 'MIX'), ('merge_type', 'AUTO'),)),
        (MergeNodes.bl_idname, 'ZERO', True, False, False,
            (('mode', 'MIX'), ('merge_type', 'AUTO'),)),
        (MergeNodes.bl_idname, 'NUMPAD_PLUS', True, False, False,
            (('mode', 'ADD'), ('merge_type', 'AUTO'),)),
        (MergeNodes.bl_idname, 'EQUAL', True, False, False,
            (('mode', 'ADD'), ('merge_type', 'AUTO'),)),
        (MergeNodes.bl_idname, 'NUMPAD_ASTERIX', True, False, False,
            (('mode', 'MULTIPLY'), ('merge_type', 'AUTO'),)),
        (MergeNodes.bl_idname, 'EIGHT', True, False, False,
            (('mode', 'MULTIPLY'), ('merge_type', 'AUTO'),)),
        (MergeNodes.bl_idname, 'NUMPAD_MINUS', True, False, False,
            (('mode', 'SUBTRACT'), ('merge_type', 'AUTO'),)),
        (MergeNodes.bl_idname, 'MINUS', True, False, False,
            (('mode', 'SUBTRACT'), ('merge_type', 'AUTO'),)),
        (MergeNodes.bl_idname, 'NUMPAD_SLASH', True, False, False,
            (('mode', 'DIVIDE'), ('merge_type', 'AUTO'),)),
        (MergeNodes.bl_idname, 'SLASH', True, False, False,
            (('mode', 'DIVIDE'), ('merge_type', 'AUTO'),)),
        (MergeNodes.bl_idname, 'COMMA', True, False, False,
            (('mode', 'LESS_THAN'), ('merge_type', 'MATH'),)),
        (MergeNodes.bl_idname, 'PERIOD', True, False, False,
            (('mode', 'GREATER_THAN'), ('merge_type', 'MATH'),)),
        # MergeNodes with Ctrl Alt (MIX)
        (MergeNodes.bl_idname, 'NUMPAD_0', True, False, True,
            (('mode', 'MIX'), ('merge_type', 'MIX'),)),
        (MergeNodes.bl_idname, 'ZERO', True, False, True,
            (('mode', 'MIX'), ('merge_type', 'MIX'),)),
        (MergeNodes.bl_idname, 'NUMPAD_PLUS', True, False, True,
            (('mode', 'ADD'), ('merge_type', 'MIX'),)),
        (MergeNodes.bl_idname, 'EQUAL', True, False, True,
            (('mode', 'ADD'), ('merge_type', 'MIX'),)),
        (MergeNodes.bl_idname, 'NUMPAD_ASTERIX', True, False, True,
            (('mode', 'MULTIPLY'), ('merge_type', 'MIX'),)),
        (MergeNodes.bl_idname, 'EIGHT', True, False, True,
            (('mode', 'MULTIPLY'), ('merge_type', 'MIX'),)),
        (MergeNodes.bl_idname, 'NUMPAD_MINUS', True, False, True,
            (('mode', 'SUBTRACT'), ('merge_type', 'MIX'),)),
        (MergeNodes.bl_idname, 'MINUS', True, False, True,
            (('mode', 'SUBTRACT'), ('merge_type', 'MIX'),)),
        (MergeNodes.bl_idname, 'NUMPAD_SLASH', True, False, True,
            (('mode', 'DIVIDE'), ('merge_type', 'MIX'),)),
        (MergeNodes.bl_idname, 'SLASH', True, False, True,
            (('mode', 'DIVIDE'), ('merge_type', 'MIX'),)),
        # MergeNodes with Ctrl Shift (MATH)
        (MergeNodes.bl_idname, 'NUMPAD_PLUS', True, True, False,
            (('mode', 'ADD'), ('merge_type', 'MATH'),)),
        (MergeNodes.bl_idname, 'EQUAL', True, True, False,
            (('mode', 'ADD'), ('merge_type', 'MATH'),)),
        (MergeNodes.bl_idname, 'NUMPAD_ASTERIX', True, True, False,
            (('mode', 'MULTIPLY'), ('merge_type', 'MATH'),)),
        (MergeNodes.bl_idname, 'EIGHT', True, True, False,
            (('mode', 'MULTIPLY'), ('merge_type', 'MATH'),)),
        (MergeNodes.bl_idname, 'NUMPAD_MINUS', True, True, False,
            (('mode', 'SUBTRACT'), ('merge_type', 'MATH'),)),
        (MergeNodes.bl_idname, 'MINUS', True, True, False,
            (('mode', 'SUBTRACT'), ('merge_type', 'MATH'),)),
        (MergeNodes.bl_idname, 'NUMPAD_SLASH', True, True, False,
            (('mode', 'DIVIDE'), ('merge_type', 'MATH'),)),
        (MergeNodes.bl_idname, 'SLASH', True, True, False,
            (('mode', 'DIVIDE'), ('merge_type', 'MATH'),)),
        (MergeNodes.bl_idname, 'COMMA', True, True, False,
            (('mode', 'LESS_THAN'), ('merge_type', 'MATH'),)),
        (MergeNodes.bl_idname, 'PERIOD', True, True, False,
            (('mode', 'GREATER_THAN'), ('merge_type', 'MATH'),)),
        # BATCH CHANGE NODES
        # BatchChangeNodes with Alt
        (BatchChangeNodes.bl_idname, 'NUMPAD_0', False, False, True,
            (('blend_type', 'MIX'), ('operation', 'CURRENT'),)),
        (BatchChangeNodes.bl_idname, 'ZERO', False, False, True,
            (('blend_type', 'MIX'), ('operation', 'CURRENT'),)),
        (BatchChangeNodes.bl_idname, 'NUMPAD_PLUS', False, False, True,
            (('blend_type', 'ADD'), ('operation', 'ADD'),)),
        (BatchChangeNodes.bl_idname, 'EQUAL', False, False, True,
            (('blend_type', 'ADD'), ('operation', 'ADD'),)),
        (BatchChangeNodes.bl_idname, 'NUMPAD_ASTERIX', False, False, True,
            (('blend_type', 'MULTIPLY'), ('operation', 'MULTIPLY'),)),
        (BatchChangeNodes.bl_idname, 'EIGHT', False, False, True,
            (('blend_type', 'MULTIPLY'), ('operation', 'MULTIPLY'),)),
        (BatchChangeNodes.bl_idname, 'NUMPAD_MINUS', False, False, True,
            (('blend_type', 'SUBTRACT'), ('operation', 'SUBTRACT'),)),
        (BatchChangeNodes.bl_idname, 'MINUS', False, False, True,
            (('blend_type', 'SUBTRACT'), ('operation', 'SUBTRACT'),)),
        (BatchChangeNodes.bl_idname, 'NUMPAD_SLASH', False, False, True,
            (('blend_type', 'DIVIDE'), ('operation', 'DIVIDE'),)),
        (BatchChangeNodes.bl_idname, 'SLASH', False, False, True,
            (('blend_type', 'DIVIDE'), ('operation', 'DIVIDE'),)),
        (BatchChangeNodes.bl_idname, 'COMMA', False, False, True,
            (('blend_type', 'CURRENT'), ('operation', 'LESS_THAN'),)),
        (BatchChangeNodes.bl_idname, 'PERIOD', False, False, True,
            (('blend_type', 'CURRENT'), ('operation', 'GREATER_THAN'),)),
        (BatchChangeNodes.bl_idname, 'DOWN_ARROW', False, False, True,
            (('blend_type', 'NEXT'), ('operation', 'NEXT'),)),
        (BatchChangeNodes.bl_idname, 'UP_ARROW', False, False, True,
            (('blend_type', 'PREV'), ('operation', 'PREV'),)),
        # LINK ACTIVE TO SELECTED
    
        # Don't use names, don't replace links (K)
        (NodesLinkActiveToSelected.bl_idname, 'K', False, False, False,
    
            (('replace', False), ('use_node_name', False), ('use_outputs_names', False),)),
    
        # Don't use names, replace links (Shift K)
        (NodesLinkActiveToSelected.bl_idname, 'K', False, True, False,
            (('replace', True), ('use_node_name', False), ('use_outputs_names', False),)),
        # Use node name, don't replace links (')
        (NodesLinkActiveToSelected.bl_idname, 'QUOTE', False, False, False,
            (('replace', False), ('use_node_name', True), ('use_outputs_names', False),)),
        # Don't use names, replace links (')
        (NodesLinkActiveToSelected.bl_idname, 'QUOTE', False, True, False,
            (('replace', True), ('use_node_name', True), ('use_outputs_names', False),)),
        (NodesLinkActiveToSelected.bl_idname, 'SEMI_COLON', False, False, False,
            (('replace', False), ('use_node_name', False), ('use_outputs_names', True),)),
        # Don't use names, replace links (')
        (NodesLinkActiveToSelected.bl_idname, 'SEMI_COLON', False, True, False,
            (('replace', True), ('use_node_name', False), ('use_outputs_names', True),)),
    
        # CHANGE MIX FACTOR
        (ChangeMixFactor.bl_idname, 'LEFT_ARROW', False, False, True, (('option', -0.1),)),
        (ChangeMixFactor.bl_idname, 'RIGHT_ARROW', False, False, True, (('option', 0.1),)),
        (ChangeMixFactor.bl_idname, 'LEFT_ARROW', False, True, True, (('option', -0.01),)),
        (ChangeMixFactor.bl_idname, 'RIGHT_ARROW', False, True, True, (('option', 0.01),)),
        (ChangeMixFactor.bl_idname, 'LEFT_ARROW', True, True, True, (('option', 0.0),)),
        (ChangeMixFactor.bl_idname, 'RIGHT_ARROW', True, True, True, (('option', 1.0),)),
        (ChangeMixFactor.bl_idname, 'NUMPAD_0', True, True, True, (('option', 0.0),)),
        (ChangeMixFactor.bl_idname, 'ZERO', True, True, True, (('option', 0.0),)),
        (ChangeMixFactor.bl_idname, 'NUMPAD_1', True, True, True, (('option', 1.0),)),
        (ChangeMixFactor.bl_idname, 'ONE', True, True, True, (('option', 1.0),)),
        # CLEAR LABEL (Alt L)
        (NodesClearLabel.bl_idname, 'L', False, False, True, (('option', False),)),
    
    Bartek Skorupa's avatar
    Bartek Skorupa committed
        # DETACH OUTPUTS (Alt Shift D)
        (DetachOutputs.bl_idname, 'D', False, True, True, None),
        # LINK TO OUTPUT NODE (O)
        (LinkToOutputNode.bl_idname, 'O', False, False, False, None),
    
        # SELECT PARENT/CHILDREN
        # Select Children
        (SelectParentChildren.bl_idname, 'RIGHT_BRACKET', False, False, False, (('option', 'CHILD'),)),
        # Select Parent
        (SelectParentChildren.bl_idname, 'LEFT_BRACKET', False, False, False, (('option', 'PARENT'),)),
    
        (NodesAddTextureSetup.bl_idname, 'T', True, False, False, None),
    
        # Copy Label from active to selected
        (NodesCopyLabel.bl_idname, 'V', False, True, False, (('option', 'FROM_ACTIVE'),)),
    
        # MENUS
        ('wm.call_menu', 'SPACE', True, False, False, (('name', EfficiencyToolsMenu.bl_idname),)),
        ('wm.call_menu', 'SLASH', False, False, False, (('name', AddReroutesMenu.bl_idname),)),
        ('wm.call_menu', 'NUMPAD_SLASH', False, False, False, (('name', AddReroutesMenu.bl_idname),)),
        ('wm.call_menu', 'EQUAL', False, True, False, (('name', NodeAlignMenu.bl_idname),)),
    
        ('wm.call_menu', 'BACK_SLASH', False, False, False, (('name', LinkActiveToSelectedMenu.bl_idname),)),
    
        ('wm.call_menu', 'C', False, True, False, (('name', CopyToSelectedMenu.bl_idname),)),
        ('wm.call_menu', 'S', False, True, False, (('name', NodesSwapMenu.bl_idname),)),
        )
    
    
    def register():
        bpy.utils.register_module(__name__)
        km = bpy.context.window_manager.keyconfigs.addon.keymaps.new(name='Node Editor', space_type="NODE_EDITOR")
        for (identifier, key, CTRL, SHIFT, ALT, props) in kmi_defs:
            kmi = km.keymap_items.new(identifier, key, 'PRESS', ctrl=CTRL, shift=SHIFT, alt=ALT)
            if props:
                for prop, value in props:
                    setattr(kmi.properties, prop, value)
            addon_keymaps.append((km, kmi))
        # menu items
        bpy.types.NODE_MT_select.append(select_parent_children_buttons)
    
    
    def unregister():
        bpy.utils.unregister_module(__name__)
        bpy.types.NODE_MT_select.remove(select_parent_children_buttons)
        for km, kmi in addon_keymaps:
            km.keymap_items.remove(kmi)
        addon_keymaps.clear()
    
    if __name__ == "__main__":
    
    Bartek Skorupa's avatar
    Bartek Skorupa committed
        register()