ソースを参照

Cleanup: Remove Lots of Boilerplate

Using better OOP to make my node classes much simpler and cleaner
now every node uses socket templates and class methods set up
mantis class at register-time
Joseph Brandenburg 1 ヶ月 前
親
コミット
7b2204669c
9 ファイル変更、274 行追加、623 行削除
  1. 54 22
      base_definitions.py
  2. 13 37
      deformer_nodes_ui.py
  3. 44 149
      link_nodes_ui.py
  4. 7 23
      math_nodes_ui.py
  5. 132 302
      misc_nodes_ui.py
  6. 6 20
      primitives_nodes_ui.py
  7. 10 0
      primitives_sockets.py
  8. 2 8
      schema_nodes_ui.py
  9. 6 62
      xForm_nodes_ui.py

+ 54 - 22
base_definitions.py

@@ -215,6 +215,15 @@ class SchemaTree(NodeTree):
 
 #TODO: do a better job explaining how MantisNode and MantisUINode relate.
 
+# TODO: I want to avoid doing any kind of class mutation at runtime
+#       so in the future I will try to do this directly rather than
+#       running this function once for each class while registering
+#       however this is not very important for UI classes since they
+#       are not a performance bottleneck.
+def mantis_class_from_library(library, class_name):
+    from importlib import import_module
+    return getattr(import_module(library, package=mantis_root), class_name)
+
 class MantisUINode:
     """
         This class contains the common user-interface features of Mantis nodes.
@@ -225,23 +234,17 @@ class MantisUINode:
     bl_icon = 'NODE'
     initialized : bpy.props.BoolProperty(default = False)
     #
-    mantis_node_library=''
     mantis_node_class_name=''
     mantis_class=None
+    socket_templates=None
+
     @classmethod
     def poll(cls, ntree):
         return (ntree.bl_idname in ['MantisTree', 'SchemaTree'])
 
-    @classmethod
-    def set_mantis_class(self):
-        from importlib import import_module
-        # do not catch errors, they should cause a failure.
-        try:
-            module = import_module(self.mantis_node_library, package=mantis_root)
-            self.mantis_class=getattr(module, self.mantis_node_class_name)
-        except Exception as e:
-            print(self)
-            raise e
+    def init(self, context):
+        self.init_sockets(self.socket_templates)
+        self.initialized = True
 
     def insert_link(self, link):
         if (bpy.app.version >= (4, 4, 0)):
@@ -286,30 +289,59 @@ class MantisUINode:
             if template.use_multi_input: # this is an array
                 socket.display_shape = 'SQUARE_DOT'
 
+# NOTE
+# MantisUINode has no proper mantis libraryclass on its own, so:
+# register()'s are in SUBclasses; they have to run AFTER library is defined
+
 class SchemaUINode(MantisUINode):
-    mantis_node_library='.schema_nodes'
     is_updating:BoolProperty(default=False)
     @classmethod
-    def poll(cls, ntree):
-        return (ntree.bl_idname in ['SchemaTree'])
+    def register(cls):
+        cls.mantis_class = mantis_class_from_library('.schema_nodes', cls.mantis_node_class_name)
 
 class LinkNode(MantisUINode):
     mantis_node_library='.link_nodes'
+    category_color=[0.5,0.5,0.5]
     @classmethod
-    def poll(cls, ntree):
-        return (ntree.bl_idname in ['MantisTree', 'SchemaTree'])
+    def register(cls):
+        cls.mantis_class = mantis_class_from_library('.link_nodes', cls.mantis_node_class_name)
+    def init(self, context):
+        super().init(context)
+        self.use_custom_color = True
+        self.color = self.category_color
 
 class xFormNode(MantisUINode):
-    mantis_node_library='.xForm_nodes'
     @classmethod
-    def poll(cls, ntree):
-        return (ntree.bl_idname in ['MantisTree', 'SchemaTree'])
+    def register(cls):
+        print (cls.__name__, cls.mantis_node_class_name)
+        cls.mantis_class = mantis_class_from_library('.xForm_nodes', cls.mantis_node_class_name)
+    def init(self, context):
+        super().init(context)
+        from mathutils import Color
+        xFormColor = Color((0.093172, 0.047735, 0.028036)).from_scene_linear_to_srgb()
+        self.use_custom_color = True
+        self.color = xFormColor # must not have alpha
 
 class DeformerNode(MantisUINode):
-    mantis_node_library='.deformer_nodes'
     @classmethod
-    def poll(cls, ntree):
-        return (ntree.bl_idname in ['MantisTree', 'SchemaTree'])
+    def register(cls):
+        cls.mantis_class = mantis_class_from_library('.deformer_nodes', cls.mantis_node_class_name)
+
+class GeometryPrimitiveNode(MantisUINode):
+    @classmethod
+    def register(cls):
+        cls.mantis_class = mantis_class_from_library('.primitives_nodes', cls.mantis_node_class_name)
+
+class MantisMiscNode(MantisUINode):
+    @classmethod
+    def register(cls):
+        cls.mantis_class = mantis_class_from_library('.misc_nodes', cls.mantis_node_class_name)
+
+class MantisMathUINode(MantisUINode):
+    @classmethod
+    def register(cls):
+        cls.mantis_class = mantis_class_from_library('.math_nodes', cls.mantis_node_class_name)
+
 
 def poll_node_tree(self, object):
     forbid = []

+ 13 - 37
deformer_nodes_ui.py

@@ -35,10 +35,7 @@ class DeformerArmatureNode(Node, DeformerNode):
     bl_icon = 'MOD_ARMATURE'
     initialized : bpy.props.BoolProperty(default = False)
     mantis_node_class_name=bl_idname
-
-    def init(self, context):
-        self.init_sockets(DeformArmatureSockets)
-        self.initialized = True
+    socket_templates = DeformArmatureSockets
     
     def display_update(self, parsed_tree, context):
         self.inputs["Copy Skin Weights From"].hide = True
@@ -55,10 +52,7 @@ class DeformerHook(Node, DeformerNode):
     bl_icon = 'HOOK'
     initialized : bpy.props.BoolProperty(default = False)
     mantis_node_class_name=bl_idname
-
-    def init(self, context):
-        self.init_sockets(HookSockets)
-        self.initialized = True
+    socket_templates = HookSockets
     
     def display_update(self, parsed_tree, context):
         curve_sockets = [
@@ -81,6 +75,7 @@ class DeformerHook(Node, DeformerNode):
 from .utilities import get_socket_maps, relink_socket_map
 
 # TODO this should probably not be in this file but intstead in Utilities or something
+# NOTE this is a re-implementation that I had to do here.
 def simple_do_relink(node, map, in_out='INPUT'):
     from bpy.types import NodeSocket
     for key, val in map.items():
@@ -116,13 +111,14 @@ class DeformerMorphTargetDeform(Node, DeformerNode):
     initialized : bpy.props.BoolProperty(default = False)
     num_targets : bpy.props.IntProperty(default = 0)
     mantis_node_class_name=bl_idname
-
+    socket_templates = MorphTargetDeformSockets
 
     def init(self, context):
+        live_updates = self.id_data.do_live_update
         self.id_data.do_live_update = False
         self.init_sockets(MorphTargetDeformSockets)
         self.update_morph_deformer()
-        self.id_data.do_live_update = True
+        self.id_data.do_live_update = live_updates
 
     def update_morph_deformer(self, force=False):
         self.initialized = False
@@ -185,11 +181,7 @@ class DeformerMorphTarget(Node, DeformerNode):
     initialized : bpy.props.BoolProperty(default = False)
     num_targets : bpy.props.IntProperty(default = 0)
     mantis_node_class_name=bl_idname
-
-    def init(self, context):
-        self.init_sockets(MorphTargetSockets)
-        self.initialized = True
-
+    socket_templates = MorphTargetSockets
 
 class DeformerSurfaceDeform(Node, DeformerNode):
     '''A node representing a Surface Deform modifier'''
@@ -199,10 +191,7 @@ class DeformerSurfaceDeform(Node, DeformerNode):
     initialized : bpy.props.BoolProperty(default = False)
     num_targets : bpy.props.IntProperty(default = 0)
     mantis_node_class_name=bl_idname
-
-    def init(self, context):
-        self.init_sockets(SurfaceDeformSockets)
-        self.initialized = True
+    socket_templates = SurfaceDeformSockets
 
 class DeformerMeshDeform(Node, DeformerNode):
     '''A node representing a Mesh Deform modifier'''
@@ -212,10 +201,7 @@ class DeformerMeshDeform(Node, DeformerNode):
     initialized : bpy.props.BoolProperty(default = False)
     num_targets : bpy.props.IntProperty(default = 0)
     mantis_node_class_name=bl_idname
-
-    def init(self, context):
-        self.init_sockets(MeshDeformSockets)
-        self.initialized = True
+    socket_templates = MeshDeformSockets
 
 class DeformerLatticeDeform(Node, DeformerNode):
     '''A node representing a Lattice Deformer'''
@@ -225,10 +211,7 @@ class DeformerLatticeDeform(Node, DeformerNode):
     initialized : bpy.props.BoolProperty(default = False)
     num_targets : bpy.props.IntProperty(default = 0)
     mantis_node_class_name=bl_idname
-
-    def init(self, context):
-        self.init_sockets(LatticeDeformSockets)
-        self.initialized = True
+    socket_templates = LatticeDeformSockets
 
 class DeformerSmoothCorrectiveDeform(Node, DeformerNode):
     '''A node representing a Corrective Smooth Deformer'''
@@ -238,20 +221,13 @@ class DeformerSmoothCorrectiveDeform(Node, DeformerNode):
     initialized : bpy.props.BoolProperty(default = False)
     num_targets : bpy.props.IntProperty(default = 0)
     mantis_node_class_name=bl_idname
-
-    def init(self, context):
-        self.init_sockets(SmoothDeformSockets)
-        self.initialized = True
+    socket_templates = SmoothDeformSockets
 
     def display_update(self, parsed_tree, context):
         use_corrective_smooth = self.inputs["Use Corrective Smooth"]
         if ( use_corrective_smooth.is_linked or 
              use_corrective_smooth.default_value == False): # this is inverted
-                    self.inputs['Corrective Smooth Scale'].hide = False
+                self.inputs['Corrective Smooth Scale'].hide = False
         else:
-                    self.inputs['Corrective Smooth Scale'].hide = True
-
+                self.inputs['Corrective Smooth Scale'].hide = True
 
-# Set up the class property that ties the UI classes to the Mantis classes.
-for cls in TellClasses():
-    cls.set_mantis_class()

+ 44 - 149
link_nodes_ui.py

@@ -52,12 +52,8 @@ class LinkInheritNode(Node, LinkNode):
     bl_icon = 'CONSTRAINT_BONE'
     initialized : bpy.props.BoolProperty(default = False)
     mantis_node_class_name="LinkInherit"
-
-    def init(self, context):
-        self.init_sockets(LinkInheritSockets)
-        self.initialized = True
-        self.use_custom_color = True
-        self.color = inheritColor
+    socket_templates = LinkInheritSockets
+    category_color=inheritColor
 
     def display_update(self, parsed_tree, context):
         node_tree = context.space_data.path[0].node_tree
@@ -98,13 +94,8 @@ class LinkInverseKinematics(Node, LinkNode):
     bl_icon = 'CON_KINEMATIC'
     initialized : bpy.props.BoolProperty(default = False)
     mantis_node_class_name=bl_idname
-
-    def init(self, context):
-        self.init_sockets(LinkInverseKinematicsSockets)
-        self.initialized = True
-        self.use_custom_color = True
-        self.color = ikColor
-
+    category_color=linkTransformColor
+    socket_templates = LinkInverseKinematicsSockets
 
 class LinkCopyLocationNode(Node, LinkNode):
     '''A node representing Copy Location'''
@@ -113,13 +104,8 @@ class LinkCopyLocationNode(Node, LinkNode):
     bl_icon = 'CON_LOCLIKE'
     initialized : bpy.props.BoolProperty(default = False)
     mantis_node_class_name=bl_idname
-
-    def init(self, context):
-        self.init_sockets(LinkCopyLocationSockets)
-        self.use_custom_color = True
-        self.color = linkTransformColor
-        self.initialized = True
-
+    category_color=linkTransformColor
+    socket_templates = LinkCopyLocationSockets
 
 class LinkCopyRotationNode(Node, LinkNode):
     '''A node representing Copy Rotation'''
@@ -128,14 +114,8 @@ class LinkCopyRotationNode(Node, LinkNode):
     bl_icon = 'CON_ROTLIKE'
     initialized : bpy.props.BoolProperty(default = False)
     mantis_node_class_name=bl_idname
-
-    def init(self, context):
-        self.init_sockets(LinkCopyRotationSockets)
-        self.use_custom_color = True
-        self.color = linkTransformColor
-        self.initialized = True
-
-
+    category_color=linkTransformColor
+    socket_templates = LinkCopyRotationSockets
 
 class LinkCopyScaleNode(Node, LinkNode):
     '''A node representing Copy Scale'''
@@ -144,14 +124,8 @@ class LinkCopyScaleNode(Node, LinkNode):
     bl_icon = 'CON_SIZELIKE'
     initialized : bpy.props.BoolProperty(default = False)
     mantis_node_class_name=bl_idname
-
-    def init(self, context):
-        self.init_sockets(LinkCopyScaleSockets)
-        self.use_custom_color = True
-        self.color = linkTransformColor
-        self.initialized = True
-
-
+    category_color=linkTransformColor
+    socket_templates = LinkCopyScaleSockets
 
 class LinkInheritConstraintNode(Node, LinkNode):
     # === Basics ===
@@ -162,13 +136,8 @@ class LinkInheritConstraintNode(Node, LinkNode):
     bl_icon = 'CON_CHILDOF'
     initialized : bpy.props.BoolProperty(default = False)
     mantis_node_class_name=bl_idname
-
-    # === Optional Functions ===
-    def init(self, context):
-        self.init_sockets(LinkInheritConstraintSockets)
-        self.use_custom_color = True
-        self.color = inheritColor
-        self.initialized = True
+    category_color=inheritColor
+    socket_templates = LinkInheritConstraintSockets
 
 class LinkCopyTransformNode(Node, LinkNode):
     # === Basics ===
@@ -179,15 +148,8 @@ class LinkCopyTransformNode(Node, LinkNode):
     bl_icon = 'CON_TRANSLIKE'
     initialized : bpy.props.BoolProperty(default = False)
     mantis_node_class_name=bl_idname
-
-    # === Optional Functions ===
-    def init(self, context):
-        self.init_sockets(LinkCopyTransformsSockets)
-        self.use_custom_color = True
-        self.color = linkTransformColor
-        self.initialized = True
-
-
+    category_color=linkTransformColor
+    socket_templates = LinkCopyTransformsSockets
 
 class LinkStretchToNode(Node, LinkNode):
     '''A node representing Stretch-To'''
@@ -196,12 +158,8 @@ class LinkStretchToNode(Node, LinkNode):
     bl_icon = 'CON_STRETCHTO'
     initialized : bpy.props.BoolProperty(default = False)
     mantis_node_class_name=bl_idname
-
-    def init(self, context):
-        self.init_sockets(LinkStretchToSockets)
-        self.initialized = True
-        self.use_custom_color = True
-        self.color = trackingColor
+    category_color=trackingColor
+    socket_templates = LinkStretchToSockets
 
 class LinkDampedTrackNode(Node, LinkNode):
     '''A node representing Stretch-To'''
@@ -210,12 +168,8 @@ class LinkDampedTrackNode(Node, LinkNode):
     bl_icon = 'CON_TRACKTO'
     initialized : bpy.props.BoolProperty(default = False)
     mantis_node_class_name=bl_idname
-
-    def init(self, context):
-        self.init_sockets(LinkDampedTrackSockets)
-        self.initialized = True
-        self.use_custom_color = True
-        self.color = trackingColor
+    category_color=trackingColor
+    socket_templates = LinkDampedTrackSockets
 
 class LinkLockedTrackNode(Node, LinkNode):
     '''A node representing Stretch-To'''
@@ -224,12 +178,8 @@ class LinkLockedTrackNode(Node, LinkNode):
     bl_icon = 'CON_LOCKTRACK'
     initialized : bpy.props.BoolProperty(default = False)
     mantis_node_class_name=bl_idname
-
-    def init(self, context):
-        self.init_sockets(LinkLockedTrackSockets)
-        self.initialized = True
-        self.use_custom_color = True
-        self.color = trackingColor
+    category_color=trackingColor
+    socket_templates = LinkLockedTrackSockets
 
 class LinkTrackToNode(Node, LinkNode):
     '''A node representing Stretch-To'''
@@ -238,12 +188,8 @@ class LinkTrackToNode(Node, LinkNode):
     bl_icon = 'CON_TRACKTO'
     initialized : bpy.props.BoolProperty(default = False)
     mantis_node_class_name=bl_idname
-
-    def init(self, context):
-        self.init_sockets(LinkTrackToSockets)
-        self.initialized = True
-        self.use_custom_color = True
-        self.color = trackingColor
+    category_color=trackingColor
+    socket_templates = LinkTrackToSockets
 
 class LinkLimitLocationNode(Node, LinkNode):
     '''A node representing Limit Location'''
@@ -252,12 +198,8 @@ class LinkLimitLocationNode(Node, LinkNode):
     bl_icon = 'CON_LOCLIMIT'
     mantis_node_class_name=bl_idname
     initialized : bpy.props.BoolProperty(default = False)
-
-    def init(self, context):
-        self.init_sockets(LinkLimitLocationScaleSockets)
-        self.initialized = True
-        self.use_custom_color = True
-        self.color = linkTransformColor
+    category_color=linkTransformColor
+    socket_templates = LinkLimitLocationScaleSockets
 
 class LinkLimitScaleNode(Node, LinkNode):
     '''A node representing Limit Scale'''
@@ -266,12 +208,8 @@ class LinkLimitScaleNode(Node, LinkNode):
     bl_icon = 'CON_SIZELIMIT'
     initialized : bpy.props.BoolProperty(default = False)
     mantis_node_class_name=bl_idname
-
-    def init(self, context):
-        self.init_sockets(LinkLimitLocationScaleSockets)
-        self.initialized = True
-        self.use_custom_color = True
-        self.color = linkTransformColor
+    category_color=linkTransformColor
+    socket_templates = LinkLimitLocationScaleSockets
 
 class LinkLimitRotationNode(Node, LinkNode):
     '''A node representing Limit Rotation'''
@@ -280,13 +218,8 @@ class LinkLimitRotationNode(Node, LinkNode):
     bl_icon = 'CON_ROTLIMIT'
     initialized : bpy.props.BoolProperty(default = False)
     mantis_node_class_name=bl_idname
-
-    def init(self, context):
-        self.init_sockets(LinkLimitRotationSockets)
-        self.initialized = True
-        # color
-        self.use_custom_color = True
-        self.color = linkTransformColor
+    category_color=linkTransformColor
+    socket_templates = LinkLimitRotationSockets
 
 class LinkLimitDistanceNode(Node, LinkNode):
     '''A node representing Limit Distance'''
@@ -295,13 +228,8 @@ class LinkLimitDistanceNode(Node, LinkNode):
     bl_icon = 'CON_DISTLIMIT'
     initialized : bpy.props.BoolProperty(default = False)
     mantis_node_class_name=bl_idname
-
-    def init(self, context):
-        self.init_sockets(LinkLimitDistanceSockets)
-        self.use_custom_color = True
-        self.color = linkTransformColor
-        self.initialized = True
-
+    category_color=linkTransformColor
+    socket_templates = LinkLimitDistanceSockets
 
 class LinkTransformationNode(Node, LinkNode):
     '''A node representing Transformation (Constraint)'''
@@ -310,12 +238,8 @@ class LinkTransformationNode(Node, LinkNode):
     bl_icon = 'CON_TRANSFORM'
     initialized : bpy.props.BoolProperty(default = False)
     mantis_node_class_name=bl_idname
-
-    def init(self, context):
-        self.init_sockets(LinkTransformationSockets)
-        self.use_custom_color = True
-        self.color = linkTransformColor
-        self.initialized = True
+    category_color=linkTransformColor
+    socket_templates = LinkTransformationSockets
 
     def display_update(self, parsed_tree, context):
         node_tree = context.space_data.path[0].node_tree
@@ -348,12 +272,8 @@ class LinkArmatureNode(Node, LinkNode):
     bl_icon = "CON_ARMATURE"
     initialized : bpy.props.BoolProperty(default = False)
     mantis_node_class_name=bl_idname
-
-    def init(self, context):
-        self.init_sockets(LinkArmatureSockets)
-        self.use_custom_color = True
-        self.color = inheritColor
-        self.initialized = True
+    category_color=inheritColor
+    socket_templates = LinkArmatureSockets
 
     def draw_buttons(self, context, layout):
         # return
@@ -370,12 +290,8 @@ class LinkSplineIKNode(Node, LinkNode):
     bl_icon = "CON_SPLINEIK"
     initialized : bpy.props.BoolProperty(default = False)
     mantis_node_class_name=bl_idname
-
-    def init(self, context):
-        self.init_sockets(LinkSplineIKSockets)
-        self.use_custom_color = True
-        self.color = ikColor
-        self.initialized = True
+    category_color=ikColor
+    socket_templates = LinkSplineIKSockets
 
 class LinkFloorNode(Node, LinkNode):
     """A node representing Blender's Floor Constraint"""
@@ -384,12 +300,8 @@ class LinkFloorNode(Node, LinkNode):
     bl_icon = "CON_FLOOR"
     initialized : bpy.props.BoolProperty(default = False)
     mantis_node_class_name=bl_idname
-
-    def init(self, context):
-        self.init_sockets(LinkFloorSockets)
-        self.use_custom_color = True
-        self.color = linkTransformColor
-        self.initialized = True
+    category_color=linkTransformColor
+    socket_templates = LinkFloorSockets
 
 class LinkShrinkWrapNode(Node, LinkNode):
     """A node representing Blender's Shrinkwrap Constraint"""
@@ -398,12 +310,8 @@ class LinkShrinkWrapNode(Node, LinkNode):
     bl_icon = "CON_SHRINKWRAP"
     initialized : bpy.props.BoolProperty(default = False)
     mantis_node_class_name=bl_idname
-
-    def init(self, context):
-        self.init_sockets(LinkShrinkWrapSockets)
-        self.use_custom_color = True
-        self.color = trackingColor
-        self.initialized = True
+    category_color=trackingColor
+    socket_templates = LinkShrinkWrapSockets
 
     def display_update(self, parsed_tree, context):
         # vast majority of the time user doesn't link this.
@@ -445,12 +353,8 @@ class LinkGeometryAttribute(Node, LinkNode):
         bl_icon = "ERROR"
     initialized : bpy.props.BoolProperty(default = False)
     mantis_node_class_name=bl_idname
-
-    def init(self, context):
-        self.init_sockets(LinkGeometryAttributeSockets)
-        self.use_custom_color = True
-        self.color = linkTransformColor
-        self.initialized = True
+    category_color=linkTransformColor
+    socket_templates = LinkGeometryAttributeSockets
     
     def draw_label(self):
         if bpy.app.version < (5,0,0):
@@ -465,7 +369,6 @@ class LinkGeometryAttribute(Node, LinkNode):
         elif self.color != linkTransformColor:
             self.color = linkTransformColor
 
-
     def display_update(self, parsed_tree, context):
         if bpy.app.version < (5,0,0):
             return
@@ -487,13 +390,5 @@ class LinkDrivenParameterNode(Node, LinkNode):
     bl_icon = "CONSTRAINT_BONE"
     initialized : bpy.props.BoolProperty(default = False)
     mantis_node_class_name=bl_idname
-
-    def init(self, context):
-        self.init_sockets(LinkDrivenParameterSockets)
-        self.use_custom_color = True
-        self.color = linkTransformColor
-        self.initialized = True
-
-# Set up the class property that ties the UI classes to the Mantis classes.
-for cls in TellClasses():
-    cls.set_mantis_class()
+    category_color=linkTransformColor
+    socket_templates = LinkDrivenParameterSockets

+ 7 - 23
math_nodes_ui.py

@@ -1,5 +1,5 @@
 import bpy
-from .base_definitions import MantisUINode
+from .base_definitions import MantisMathUINode
 from bpy.types import Node
 from .utilities import (prRed, prGreen, prPurple, prWhite,
                               prOrange,
@@ -16,19 +16,14 @@ def TellClasses():
      MathStaticVectorNode,
     ]
 
-
-class MathStaticInt(Node, MantisUINode):
+class MathStaticInt(Node, MantisMathUINode):
     """A node that performs mathematical operations on float numbers as a preprocess step before generating the rig."""
     bl_idname = "MathStaticInt"
     bl_label = "Static Int Math"
     bl_icon = "NODE"
     initialized : bpy.props.BoolProperty(default = False)
     mantis_node_class_name=bl_idname
-
-
-    def init(self, context):
-        self.init_sockets(StaticIntSockets)
-        self.initialized = True
+    socket_templates = StaticIntSockets
 
     def display_update(self, parsed_tree, context):
         if context.space_data:
@@ -40,17 +35,14 @@ class MathStaticInt(Node, MantisUINode):
             else:
                 self.inputs["Int B"].hide = False
 
-class MathStaticFloatNode(Node, MantisUINode):
+class MathStaticFloatNode(Node, MantisMathUINode):
     """A node that performs mathematical operations on float numbers as a preprocess step before generating the rig."""
     bl_idname = "MathStaticFloat"
     bl_label = "Static Float Math"
     bl_icon = "NODE"
     initialized : bpy.props.BoolProperty(default = False)
     mantis_node_class_name=bl_idname
-
-    def init(self, context):
-        self.init_sockets(StaticFloatSockets)
-        self.initialized = True
+    socket_templates = StaticFloatSockets
 
     def display_update(self, parsed_tree, context):
         if context.space_data:
@@ -62,17 +54,14 @@ class MathStaticFloatNode(Node, MantisUINode):
             else:
                 self.inputs["Float B"].hide = False
 
-class MathStaticVectorNode(Node, MantisUINode):
+class MathStaticVectorNode(Node, MantisMathUINode):
     """Performs a vector math operation as a preprocess before executing the tree."""
     bl_idname = "MathStaticVector"
     bl_label = "Static Vector Math"
     bl_icon = "NODE"
     initialized : bpy.props.BoolProperty(default = False)
     mantis_node_class_name=bl_idname
-    
-    def init(self, context):
-        self.init_sockets(StaticVectorSockets)
-        self.initialized = True
+    socket_templates = StaticVectorSockets
 
     def display_update(self, parsed_tree, context):
         if context.space_data:
@@ -100,8 +89,3 @@ class MathStaticVectorNode(Node, MantisUINode):
             else:
                 self.inputs["Vector B"].hide = False
                 self.inputs["Scalar A"].hide = True
-
-# Set up the class property that ties the UI classes to the Mantis classes.
-for cls in TellClasses():
-    cls.mantis_node_library='.math_nodes'
-    cls.set_mantis_class()

+ 132 - 302
misc_nodes_ui.py

@@ -1,6 +1,6 @@
 import bpy
 from bpy.types import Node
-from .base_definitions import MantisUINode, get_signature_from_edited_tree
+from .base_definitions import MantisMiscNode, get_signature_from_edited_tree
 from .misc_nodes_socket_templates import *
 
 from .utilities import (prRed, prGreen, prPurple, prWhite,
@@ -92,87 +92,73 @@ def socket_data_from_collection_paths(root_data, root_name, path, socket_data):
         path.pop()
     return socket_data
 
-class InputFloatNode(Node, MantisUINode):
+#################################################
+# Base Classes for the Misc Nodes
+#################################################
+
+class SimpleInputNode(MantisMiscNode):
+    def init(self, context):
+        super().init(context)
+        for s in self.outputs:
+            s.input=True # give it the property that makes it draw correctly
+
+class InputFloatNode(Node, SimpleInputNode):
     '''A node representing inheritance'''
     bl_idname = 'InputFloatNode'
     bl_label = "Float"
     mantis_node_class_name=bl_idname[:-4]
+    socket_templates=InputFloatSockets
 
-    def init(self, context):
-        self.init_sockets(InputFloatSockets)
-        self.initialized = True
-
-class InputIntNode(Node, MantisUINode):
+class InputIntNode(Node, SimpleInputNode):
     '''A node representing inheritance'''
     bl_idname = 'InputIntNode'
     bl_label = "Integer"
     mantis_node_class_name=bl_idname
-
-    def init(self, context):
-        self.init_sockets(InputIntSockets)
-        self.initialized = True
+    socket_templates=InputIntSockets
     
-class InputVectorNode(Node, MantisUINode):
+class InputVectorNode(Node, SimpleInputNode):
     '''A node representing inheritance'''
     bl_idname = 'InputVectorNode'
     bl_label = "Vector"
     mantis_node_class_name=bl_idname[:-4]
+    socket_templates=InputVectorSockets
 
-    def init(self, context):
-        self.init_sockets(InputVectorSockets)
-        self.initialized = True
-
-class InputBooleanNode(Node, MantisUINode):
+class InputBooleanNode(Node, SimpleInputNode):
     '''A node representing inheritance'''
     bl_idname = 'InputBooleanNode'
     bl_label = "Boolean"
     mantis_node_class_name=bl_idname[:-4]
+    socket_templates=InputBooleanSockets
 
-    def init(self, context):
-        self.init_sockets(InputBooleanSockets)
-        self.initialized = True
-
-class InputBooleanThreeTupleNode(Node, MantisUINode):
+class InputBooleanThreeTupleNode(Node, SimpleInputNode):
     '''A node representing inheritance'''
     bl_idname = 'InputBooleanThreeTupleNode'
     bl_label = "Boolean Vector"
     mantis_node_class_name=bl_idname[:-4]
+    socket_templates=InputBooleanThreeTupleSockets
 
-    def init(self, context):
-        self.init_sockets(InputBooleanThreeTupleSockets)
-        self.initialized = True
-
-class InputRotationOrderNode(Node, MantisUINode):
+class InputRotationOrderNode(Node, SimpleInputNode):
     '''A node representing inheritance'''
     bl_idname = 'InputRotationOrderNode'
     bl_label = "Rotation Order"
     mantis_node_class_name=bl_idname[:-4]
+    socket_templates=InputRotationOrderSockets
 
-    def init(self, context):
-        self.init_sockets(InputRotationOrderSockets)
-        self.initialized = True
-
-class InputTransformSpaceNode(Node, MantisUINode):
+class InputTransformSpaceNode(Node, SimpleInputNode):
     '''A node representing inheritance'''
     bl_idname = 'InputTransformSpaceNode'
     bl_label = "Transform Space"
     mantis_node_class_name=bl_idname[:-4]
+    socket_templates=InputTransformSpaceSockets
 
-    def init(self, context):
-        self.init_sockets(InputTransformSpaceSockets)
-        self.initialized = True
-
-class InputStringNode(Node, MantisUINode):
+class InputStringNode(Node, SimpleInputNode):
     '''A node representing inheritance'''
     bl_idname = 'InputStringNode'
     bl_label = "String"
     mantis_node_class_name=bl_idname[:-4]
+    socket_templates=InputStringSockets
 
-    def init(self, context):
-        self.init_sockets(InputStringSockets)
-        self.initialized = True
-
-class InputMatrixNode(Node, MantisUINode):
+class InputMatrixNode(Node, SimpleInputNode):
     '''A node representing inheritance'''
     bl_idname = 'InputMatrixNode'
     bl_label = "Matrix"
@@ -203,7 +189,7 @@ class InputMatrixNode(Node, MantisUINode):
         mat_sock = self.outputs[0]
         mat_sock.default_value = self.set_matrix()
 
-class InputThemeBoneColorSets(Node, MantisUINode):
+class InputThemeBoneColorSets(Node, MantisMiscNode):
     """Displays the theme's colors."""
     bl_idname = "InputThemeBoneColorSets"
     bl_label = "Theme Colors"
@@ -217,7 +203,7 @@ class InputThemeBoneColorSets(Node, MantisUINode):
             s.color_index=i
         self.initialized = True
 
-class InputColorSetPallete(Node, MantisUINode):
+class InputColorSetPallete(Node, MantisMiscNode):
     """Displays the theme's colors."""
     bl_idname = "InputColorSetPallete"
     bl_label = "Color Pallete"
@@ -233,64 +219,46 @@ class InputColorSetPallete(Node, MantisUINode):
         ops_props.tree_invoked = self.id_data.name
         ops_props.node_invoked = self.name
 
-class UtilityMatrixFromCurve(Node, MantisUINode):
+class UtilityMatrixFromCurve(Node, MantisMiscNode):
     """Gets a matrix from a curve."""
     bl_idname = "UtilityMatrixFromCurve"
     bl_label = "Matrix from Curve"
     mantis_node_class_name=bl_idname
-    
-    def init(self, context):
-        self.init_sockets(MatrixFromCurveSockets)
-        self.initialized = True
+    socket_templates=MatrixFromCurveSockets
 
-class UtilityPointFromCurve(Node, MantisUINode):
+class UtilityPointFromCurve(Node, MantisMiscNode):
     """Gets a point from a curve."""
     bl_idname = "UtilityPointFromCurve"
     bl_label = "Point from Curve"
     mantis_node_class_name=bl_idname
-    
-    def init(self, context):
-        self.init_sockets(PointFromCurveSockets)
-        self.initialized = True
+    socket_templates=PointFromCurveSockets
 
-class UtilityNumberOfCurveSegments(Node, MantisUINode):
+class UtilityNumberOfCurveSegments(Node, MantisMiscNode):
     """Tells the number of segments in a curve."""
     bl_idname = "UtilityNumberOfCurveSegments"
     bl_label = "Number of Curve Segments"
     mantis_node_class_name=bl_idname
+    socket_templates=NumberOfCurveSegmentsSockets
     
-    def init(self, context):
-        self.init_sockets(NumberOfCurveSegmentsSockets)
-        self.initialized = True
-    
-class UtilityNumberOfSplines(Node, MantisUINode):
+class UtilityNumberOfSplines(Node, MantisMiscNode):
     """Tells the number of splines in a curve."""
     bl_idname = "UtilityNumberOfSplines"
     bl_label = "Number of Splines"
     mantis_node_class_name=bl_idname
-    
-    def init(self, context):
-        self.init_sockets(NumberOfSplinesSockets)
-        self.initialized = True
+    socket_templates=NumberOfSplinesSockets
 
-class UtilityMatrixFromCurveSegment(Node, MantisUINode):
+class UtilityMatrixFromCurveSegment(Node, MantisMiscNode):
     """Gets a matrix from a curve segment."""
     bl_idname = "UtilityMatrixFromCurveSegment"
     bl_label = "Matrix from Curve Segment"
     mantis_node_class_name=bl_idname
-    
-    def init(self, context):
-        self.init_sockets(MatrixFromCurveSegmentSockets)
-        self.initialized = True
+    socket_templates=MatrixFromCurveSegmentSockets
 
-class UtilityGetCurvePoint(Node, MantisUINode):
+class UtilityGetCurvePoint(Node, MantisMiscNode):
     bl_idname = 'UtilityGetCurvePoint'
     bl_label = "Control Point from Curve"
     mantis_node_class_name=bl_idname
-
-    def init(self, context):
-        self.init_sockets(GetCurvePointSockets)
-        self.initialized = True
+    socket_templates=GetCurvePointSockets
 
     def display_update(self, parsed_tree, context):
         self.outputs["Point"].hide=False
@@ -313,15 +281,12 @@ class UtilityGetCurvePoint(Node, MantisUINode):
                 self.outputs["Left Handle"].hide=False
                 self.outputs["Right Handle"].hide=False
     
-class UtilityMatricesFromCurve(Node, MantisUINode):
+class UtilityMatricesFromCurve(Node, MantisMiscNode):
     """Gets a matrix from a curve."""
     bl_idname = "UtilityMatricesFromCurve"
     bl_label = "Matrices from Curve"
     mantis_node_class_name=bl_idname
-    
-    def init(self, context):
-        self.init_sockets(MatricesFromCurveSockets)
-        self.initialized = True
+    socket_templates=MatricesFromCurveSockets
 
 def display_update_choose_nearest(self, parsed_tree, context):
     number_of_points = self.inputs['Number to Find'].default_value
@@ -336,52 +301,40 @@ def display_update_choose_nearest(self, parsed_tree, context):
     else:
         self.outputs.display_shape = 'CIRCLE'
 
-class UtilityGetNearestFactorOnCurve(Node, MantisUINode):
+class UtilityGetNearestFactorOnCurve(Node, MantisMiscNode):
     bl_idname = 'UtilityGetNearestFactorOnCurve'
     bl_label = "Get Factor on Curve at Point"
     mantis_node_class_name=bl_idname
+    socket_templates=GetNearestFactorOnCurveSockets
 
-    def init(self, context):
-        self.init_sockets(GetNearestFactorOnCurveSockets)
-        self.initialized = True
-
-class UtilityKDChoosePoint(Node, MantisUINode):
+class UtilityKDChoosePoint(Node, MantisMiscNode):
     """Chooses the nearest point with a KD Tree."""
     bl_idname = "UtilityKDChoosePoint"
     bl_label = "Choose Nearest Point"
     mantis_node_class_name=bl_idname
-    
-    def init(self, context):
-        self.init_sockets(KDChoosePointSockets)
-        self.initialized = True
+    socket_templates=KDChoosePointSockets
     
     def display_update(self, parsed_tree, context):
         display_update_choose_nearest(self, parsed_tree, context)
 
-class UtilityKDChooseXForm(Node, MantisUINode):
+class UtilityKDChooseXForm(Node, MantisMiscNode):
     """Chooses the nearest xForm with a KD Tree."""
     bl_idname = "UtilityKDChooseXForm"
     bl_label = "Choose Nearest xForm"
     mantis_node_class_name=bl_idname
-    
-    def init(self, context):
-        self.init_sockets(KDChooseXFormSockets)
-        self.initialized = True
+    socket_templates=KDChooseXFormSockets
     
     def display_update(self, parsed_tree, context):
         display_update_choose_nearest(self, parsed_tree, context)
 
-class UtilityMetaRigNode(Node, MantisUINode):
+class UtilityMetaRigNode(Node, MantisMiscNode):
     """Gets a matrix from a meta-rig bone."""
     bl_idname = "UtilityMetaRig"
     bl_label = "Meta-Rig"
     armature:bpy.props.StringProperty()
     pose_bone:bpy.props.StringProperty()
     mantis_node_class_name=bl_idname
-    
-    def init(self, context):
-        self.init_sockets(MetaRigSockets)
-        self.initialized = True
+    socket_templates=MetaRigSockets
     
     def display_update(self, parsed_tree, context):
         mantis_node = parsed_tree.get(get_signature_from_edited_tree(self, context))
@@ -397,28 +350,22 @@ class UtilityMetaRigNode(Node, MantisUINode):
         if self.inputs["Meta-Bone"].is_linked:
             self.inputs["Meta-Bone"].search_prop = None
 
-class UtilityBonePropertiesNode(Node, MantisUINode):
+class UtilityBonePropertiesNode(Node, MantisMiscNode):
     """Provides as sockets strings identifying bone transform properties."""
     bl_idname = "UtilityBoneProperties"
     bl_label = "Bone Properties"
     initialized : bpy.props.BoolProperty(default = False)
     mantis_node_class_name=bl_idname
-    
-    def init(self, context):
-        self.init_sockets(BonePropertiesSockets)
-        self.initialized = True
+    socket_templates=BonePropertiesSockets
         
 
-class UtilityDriverVariableNode(Node, MantisUINode):
+class UtilityDriverVariableNode(Node, MantisMiscNode):
     """Creates a variable for use in a driver."""
     bl_idname = "UtilityDriverVariable"
     bl_label = "Driver Variable"
     mantis_node_class_name=bl_idname
-    
-    def init(self, context):
-        self.init_sockets(DriverVariableSockets)
-        self.initialized = True
-    
+    socket_templates=DriverVariableSockets
+
     def display_update(self, parsed_tree, context):
         if self.inputs["Variable Type"].is_linked:
             if context.space_data:
@@ -461,17 +408,13 @@ class UtilityDriverVariableNode(Node, MantisUINode):
 # TODO: make a way to edit the fCurve directly.
 # I had a working version of this in the past, but it required doing sinful things like
 # keeping track of the RAM address of the window.
-class UtilityFCurveNode(Node, MantisUINode):
+class UtilityFCurveNode(Node, MantisMiscNode):
     """Creates an fCurve for use with a driver."""
     bl_idname = "UtilityFCurve"
     bl_label = "fCurve"
-    
-    use_kf_nodes   : bpy.props.BoolProperty(default=True)
     mantis_node_class_name=bl_idname
-    
-    def init(self, context):
-        self.init_sockets(FCurveSockets)
-        self.initialized = True
+    socket_templates=FCurveSockets
+    use_kf_nodes   : bpy.props.BoolProperty(default=True)
             
     def draw_buttons(self, context, layout):
         layout.operator( 'mantis.fcurve_node_add_kf' )
@@ -479,16 +422,13 @@ class UtilityFCurveNode(Node, MantisUINode):
             layout.operator( 'mantis.fcurve_node_remove_kf' )
 
 
-class UtilityDriverNode(Node, MantisUINode):
+class UtilityDriverNode(Node, MantisMiscNode):
     """Represents a Driver relationship"""
     bl_idname = "UtilityDriver"
     bl_label = "Driver"
     mantis_node_class_name=bl_idname
+    socket_templates=DriverSockets
     
-    def init(self, context):
-        self.init_sockets(DriverSockets)
-        self.initialized = True
-        
     def display_update(self, parsed_tree, context):
         if not self.inputs["Driver Type"].is_linked:
             dType = self.inputs["Driver Type"].default_value
@@ -506,54 +446,40 @@ class UtilityDriverNode(Node, MantisUINode):
         if (len(self.inputs) > 3):
             layout.operator( 'mantis.driver_node_remove_variable' )
 
-class UtilitySwitchNode(Node, MantisUINode):
+class UtilitySwitchNode(Node, MantisMiscNode):
     """Represents a switch relationship between one driver property and one or more driven properties."""
     bl_idname = "UtilitySwitch"
     bl_label = "Switch"
     mantis_node_class_name=bl_idname
-    
-    def init(self, context):
-        self.init_sockets(SwitchSockets)
-        self.initialized = True
+    socket_templates=SwitchSockets
 
-class UtilityCombineThreeBoolNode(Node, MantisUINode):
+class UtilityCombineThreeBoolNode(Node, MantisMiscNode):
     """Combines three booleans into a three-bool."""
     bl_idname = "UtilityCombineThreeBool"
     bl_label = "CombineThreeBool"
     mantis_node_class_name=bl_idname
-    
-    def init(self, context):
-        self.init_sockets(CombineThreeBoolSockets)
-        self.initialized = True
+    socket_templates=CombineThreeBoolSockets
 
-class UtilityCombineVectorNode(Node, MantisUINode):
+class UtilityCombineVectorNode(Node, MantisMiscNode):
     """Combines three floats into a vector."""
     bl_idname = "UtilityCombineVector"
     bl_label = "CombineVector"
     mantis_node_class_name=bl_idname
-    
-    def init(self, context):
-        self.init_sockets(CombineVectorSockets)
+    socket_templates=CombineVectorSockets
         
-class UtilitySeparateVector(Node, MantisUINode):
+class UtilitySeparateVector(Node, MantisMiscNode):
     """Separates a vector into three floats"""
     bl_idname = "UtilitySeparateVector"
     bl_label = "Separate Vector"
     mantis_node_class_name=bl_idname
-    
-    def init(self, context):
-        self.init_sockets(SeparateVectorSockets)
-        self.initialized = True
+    socket_templates=SeparateVectorSockets
         
-class UtilityCatStringsNode(Node, MantisUINode):
+class UtilityCatStringsNode(Node, MantisMiscNode):
     """Combines multiple strings into one."""
     bl_idname = "UtilityCatStrings"
     bl_label = "Join Strings"
     mantis_node_class_name=bl_idname
-    
-    def init(self, context):
-        self.init_sockets(CatStringsSockets)
-        self.initialized = True
+    socket_templates=CatStringsSockets
 
     def draw_label(self): # this will prefer a user-set label, or return the evaluated name
         if self.label:
@@ -578,27 +504,21 @@ class UtilityCatStringsNode(Node, MantisUINode):
                     return # the tree isn't ready yet.
                 
 
-class InputWidget(Node, MantisUINode):
+class InputWidget(Node, MantisMiscNode):
     """Fetches a Widget from the Widget Library."""
     bl_idname = "InputWidget"
     bl_label = "Widget"
     mantis_node_class_name=bl_idname
+    socket_templates=InputWidgetSockets
     
-    def init(self, context):
-        self.init_sockets(InputWidgetSockets)
-        self.initialized = True
-    
-class InputExistingGeometryObjectNode(Node, MantisUINode):
+class InputExistingGeometryObjectNode(Node, MantisMiscNode):
     """Represents an existing geometry object from within the scene."""
     bl_idname = "InputExistingGeometryObject"
     bl_label = "Existing Object"
     mantis_node_class_name=bl_idname
     # We want Mantis to import widgets and stuff, so we hold a reference to the object
-    object_reference : bpy.props.PointerProperty(type=bpy.types.Object,) 
-    
-    def init(self, context):
-        self.init_sockets(InputExistingGeometryObjectSockets)
-        self.initialized = True
+    object_reference : bpy.props.PointerProperty(type=bpy.types.Object,)
+    socket_templates=InputExistingGeometryObjectSockets
     
     def display_update(self, parsed_tree, context):
         mantis_node = parsed_tree.get(get_signature_from_edited_tree(self, context))
@@ -607,25 +527,20 @@ class InputExistingGeometryObjectNode(Node, MantisUINode):
     
 # TODO: maybe I should hold a data reference here, too.
 #       but it is complicated by the fact that Mantis does not distinguish b/tw geo types
-class InputExistingGeometryDataNode(Node, MantisUINode):
+class InputExistingGeometryDataNode(Node, MantisMiscNode):
     """Represents a mesh or curve datablock from the scene."""
     bl_idname = "InputExistingGeometryData"
     bl_label = "Existing Geometry"
     mantis_node_class_name=bl_idname
-    
-    def init(self, context):
-        self.init_sockets(InputExistingGeometrySockets)
-        self.initialized = True
+    socket_templates=InputExistingGeometrySockets
 
-class UtilityCustomProperty(Node, MantisUINode):
+class UtilityCustomProperty(Node, MantisMiscNode):
     """A declaration of a custom property."""
     bl_idname = "UtilityCustomProperty"
     bl_label  = "Custom Property"
     bl_icon   = "NODE"
     mantis_node_class_name=bl_idname
-    def init(self, context):
-        self.init_sockets(UtilityCustomPropertySockets)
-        self.initialized = True
+    socket_templates=UtilityCustomPropertySockets
     
     def display_update(self, parsed_tree, context):
         mantis_node = parsed_tree.get(get_signature_from_edited_tree(self, context))
@@ -656,7 +571,7 @@ class UtilityCustomProperty(Node, MantisUINode):
             return self.inputs['Name'].display_text
         return self.name
 
-class UtilityDeclareCollections(Node, MantisUINode):
+class UtilityDeclareCollections(Node, MantisMiscNode):
     """A utility used to declare bone collections."""
     bl_idname = "UtilityDeclareCollections"
     bl_label  = "Collections"
@@ -707,89 +622,66 @@ class UtilityDeclareCollections(Node, MantisUINode):
         op_props.socket_invoked = '' # this isn't reset between invocations
         # so we have to make sure to unset it when running it from the node
 
-class UtilityCollectionJoin(Node, MantisUINode):
+class UtilityCollectionJoin(Node, MantisMiscNode):
     """A utility used to join bone collection declarations."""
     bl_idname = "UtilityCollectionJoin"
     bl_label  = "Join Collection Declarations"
     bl_icon   = "NODE"
     mantis_node_class_name=bl_idname
-    def init(self, context):
-        self.init_sockets(CollectionJoinSockets)
-        self.initialized = True
+    socket_templates=CollectionJoinSockets
 
-class UtilityCollectionHierarchy(Node, MantisUINode):
+class UtilityCollectionHierarchy(Node, MantisMiscNode):
     """A utility used to declare bone collection hierarchies."""
     bl_idname = "UtilityCollectionHierarchy"
     bl_label  = "Collection Child Declaration"
     bl_icon   = "NODE"
     mantis_node_class_name=bl_idname
-    def init(self, context):
-        self.init_sockets(CollectionHierarchySockets)
-        self.initialized = True
+    socket_templates=CollectionHierarchySockets
         
-class UtilityGeometryOfXForm(Node, MantisUINode):
+class UtilityGeometryOfXForm(Node, MantisMiscNode):
     """Retrieves a mesh or curve datablock from an xForm."""
     bl_idname = "UtilityGeometryOfXForm"
     bl_label = "Geometry of xForm"
     mantis_node_class_name=bl_idname
-    
-    def init(self, context):
-        self.init_sockets(GeometryOfXFormSockets)
-        self.initialized = True
-
+    socket_templates=GeometryOfXFormSockets
 
-class UtilityNameOfXForm(Node, MantisUINode):
+class UtilityNameOfXForm(Node, MantisMiscNode):
     """Retrieves the name of a xForm."""
     bl_idname = "UtilityNameOfXForm"
     bl_label = "Name of xForm"
     mantis_node_class_name=bl_idname
-    
-    def init(self, context):
-        self.init_sockets(NameOfXFormSockets)
-        self.initialized = True
+    socket_templates=NameOfXFormSockets
 
-class UtilityGetBoneLength(Node, MantisUINode):
+class UtilityGetBoneLength(Node, MantisMiscNode):
     """Returns the length of the bone from its matrix."""
     bl_idname = "UtilityGetBoneLength"
     bl_label = "Get Bone Length"
     mantis_node_class_name=bl_idname
-    
-    def init(self, context):
-        self.init_sockets(GetBoneLengthSockets)
-        self.initialized = True
+    socket_templates=GetBoneLengthSockets
 
 # TODO: make it work with BBones!
-class UtilityPointFromBoneMatrix(Node, MantisUINode):
+class UtilityPointFromBoneMatrix(Node, MantisMiscNode):
     """Returns a point representing the location along a bone, given a matrix representing that bone's shape."""
     bl_idname = "UtilityPointFromBoneMatrix"
     bl_label = "Point from Bone Matrix"
     mantis_node_class_name=bl_idname
-    
-    def init(self, context):
-        self.init_sockets(PointFromBoneMatrixSockets)
-        self.initialized = True
+    socket_templates=PointFromBoneMatrixSockets
 
-class UtilitySetBoneLength(Node, MantisUINode):
+class UtilitySetBoneLength(Node, MantisMiscNode):
     """Sets the length of a bone matrix."""
     bl_idname = "UtilitySetBoneLength"
     bl_label = "Set Bone Matrix Length"
     mantis_node_class_name=bl_idname
-    
-    def init(self, context):
-        self.init_sockets(SetBoneLengthSockets)
-        self.initialized = True
+    socket_templates=SetBoneLengthSockets
 
 # TODO: more keyframe types should be supported in the future.
 # Some of the code that can do this is commented out here until I can implement it properly.
-class UtilityKeyframe(Node, MantisUINode):
+class UtilityKeyframe(Node, MantisMiscNode):
     """A keyframe for a FCurve"""
     bl_idname = "UtilityKeyframe"
     bl_label = "KeyFrame"
     mantis_node_class_name=bl_idname
-    
-    def init(self, context):
-        self.init_sockets(KeyframeSockets)
-        self.initialized = True
+    socket_templates=KeyframeSockets
 
     # TODO: I'll implement this when I finish adding the extra features to the Keyframe node
     # def display_update(self, parsed_tree, context):
@@ -805,89 +697,61 @@ class UtilityKeyframe(Node, MantisUINode):
     #                 inp.hide = False
 
 
-class UtilityBoneMatrixHeadTailFlip(Node, MantisUINode):
+class UtilityBoneMatrixHeadTailFlip(Node, MantisMiscNode):
     """Flips a bone matrix so that the head is where the tail was and visa versa."""
     bl_idname = "UtilityBoneMatrixHeadTailFlip"
     bl_label = "Flip Head/Tail"
     mantis_node_class_name=bl_idname
-    
-    def init(self, context):
-        self.init_sockets(BoneMatrixHeadTailFlipSockets)
-        self.initialized = True
+    socket_templates=BoneMatrixHeadTailFlipSockets
 
-class UtilityMatrixTransform(Node, MantisUINode):
+class UtilityMatrixTransform(Node, MantisMiscNode):
     """Transforms a matrix by another."""
     bl_idname = "UtilityMatrixTransform"
     bl_label = "Multiply Matrices"
     mantis_node_class_name=bl_idname
-    
-    def init(self, context):
-        self.init_sockets(MatrixTransformSockets)
-        self.initialized = True
+    socket_templates=MatrixTransformSockets
 
-class UtilityMatrixInvert(Node, MantisUINode):
+class UtilityMatrixInvert(Node, MantisMiscNode):
     """Inverts an invertable matrix, otherwise throws an error."""
     bl_idname = "UtilityMatrixInvert"
     bl_label = "Invert Matrix"
     mantis_node_class_name=bl_idname
-    
-    def init(self, context):
-        self.init_sockets(MatrixInvertSockets)
-        self.initialized = True
+    socket_templates=MatrixInvertSockets
 
-class UtilityMatrixCompose(Node, MantisUINode):
+class UtilityMatrixCompose(Node, MantisMiscNode):
     """Inverts an invertable matrix, otherwise throws an error."""
     bl_idname = "UtilityMatrixCompose"
     bl_label = "Compose Matrix"
     mantis_node_class_name=bl_idname
-    
-    def init(self, context):
-        self.init_sockets(MatrixComposeSockets)
-        self.initialized = True
+    socket_templates=MatrixComposeSockets
 
-class UtilityMatrixAlignRoll(Node, MantisUINode):
+class UtilityMatrixAlignRoll(Node, MantisMiscNode):
     """Aligns the Z axis of a matrix to point in a direction."""
     bl_idname = "UtilityMatrixAlignRoll"
     bl_label = "Align Matrix Roll"
     mantis_node_class_name=bl_idname
-    
-    def init(self, context):
-        self.init_sockets(MatrixAlignRollSockets)
-        self.initialized = True
+    socket_templates=MatrixAlignRollSockets
 
-class UtilityMatrixSetLocation(Node, MantisUINode):
+class UtilityMatrixSetLocation(Node, MantisMiscNode):
     """Sets a matrix's location."""
     bl_idname = "UtilityMatrixSetLocation"
     bl_label = "Set Matrix Location"
     mantis_node_class_name=bl_idname
-    
-    def init(self, context):
-        self.init_sockets(MatrixSetLocationSockets)
-        self.initialized = True
+    socket_templates=MatrixSetLocationSockets
 
-class UtilityMatrixGetLocation(Node, MantisUINode):
+class UtilityMatrixGetLocation(Node, MantisMiscNode):
     """Gets a matrix's location."""
     bl_idname = "UtilityMatrixGetLocation"
     bl_label = "Get Matrix Location"
     mantis_node_class_name=bl_idname
-    
-    def init(self, context):
-        self.init_sockets(MatrixGetLocationSockets)
-        self.initialized = True
+    socket_templates=MatrixGetLocationSockets
 
-class UtilityTransformationMatrix(Node, MantisUINode):
+class UtilityTransformationMatrix(Node, MantisMiscNode):
     """Constructs a matrix representing a transformation"""
     bl_idname = "UtilityTransformationMatrix"
     bl_label = "Transformation Matrix"
     mantis_node_class_name=bl_idname
-    
-    def init(self, context):
-        # first input is a transformation type - translation, rotation, or scale
-        #                         rotation is an especially annoying feature because it can take multiple types
-        #   so Euler, axis/angle, quaternion, matrix...
-        #   for now I am only going to implement axis-angle
-        self.init_sockets(TransformationMatrixSockets)
-        self.initialized = True
+    socket_templates=TransformationMatrixSockets
 
     def display_update(self, parsed_tree, context):
         operation = self.inputs['Operation'].default_value
@@ -910,58 +774,41 @@ class UtilityTransformationMatrix(Node, MantisUINode):
 # So instead, we need to avoid calculating the roll for now.
 # but I want to make that its own node and add roll-recalc to this node, too.
 
-class UtilitySetBoneMatrixTail(Node, MantisUINode):
+class UtilitySetBoneMatrixTail(Node, MantisMiscNode):
     """Constructs a matrix representing a transformation"""
     bl_idname = "UtilitySetBoneMatrixTail"
     bl_label = "Set Bone Matrix Tail"
     mantis_node_class_name=bl_idname
-    
-    def init(self, context):
-        self.init_sockets(SetBoneMatrixTailSockets)
-        self.initialized = True
+    socket_templates=SetBoneMatrixTailSockets
 
-
-class UtilityMatrixFromXForm(Node, MantisUINode):
+class UtilityMatrixFromXForm(Node, MantisMiscNode):
     """Returns the matrix of the given xForm node."""
     bl_idname = "UtilityMatrixFromXForm"
     bl_label = "Matrix of xForm"
     mantis_node_class_name=bl_idname
-    
-    def init(self, context):
-        self.init_sockets(MatrixFromXFormSockets)
-        self.initialized = True
+    socket_templates=MatrixFromXFormSockets
 
-class UtilityAxesFromMatrix(Node, MantisUINode):
+class UtilityAxesFromMatrix(Node, MantisMiscNode):
     """Returns the axes of the matrix."""
     bl_idname = "UtilityAxesFromMatrix"
     bl_label = "Axes of Matrix"
     mantis_node_class_name=bl_idname
-    
-    def init(self, context):
-        self.init_sockets(AxesFromMatrixSockets)
-        self.initialized = True
+    socket_templates=AxesFromMatrixSockets
 
-class UtilityIntToString(Node, MantisUINode):
+class UtilityIntToString(Node, MantisMiscNode):
     """Converts a number to a string"""
     bl_idname = "UtilityIntToString"
     bl_label = "Number String"
     mantis_node_class_name=bl_idname
-    
-    def init(self, context):
-        self.init_sockets(IntToStringSockets)
-        self.initialized = True
-
+    socket_templates=IntToStringSockets
 
-class UtilityArrayGet(Node, MantisUINode):
+class UtilityArrayGet(Node, MantisMiscNode):
     """Gets a value from an array at a specified index."""
     bl_idname = "UtilityArrayGet"
     bl_label  = "Array Get"
     bl_icon   = "NODE"
     mantis_node_class_name=bl_idname
-    
-    def init(self, context):
-        self.init_sockets(ArrayGetSockets)
-        self.initialized = True
+    socket_templates=ArrayGetSockets
     
     def update(self):
         wildcard_color = (0.0,0.0,0.0,0.0)
@@ -977,16 +824,13 @@ class UtilityArrayGet(Node, MantisUINode):
                 self.inputs['Array'].color = from_socket.color
                 self.outputs['Output'].color = from_socket.color
 
-class UtilityArrayLength(Node, MantisUINode):
+class UtilityArrayLength(Node, MantisMiscNode):
     """Gets The length of an array."""
     bl_idname = "UtilityArrayLength"
     bl_label  = "Array Length"
     bl_icon   = "NODE"
     mantis_node_class_name=bl_idname
-    
-    def init(self, context):
-        s = self.init_sockets(UtilityArrayLengthSockets)
-        self.initialized = True
+    socket_templates=UtilityArrayLengthSockets
     
     def update(self):
         wildcard_color = (0.0,0.0,0.0,0.0)
@@ -1001,15 +845,12 @@ class UtilityArrayLength(Node, MantisUINode):
                 self.inputs['Array'].color = from_socket.color
 
 
-class UtilityCompare(Node, MantisUINode):
+class UtilityCompare(Node, MantisMiscNode):
     """Compares two inputs and produces a boolean output"""
     bl_idname = "UtilityCompare"
     bl_label = "Compare"
     mantis_node_class_name=bl_idname
-    
-    def init(self, context):
-        self.init_sockets(CompareSockets)
-        self.initialized = True
+    socket_templates=CompareSockets
     
     def update(self):
         wildcard_color = (0.0,0.0,0.0,0.0)
@@ -1029,15 +870,12 @@ class UtilityCompare(Node, MantisUINode):
             if hasattr(link.from_socket, "color"):
                 self.inputs['B'].color = link.from_socket.color
 
-class UtilityChoose(Node, MantisUINode):
+class UtilityChoose(Node, MantisMiscNode):
     """Chooses an output"""
     bl_idname = "UtilityChoose"
     bl_label = "Choose"
     mantis_node_class_name=bl_idname
-    
-    def init(self, context):
-        self.init_sockets(ChooseSockets)
-        self.initialized = True
+    socket_templates=ChooseSockets
     
     def display_update(self, parsed_tree, context):
         wildcard_color = (0.0,0.0,0.0,0.0)
@@ -1071,18 +909,10 @@ class UtilityChoose(Node, MantisUINode):
                 self.inputs['B'].color = link.from_socket.color
 
 
-class UtilityPrint(Node, MantisUINode):
+class UtilityPrint(Node, MantisMiscNode):
     """A utility used to print arbitrary values."""
     bl_idname = "UtilityPrint"
     bl_label  = "Print"
     bl_icon   = "NODE"
     mantis_node_class_name=bl_idname
-    
-    def init(self, context):
-        self.init_sockets(PrintSockets)
-        self.initialized = True
-
-# Set up the class property that ties the UI classes to the Mantis classes.
-for cls in TellClasses():
-    cls.mantis_node_library='.misc_nodes'
-    cls.set_mantis_class()
+    socket_templates=PrintSockets

+ 6 - 20
primitives_nodes_ui.py

@@ -1,6 +1,7 @@
 import bpy
 from bpy.types import Node
-from .base_definitions import MantisUINode
+from .base_definitions import GeometryPrimitiveNode
+from .primitives_sockets import *
 
 def TellClasses():
     return [
@@ -11,36 +12,21 @@ def TellClasses():
 def default_traverse(self,socket):
     return None
 
-
-class GeometryCirclePrimitive(Node, MantisUINode):
+class GeometryCirclePrimitive(Node, GeometryPrimitiveNode):
     '''A node representing a circle primitive'''
     bl_idname = 'GeometryCirclePrimitive'
     bl_label = "Circle Primitive"
     bl_icon = 'NODE'
     initialized : bpy.props.BoolProperty(default = False)
     mantis_node_class_name="CirclePrimitive"
-
-    def init(self, context):
-        self.inputs.new('StringSocket', "Name")
-        self.inputs.new('FloatPositiveSocket', "Radius")
-        self.inputs.new('IntSocket', "Number of Points")
-        self.outputs.new('GeometrySocket', "Circle")
-        self.initialized = True
+    socket_templates = CirclePrimitiveSockets
 
 from .primitives_sockets import LatticeSockets
-class GeometryLattice(Node, MantisUINode):
+class GeometryLattice(Node, GeometryPrimitiveNode):
     '''A node representing a lattice geometry'''
     bl_idname = "GeometryLattice"
     bl_label = "Lattice"
     bl_icon = "NODE"
     initialized : bpy.props.BoolProperty(default = False)
     mantis_node_class_name=bl_idname
-    
-    def init(self, context):
-        self.init_sockets(LatticeSockets)
-        self.initialized = True
-
-
-for cls in TellClasses():
-    cls.mantis_node_library='.primitives_nodes'
-    cls.set_mantis_class()
+    socket_templates = LatticeSockets

+ 10 - 0
primitives_sockets.py

@@ -24,4 +24,14 @@ LatticeSockets = [
             blender_property="interpolation_type_w",
             is_input=True, default_value='KEY_BSPLINE'),
     GeometryOutput := SockTemplate(name="Lattice Geometry", bl_idname="GeometrySocket")
+]
+
+CirclePrimitiveSockets = [
+    replace(Name, default_value='Circle',),
+    Radius :=SockTemplate(name = "Radius", bl_idname="FloatPositiveSocket",
+            is_input=True, default_value=1.0),
+    # TODO: this should be an UnsignedIntSocket
+    NumberOfPoints :=SockTemplate(name = "Number of Points", bl_idname="IntSocket",
+            is_input=True, default_value=32),
+    GeometryOutput := SockTemplate(name="Circle", bl_idname="GeometrySocket"),
 ]

+ 2 - 8
schema_nodes_ui.py

@@ -38,10 +38,7 @@ class SchemaIndex(Node, SchemaUINode):
     bl_icon = 'GIZMO'
     initialized : bpy.props.BoolProperty(default = False)
     mantis_node_class_name=bl_idname
-    
-    def init(self, context):
-        self.init_sockets(SchemaIndexSockets)
-        self.initialized = True
+    socket_templates = SchemaIndexSockets
 
 class SchemaArrayInput(Node, SchemaUINode):
     '''Array Inputs'''
@@ -116,6 +113,7 @@ class SchemaArrayInputGet(Node, SchemaUINode):
     bl_icon = 'GIZMO'
     initialized : bpy.props.BoolProperty(default = False)
     mantis_node_class_name=bl_idname
+    socket_templates = SchemaArrayInputGetSockets
 
     def init(self, context):
         self.init_sockets(SchemaArrayInputGetSockets)
@@ -322,7 +320,3 @@ class SchemaIncomingConnection(Node, SchemaUINode):
             self.outputs.new('WildcardSocket', '', identifier='__extend__')
         self.initialized = True
         self.is_updating = False
-
-
-for cls in TellClasses():
-    cls.set_mantis_class()

+ 6 - 62
xForm_nodes_ui.py

@@ -26,22 +26,6 @@ def default_traverse(self, socket):
         return self.outputs["xForm Out"]
     return None
 
-# Representing an Empty or non-armature-Object
-# class xFormNullNode(Node, xFormNode):
-#     '''A node representing a Null node'''
-#     bl_idname = 'xFormNullNode'
-#     bl_label = "Null"
-#     bl_icon = 'EMPTY_AXIS'
-
-#     # === Optional Functions ===
-#     def init(self, context):
-#         self.inputs.new('StringSocket', "Name")
-#         self.inputs.new('RelationshipSocket', "Relationship")
-#         self.inputs.new('RotationOrderSocket', "Rotation Order")
-#         self.inputs.new('MatrixSocket', "Matrix")
-#         self.outputs.new('xFormSocket', "xForm Out")
-
-
 def check_if_connected(start, end, line):
     started=False
     for path_mantis_node in line:
@@ -132,9 +116,6 @@ def custom_prop_display_update(self, mantis_node = None):
             do_relink(self, socket, socket_map_out, in_out='OUTPUT')
 
 
-from mathutils import Color
-xFormColor = Color((0.093172, 0.047735, 0.028036)).from_scene_linear_to_srgb()
-
 class xFormBoneNode(Node, xFormNode):
     '''A node representing a Bone'''
     bl_idname = 'xFormBoneNode'
@@ -145,18 +126,10 @@ class xFormBoneNode(Node, xFormNode):
     display_vp_settings : bpy.props.BoolProperty(default=False)
     display_def_settings : bpy.props.BoolProperty(default=False)
     display_bb_settings : bpy.props.BoolProperty(default=False)
-    socket_count : bpy.props.IntProperty()
     initialized : bpy.props.BoolProperty(default = False)
     mantis_node_class_name=bl_idname[:-4]
     socket_templates = xFormBoneSockets
     
-    def init(self, context):
-        self.init_sockets(self.__class__.socket_templates)
-        self.socket_count = len(self.inputs)
-        self.use_custom_color = True
-        self.color = xFormColor
-        self.initialized=True
-    
     def draw_label(self): # this will prefer a user-set label, or return the evaluated name
         return main_draw_label(self)
         
@@ -213,12 +186,7 @@ class xFormArmatureNode(Node, xFormNode):
     bl_icon = 'OUTLINER_OB_ARMATURE'
     initialized : bpy.props.BoolProperty(default = False)
     mantis_node_class_name=bl_idname[:-4]
-
-    def init(self, context):
-        self.init_sockets(xFormArmatureSockets)
-        self.use_custom_color = True
-        self.color = xFormColor
-        self.initialized=True
+    socket_templates = xFormArmatureSockets
 
     def draw_label(self): # this will prefer a user-set label, or return the evaluated name
         return main_draw_label(self)
@@ -233,12 +201,7 @@ class xFormGeometryObjectNode(Node, xFormNode):
     bl_icon = "EMPTY_AXIS"
     initialized : bpy.props.BoolProperty(default = False)
     mantis_node_class_name=bl_idname
-    
-    def init(self, context):
-        self.init_sockets(xFormGeometryObjectSockets)
-        self.use_custom_color = True
-        self.color = xFormColor
-        self.initialized=True
+    socket_templates = xFormGeometryObjectSockets
 
     def draw_label(self): # this will prefer a user-set label, or return the evaluated name
         return main_draw_label(self)
@@ -253,12 +216,7 @@ class xFormObjectInstance(Node, xFormNode):
     bl_icon = "EMPTY_AXIS"
     initialized : bpy.props.BoolProperty(default = False)
     mantis_node_class_name=bl_idname
-    
-    def init(self, context):
-        self.init_sockets(xFormGeometryObjectInstanceSockets)
-        self.use_custom_color = True
-        self.color = xFormColor
-        self.initialized=True
+    socket_templates = xFormGeometryObjectInstanceSockets
 
     def draw_label(self): # this will prefer a user-set label, or return the evaluated name
         return main_draw_label(self)
@@ -266,7 +224,6 @@ class xFormObjectInstance(Node, xFormNode):
     def display_update(self, parsed_tree, context):
         object_displaty_update(self, parsed_tree, context)
 
-from .xForm_nodes import xFormCurvePinSockets
 class xFormCurvePin(Node, xFormNode):
     """"A node representing a curve pin"""
     bl_idname = "xFormCurvePin"
@@ -274,12 +231,7 @@ class xFormCurvePin(Node, xFormNode):
     bl_icon = "FORCE_CURVE"
     initialized : bpy.props.BoolProperty(default = False)
     mantis_node_class_name=bl_idname
-    
-    def init(self, context):
-        self.init_sockets(xFormCurvePinSockets)
-        self.use_custom_color = True
-        self.color = xFormColor
-        self.initialized = True
+    socket_templates = xFormCurvePinSockets
 
 class xFormGetBone(Node, xFormNode):
     """"A node representing an existing bone"""
@@ -289,19 +241,11 @@ class xFormGetBone(Node, xFormNode):
     initialized : bpy.props.BoolProperty(default = False)
     armature : bpy.props.StringProperty(default="")
     mantis_node_class_name=bl_idname
-    
-    def init(self, context):
-        self.init_sockets(xFormGetBoneSockets)
-        self.use_custom_color = True
-        self.color = xFormColor
-        self.initialized = True
+    socket_templates = xFormGetBoneSockets
 
     def display_update(self, parsed_tree, context):
         if context.space_data:
             mantis_node = parsed_tree.get(get_signature_from_edited_tree(self, context))
             if mantis_node:
                 # need this parent armature to use the bone picker.
-                self.inputs["Bone"].armature = mantis_node.bGetParentArmature()
-
-for cls in TellClasses():
-    cls.set_mantis_class()
+                self.inputs["Bone"].armature = mantis_node.bGetParentArmature()