xForm_nodes_ui.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. import bpy
  2. from .base_definitions import xFormNode
  3. from bpy.types import Node
  4. from .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 .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 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. initialized : bpy.props.BoolProperty(default = False)
  119. mantis_node_class_name=bl_idname[:-4]
  120. socket_templates = xFormBoneSockets
  121. def draw_label(self): # this will prefer a user-set label, or return the evaluated name
  122. return main_draw_label(self)
  123. def display_update(self, parsed_tree, context):
  124. # let's setup the outputs for the custom properties:
  125. # we'll start by trying to do it without the special mantis data
  126. if self.id_data.mantis_version[1] < 13: return #or the old custom properties will get wiped.
  127. custom_prop_display_update(self)
  128. if context.space_data:
  129. mantis_node = parsed_tree.get(get_signature_from_edited_tree(self, context))
  130. if mantis_node and mantis_node.prepared:
  131. custom_prop_display_update(self, mantis_node)
  132. self.display_ik_settings = False
  133. if mantis_node and (pb := mantis_node.bGetObject(mode='POSE')):
  134. self.display_ik_settings = pb.is_in_ik_chain
  135. self.inputs['Name'].display_text = ""
  136. if mantis_node and mantis_node.prepared:
  137. try:
  138. self.inputs['Name'].display_text = mantis_node.evaluate_input("Name")
  139. self.display_vp_settings = mantis_node.inputs["Custom Object"].is_connected
  140. self.display_def_settings = mantis_node.evaluate_input("Deform")
  141. self.display_bb_settings = mantis_node.evaluate_input("BBone Segments") > 1
  142. except KeyError:
  143. return # the tree isn't ready yet.
  144. for template in self.socket_templates:
  145. name = template.name
  146. category = template.category
  147. if category == "IK":
  148. self.inputs[name].hide = not self.display_ik_settings
  149. if category == "Display":
  150. if name in ['Custom Object', 'Bone Collection']: continue
  151. self.inputs[name].hide = not self.display_vp_settings
  152. if category == "Deform":
  153. if name in ['Deform']: continue
  154. self.inputs[name].hide = not self.display_def_settings
  155. if category == "bbone":
  156. if name in ['BBone Segments']: continue
  157. self.inputs[name].hide = not self.display_bb_settings
  158. def object_displaty_update(self, parsed_tree, context):
  159. custom_prop_display_update(self)
  160. if context.space_data:
  161. mantis_node = parsed_tree.get(get_signature_from_edited_tree(self, context))
  162. self.inputs['Name'].display_text = ""
  163. if mantis_node and mantis_node.prepared:
  164. self.inputs['Name'].display_text = mantis_node.evaluate_input("Name")
  165. custom_prop_display_update(self, mantis_node)
  166. class xFormArmatureNode(Node, xFormNode):
  167. '''A node representing an Armature object node'''
  168. bl_idname = 'xFormArmatureNode'
  169. bl_label = "Armature"
  170. bl_icon = 'OUTLINER_OB_ARMATURE'
  171. initialized : bpy.props.BoolProperty(default = False)
  172. mantis_node_class_name=bl_idname[:-4]
  173. socket_templates = xFormArmatureSockets
  174. def draw_label(self): # this will prefer a user-set label, or return the evaluated name
  175. return main_draw_label(self)
  176. def display_update(self, parsed_tree, context):
  177. object_displaty_update(self, parsed_tree, context)
  178. class xFormGeometryObjectNode(Node, xFormNode):
  179. """Represents a curve or mesh object."""
  180. bl_idname = "xFormGeometryObject"
  181. bl_label = "Geometry Object"
  182. bl_icon = "EMPTY_AXIS"
  183. initialized : bpy.props.BoolProperty(default = False)
  184. mantis_node_class_name=bl_idname
  185. socket_templates = xFormGeometryObjectSockets
  186. def draw_label(self): # this will prefer a user-set label, or return the evaluated name
  187. return main_draw_label(self)
  188. def display_update(self, parsed_tree, context):
  189. object_displaty_update(self, parsed_tree, context)
  190. class xFormObjectInstance(Node, xFormNode):
  191. """Represents an instance of an existing geometry object."""
  192. bl_idname = "xFormObjectInstance"
  193. bl_label = "Object Instance"
  194. bl_icon = "EMPTY_AXIS"
  195. initialized : bpy.props.BoolProperty(default = False)
  196. mantis_node_class_name=bl_idname
  197. socket_templates = xFormGeometryObjectInstanceSockets
  198. def draw_label(self): # this will prefer a user-set label, or return the evaluated name
  199. return main_draw_label(self)
  200. def display_update(self, parsed_tree, context):
  201. object_displaty_update(self, parsed_tree, context)
  202. class xFormCurvePin(Node, xFormNode):
  203. """"A node representing a curve pin"""
  204. bl_idname = "xFormCurvePin"
  205. bl_label = "Curve Pin"
  206. bl_icon = "FORCE_CURVE"
  207. initialized : bpy.props.BoolProperty(default = False)
  208. mantis_node_class_name=bl_idname
  209. socket_templates = xFormCurvePinSockets
  210. class xFormGetBone(Node, xFormNode):
  211. """"A node representing an existing bone"""
  212. bl_idname = "xFormGetBone"
  213. bl_label = "Existing Bone"
  214. bl_icon = "BONE_DATA"
  215. initialized : bpy.props.BoolProperty(default = False)
  216. armature : bpy.props.StringProperty(default="")
  217. mantis_node_class_name=bl_idname
  218. socket_templates = xFormGetBoneSockets
  219. def display_update(self, parsed_tree, context):
  220. if context.space_data:
  221. mantis_node = parsed_tree.get(get_signature_from_edited_tree(self, context))
  222. if mantis_node:
  223. # need this parent armature to use the bone picker.
  224. self.inputs["Bone"].armature = mantis_node.bGetParentArmature()