Skip to content
Snippets Groups Projects
node_wrangler.py 226 KiB
Newer Older
  • Learn to ignore specific revisions
  •     layout = self.layout
    
        layout.operator(NWSelectParentChildren.bl_idname, text="Select frame's members (children)").option = 'CHILD'
        layout.operator(NWSelectParentChildren.bl_idname, text="Select parent frame").option = 'PARENT'
    
    
    def attr_nodes_menu_func(self, context):
        col = self.layout.column(align=True)
        col.menu("NODE_MT_nw_node_vertex_color_menu")
        col.separator()
    
    
    
    def multipleimages_menu_func(self, context):
        col = self.layout.column(align=True)
        col.operator(NWAddMultipleImages.bl_idname, text="Multiple Images")
        col.operator(NWAddSequence.bl_idname, text="Image Sequence")
        col.separator()
    
    def bgreset_menu_func(self, context):
        self.layout.operator(NWResetBG.bl_idname)
    
    
    def save_viewer_menu_func(self, context):
    
    Greg's avatar
    Greg committed
        if nw_check(context):
            if context.space_data.tree_type == 'CompositorNodeTree':
                if context.scene.node_tree.nodes.active:
                    if context.scene.node_tree.nodes.active.type == "VIEWER":
                        self.layout.operator(NWSaveViewer.bl_idname, icon='FILE_IMAGE')
    
    def reset_nodes_button(self, context):
        node_active = context.active_node
        node_selected = context.selected_nodes
        node_ignore = ["FRAME","REROUTE", "GROUP"]
    
        # Check if active node is in the selection and respective type
        if (len(node_selected) == 1) and node_active.select and node_active.type not in node_ignore:
            row = self.layout.row()
            row.operator("node.nw_reset_nodes", text="Reset Node", icon="FILE_REFRESH")
            self.layout.separator()
    
        elif (len(node_selected) == 1) and node_active.select and node_active.type == "FRAME":
            row = self.layout.row()
            row.operator("node.nw_reset_nodes", text="Reset Nodes in Frame", icon="FILE_REFRESH")
            self.layout.separator()
    
    
    
    #  REGISTER/UNREGISTER CLASSES AND KEYMAP ITEMS
    
    switch_category_menus = []
    
    addon_keymaps = []
    
    # kmi_defs entry: (identifier, key, action, CTRL, SHIFT, ALT, props, nice name)
    
    # props entry: (property name, property value)
    kmi_defs = (
        # MERGE NODES
    
        # NWMergeNodes with Ctrl (AUTO).
    
        (NWMergeNodes.bl_idname, 'NUMPAD_0', 'PRESS', True, False, False,
    
            (('mode', 'MIX'), ('merge_type', 'AUTO'),), "Merge Nodes (Automatic)"),
    
        (NWMergeNodes.bl_idname, 'ZERO', 'PRESS', True, False, False,
    
            (('mode', 'MIX'), ('merge_type', 'AUTO'),), "Merge Nodes (Automatic)"),
    
        (NWMergeNodes.bl_idname, 'NUMPAD_PLUS', 'PRESS', True, False, False,
    
            (('mode', 'ADD'), ('merge_type', 'AUTO'),), "Merge Nodes (Add)"),
    
        (NWMergeNodes.bl_idname, 'EQUAL', 'PRESS', True, False, False,
    
            (('mode', 'ADD'), ('merge_type', 'AUTO'),), "Merge Nodes (Add)"),
    
        (NWMergeNodes.bl_idname, 'NUMPAD_ASTERIX', 'PRESS', True, False, False,
    
            (('mode', 'MULTIPLY'), ('merge_type', 'AUTO'),), "Merge Nodes (Multiply)"),
    
        (NWMergeNodes.bl_idname, 'EIGHT', 'PRESS', True, False, False,
    
            (('mode', 'MULTIPLY'), ('merge_type', 'AUTO'),), "Merge Nodes (Multiply)"),
    
        (NWMergeNodes.bl_idname, 'NUMPAD_MINUS', 'PRESS', True, False, False,
    
            (('mode', 'SUBTRACT'), ('merge_type', 'AUTO'),), "Merge Nodes (Subtract)"),
    
        (NWMergeNodes.bl_idname, 'MINUS', 'PRESS', True, False, False,
    
            (('mode', 'SUBTRACT'), ('merge_type', 'AUTO'),), "Merge Nodes (Subtract)"),
    
        (NWMergeNodes.bl_idname, 'NUMPAD_SLASH', 'PRESS', True, False, False,
    
            (('mode', 'DIVIDE'), ('merge_type', 'AUTO'),), "Merge Nodes (Divide)"),
    
        (NWMergeNodes.bl_idname, 'SLASH', 'PRESS', True, False, False,
    
            (('mode', 'DIVIDE'), ('merge_type', 'AUTO'),), "Merge Nodes (Divide)"),
    
        (NWMergeNodes.bl_idname, 'COMMA', 'PRESS', True, False, False,
    
            (('mode', 'LESS_THAN'), ('merge_type', 'MATH'),), "Merge Nodes (Less than)"),
    
        (NWMergeNodes.bl_idname, 'PERIOD', 'PRESS', True, False, False,
    
            (('mode', 'GREATER_THAN'), ('merge_type', 'MATH'),), "Merge Nodes (Greater than)"),
    
        (NWMergeNodes.bl_idname, 'NUMPAD_PERIOD', 'PRESS', True, False, False,
    
            (('mode', 'MIX'), ('merge_type', 'ZCOMBINE'),), "Merge Nodes (Z-Combine)"),
    
        # NWMergeNodes with Ctrl Alt (MIX or ALPHAOVER)
    
        (NWMergeNodes.bl_idname, 'NUMPAD_0', 'PRESS', True, False, True,
    
            (('mode', 'MIX'), ('merge_type', 'ALPHAOVER'),), "Merge Nodes (Alpha Over)"),
    
        (NWMergeNodes.bl_idname, 'ZERO', 'PRESS', True, False, True,
    
            (('mode', 'MIX'), ('merge_type', 'ALPHAOVER'),), "Merge Nodes (Alpha Over)"),
    
        (NWMergeNodes.bl_idname, 'NUMPAD_PLUS', 'PRESS', True, False, True,
    
            (('mode', 'ADD'), ('merge_type', 'MIX'),), "Merge Nodes (Color, Add)"),
    
        (NWMergeNodes.bl_idname, 'EQUAL', 'PRESS', True, False, True,
    
            (('mode', 'ADD'), ('merge_type', 'MIX'),), "Merge Nodes (Color, Add)"),
    
        (NWMergeNodes.bl_idname, 'NUMPAD_ASTERIX', 'PRESS', True, False, True,
    
            (('mode', 'MULTIPLY'), ('merge_type', 'MIX'),), "Merge Nodes (Color, Multiply)"),
    
        (NWMergeNodes.bl_idname, 'EIGHT', 'PRESS', True, False, True,
    
            (('mode', 'MULTIPLY'), ('merge_type', 'MIX'),), "Merge Nodes (Color, Multiply)"),
    
        (NWMergeNodes.bl_idname, 'NUMPAD_MINUS', 'PRESS', True, False, True,
    
            (('mode', 'SUBTRACT'), ('merge_type', 'MIX'),), "Merge Nodes (Color, Subtract)"),
    
        (NWMergeNodes.bl_idname, 'MINUS', 'PRESS', True, False, True,
    
            (('mode', 'SUBTRACT'), ('merge_type', 'MIX'),), "Merge Nodes (Color, Subtract)"),
    
        (NWMergeNodes.bl_idname, 'NUMPAD_SLASH', 'PRESS', True, False, True,
    
            (('mode', 'DIVIDE'), ('merge_type', 'MIX'),), "Merge Nodes (Color, Divide)"),
    
        (NWMergeNodes.bl_idname, 'SLASH', 'PRESS', True, False, True,
    
            (('mode', 'DIVIDE'), ('merge_type', 'MIX'),), "Merge Nodes (Color, Divide)"),
        # NWMergeNodes with Ctrl Shift (MATH)
    
        (NWMergeNodes.bl_idname, 'NUMPAD_PLUS', 'PRESS', True, True, False,
    
            (('mode', 'ADD'), ('merge_type', 'MATH'),), "Merge Nodes (Math, Add)"),
    
        (NWMergeNodes.bl_idname, 'EQUAL', 'PRESS', True, True, False,
    
            (('mode', 'ADD'), ('merge_type', 'MATH'),), "Merge Nodes (Math, Add)"),
    
        (NWMergeNodes.bl_idname, 'NUMPAD_ASTERIX', 'PRESS', True, True, False,
    
            (('mode', 'MULTIPLY'), ('merge_type', 'MATH'),), "Merge Nodes (Math, Multiply)"),
    
        (NWMergeNodes.bl_idname, 'EIGHT', 'PRESS', True, True, False,
    
            (('mode', 'MULTIPLY'), ('merge_type', 'MATH'),), "Merge Nodes (Math, Multiply)"),
    
        (NWMergeNodes.bl_idname, 'NUMPAD_MINUS', 'PRESS', True, True, False,
    
            (('mode', 'SUBTRACT'), ('merge_type', 'MATH'),), "Merge Nodes (Math, Subtract)"),
    
        (NWMergeNodes.bl_idname, 'MINUS', 'PRESS', True, True, False,
    
            (('mode', 'SUBTRACT'), ('merge_type', 'MATH'),), "Merge Nodes (Math, Subtract)"),
    
        (NWMergeNodes.bl_idname, 'NUMPAD_SLASH', 'PRESS', True, True, False,
    
            (('mode', 'DIVIDE'), ('merge_type', 'MATH'),), "Merge Nodes (Math, Divide)"),
    
        (NWMergeNodes.bl_idname, 'SLASH', 'PRESS', True, True, False,
    
            (('mode', 'DIVIDE'), ('merge_type', 'MATH'),), "Merge Nodes (Math, Divide)"),
    
        (NWMergeNodes.bl_idname, 'COMMA', 'PRESS', True, True, False,
    
            (('mode', 'LESS_THAN'), ('merge_type', 'MATH'),), "Merge Nodes (Math, Less than)"),
    
        (NWMergeNodes.bl_idname, 'PERIOD', 'PRESS', True, True, False,
    
            (('mode', 'GREATER_THAN'), ('merge_type', 'MATH'),), "Merge Nodes (Math, Greater than)"),
    
        # BATCH CHANGE NODES
    
        # NWBatchChangeNodes with Alt
    
        (NWBatchChangeNodes.bl_idname, 'NUMPAD_0', 'PRESS', False, False, True,
    
            (('blend_type', 'MIX'), ('operation', 'CURRENT'),), "Batch change blend type (Mix)"),
    
        (NWBatchChangeNodes.bl_idname, 'ZERO', 'PRESS', False, False, True,
    
            (('blend_type', 'MIX'), ('operation', 'CURRENT'),), "Batch change blend type (Mix)"),
    
        (NWBatchChangeNodes.bl_idname, 'NUMPAD_PLUS', 'PRESS', False, False, True,
    
            (('blend_type', 'ADD'), ('operation', 'ADD'),), "Batch change blend type (Add)"),
    
        (NWBatchChangeNodes.bl_idname, 'EQUAL', 'PRESS', False, False, True,
    
            (('blend_type', 'ADD'), ('operation', 'ADD'),), "Batch change blend type (Add)"),
    
        (NWBatchChangeNodes.bl_idname, 'NUMPAD_ASTERIX', 'PRESS', False, False, True,
    
            (('blend_type', 'MULTIPLY'), ('operation', 'MULTIPLY'),), "Batch change blend type (Multiply)"),
    
        (NWBatchChangeNodes.bl_idname, 'EIGHT', 'PRESS', False, False, True,
    
            (('blend_type', 'MULTIPLY'), ('operation', 'MULTIPLY'),), "Batch change blend type (Multiply)"),
    
        (NWBatchChangeNodes.bl_idname, 'NUMPAD_MINUS', 'PRESS', False, False, True,
    
            (('blend_type', 'SUBTRACT'), ('operation', 'SUBTRACT'),), "Batch change blend type (Subtract)"),
    
        (NWBatchChangeNodes.bl_idname, 'MINUS', 'PRESS', False, False, True,
    
            (('blend_type', 'SUBTRACT'), ('operation', 'SUBTRACT'),), "Batch change blend type (Subtract)"),
    
        (NWBatchChangeNodes.bl_idname, 'NUMPAD_SLASH', 'PRESS', False, False, True,
    
            (('blend_type', 'DIVIDE'), ('operation', 'DIVIDE'),), "Batch change blend type (Divide)"),
    
        (NWBatchChangeNodes.bl_idname, 'SLASH', 'PRESS', False, False, True,
    
            (('blend_type', 'DIVIDE'), ('operation', 'DIVIDE'),), "Batch change blend type (Divide)"),
    
        (NWBatchChangeNodes.bl_idname, 'COMMA', 'PRESS', False, False, True,
    
            (('blend_type', 'CURRENT'), ('operation', 'LESS_THAN'),), "Batch change blend type (Current)"),
    
        (NWBatchChangeNodes.bl_idname, 'PERIOD', 'PRESS', False, False, True,
    
            (('blend_type', 'CURRENT'), ('operation', 'GREATER_THAN'),), "Batch change blend type (Current)"),
    
        (NWBatchChangeNodes.bl_idname, 'DOWN_ARROW', 'PRESS', False, False, True,
    
            (('blend_type', 'NEXT'), ('operation', 'NEXT'),), "Batch change blend type (Next)"),
    
        (NWBatchChangeNodes.bl_idname, 'UP_ARROW', 'PRESS', False, False, True,
    
            (('blend_type', 'PREV'), ('operation', 'PREV'),), "Batch change blend type (Previous)"),
    
        # LINK ACTIVE TO SELECTED
    
        # Don't use names, don't replace links (K)
    
        (NWLinkActiveToSelected.bl_idname, 'K', 'PRESS', False, False, False,
    
            (('replace', False), ('use_node_name', False), ('use_outputs_names', False),), "Link active to selected (Don't replace links)"),
    
        # Don't use names, replace links (Shift K)
    
        (NWLinkActiveToSelected.bl_idname, 'K', 'PRESS', False, True, False,
    
            (('replace', True), ('use_node_name', False), ('use_outputs_names', False),), "Link active to selected (Replace links)"),
    
        # Use node name, don't replace links (')
    
        (NWLinkActiveToSelected.bl_idname, 'QUOTE', 'PRESS', False, False, False,
    
            (('replace', False), ('use_node_name', True), ('use_outputs_names', False),), "Link active to selected (Don't replace links, node names)"),
        # Use node name, replace links (Shift ')
    
        (NWLinkActiveToSelected.bl_idname, 'QUOTE', 'PRESS', False, True, False,
    
            (('replace', True), ('use_node_name', True), ('use_outputs_names', False),), "Link active to selected (Replace links, node names)"),
        # Don't use names, don't replace links (;)
    
        (NWLinkActiveToSelected.bl_idname, 'SEMI_COLON', 'PRESS', False, False, False,
    
            (('replace', False), ('use_node_name', False), ('use_outputs_names', True),), "Link active to selected (Don't replace links, output names)"),
    
        # Don't use names, replace links (')
    
        (NWLinkActiveToSelected.bl_idname, 'SEMI_COLON', 'PRESS', False, True, False,
    
            (('replace', True), ('use_node_name', False), ('use_outputs_names', True),), "Link active to selected (Replace links, output names)"),
    
        # CHANGE MIX FACTOR
    
        (NWChangeMixFactor.bl_idname, 'LEFT_ARROW', 'PRESS', False, False, True, (('option', -0.1),), "Reduce Mix Factor by 0.1"),
        (NWChangeMixFactor.bl_idname, 'RIGHT_ARROW', 'PRESS', False, False, True, (('option', 0.1),), "Increase Mix Factor by 0.1"),
        (NWChangeMixFactor.bl_idname, 'LEFT_ARROW', 'PRESS', False, True, True, (('option', -0.01),), "Reduce Mix Factor by 0.01"),
        (NWChangeMixFactor.bl_idname, 'RIGHT_ARROW', 'PRESS', False, True, True, (('option', 0.01),), "Increase Mix Factor by 0.01"),
        (NWChangeMixFactor.bl_idname, 'LEFT_ARROW', 'PRESS', True, True, True, (('option', 0.0),), "Set Mix Factor to 0.0"),
        (NWChangeMixFactor.bl_idname, 'RIGHT_ARROW', 'PRESS', True, True, True, (('option', 1.0),), "Set Mix Factor to 1.0"),
        (NWChangeMixFactor.bl_idname, 'NUMPAD_0', 'PRESS', True, True, True, (('option', 0.0),), "Set Mix Factor to 0.0"),
        (NWChangeMixFactor.bl_idname, 'ZERO', 'PRESS', True, True, True, (('option', 0.0),), "Set Mix Factor to 0.0"),
        (NWChangeMixFactor.bl_idname, 'NUMPAD_1', 'PRESS', True, True, True, (('option', 1.0),), "Mix Factor to 1.0"),
        (NWChangeMixFactor.bl_idname, 'ONE', 'PRESS', True, True, True, (('option', 1.0),), "Set Mix Factor to 1.0"),
    
        # CLEAR LABEL (Alt L)
    
        (NWClearLabel.bl_idname, 'L', 'PRESS', False, False, True, (('option', False),), "Clear node labels"),
    
        # MODIFY LABEL (Alt Shift L)
    
        (NWModifyLabels.bl_idname, 'L', 'PRESS', False, True, True, None, "Modify node labels"),
    
        # Copy Label from active to selected
    
        (NWCopyLabel.bl_idname, 'V', 'PRESS', False, True, False, (('option', 'FROM_ACTIVE'),), "Copy label from active to selected"),
    
    Bartek Skorupa's avatar
    Bartek Skorupa committed
        # DETACH OUTPUTS (Alt Shift D)
    
        (NWDetachOutputs.bl_idname, 'D', 'PRESS', False, True, True, None, "Detach outputs"),
    
    Bartek Skorupa's avatar
    Bartek Skorupa committed
        # LINK TO OUTPUT NODE (O)
    
        (NWLinkToOutputNode.bl_idname, 'O', 'PRESS', False, False, False, None, "Link to output node"),
    
        # SELECT PARENT/CHILDREN
        # Select Children
    
        (NWSelectParentChildren.bl_idname, 'RIGHT_BRACKET', 'PRESS', False, False, False, (('option', 'CHILD'),), "Select children"),
    
        (NWSelectParentChildren.bl_idname, 'LEFT_BRACKET', 'PRESS', False, False, False, (('option', 'PARENT'),), "Select Parent"),
    
        (NWAddTextureSetup.bl_idname, 'T', 'PRESS', True, False, False, None, "Add texture setup"),
    
        # Add Principled BSDF Texture Setup
        (NWAddPrincipledSetup.bl_idname, 'T', 'PRESS', True, True, False, None, "Add Principled texture setup"),
    
        (NWResetBG.bl_idname, 'Z', 'PRESS', False, False, False, None, "Reset backdrop image zoom"),
    
        (NWDeleteUnused.bl_idname, 'X', 'PRESS', False, False, True, None, "Delete unused nodes"),
    
        (NWFrameSelected.bl_idname, 'P', 'PRESS', False, True, False, None, "Frame selected nodes"),
    
        (NWSwapLinks.bl_idname, 'S', 'PRESS', False, False, True, None, "Swap Outputs"),
    
        (NWPreviewNode.bl_idname, 'LEFTMOUSE', 'PRESS', True, True, False, (('run_in_geometry_nodes', False),), "Preview node output"),
        (NWPreviewNode.bl_idname, 'LEFTMOUSE', 'PRESS', False, True, True, (('run_in_geometry_nodes', True),), "Preview node output"),
    
        (NWReloadImages.bl_idname, 'R', 'PRESS', False, False, True, None, "Reload images"),
    
        (NWLazyMix.bl_idname, 'RIGHTMOUSE', 'PRESS', True, True, False, None, "Lazy Mix"),
    
        (NWLazyConnect.bl_idname, 'RIGHTMOUSE', 'PRESS', False, False, True, (('with_menu', False),), "Lazy Connect"),
    
        # Lazy Connect with Menu
    
        (NWLazyConnect.bl_idname, 'RIGHTMOUSE', 'PRESS', False, True, True, (('with_menu', True),), "Lazy Connect with Socket Menu"),
    
        # Viewer Tile Center
        (NWViewerFocus.bl_idname, 'LEFTMOUSE', 'DOUBLE_CLICK', False, False, False, None, "Set Viewers Tile Center"),
    
        # Align Nodes
        (NWAlignNodes.bl_idname, 'EQUAL', 'PRESS', False, True, False, None, "Align selected nodes neatly in a row/column"),
    
        # Reset Nodes (Back Space)
        (NWResetNodes.bl_idname, 'BACK_SPACE', 'PRESS', False, False, False, None, "Revert node back to default state, but keep connections"),
    
        ('wm.call_menu', 'W', 'PRESS', False, True, False, (('name', NodeWranglerMenu.bl_idname),), "Node Wrangler menu"),
    
        ('wm.call_menu', 'SLASH', 'PRESS', False, False, False, (('name', NWAddReroutesMenu.bl_idname),), "Add Reroutes menu"),
        ('wm.call_menu', 'NUMPAD_SLASH', 'PRESS', False, False, False, (('name', NWAddReroutesMenu.bl_idname),), "Add Reroutes menu"),
        ('wm.call_menu', 'BACK_SLASH', 'PRESS', False, False, False, (('name', NWLinkActiveToSelectedMenu.bl_idname),), "Link active to selected (menu)"),
        ('wm.call_menu', 'C', 'PRESS', False, True, False, (('name', NWCopyToSelectedMenu.bl_idname),), "Copy to selected (menu)"),
        ('wm.call_menu', 'S', 'PRESS', False, True, False, (('name', NWSwitchNodeTypeMenu.bl_idname),), "Switch node type menu"),
    
    classes = (
        NWPrincipledPreferences,
        NWNodeWrangler,
        NWLazyMix,
        NWLazyConnect,
        NWDeleteUnused,
        NWSwapLinks,
        NWResetBG,
        NWAddAttrNode,
    
        NWFrameSelected,
        NWReloadImages,
        NWSwitchNodeType,
        NWMergeNodes,
        NWBatchChangeNodes,
        NWChangeMixFactor,
        NWCopySettings,
        NWCopyLabel,
        NWClearLabel,
        NWModifyLabels,
        NWAddTextureSetup,
        NWAddPrincipledSetup,
        NWAddReroutes,
        NWLinkActiveToSelected,
        NWAlignNodes,
        NWSelectParentChildren,
        NWDetachOutputs,
        NWLinkToOutputNode,
        NWMakeLink,
        NWCallInputsMenu,
        NWAddSequence,
        NWAddMultipleImages,
        NWViewerFocus,
        NWSaveViewer,
        NWResetNodes,
        NodeWranglerPanel,
        NodeWranglerMenu,
        NWMergeNodesMenu,
        NWMergeShadersMenu,
    
        NWMergeGeometryMenu,
    
        NWMergeMixMenu,
        NWConnectionListOutputs,
        NWConnectionListInputs,
        NWMergeMathMenu,
        NWBatchChangeNodesMenu,
        NWBatchChangeBlendTypeMenu,
        NWBatchChangeOperationMenu,
        NWCopyToSelectedMenu,
        NWCopyLabelMenu,
        NWAddReroutesMenu,
        NWLinkActiveToSelectedMenu,
        NWLinkStandardMenu,
        NWLinkUseNodeNameMenu,
        NWLinkUseOutputsNamesMenu,
        NWVertColMenu,
        NWSwitchNodeTypeMenu,
        NWSwitchShadersInputSubmenu,
        NWSwitchShadersOutputSubmenu,
        NWSwitchShadersShaderSubmenu,
        NWSwitchShadersTextureSubmenu,
        NWSwitchShadersColorSubmenu,
        NWSwitchShadersVectorSubmenu,
        NWSwitchShadersConverterSubmenu,
        NWSwitchShadersLayoutSubmenu,
        NWSwitchCompoInputSubmenu,
        NWSwitchCompoOutputSubmenu,
        NWSwitchCompoColorSubmenu,
        NWSwitchCompoConverterSubmenu,
        NWSwitchCompoFilterSubmenu,
        NWSwitchCompoVectorSubmenu,
        NWSwitchCompoMatteSubmenu,
        NWSwitchCompoDistortSubmenu,
        NWSwitchCompoLayoutSubmenu,
        NWSwitchMatInputSubmenu,
        NWSwitchMatOutputSubmenu,
        NWSwitchMatColorSubmenu,
        NWSwitchMatVectorSubmenu,
        NWSwitchMatConverterSubmenu,
        NWSwitchMatLayoutSubmenu,
        NWSwitchTexInputSubmenu,
        NWSwitchTexOutputSubmenu,
        NWSwitchTexColorSubmenu,
        NWSwitchTexPatternSubmenu,
        NWSwitchTexTexturesSubmenu,
        NWSwitchTexConverterSubmenu,
        NWSwitchTexDistortSubmenu,
        NWSwitchTexLayoutSubmenu,
    )
    
    
        from bpy.utils import register_class
    
    
        # props
        bpy.types.Scene.NWBusyDrawing = StringProperty(
            name="Busy Drawing!",
            default="",
            description="An internal property used to store only the first mouse position")
    
        bpy.types.Scene.NWLazySource = StringProperty(
            name="Lazy Source!",
            default="x",
            description="An internal property used to store the first node in a Lazy Connect operation")
        bpy.types.Scene.NWLazyTarget = StringProperty(
            name="Lazy Target!",
    
            description="An internal property used to store the last node in a Lazy Connect operation")
        bpy.types.Scene.NWSourceSocket = IntProperty(
            name="Source Socket!",
            default=0,
            description="An internal property used to store the source socket in a Lazy Connect operation")
    
        bpy.types.NodeSocketInterface.NWViewerSocket = BoolProperty(
            name="NW Socket",
            default=False,
            description="An internal property used to determine if a socket is generated by the addon"
        )
    
        for cls in classes:
            register_class(cls)
    
        addon_keymaps.clear()
        kc = bpy.context.window_manager.keyconfigs.addon
        if kc:
            km = kc.keymaps.new(name='Node Editor', space_type="NODE_EDITOR")
    
            for (identifier, key, action, CTRL, SHIFT, ALT, props, nicename) in kmi_defs:
                kmi = km.keymap_items.new(identifier, key, action, 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)
    
        bpy.types.NODE_MT_category_SH_NEW_INPUT.prepend(attr_nodes_menu_func)
        bpy.types.NODE_PT_backdrop.append(bgreset_menu_func)
    
        bpy.types.NODE_PT_active_node_generic.append(save_viewer_menu_func)
    
        bpy.types.NODE_MT_category_SH_NEW_TEXTURE.prepend(multipleimages_menu_func)
        bpy.types.NODE_MT_category_CMP_INPUT.prepend(multipleimages_menu_func)
    
        bpy.types.NODE_PT_active_node_generic.prepend(reset_nodes_button)
        bpy.types.NODE_MT_node.prepend(reset_nodes_button)
    
        # switch submenus
        switch_category_menus.clear()
        for cat in node_categories_iter(None):
            if cat.name not in ['Group', 'Script'] and cat.identifier.startswith('GEO'):
                idname = f"NODE_MT_nw_switch_{cat.identifier}_submenu"
                switch_category_type = type(idname, (bpy.types.Menu,), {
                    "bl_space_type": 'NODE_EDITOR',
                    "bl_label": cat.name,
                    "category": cat,
                    "poll": cat.poll,
                    "draw": draw_switch_category_submenu,
                })
    
                switch_category_menus.append(switch_category_type)
    
                bpy.utils.register_class(switch_category_type)
    
    
        from bpy.utils import unregister_class
    
    
        # props
        del bpy.types.Scene.NWBusyDrawing
    
        del bpy.types.Scene.NWLazySource
        del bpy.types.Scene.NWLazyTarget
        del bpy.types.Scene.NWSourceSocket
    
        del bpy.types.NodeSocketInterface.NWViewerSocket
    
        for cat_types in switch_category_menus:
            bpy.utils.unregister_class(cat_types)
        switch_category_menus.clear()
    
    
        for km, kmi in addon_keymaps:
            km.keymap_items.remove(kmi)
        addon_keymaps.clear()
    
    
        # menuitems
        bpy.types.NODE_MT_select.remove(select_parent_children_buttons)
        bpy.types.NODE_MT_category_SH_NEW_INPUT.remove(attr_nodes_menu_func)
        bpy.types.NODE_PT_backdrop.remove(bgreset_menu_func)
    
        bpy.types.NODE_PT_active_node_generic.remove(save_viewer_menu_func)
    
        bpy.types.NODE_MT_category_SH_NEW_TEXTURE.remove(multipleimages_menu_func)
        bpy.types.NODE_MT_category_CMP_INPUT.remove(multipleimages_menu_func)
    
        bpy.types.NODE_PT_active_node_generic.remove(reset_nodes_button)
        bpy.types.NODE_MT_node.remove(reset_nodes_button)
    
        for cls in classes:
            unregister_class(cls)
    
    if __name__ == "__main__":