| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296 | 
							- from .utilities import (prRed, prGreen, prPurple, prWhite,
 
-                               prOrange,
 
-                               wrapRed, wrapGreen, wrapPurple, wrapWhite,
 
-                               wrapOrange,)
 
- from .base_definitions import GraphError, NodeSocket, MantisNode
 
- from collections.abc import Callable
 
- # BE VERY CAREFUL
 
- # the x_containers files import * from this file
 
- # so all the top-level imports are carried over
 
- #TODO: refactor the socket definitions so this becomes unnecessary.
 
- def get_socket_value(node_socket):
 
-     value = None
 
-     if hasattr(node_socket, "default_value"): 
 
-         value = node_socket.default_value
 
-     if node_socket.bl_idname == 'MatrixSocket':
 
-         value =  node_socket.TellValue()
 
-     return value
 
- # TODO: modify this to work with multi-input nodes
 
- def trace_single_line(node_container, input_name, link_index=0):
 
-     # DO: refactor this for new link class
 
-     """Traces a line to its input."""
 
-     nodes = [node_container]
 
-     # Trace a single line
 
-     if (socket := node_container.inputs.get(input_name) ):
 
-         while (socket.is_linked):
 
-             link = socket.links[link_index]; link_index = 0
 
-             if (socket := link.from_node.outputs.get(link.from_socket)):
 
-                 nodes.append(socket.node)
 
-                 if socket.can_traverse:
 
-                     socket = socket.traverse_target
 
-                 else: # this is an output.
 
-                     break
 
-             else:
 
-                 break
 
-     return nodes, socket
 
- # this is same as the other, just flip from/to and in/out
 
- def trace_single_line_up(node_container, output_name,):
 
-     """I use this to get the xForm from a link node."""
 
-     nodes = [node_container]
 
-     if hasattr(node_container, "outputs"):
 
-         # Trace a single line
 
-         if (socket := node_container.outputs.get(output_name) ):
 
-             while (socket.is_linked):
 
-                 # This is bad, but it's efficient for nodes that only expect
 
-                 #  one path along the given line
 
-                 link = socket.links[0] # TODO: find out if this is wise.
 
-                 other = link.to_node.inputs.get(link.to_socket)
 
-                 if (other):
 
-                     socket = other
 
-                     if socket.can_traverse:
 
-                         socket = socket.traverse_target
 
-                         nodes.append(socket.node)
 
-                     else: # this is an input.
 
-                         nodes.append(socket.node)
 
-                         break
 
-                 else:
 
-                     break
 
-     return nodes, socket
 
- def trace_line_up_branching(node : MantisNode, output_name : str,
 
-         break_condition : Callable = lambda node : False):
 
-     """ Returns all leaf nodes at the ends of branching lines from an output."""
 
-     leaf_nodes = []
 
-     if hasattr(node, "outputs"):
 
-         # Trace a single line
 
-         if (socket := node.outputs.get(output_name) ):
 
-             check_sockets={socket}
 
-             while (check_sockets):
 
-                 # This is bad, but it's efficient for nodes that only expect
 
-                 #  one path along the given line
 
-                 socket = check_sockets.pop()
 
-                 for link in socket.links:
 
-                     other = link.to_node.inputs.get(link.to_socket)
 
-                     if (other):
 
-                         socket = other
 
-                         if break_condition(socket.node):
 
-                             leaf_nodes.append(socket.node)
 
-                         elif socket.is_input and socket.can_traverse:
 
-                             check_sockets.add(socket.traverse_target)
 
-                         else: # this is an input.
 
-                             leaf_nodes.append(socket.node)
 
-     return leaf_nodes
 
- def setup_custom_props(nc):
 
-     from .utilities import get_node_prototype
 
-     if nc.signature[0] == 'SCHEMA_AUTOGENERATED':
 
-         from .base_definitions import custom_props_types
 
-         if nc.__class__.__name__ not in custom_props_types:
 
-             # prRed(f"Reminder: figure out how to deal with custom property setting for Schema Node {nc}")
 
-             raise RuntimeError(wrapRed(f"Custom Properties not set up for node {nc}"))
 
-         return
 
-     else:
 
-         np = get_node_prototype(nc.signature, nc.base_tree)
 
-     if np:
 
-         setup_custom_props_from_np(nc, np)
 
-     else:
 
-         prRed("Failed to setup custom properties for: nc")
 
- def setup_custom_props_from_np(nc, np):
 
-     for inp in np.inputs:
 
-         if inp.identifier == "__extend__": continue
 
-         if not (inp.name in nc.inputs.keys()) :
 
-             socket = NodeSocket(is_input = True, name = inp.name, node = nc,)
 
-             nc.inputs[inp.name] = socket
 
-             nc.parameters[inp.name] = None
 
-             for attr_name in ["min", "max", "soft_min", "soft_max", "description"]:
 
-                 try:
 
-                     setattr(socket, attr_name, getattr(inp, attr_name))
 
-                 except AttributeError:
 
-                     pass
 
-     for out in np.outputs:
 
-         if out.identifier == "__extend__": continue
 
-         if not (out.name in nc.outputs.keys()) :
 
-             nc.outputs[out.name] = NodeSocket(is_input = False, name = out.name, node = nc,)
 
-             
 
- def prepare_parameters(nc):
 
-     # some nodes add new parameters at runtime, e.g. Drivers
 
-     # so we need to take that stuff from the node_containers that have
 
-     #  been executed prior to this node.
 
-     for s_name, sock in nc.inputs.items():
 
-         if not (sock.is_linked):
 
-             continue
 
-         if (sock.name  in sock.links[0].from_node.parameters.keys()):
 
-             nc.parameters[s_name] = sock.links[0].from_node.parameters[sock.name]
 
-     # should work, this is ugly.
 
- def check_for_driver(node_container, input_name, index = None):
 
-     prop = node_container.evaluate_input(input_name)
 
-     if (index is not None):
 
-         prop = prop[index]
 
-     return (prop.__class__.__name__ == 'MantisDriver')
 
- # TODO: this should handle sub-properties better
 
- def evaluate_sockets(nc, b_object, props_sockets,):
 
-     # this is neccesary because some things use dict properties for dynamic properties and setattr doesn't work
 
-     def safe_setattr(ob, att_name, val):
 
-         if ob.__class__.__name__ in ["NodesModifier"]:
 
-             ob[att_name]=val
 
-         elif b_object.__class__.__name__ in ["Key"]:
 
-             if not val: val=0
 
-             ob.key_blocks[att_name].value=val
 
-         elif "]." in att_name:
 
-             # it is of the form prop[int].prop2
 
-             prop=att_name.split('[')[0]
 
-             prop1=att_name.split('.')[1]
 
-             index = int(att_name.split('[')[1][0])
 
-             setattr(getattr(b_object, prop)[index], prop1, val)
 
-         else:
 
-             try:
 
-                 setattr(ob, att_name, val)
 
-             except Exception as e:
 
-                 prRed(ob, att_name, val); raise e
 
-     for prop, (sock, default) in props_sockets.items():
 
-         # annoyingly, sometimes the socket is an array
 
-         index = None
 
-         if isinstance(sock, tuple):
 
-             index = sock[1]; sock = sock[0]
 
-         if (check_for_driver(nc, sock, index)):
 
-             sock = (sock, index)
 
-             original_prop = prop
 
-             # TODO: deduplicate this terrible hack
 
-             if ("." in prop) and not b_object.__class__.__name__ in ["Key"]: # this is a property of a property...
 
-                 sub_props = [b_object]
 
-                 while ("." in prop):
 
-                     split_prop = prop.split(".")
 
-                     prop = split_prop[1]
 
-                     sub_prop = (split_prop[0])
 
-                     if ("[" in sub_prop):
 
-                         sub_prop, index = sub_prop.split("[")
 
-                         index = int(index[0])
 
-                         sub_props.append(getattr(sub_props[-1], sub_prop)[index])
 
-                     else:
 
-                         sub_props.append(getattr(sub_props[-1], sub_prop))
 
-                 safe_setattr(sub_props[-1], prop, default)
 
-             # this is really stupid
 
-             else:
 
-                 safe_setattr(b_object, prop, default)
 
-             if nc.node_type in ['LINK',]:
 
-                 printname  = wrapOrange(b_object.id_data.name)
 
-             elif nc.node_type in ['XFORM',]:
 
-                 printname  = wrapOrange(nc.bGetObject().name)
 
-             else:
 
-                 printname = wrapOrange(nc)
 
-             print("Adding driver %s to %s in %s" % (wrapPurple(original_prop), wrapWhite(nc.signature[-1]), printname))
 
-             if b_object.__class__.__name__ in ["NodesModifier"]:
 
-                 nc.drivers[sock] = "[\""+original_prop+"\"]" # lol. It is a dict element not a "true" property
 
-             elif b_object.__class__.__name__ in ["Key"]:
 
-                 nc.drivers[sock] = "key_blocks[\""+original_prop+"\"].value"
 
-             else:
 
-                 nc.drivers[sock] = original_prop
 
-         else: # here we can do error checking for the socket if needed
 
-             if (index is not None):
 
-                 safe_setattr(b_object, prop, nc.evaluate_input(sock)[index])
 
-             else:                    # 'mute' is better than 'enabled'
 
-                 # UGLY HACK          # because it is available in older
 
-                 if (prop == 'mute'): # Blenders.
 
-                     safe_setattr(b_object, prop, not bool(nc.evaluate_input(sock)))
 
-                 elif (prop == 'hide'): # this will not cast it for me, annoying.
 
-                     safe_setattr(b_object, prop, bool(nc.evaluate_input(sock)))
 
-                 else:
 
-                     try:
 
-                         # prRed(b_object.name, nc, prop, nc.evaluate_input(sock) )
 
-                         # print( nc.evaluate_input(sock))
 
-                     # value_eval = nc.evaluate_input(sock)
 
-                     # just wanna see if we are dealing with some collection
 
-                     # check hasattr in case it is one of those ["such-and-such"] props, and ignore those
 
-                         if hasattr(b_object, prop) and (not isinstance(getattr(b_object, prop), str)) and hasattr(getattr(b_object, prop), "__getitem__"):
 
-                             # prGreen("Doing the thing")
 
-                             for val_index, value in enumerate(nc.evaluate_input(sock)):
 
-                                 # assume this will work, both because val should have the right number of elements, and because this should be the right data type.
 
-                                 from .drivers import MantisDriver
 
-                                 if isinstance(value, MantisDriver):
 
-                                     getattr(b_object,prop)[val_index] =  default[val_index]
 
-                                     print("Adding driver %s to %s in %s" % (wrapPurple(prop), wrapWhite(nc.signature[-1]), nc))
 
-                                     try:
 
-                                         nc.drivers[sock].append((prop, val_index))
 
-                                     except:
 
-                                         nc.drivers[sock] = [(prop, val_index)]
 
-                                 else:
 
-                                     getattr(b_object,prop)[val_index] =  value
 
-                         else:
 
-                             # prOrange("Skipping the Thing", getattr(b_object, prop))
 
-                             safe_setattr(b_object, prop, nc.evaluate_input(sock))
 
-                     except Exception as e:
 
-                         prRed(b_object, nc, prop, sock, nc.evaluate_input(sock))
 
-                         raise e
 
- def finish_driver(nc, b_object, driver_item, prop):
 
-     # prWhite(nc, prop)
 
-     index = driver_item[1]; driver_sock = driver_item[0]
 
-     driver_trace = trace_single_line(nc, driver_sock)
 
-     driver_provider, driver_socket = driver_trace[0][-1], driver_trace[1]
 
-     if index is not None:
 
-         driver = driver_provider.parameters[driver_socket.name][index].copy()
 
-         # this is harmless and necessary for the weird ones where the property is a vector too
 
-         driver["ind"] = index
 
-     else:
 
-         driver = driver_provider.parameters[driver_socket.name].copy()
 
-     if driver:
 
-         if ("." in prop) and nc.__class__.__name__ != "DeformerMorphTargetDeform": # this is a property of a property...
 
-             sub_props = [b_object]
 
-             while ("." in prop):
 
-                 split_prop = prop.split(".")
 
-                 prop = split_prop[1]
 
-                 sub_prop = (split_prop[0])
 
-                 if ("[" in sub_prop):
 
-                     sub_prop, index = sub_prop.split("[")
 
-                     index = int(index[0])
 
-                     sub_props.append(getattr(sub_props[-1], sub_prop)[index])
 
-                 else:
 
-                     sub_props.append(getattr(sub_props[-1], sub_prop))
 
-             driver["owner"] = sub_props[-1]
 
-         elif nc.node_type in ['XFORM',] and nc.__class__.__name__ in ['xFormBone']:
 
-             # TODO: I really shouldn't have to hardcode this. Look into better solutions.
 
-             if prop in ['hide', 'show_wire']: # we need to get the bone, not the pose bone.
 
-                 bone_col = nc.bGetParentArmature().data.bones
 
-             else:
 
-                 bone_col = nc.bGetParentArmature().pose.bones
 
-             driver["owner"] = bone_col[b_object] # we use "unsafe" brackets instead of get() because we want to see any errors that occur
 
-         # HACK having special cases here is indicitave of a deeper problem that should be refactored
 
-         elif nc.__class__.__name__ in ['xFormCurvePin'] and \
 
-                       prop in ['offset_factor', 'forward_axis', 'up_axis']:
 
-                 driver["owner"] = b_object.constraints['Curve Pin']
 
-         else:
 
-             driver["owner"] = b_object
 
-         driver["prop"] = prop
 
-         return driver
 
-     else:
 
-         prOrange("Provider", driver_provider)
 
-         prGreen("socket", driver_socket)
 
-         print (index)
 
-         prPurple(driver_provider.parameters[driver_socket.name])
 
-         prRed("Failed to create driver for %s" % prop)
 
-         return None
 
- def finish_drivers(nc):
 
-     drivers = []
 
-     if not hasattr(nc, "drivers"):
 
-         return # HACK
 
-     for driver_item, prop in nc.drivers.items():
 
-         b_objects = [nc.bObject]
 
-         if nc.node_type == 'LINK':
 
-             b_objects = nc.bObject # this is already a list
 
-         for b_object in b_objects:
 
-             if isinstance(prop, list):
 
-                 for sub_item in prop:
 
-                         drivers.append(finish_driver(nc, b_object, (driver_item, sub_item[1]), sub_item[0]))
 
-                 else:
 
-                     drivers.append(finish_driver(nc, b_object, (driver_item, sub_item[1]), sub_item[0]))
 
-             else:
 
-                 drivers.append(finish_driver(nc, b_object, driver_item, prop))
 
-     from .drivers import CreateDrivers
 
-     CreateDrivers(drivers)
 
 
  |