link_nodes_ui.py 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394
  1. import bpy
  2. from bpy.types import NodeTree, Node, NodeSocket
  3. from .base_definitions import LinkNode, GraphError
  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 .link_socket_templates import *
  10. def TellClasses():
  11. return [ LinkInheritNode,
  12. LinkInverseKinematics,
  13. LinkCopyLocationNode,
  14. LinkCopyRotationNode,
  15. LinkCopyScaleNode,
  16. LinkInheritConstraintNode,
  17. LinkCopyTransformNode,
  18. LinkStretchToNode,
  19. LinkDampedTrackNode,
  20. LinkLockedTrackNode,
  21. LinkTrackToNode,
  22. LinkLimitLocationNode,
  23. LinkLimitScaleNode,
  24. LinkLimitRotationNode,
  25. LinkLimitDistanceNode,
  26. LinkDrivenParameterNode,
  27. LinkArmatureNode,
  28. LinkSplineIKNode,
  29. LinkFloorNode,
  30. LinkShrinkWrapNode,
  31. LinkGeometryAttribute,
  32. LinkTransformationNode,
  33. ]
  34. from mathutils import Color # these colors were sampled from Blender's UI
  35. # TODO: maybe read the relevant colors from the Theme
  36. linkTransformColor = Color((0.028034, 0.093164, 0.070379)).from_scene_linear_to_srgb()
  37. inheritColor = Color((0.083213, 0.131242, 0.116497)).from_scene_linear_to_srgb()
  38. trackingColor = Color((0.033114, 0.049013, 0.131248)).from_scene_linear_to_srgb()
  39. ikColor = Color((0.131117, 0.131248, 0.006971)).from_scene_linear_to_srgb()
  40. driverColor = Color((0.043782, 0.014745, 0.131248,)).from_scene_linear_to_srgb()
  41. class LinkInheritNode(Node, LinkNode):
  42. '''A node representing inheritance'''
  43. # cuss, messed this up
  44. bl_idname = 'linkInherit' # l should be L
  45. # need to fix this
  46. bl_label = "Inherit"
  47. bl_icon = 'CONSTRAINT_BONE'
  48. initialized : bpy.props.BoolProperty(default = False)
  49. mantis_node_class_name="LinkInherit"
  50. socket_templates = LinkInheritSockets
  51. category_color=inheritColor
  52. def display_update(self, parsed_tree, context):
  53. node_tree = context.space_data.path[0].node_tree
  54. mantis_node = parsed_tree.get(get_signature_from_edited_tree(self, context))
  55. if mantis_node:
  56. bone_prev, bone_next = False, False
  57. if (inp := mantis_node.inputs["Parent"]).is_connected:
  58. if from_node := inp.links[0].from_node:
  59. if from_node.__class__.__name__ in ["xFormBone"]:
  60. bone_prev=True
  61. bone_next=True
  62. try:
  63. xForm = mantis_node.GetxForm()
  64. if xForm.__class__.__name__ not in "xFormBone":
  65. bone_next=False
  66. except GraphError:
  67. bone_next=False
  68. # print(bone_prev, bone_next )
  69. if bone_next and bone_prev:
  70. self.inputs["Inherit Rotation"].hide = False
  71. self.inputs["Inherit Scale"].hide = False
  72. self.inputs["Connected"].hide = False
  73. else:
  74. self.inputs["Inherit Rotation"].hide = True or self.inputs["Inherit Rotation"].is_connected
  75. self.inputs["Inherit Scale"].hide = True or self.inputs["Inherit Scale"].is_connected
  76. self.inputs["Connected"].hide = True or self.inputs["Connected"].is_connected
  77. # the node_groups on the way here ought to be active if there
  78. # is no funny business going on.
  79. # DO: make another node for ITASC IK, eh?
  80. class LinkInverseKinematics(Node, LinkNode):
  81. '''A node representing inverse kinematics'''
  82. bl_idname = 'LinkInverseKinematics'
  83. bl_label = "Inverse Kinematics"
  84. bl_icon = 'CON_KINEMATIC'
  85. initialized : bpy.props.BoolProperty(default = False)
  86. mantis_node_class_name=bl_idname
  87. category_color=linkTransformColor
  88. socket_templates = LinkInverseKinematicsSockets
  89. class LinkCopyLocationNode(Node, LinkNode):
  90. '''A node representing Copy Location'''
  91. bl_idname = 'LinkCopyLocation'
  92. bl_label = "Copy Location"
  93. bl_icon = 'CON_LOCLIKE'
  94. initialized : bpy.props.BoolProperty(default = False)
  95. mantis_node_class_name=bl_idname
  96. category_color=linkTransformColor
  97. socket_templates = LinkCopyLocationSockets
  98. class LinkCopyRotationNode(Node, LinkNode):
  99. '''A node representing Copy Rotation'''
  100. bl_idname = 'LinkCopyRotation'
  101. bl_label = "Copy Rotation"
  102. bl_icon = 'CON_ROTLIKE'
  103. initialized : bpy.props.BoolProperty(default = False)
  104. mantis_node_class_name=bl_idname
  105. category_color=linkTransformColor
  106. socket_templates = LinkCopyRotationSockets
  107. class LinkCopyScaleNode(Node, LinkNode):
  108. '''A node representing Copy Scale'''
  109. bl_idname = 'LinkCopyScale'
  110. bl_label = "Copy Scale"
  111. bl_icon = 'CON_SIZELIKE'
  112. initialized : bpy.props.BoolProperty(default = False)
  113. mantis_node_class_name=bl_idname
  114. category_color=linkTransformColor
  115. socket_templates = LinkCopyScaleSockets
  116. class LinkInheritConstraintNode(Node, LinkNode):
  117. # === Basics ===
  118. # Description string
  119. '''A node representing a parent constraint'''
  120. bl_idname = 'LinkInheritConstraint'
  121. bl_label = "Inherit (constraint)"
  122. bl_icon = 'CON_CHILDOF'
  123. initialized : bpy.props.BoolProperty(default = False)
  124. mantis_node_class_name=bl_idname
  125. category_color=inheritColor
  126. socket_templates = LinkInheritConstraintSockets
  127. class LinkCopyTransformNode(Node, LinkNode):
  128. # === Basics ===
  129. # Description string
  130. '''A node representing Copy Transform'''
  131. bl_idname = 'LinkCopyTransforms'
  132. bl_label = "Copy Transform"
  133. bl_icon = 'CON_TRANSLIKE'
  134. initialized : bpy.props.BoolProperty(default = False)
  135. mantis_node_class_name=bl_idname
  136. category_color=linkTransformColor
  137. socket_templates = LinkCopyTransformsSockets
  138. class LinkStretchToNode(Node, LinkNode):
  139. '''A node representing Stretch-To'''
  140. bl_idname = 'LinkStretchTo'
  141. bl_label = "Stretch To"
  142. bl_icon = 'CON_STRETCHTO'
  143. initialized : bpy.props.BoolProperty(default = False)
  144. mantis_node_class_name=bl_idname
  145. category_color=trackingColor
  146. socket_templates = LinkStretchToSockets
  147. class LinkDampedTrackNode(Node, LinkNode):
  148. '''A node representing Stretch-To'''
  149. bl_idname = 'LinkDampedTrack'
  150. bl_label = "Damped Track"
  151. bl_icon = 'CON_TRACKTO'
  152. initialized : bpy.props.BoolProperty(default = False)
  153. mantis_node_class_name=bl_idname
  154. category_color=trackingColor
  155. socket_templates = LinkDampedTrackSockets
  156. class LinkLockedTrackNode(Node, LinkNode):
  157. '''A node representing Stretch-To'''
  158. bl_idname = 'LinkLockedTrack'
  159. bl_label = "Locked Track"
  160. bl_icon = 'CON_LOCKTRACK'
  161. initialized : bpy.props.BoolProperty(default = False)
  162. mantis_node_class_name=bl_idname
  163. category_color=trackingColor
  164. socket_templates = LinkLockedTrackSockets
  165. class LinkTrackToNode(Node, LinkNode):
  166. '''A node representing Stretch-To'''
  167. bl_idname = 'LinkTrackTo'
  168. bl_label = "Track To"
  169. bl_icon = 'CON_TRACKTO'
  170. initialized : bpy.props.BoolProperty(default = False)
  171. mantis_node_class_name=bl_idname
  172. category_color=trackingColor
  173. socket_templates = LinkTrackToSockets
  174. class LinkLimitLocationNode(Node, LinkNode):
  175. '''A node representing Limit Location'''
  176. bl_idname = 'LinkLimitLocation'
  177. bl_label = "Limit Location"
  178. bl_icon = 'CON_LOCLIMIT'
  179. mantis_node_class_name=bl_idname
  180. initialized : bpy.props.BoolProperty(default = False)
  181. category_color=linkTransformColor
  182. socket_templates = LinkLimitLocationScaleSockets
  183. class LinkLimitScaleNode(Node, LinkNode):
  184. '''A node representing Limit Scale'''
  185. bl_idname = 'LinkLimitScale'
  186. bl_label = "Limit Scale"
  187. bl_icon = 'CON_SIZELIMIT'
  188. initialized : bpy.props.BoolProperty(default = False)
  189. mantis_node_class_name=bl_idname
  190. category_color=linkTransformColor
  191. socket_templates = LinkLimitLocationScaleSockets
  192. class LinkLimitRotationNode(Node, LinkNode):
  193. '''A node representing Limit Rotation'''
  194. bl_idname = 'LinkLimitRotation'
  195. bl_label = "Limit Rotation"
  196. bl_icon = 'CON_ROTLIMIT'
  197. initialized : bpy.props.BoolProperty(default = False)
  198. mantis_node_class_name=bl_idname
  199. category_color=linkTransformColor
  200. socket_templates = LinkLimitRotationSockets
  201. class LinkLimitDistanceNode(Node, LinkNode):
  202. '''A node representing Limit Distance'''
  203. bl_idname = 'LinkLimitDistance'
  204. bl_label = "Limit Distance"
  205. bl_icon = 'CON_DISTLIMIT'
  206. initialized : bpy.props.BoolProperty(default = False)
  207. mantis_node_class_name=bl_idname
  208. category_color=linkTransformColor
  209. socket_templates = LinkLimitDistanceSockets
  210. class LinkTransformationNode(Node, LinkNode):
  211. '''A node representing Transformation (Constraint)'''
  212. bl_idname = 'LinkTransformation'
  213. bl_label = "Transformation"
  214. bl_icon = 'CON_TRANSFORM'
  215. initialized : bpy.props.BoolProperty(default = False)
  216. mantis_node_class_name=bl_idname
  217. category_color=linkTransformColor
  218. socket_templates = LinkTransformationSockets
  219. def display_update(self, parsed_tree, context):
  220. node_tree = context.space_data.path[0].node_tree
  221. mantis_node = parsed_tree.get(get_signature_from_edited_tree(self, context))
  222. if mantis_node:
  223. if mantis_node.evaluate_input("Map From") == "ROTATION":
  224. self.inputs["Rotation Mode"].hide=False
  225. else:
  226. self.inputs["Rotation Mode"].hide=True
  227. if mantis_node.evaluate_input("Map To") == "TRANSLATION":
  228. self.inputs["Rotation Order"].hide=True
  229. self.inputs["Mix Mode (Translation)"].hide=False
  230. self.inputs["Mix Mode (Rotation)"].hide=True
  231. self.inputs["Mix Mode (Scale)"].hide=True
  232. elif mantis_node.evaluate_input("Map To") == "ROTATION":
  233. self.inputs["Rotation Order"].hide=False
  234. self.inputs["Mix Mode (Translation)"].hide=True
  235. self.inputs["Mix Mode (Rotation)"].hide=False
  236. self.inputs["Mix Mode (Scale)"].hide=True
  237. elif mantis_node.evaluate_input("Map To") == "SCALE":
  238. self.inputs["Rotation Order"].hide=True
  239. self.inputs["Mix Mode (Translation)"].hide=True
  240. self.inputs["Mix Mode (Rotation)"].hide=True
  241. self.inputs["Mix Mode (Scale)"].hide=False
  242. class LinkArmatureNode(Node, LinkNode):
  243. """A node representing Blender's Armature Constraint"""
  244. bl_idname = "LinkArmature"
  245. bl_label = "Armature (Constraint)"
  246. bl_icon = "CON_ARMATURE"
  247. initialized : bpy.props.BoolProperty(default = False)
  248. mantis_node_class_name=bl_idname
  249. category_color=inheritColor
  250. socket_templates = LinkArmatureSockets
  251. def draw_buttons(self, context, layout):
  252. # return
  253. layout.operator( 'mantis.link_armature_node_add_target' )
  254. if (len(self.inputs) > 6):
  255. layout.operator( 'mantis.link_armature_node_remove_target' )
  256. else:
  257. layout.label(text="")
  258. class LinkSplineIKNode(Node, LinkNode):
  259. """"A node representing Spline IK"""
  260. bl_idname = "LinkSplineIK"
  261. bl_label = "Spline IK"
  262. bl_icon = "CON_SPLINEIK"
  263. initialized : bpy.props.BoolProperty(default = False)
  264. mantis_node_class_name=bl_idname
  265. category_color=ikColor
  266. socket_templates = LinkSplineIKSockets
  267. class LinkFloorNode(Node, LinkNode):
  268. """A node representing Blender's Floor Constraint"""
  269. bl_idname = "LinkFloor"
  270. bl_label = "Floor"
  271. bl_icon = "CON_FLOOR"
  272. initialized : bpy.props.BoolProperty(default = False)
  273. mantis_node_class_name=bl_idname
  274. category_color=linkTransformColor
  275. socket_templates = LinkFloorSockets
  276. class LinkShrinkWrapNode(Node, LinkNode):
  277. """A node representing Blender's Shrinkwrap Constraint"""
  278. bl_idname = "LinkShrinkWrap"
  279. bl_label = "Shrinkwrap"
  280. bl_icon = "CON_SHRINKWRAP"
  281. initialized : bpy.props.BoolProperty(default = False)
  282. mantis_node_class_name=bl_idname
  283. category_color=trackingColor
  284. socket_templates = LinkShrinkWrapSockets
  285. def display_update(self, parsed_tree, context):
  286. # vast majority of the time user doesn't link this.
  287. shrink_type = self.inputs['Mode'].default_value
  288. if self.inputs['Mode'].is_linked:# 1% or less of cases
  289. node_tree = context.space_data.path[0].node_tree
  290. mantis_node = parsed_tree.get(get_signature_from_edited_tree(self, context))
  291. shrink_is_project = False
  292. if mantis_node:
  293. shrink_type = mantis_node.evaluate_input("Mode")
  294. if shrink_type != "PROJECT":
  295. self.inputs['Project Axis'].hide=True
  296. self.inputs['Space'].hide=True
  297. self.inputs['Project Distance'].hide=True
  298. self.inputs['Project Opposite'].hide=True
  299. self.inputs['Face Cull'].hide=True
  300. self.inputs['Invert Cull'].hide=True
  301. else:
  302. for inp in self.inputs:
  303. inp.hide=False
  304. if shrink_type == 'NEAREST_VERTEX':
  305. self.inputs['Snap Mode'].hide=True
  306. self.inputs['Align to Normal'].hide=True
  307. self.inputs['Align Normal Axis'].hide=True
  308. else:
  309. self.inputs['Snap Mode'].hide=False
  310. self.inputs['Align to Normal'].hide=False
  311. self.inputs['Align Normal Axis'].hide=False
  312. # TODO: this stuff should be handled by input tags
  313. # once I get that working.
  314. class LinkGeometryAttribute(Node, LinkNode):
  315. """A node representing Blender's Geometry Attribute Constraint"""
  316. bl_idname = "LinkGeometryAttribute"
  317. bl_label = "Geometry Attribute"
  318. if bpy.app.version >= (5,0,0):
  319. bl_icon = "CON_GEOMETRYATTRIBUTE"
  320. else:
  321. bl_icon = "ERROR"
  322. initialized : bpy.props.BoolProperty(default = False)
  323. mantis_node_class_name=bl_idname
  324. category_color=linkTransformColor
  325. socket_templates = LinkGeometryAttributeSockets
  326. def draw_label(self):
  327. if bpy.app.version < (5,0,0):
  328. return "ERROR: ONLY SUPPORTED IN Blender 5.0 OR NEWER"
  329. elif self.label:
  330. return self.label
  331. return self.bl_label
  332. def update(self):
  333. if bpy.app.version < (5,0,0):
  334. self.color = Color((1.0, 0.15, 0.15,)).from_scene_linear_to_srgb()
  335. elif self.color != linkTransformColor:
  336. self.color = linkTransformColor
  337. def display_update(self, parsed_tree, context):
  338. if bpy.app.version < (5,0,0):
  339. return
  340. data_type = self.inputs['Data Type'].default_value
  341. if self.inputs['Data Type'].is_linked:
  342. node_tree = context.space_data.path[0].node_tree
  343. mantis_node = parsed_tree.get(get_signature_from_edited_tree(self, context))
  344. if mantis_node: data_type = mantis_node.evaluate_input("Data Type")
  345. not_matrix_mode = (data_type != 'FLOAT4X4')
  346. self.inputs['Enabled Location'].hide=not_matrix_mode
  347. self.inputs['Enabled Rotation'].hide=not_matrix_mode
  348. self.inputs['Enabled Scale'].hide=not_matrix_mode
  349. # DRIVERS!!
  350. class LinkDrivenParameterNode(Node, LinkNode):
  351. """Represents a driven parameter in the downstream xForm node."""
  352. bl_idname = "LinkDrivenParameter"
  353. bl_label = "Driven Parameter"
  354. bl_icon = "CONSTRAINT_BONE"
  355. initialized : bpy.props.BoolProperty(default = False)
  356. mantis_node_class_name=bl_idname
  357. category_color=linkTransformColor
  358. socket_templates = LinkDrivenParameterSockets