xForm_nodes_ui.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. import bpy
  2. from .base_definitions import xFormNode
  3. from bpy.types import Node
  4. from .utilities.utilities import (prRed, prGreen, prPurple, prWhite,
  5. prOrange,
  6. wrapRed, wrapGreen, wrapPurple, wrapWhite,
  7. wrapOrange,)
  8. from .base_definitions import get_signature_from_edited_tree
  9. from .xForm_socket_templates import *
  10. def TellClasses():
  11. return [
  12. # xFormNullNode,
  13. xFormBoneNode,
  14. xFormArmatureNode,
  15. xFormGeometryObjectNode,
  16. xFormObjectInstance,
  17. xFormCurvePin,
  18. xFormGetBone,
  19. ]
  20. def default_traverse(self, socket):
  21. if (socket == self.outputs["xForm Out"]):
  22. return self.inputs["Relationship"]
  23. if (socket == self.inputs["Relationship"]):
  24. return self.outputs["xForm Out"]
  25. return None
  26. def check_if_connected(start, end, line):
  27. started=False
  28. for path_mantis_node in line:
  29. prWhite(" ", path_mantis_node.signature)
  30. if path_mantis_node.signature == start.signature:
  31. started = True
  32. elif path_mantis_node.signature == end.signature:
  33. break
  34. if started:
  35. if path_mantis_node.inputs.get("Connected"):
  36. if path_mantis_node.evaluate_input("Connected") == False:
  37. return False
  38. else:
  39. return False
  40. return True
  41. def main_draw_label(self): # this will prefer a user-set label, or return the evaluated name
  42. if self.label:
  43. return self.label
  44. if self.inputs['Name'].display_text:
  45. return self.inputs['Name'].display_text
  46. return self.name
  47. def custom_prop_display_update(self, mantis_node = None):
  48. custom_props = {}
  49. type_map = {
  50. 'BOOL' : 'ParameterBoolSocket',
  51. 'INT' : 'ParameterIntSocket',
  52. 'FLOAT' : 'ParameterFloatSocket',
  53. 'VECTOR' : 'ParameterVectorSocket',
  54. 'STRING' : 'ParameterStringSocket',
  55. }
  56. cant_read=0
  57. if not mantis_node:
  58. links = [link for link in self.inputs['Custom Properties'].links]
  59. links.sort(key=lambda a : -a.multi_input_sort_id)
  60. for link in links:
  61. if link.from_node.bl_idname == 'UtilityCustomProperty':
  62. if (link.from_node.inputs['Name'].is_linked or
  63. link.from_node.inputs['Type'].is_linked):
  64. cant_read+=1 # we can't eval this without the Mantis data
  65. continue # but we need to count it
  66. else:
  67. custom_props[link.from_node.inputs['Name'].default_value] = \
  68. type_map[link.from_node.inputs['Type'].default_value]
  69. else:
  70. cant_read+=1
  71. for name, type in custom_props.items():
  72. if self.outputs.get(name): continue # already there
  73. else:
  74. self.outputs.new(type, name)
  75. else:
  76. from .misc_nodes import UtilityCustomProperty
  77. from .mantis_dataclasses import custom_prop_template
  78. mantis_node.inputs['Custom Properties'].flush_links() # clean/sort the links
  79. if len(mantis_node.inputs['Custom Properties'].links) != len(self.inputs['Custom Properties'].links):
  80. return # there is a problem somewhere
  81. for i, link in enumerate(mantis_node.inputs['Custom Properties'].links):
  82. from .utilities.node_common import trace_single_line
  83. node_line, _last_socket = trace_single_line(mantis_node, 'Custom Properties', i)
  84. if not node_line[-1].prepared:
  85. return
  86. custom_prop_data = mantis_node.evaluate_input('Custom Property', i)
  87. if isinstance(node_line[-1], UtilityCustomProperty) and \
  88. not isinstance(custom_prop_data, custom_prop_template):
  89. return
  90. elif not isinstance(custom_prop_data, custom_prop_template):
  91. continue # wrong connection
  92. name = custom_prop_data.name
  93. type = custom_prop_data.prop_type
  94. custom_props[name] = type_map[type]
  95. from .utilities.utilities import get_socket_maps, do_relink
  96. _socket_map_in, socket_map_out = get_socket_maps(self)
  97. for name, type in custom_props.items():
  98. if socket_map_out.get(name) is None:
  99. socket_map_out[name] = None # initialize the new ones
  100. # remove and replace sockets
  101. if cant_read == 0:
  102. remove_me = self.outputs[1:]
  103. while remove_me:
  104. remove_socket = remove_me.pop()
  105. self.outputs.remove(remove_socket)
  106. for name, type in custom_props.items():
  107. socket = self.outputs.new(type, name)
  108. do_relink(self, socket, socket_map_out, in_out='OUTPUT')
  109. class xFormBoneNode(Node, xFormNode):
  110. '''A node representing a Bone'''
  111. bl_idname = 'xFormBoneNode'
  112. bl_label = "Bone"
  113. bl_icon = 'BONE_DATA'
  114. display_ik_settings : bpy.props.BoolProperty(default=False)
  115. display_vp_settings : bpy.props.BoolProperty(default=False)
  116. display_def_settings : bpy.props.BoolProperty(default=False)
  117. display_bb_settings : bpy.props.BoolProperty(default=False)
  118. mantis_node_class_name=bl_idname[:-4]
  119. socket_templates = xFormBoneSockets
  120. def draw_label(self): # this will prefer a user-set label, or return the evaluated name
  121. return main_draw_label(self)
  122. def display_update(self, parsed_tree, context):
  123. # let's setup the outputs for the custom properties:
  124. # we'll start by trying to do it without the special mantis data
  125. if self.id_data.mantis_version[1] < 13: return #or the old custom properties will get wiped.
  126. custom_prop_display_update(self)
  127. if context.space_data:
  128. mantis_node = parsed_tree.get(get_signature_from_edited_tree(self, context))
  129. if mantis_node and mantis_node.prepared:
  130. custom_prop_display_update(self, mantis_node)
  131. self.display_ik_settings = False
  132. if mantis_node and (pb := mantis_node.bGetObject(mode='POSE')):
  133. self.display_ik_settings = pb.is_in_ik_chain
  134. self.inputs['Name'].display_text = ""
  135. if mantis_node and mantis_node.prepared:
  136. try:
  137. self.inputs['Name'].display_text = mantis_node.evaluate_input("Name")
  138. self.display_vp_settings = mantis_node.inputs["Custom Object"].is_connected
  139. self.display_def_settings = mantis_node.evaluate_input("Deform")
  140. self.display_bb_settings = mantis_node.evaluate_input("BBone Segments") > 1
  141. except KeyError:
  142. return # the tree isn't ready yet.
  143. for template in self.socket_templates:
  144. name = template.name
  145. category = template.category
  146. if category == "IK":
  147. self.inputs[name].hide = not self.display_ik_settings
  148. if category == "Display":
  149. if name in ['Custom Object', 'Bone Collection']: continue
  150. self.inputs[name].hide = not self.display_vp_settings
  151. if category == "Deform":
  152. if name in ['Deform']: continue
  153. self.inputs[name].hide = not self.display_def_settings
  154. if category == "bbone":
  155. if name in ['BBone Segments']: continue
  156. self.inputs[name].hide = not self.display_bb_settings
  157. def object_displaty_update(self, parsed_tree, context):
  158. custom_prop_display_update(self)
  159. if context.space_data:
  160. mantis_node = parsed_tree.get(get_signature_from_edited_tree(self, context))
  161. self.inputs['Name'].display_text = ""
  162. if mantis_node and mantis_node.prepared:
  163. self.inputs['Name'].display_text = mantis_node.evaluate_input("Name")
  164. custom_prop_display_update(self, mantis_node)
  165. class xFormArmatureNode(Node, xFormNode):
  166. '''A node representing an Armature object node'''
  167. bl_idname = 'xFormArmatureNode'
  168. bl_label = "Armature"
  169. bl_icon = 'OUTLINER_OB_ARMATURE'
  170. mantis_node_class_name=bl_idname[:-4]
  171. socket_templates = xFormArmatureSockets
  172. def draw_label(self): # this will prefer a user-set label, or return the evaluated name
  173. return main_draw_label(self)
  174. def display_update(self, parsed_tree, context):
  175. object_displaty_update(self, parsed_tree, context)
  176. class xFormGeometryObjectNode(Node, xFormNode):
  177. """Represents a curve or mesh object."""
  178. bl_idname = "xFormGeometryObject"
  179. bl_label = "Geometry Object"
  180. bl_icon = "EMPTY_AXIS"
  181. mantis_node_class_name=bl_idname
  182. socket_templates = xFormGeometryObjectSockets
  183. def draw_label(self): # this will prefer a user-set label, or return the evaluated name
  184. return main_draw_label(self)
  185. def display_update(self, parsed_tree, context):
  186. object_displaty_update(self, parsed_tree, context)
  187. class xFormObjectInstance(Node, xFormNode):
  188. """Represents an instance of an existing geometry object."""
  189. bl_idname = "xFormObjectInstance"
  190. bl_label = "Object Instance"
  191. bl_icon = "EMPTY_AXIS"
  192. mantis_node_class_name=bl_idname
  193. socket_templates = xFormGeometryObjectInstanceSockets
  194. def draw_label(self): # this will prefer a user-set label, or return the evaluated name
  195. return main_draw_label(self)
  196. def display_update(self, parsed_tree, context):
  197. object_displaty_update(self, parsed_tree, context)
  198. class xFormCurvePin(Node, xFormNode):
  199. """"A node representing a curve pin"""
  200. bl_idname = "xFormCurvePin"
  201. bl_label = "Curve Pin"
  202. bl_icon = "FORCE_CURVE"
  203. mantis_node_class_name=bl_idname
  204. socket_templates = xFormCurvePinSockets
  205. class xFormGetBone(Node, xFormNode):
  206. """"A node representing an existing bone"""
  207. bl_idname = "xFormGetBone"
  208. bl_label = "Existing Bone"
  209. bl_icon = "BONE_DATA"
  210. armature : bpy.props.StringProperty(default="")
  211. mantis_node_class_name=bl_idname
  212. socket_templates = xFormGetBoneSockets
  213. def display_update(self, parsed_tree, context):
  214. if context.space_data:
  215. mantis_node = parsed_tree.get(get_signature_from_edited_tree(self, context))
  216. if mantis_node:
  217. # need this parent armature to use the bone picker.
  218. self.inputs["Bone"].armature = mantis_node.bGetParentArmature()