link_nodes_ui.py 16 KB

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