Explorar o código

Operators tfor making bulk connections

Select All Nodes of Type selects all nodes sharing the same type (and tree, for node groups). ConnectNodeToInput connects a Node Group Input to all sockets in selected nodes if possible.
This is not optimized, and could be sped up by recording and using the indices of the node sockets, but this is safe and much faster than doing it by hand
Joseph Brandenburg hai 8 meses
pai
achega
e095cd348b
Modificáronse 3 ficheiros con 114 adicións e 6 borrados
  1. 1 1
      __init__.py
  2. 1 1
      blender_manifest.toml
  3. 112 4
      ops_nodegroup.py

+ 1 - 1
__init__.py

@@ -17,7 +17,7 @@ from .utilities import prRed
 
 MANTIS_VERSION_MAJOR=0
 MANTIS_VERSION_MINOR=9
-MANTIS_VERSION_SUB=8
+MANTIS_VERSION_SUB=9
 
 
 classLists = [module.TellClasses() for module in [

+ 1 - 1
blender_manifest.toml

@@ -3,7 +3,7 @@ schema_version = "1.0.0"
 # Example of manifest file for a Blender extension
 # Change the values according to your extension
 id = "mantis"
-version = "0.9.8"
+version = "0.9.9"
 name = "Mantis"
 tagline = "Mantis is a rigging nodes toolkit"
 maintainer = "Nodespaghetti <josephbburg@protonmail.com>"

+ 112 - 4
ops_nodegroup.py

@@ -17,6 +17,8 @@ def TellClasses():
         ForceDisplayUpdate,
         CleanUpNodeGraph,
         MantisMuteNode,
+        SelectNodesOfType,
+        ConnectNodeToInput,
         # xForm
         AddCustomProperty,
         EditCustomProperty,
@@ -39,6 +41,11 @@ def mantis_tree_poll_op(context):
             return (space.tree_type in ["MantisTree", "SchemaTree"])
     return False
 
+def any_tree_poll(context):
+    space = context.space_data
+    if hasattr(space, "node_tree"):
+        return True
+    return False
 
 #########################################################################3
 
@@ -223,21 +230,122 @@ class ExecuteNodeTree(Operator):
         prGreen("Finished executing tree in %f seconds" % (time() - start_time))
         return {"FINISHED"}
 
+
+class SelectNodesOfType(Operator):
+    """Selects all nodes of same type as active node."""
+    bl_idname = "mantis.select_nodes_of_type"
+    bl_label = "Select Nodes of Same Type as Active"
+    bl_options = {'REGISTER', 'UNDO'}
+
+    @classmethod
+    def poll(cls, context):
+        return (any_tree_poll(context))
+
+    def execute(self, context):
+        active_node = context.active_node
+        tree = active_node.id_data
+        if not hasattr(active_node, "node_tree"):
+            for node in tree.nodes:
+                node.select = (active_node.bl_idname == node.bl_idname)
+        else:
+            for node in tree.nodes:
+                node.select = (active_node.bl_idname == node.bl_idname) and (active_node.node_tree == node.node_tree)
+
+        return {"FINISHED"}
+
+
+def get_parent_tree_interface_enum(operator, context):
+    ret = []; i = -1
+    tree = bpy.data.node_groups[operator.tree_invoked]
+    for sock in tree.interface.items_tree:
+        if sock.item_type == 'PANEL': continue
+        if sock.in_out == "OUTPUT": continue
+        ret.append( (sock.identifier, sock.name, "Socket from Node Group Input", i := i + 1), )
+    return ret
+
+def get_node_inputs_enum(operator, context):
+    ret = []; i = -1
+    n = bpy.data.node_groups[operator.tree_invoked].nodes[operator.node_invoked]
+    for inp in n.inputs:
+        ret.append( (inp.identifier, inp.name, "Socket of node to connect to.", i := i + 1), )
+    return ret
+
+class ConnectNodeToInput(Operator):
+    """Connects a Node Group Input socket to specified socket of active node and all selected same-type nodes."""
+    bl_idname = "mantis.connect_nodes_to_input"
+    bl_label = "Connect Socket to Input for Selected Nodes"
+    bl_options = {'REGISTER', 'UNDO'}
+
+    group_output : bpy.props.EnumProperty(
+        items=get_parent_tree_interface_enum,
+        name="Node Group Input Socket",
+        description="Select which socket from the Node Group Input to connect to this node",)
+    node_input : bpy.props.EnumProperty(
+        items=get_node_inputs_enum,
+        name="Node Input Socket",
+        description="Select which of this node's sockets to recieve the connection",)
+    tree_invoked : bpy.props.StringProperty(options ={'HIDDEN'})
+    node_invoked : bpy.props.StringProperty(options ={'HIDDEN'})
+
+    @classmethod
+    def poll(cls, context):
+        return (any_tree_poll(context))
+
+    def invoke(self, context, event):
+        self.tree_invoked = context.active_node.id_data.name
+        self.node_invoked = context.active_node.name
+        # we use active_node here ^ because we are comparing the active node to the selection.
+        wm = context.window_manager
+        return wm.invoke_props_dialog(self)
+    
+    def execute(self, context):
+        t = bpy.data.node_groups[self.tree_invoked]
+        if hasattr(t, "is_executing"): # for Mantis trees, but this function should just work anywhere.
+            t.is_executing = True
+        n = t.nodes[self.node_invoked]
+        for node in t.nodes:
+            if n.bl_idname == node.bl_idname and node.select:
+                # the bl_idname is the same so they both have node_tree
+                if hasattr(n, "node_tree") and n.node_tree != node.node_tree: continue
+                # TODO: maybe I should try and find a nearby input node and reuse it
+                # doing these identifier lookups again and again is slow, whatever. faster than doing it by hand
+                for connect_to_me in node.inputs:
+                    if connect_to_me.identifier == self.node_input: break
+                if connect_to_me.is_linked: connect_to_me = None
+                if connect_to_me: # only make the node if the socket is there and free
+                    inp = t.nodes.new("NodeGroupInput")
+                    connect_me = None
+                    for s in inp.outputs:
+                        if s.identifier != self.group_output: s.hide = True
+                        else: connect_me = s
+                        inp.location = node.location
+                        inp.location.x-=200
+                    t.links.new(input=connect_me, output=connect_to_me)
+
+        if hasattr(t, "is_executing"):
+            t.is_executing = False
+        return {"FINISHED"}
+
+
 class QueryNodeSockets(Operator):
     """Utility Operator for querying the data in a socket"""
     bl_idname = "mantis.query_sockets"
     bl_label = "Query Node Sockets"
     bl_options = {'REGISTER', 'UNDO'}
 
+
+
     @classmethod
     def poll(cls, context):
         return (mantis_tree_poll_op(context))
 
     def execute(self, context):
-        node = context.active_node
-        print ("Node type: ", node.bl_idname)
-        
-        # This is useful. Todo: reimplement this eventually.
+        active_node = context.active_node
+        tree = active_node.id_data
+        for node in tree.nodes:
+            if not node.select: continue
+
+
         
         return {"FINISHED"}