Browse Source

Implement Custom Interface Classes

this commit implements versioning and basic functionality for
 - default values on group sockets
 - arrays and connections editable in the Node Group Interface
 - array support for regular Node Groups

tested and working with Human, Elephant, and Stego files.
Joseph Brandenburg 3 weeks ago
parent
commit
c0b20ed5c9
6 changed files with 84 additions and 40 deletions
  1. 5 5
      base_definitions.py
  2. 2 2
      schema_nodes.py
  3. 18 10
      schema_nodes_ui.py
  4. 3 3
      schema_solve.py
  5. 47 16
      utilities.py
  6. 9 4
      versioning.py

+ 5 - 5
base_definitions.py

@@ -465,18 +465,18 @@ def node_group_update(node, force = False):
             reorder_collection = reorder_me_input if is_input else reorder_me_output
             if socket_map:
                 if item.identifier in socket_map.keys():
-                    socket = relink_socket_map_add_socket(node, socket_collection, item)
+                    socket = relink_socket_map_add_socket(node, socket_collection, item, item.in_out)
                     do_relink(node, socket, socket_map, item.in_out)
                 else:
                     for has_socket in socket_collection:
                         if has_socket.bl_idname == item.bl_socket_idname and \
-                            has_socket.name == item.name:
+                                has_socket.name == item.name:
                             reorder_collection.append((has_socket, counter))
                             break
                     else:
-                        socket = relink_socket_map_add_socket(node, socket_collection, item)
+                        socket = relink_socket_map_add_socket(node, socket_collection, item, item.in_out)
             else:
-                socket = relink_socket_map_add_socket(node, socket_collection, item)
+                socket = relink_socket_map_add_socket(node, socket_collection, item, item.in_out)
             counter += 1
 
         # TODO: de-duplicate this hideous stuff
@@ -502,7 +502,7 @@ def node_group_update(node, force = False):
                         if exists.identifier == item.identifier:
                             break
                     else:
-                        update_group_sockets(item, True)
+                        update_group_sockets(item, False)
                 else:
                     update_group_sockets(item, False)
                 output_index += 1

+ 2 - 2
schema_nodes.py

@@ -16,7 +16,7 @@ def TellClasses():
     ]
 
 def schema_init_sockets(nc, is_input = True, in_out='INPUT', category=''):
-    from .utilities import tree_from_nc
+    from .utilities import tree_from_nc, read_schema_type
     parent_tree = tree_from_nc(nc.signature, nc.base_tree)
     if is_input:
         sockets=nc.inputs
@@ -25,7 +25,7 @@ def schema_init_sockets(nc, is_input = True, in_out='INPUT', category=''):
     if category in ['Constant', 'Array', 'Connection']:
         for item in parent_tree.interface.items_tree:
             if item.item_type == 'PANEL': continue
-            if item.parent and item.parent.name == category:
+            if item.parent and read_schema_type(item) == category:
                 if item.in_out == in_out:
                     sockets.init_sockets([item.name])
     nc.init_parameters()

+ 18 - 10
schema_nodes_ui.py

@@ -7,7 +7,8 @@ from .utilities import (prRed, prGreen, prPurple, prWhite,
                               wrapOrange,)
 from bpy.props import BoolProperty
 
-from .utilities import get_socket_maps, relink_socket_map, do_relink
+from .utilities import (get_socket_maps, relink_socket_map,
+                        do_relink, read_schema_type)
 
 
 def TellClasses():
@@ -29,7 +30,6 @@ def TellClasses():
 # - check what happens when these get plugged into each other
 # - probably disallow all or most of these connections in insert_link or update
 
-
 class SchemaIndex(Node, SchemaUINode):
     '''The current index of the schema execution'''
     bl_idname = 'SchemaIndex'
@@ -66,7 +66,8 @@ class SchemaArrayInput(Node, SchemaUINode):
         self.outputs.clear()
         for item in self.id_data.interface.items_tree:
             if item.item_type == 'PANEL': continue
-            if item.parent and item.in_out == 'INPUT' and item.parent.name == 'Array':
+            parent_name = read_schema_type(item)
+            if item.in_out == 'INPUT' and parent_name == 'Array':
                 relink_socket_map(self, self.outputs, output_map, item, in_out='OUTPUT')
         if '__extend__' in output_map.keys() and output_map['__extend__']:
             do_relink(self, None, output_map, in_out='OUTPUT', parent_name='Array' )
@@ -98,7 +99,8 @@ class SchemaArrayInputAll(Node, SchemaUINode):
         self.outputs.clear()
         for item in self.id_data.interface.items_tree:
             if item.item_type == 'PANEL': continue
-            if item.parent and item.in_out == 'INPUT' and item.parent.name == 'Array':
+            parent_name = read_schema_type(item)
+            if item.in_out == 'INPUT' and parent_name == 'Array':
                 relink_socket_map(self, self.outputs, output_map, item, in_out='OUTPUT')
         if '__extend__' in output_map.keys() and output_map['__extend__']:
             do_relink(self, None, output_map, in_out='OUTPUT', parent_name='Array' )
@@ -132,7 +134,8 @@ class SchemaArrayInputGet(Node, SchemaUINode):
         self.outputs.clear()
         for item in self.id_data.interface.items_tree:
             if item.item_type == 'PANEL': continue
-            if item.parent and item.in_out == 'INPUT' and item.parent.name == 'Array':
+            parent_name = read_schema_type(item)
+            if item.in_out == 'INPUT' and parent_name == 'Array':
                 relink_socket_map(self, self.outputs, output_map, item, in_out='OUTPUT')
         if '__extend__' in output_map.keys() and output_map['__extend__']:
             do_relink(self, None, output_map, in_out='OUTPUT', parent_name='Array' )
@@ -164,7 +167,8 @@ class SchemaArrayOutput(Node, SchemaUINode):
         self.inputs.clear()
         for item in self.id_data.interface.items_tree:
             if item.item_type == 'PANEL': continue
-            if item.parent and item.in_out == 'OUTPUT' and item.parent.name == 'Array':
+            parent_name = read_schema_type(item)
+            if item.in_out == 'OUTPUT' and parent_name == 'Array':
                 relink_socket_map(self, self.inputs, input_map, item, in_out='INPUT')
         if '__extend__' in input_map.keys() and input_map['__extend__']:
             do_relink(self, None, input_map, in_out='INPUT', parent_name='Array' )
@@ -198,7 +202,8 @@ class SchemaConstInput(Node, SchemaUINode):
         self.outputs.clear()
         for item in self.id_data.interface.items_tree:
             if item.item_type == 'PANEL': continue
-            if item.parent and item.in_out == 'INPUT' and item.parent.name == 'Constant':
+            parent_name = read_schema_type(item)
+            if item.in_out == 'INPUT' and parent_name == 'Constant':
                 relink_socket_map(self, self.outputs, output_map, item, in_out='OUTPUT')
         if '__extend__' in output_map.keys() and output_map['__extend__']:
             do_relink(self, None, output_map, in_out='OUTPUT', parent_name='Constant' )
@@ -233,7 +238,8 @@ class SchemaConstOutput(Node, SchemaUINode):
         s = self.inputs.new('UnsignedIntSocket', "Expose at Index")
         for item in self.id_data.interface.items_tree:
             if item.item_type == 'PANEL': continue
-            if item.parent and item.in_out == 'OUTPUT' and item.parent.name == 'Constant':
+            parent_name = read_schema_type(item)
+            if item.in_out == 'OUTPUT' and parent_name == 'Constant':
                 relink_socket_map(self, self.inputs, input_map, item, in_out='INPUT')
         if '__extend__' in input_map.keys() and input_map['__extend__']:
             do_relink(self, None, input_map, in_out='INPUT', parent_name='Constant' )
@@ -271,7 +277,8 @@ class SchemaOutgoingConnection(Node, SchemaUINode):
         self.inputs.clear()
         for item in self.id_data.interface.items_tree:
             if item.item_type == 'PANEL': continue
-            if item.parent and item.in_out == 'OUTPUT' and item.parent.name == 'Connection':
+            parent_name = read_schema_type(item)
+            if item.in_out == 'OUTPUT' and parent_name == 'Connection':
                 relink_socket_map(self, self.inputs, input_map, item, in_out='INPUT')
         if '__extend__' in input_map.keys() and input_map['__extend__']:
             do_relink(self, None, input_map, in_out='INPUT', parent_name='Connection' )
@@ -307,7 +314,8 @@ class SchemaIncomingConnection(Node, SchemaUINode):
         self.outputs.clear()
         for item in self.id_data.interface.items_tree:
             if item.item_type == 'PANEL': continue
-            if item.parent and item.in_out == 'INPUT' and item.parent.name == 'Connection':
+            parent_name = read_schema_type(item)
+            if item.in_out == 'INPUT' and parent_name == 'Connection':
                 relink_socket_map(self, self.outputs, output_map, item, in_out='OUTPUT')
         if '__extend__' in output_map.keys() and output_map['__extend__']:
             do_relink(self, None, output_map, in_out='OUTPUT', parent_name='Connection' )

+ 3 - 3
schema_solve.py

@@ -101,9 +101,9 @@ class SchemaSolver:
         """ Sort and store the links to/from the Schema group node."""
         for item in self.tree.interface.items_tree:
             if item.item_type == 'PANEL': continue
-            parent_name='Constant'
-            if item.parent.name != '': # in an "prphan" item this is left blank , it is not None or an AttributeError.
-                parent_name = item.parent.name
+            from .utilities import read_schema_type
+            parent_name = read_schema_type(item)
+            # just gonna try and make the 
             match parent_name:
                 case 'Connection':
                     if item.in_out == 'INPUT':

+ 47 - 16
utilities.py

@@ -247,6 +247,28 @@ def do_relink(node, socket, map, in_out='INPUT', parent_name = ''):
             except (AttributeError, ValueError): # must be readonly or maybe it doesn't have a d.v.
                 pass
 
+def read_schema_type(interface_item):
+    # VERSIONING CODE
+    tree=interface_item.id_data
+    version = tree.mantis_version
+    old_version = False
+    if  version[0] == 0: 
+        if version[1] < 12: old_version = True
+        elif version[1] == 12 and version[2] < 27: old_version = True
+    # unfortunately we need to check this stuff for the versioning code to run correctly the first time.
+    # UNLESS I can find a way to prevent this code from running before versioning
+
+    if old_version or (not hasattr(interface_item, 'is_array')):
+        # it is not a custom interface class and/or the file is old.
+        if interface_item.parent:
+            return interface_item.parent.name
+    else:
+        if interface_item.is_array:
+            return 'Array'
+        if interface_item.is_connection:
+            return 'Connection'
+    return 'Constant'
+
 def update_interface(interface, name, in_out, sock_type, parent_name):
     from bpy.app import version as bpy_version
     if parent_name:
@@ -268,14 +290,18 @@ def update_interface(interface, name, in_out, sock_type, parent_name):
 
 # D.node_groups['Rigging Nodes'].interface.new_socket('beans', description='the b word', socket_type='NodeSocketGeometry')
 #UGLY BAD REFACTOR
-def relink_socket_map_add_socket(node, socket_collection, item, in_out=None,):
+def relink_socket_map_add_socket(node, socket_collection, item,  in_out=None,):
     from bpy.app import version as bpy_version
-    if not in_out: in_out=item.in_out
+    # if not in_out: in_out=item.in_out
     multi=False
-    if hasattr(item, 'is_array'):
-        multi = item.is_array
-    if node.bl_idname in ['MantisSchemaGroup'] and item.parent and item.parent.name == 'Array':
-        multi = True if in_out == 'INPUT' else False
+    if in_out == 'INPUT' and read_schema_type(item) == 'Array':
+        multi = True
+
+    # multi=False
+    # if hasattr(item, 'is_array'):
+    #     multi = item.is_array
+    # if node.bl_idname in ['MantisSchemaGroup'] and item.parent and item.parent.name == 'Array':
+    #     multi = True if in_out == 'INPUT' else False
     # have to work around a bug in 4.5.0 that prevents me from declaring custom socket types
     # I have arbitrarily chosen to use the NodeSocketGeometry type to signal that this one is affected.
     if bpy_version == (4, 5, 0) and item.bl_socket_idname == 'NodeSocketGeometry':
@@ -283,8 +309,8 @@ def relink_socket_map_add_socket(node, socket_collection, item, in_out=None,):
         s = socket_add_workaround_for_4_5_0_LTS(item, socket_collection, multi)
     else:
         s = socket_collection.new(type=item.bl_socket_idname, name=item.name, identifier=item.identifier,  use_multi_input=multi)
-    if hasattr(s, 'default_value') and hasattr(s, 'valid_interface_type') and \
-          s.valid_interface_type == True:
+    if hasattr(s, 'default_value') and hasattr(s, 'is_valid_interface_type') and \
+          s.is_valid_interface_type == True:
         from bpy.types import bpy_prop_array
         from mathutils import Vector
         default_value = 'REPORT BUG ON GITLAB' # default to bug string
@@ -296,8 +322,12 @@ def relink_socket_map_add_socket(node, socket_collection, item, in_out=None,):
         if val_type is str: default_value = item.default_string
         if val_type is bpy_prop_array: default_value = item.default_float
         s.default_value = default_value
-    if item.parent.name == 'Array': s.display_shape = 'SQUARE_DOT'
-    elif item.parent.name == 'Constant': s.display_shape='CIRCLE_DOT'
+    if read_schema_type(item) == 'Array': s.display_shape = 'SQUARE_DOT'
+    elif node.bl_idname in ['MantisSchemaGroup'] and read_schema_type(item) == 'Constant':
+        s.display_shape='CIRCLE_DOT'
+
+    # if item.parent.name == 'Array': s.display_shape = 'SQUARE_DOT'
+    # elif item.parent.name == 'Constant': s.display_shape='CIRCLE_DOT'
     return s
 
 # TODO REFACTOR THIS
@@ -305,9 +335,9 @@ def relink_socket_map_add_socket(node, socket_collection, item, in_out=None,):
 # but I have provided this interface to Mantis
 # I did not follow the Single Responsibility Principle
 # I am now suffering for it, as I rightly deserve.
-def relink_socket_map(node, socket_collection, map, item, in_out=None,):
-    s = relink_socket_map_add_socket(node, socket_collection, item, in_out=None,)
-    do_relink(node, s, map)
+def relink_socket_map(node, socket_collection, map, item, in_out):
+    new_socket = relink_socket_map_add_socket(node, socket_collection, item, in_out,)
+    do_relink(node, new_socket, map, in_out, parent_name=read_schema_type(item))
 
 def unique_socket_name(node, other_socket, tree):
     name_stem = other_socket.bl_label; num=0
@@ -599,7 +629,8 @@ def schema_dependency_handle_item(schema, all_nc, item,):
     if item.in_out == 'INPUT':
         dependencies = schema.dependencies
         hierarchy_dependencies = schema.hierarchy_dependencies
-        if item.parent and item.parent.name == 'Array':
+        parent_name = read_schema_type(item)
+        if parent_name == 'Array':
             for schema_idname in ['SchemaArrayInput', 'SchemaArrayInputGet', 'SchemaArrayInputAll']:
                 if (nc := all_nc.get( (*schema.signature, schema_idname) )):
                     for to_link in nc.outputs[item.name].links:
@@ -614,7 +645,7 @@ def schema_dependency_handle_item(schema, all_nc, item,):
                             if hierarchy:
                                 hierarchy_dependencies.append(from_link.from_node)
                             dependencies.append(from_link.from_node)
-        if item.parent and item.parent.name == 'Constant':
+        if parent_name == 'Constant':
             if nc := all_nc.get((*schema.signature, 'SchemaConstInput')):
                 for to_link in nc.outputs[item.name].links:
                     if to_link.to_socket in to_name_filter:
@@ -628,7 +659,7 @@ def schema_dependency_handle_item(schema, all_nc, item,):
                         if hierarchy:
                             hierarchy_dependencies.append(from_link.from_node)
                         dependencies.append(from_link.from_node)
-        if item.parent and item.parent.name == 'Connection':
+        if parent_name == 'Connection':
             if nc := all_nc.get((*schema.signature, 'SchemaIncomingConnection')):
                 for to_link in nc.outputs[item.name].links:
                     if to_link.to_socket in to_name_filter:

+ 9 - 4
versioning.py

@@ -244,6 +244,7 @@ def up_0_12_25_replace_floor_offset_type(*args, **kwargs):
 
 
 def schema_enable_custom_interface_types(*args, **kwargs):
+    # return
     tree = kwargs['tree']
     current_major_version = tree.mantis_version[0]
     current_minor_version = tree.mantis_version[1]
@@ -257,12 +258,16 @@ def schema_enable_custom_interface_types(*args, **kwargs):
         for item in tree.interface.items_tree:
             if item.item_type == 'PANEL':
                 continue
-            elif hasattr (item, 'is_array'):
-                if item.parent and item.parent.name == 'Array':
-                    item.is_array = True
+            parent_name = 'Constant'
+            if item.parent:
+                parent_name=item.parent.name
+            if hasattr(item, "is_array"):
                 # if is_array exists we're in the custom interface class
                 # so we'll assume the other attributes exist
-                if item.parent and item.parent.name == 'Connection':
+                if parent_name == 'Array':
+                    item.is_array = True
+                if parent_name == 'Connection':
+                    item.is_array = False
                     item.is_connection=True
                     item.connected_to=item.name
                     # since heretofore it has been a requirement that the names match