properties_data_bone.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431
  1. # ##### BEGIN GPL LICENSE BLOCK #####
  2. #
  3. # This program is free software; you can redistribute it and/or
  4. # modify it under the terms of the GNU General Public License
  5. # as published by the Free Software Foundation; either version 2
  6. # of the License, or (at your option) any later version.
  7. #
  8. # This program is distributed in the hope that it will be useful,
  9. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. # GNU General Public License for more details.
  12. #
  13. # You should have received a copy of the GNU General Public License
  14. # along with this program; if not, write to the Free Software Foundation,
  15. # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  16. #
  17. # ##### END GPL LICENSE BLOCK #####
  18. # <pep8 compliant>
  19. import bpy
  20. from bpy.types import Panel
  21. from rna_prop_ui import PropertyPanel
  22. class BoneButtonsPanel:
  23. bl_space_type = 'PROPERTIES'
  24. bl_region_type = 'WINDOW'
  25. bl_context = "bone"
  26. @classmethod
  27. def poll(cls, context):
  28. return (context.bone or context.edit_bone)
  29. class BONE_PT_context_bone(BoneButtonsPanel, Panel):
  30. bl_label = ""
  31. bl_options = {'HIDE_HEADER'}
  32. def draw(self, context):
  33. layout = self.layout
  34. bone = context.bone
  35. if not bone:
  36. bone = context.edit_bone
  37. row = layout.row()
  38. row.label(text="", icon='BONE_DATA')
  39. row.prop(bone, "name", text="")
  40. class BONE_PT_transform(BoneButtonsPanel, Panel):
  41. bl_label = "Transform"
  42. @classmethod
  43. def poll(cls, context):
  44. if context.edit_bone:
  45. return True
  46. ob = context.object
  47. return ob and ob.mode == 'POSE' and context.bone
  48. def draw(self, context):
  49. layout = self.layout
  50. layout.use_property_split = True
  51. ob = context.object
  52. bone = context.bone
  53. col = layout.column()
  54. if bone and ob:
  55. pchan = ob.pose.bones[bone.name]
  56. col.active = not (bone.parent and bone.use_connect)
  57. sub = col.row(align=True)
  58. sub.prop(pchan, "location")
  59. sub.prop(pchan, "lock_location", text="")
  60. col = layout.column()
  61. rotation_mode = pchan.rotation_mode
  62. if rotation_mode == 'QUATERNION':
  63. sub = col.row(align=True)
  64. sub.prop(pchan, "rotation_quaternion", text="Rotation")
  65. subsub = sub.column(align=True)
  66. subsub.prop(pchan, "lock_rotation_w", text="")
  67. subsub.prop(pchan, "lock_rotation", text="")
  68. elif rotation_mode == 'AXIS_ANGLE':
  69. sub = col.row(align=True)
  70. sub.prop(pchan, "rotation_axis_angle", text="Rotation")
  71. subsub = sub.column(align=True)
  72. subsub.prop(pchan, "lock_rotation_w", text="")
  73. subsub.prop(pchan, "lock_rotation", text="")
  74. else:
  75. sub = col.row(align=True)
  76. sub.prop(pchan, "rotation_euler", text="Rotation")
  77. sub.prop(pchan, "lock_rotation", text="")
  78. col = layout.column()
  79. sub = col.row(align=True)
  80. sub.prop(pchan, "scale")
  81. sub.prop(pchan, "lock_scale", text="")
  82. col = layout.column()
  83. col.prop(pchan, "rotation_mode")
  84. elif context.edit_bone:
  85. bone = context.edit_bone
  86. col = layout.column()
  87. col.prop(bone, "head")
  88. col.prop(bone, "tail")
  89. col = layout.column()
  90. col.prop(bone, "roll")
  91. col.prop(bone, "lock")
  92. col = layout.column()
  93. col.prop(bone, "tail_radius")
  94. col.prop(bone, "envelope_distance")
  95. class BONE_PT_curved(BoneButtonsPanel, Panel):
  96. bl_label = "Bendy Bones"
  97. bl_options = {'DEFAULT_CLOSED'}
  98. def draw(self, context):
  99. ob = context.object
  100. bone = context.bone
  101. arm = context.armature
  102. bone_list = "bones"
  103. if ob and bone:
  104. bbone = ob.pose.bones[bone.name]
  105. elif bone is None:
  106. bone = context.edit_bone
  107. bbone = bone
  108. bone_list = "edit_bones"
  109. else:
  110. bbone = bone
  111. layout = self.layout
  112. layout.use_property_split = True
  113. layout.prop(bone, "bbone_segments", text="Segments")
  114. topcol = layout.column()
  115. topcol.active = bone.bbone_segments > 1
  116. col = topcol.column(align=True)
  117. col.prop(bbone, "bbone_curveinx", text="Curve In X")
  118. col.prop(bbone, "bbone_curveiny", text="In Y")
  119. col = topcol.column(align=True)
  120. col.prop(bbone, "bbone_curveoutx", text="Curve Out X")
  121. col.prop(bbone, "bbone_curveouty", text="Out Y")
  122. col = topcol.column(align=True)
  123. col.prop(bbone, "bbone_rollin", text="Roll In")
  124. col.prop(bbone, "bbone_rollout", text="Out")
  125. col.prop(bone, "use_endroll_as_inroll")
  126. col = topcol.column(align=True)
  127. col.prop(bbone, "bbone_scaleinx", text="Scale In X")
  128. col.prop(bbone, "bbone_scaleiny", text="In Y")
  129. col = topcol.column(align=True)
  130. col.prop(bbone, "bbone_scaleoutx", text="Scale Out X")
  131. col.prop(bbone, "bbone_scaleouty", text="Out Y")
  132. col = topcol.column(align=True)
  133. col.prop(bbone, "bbone_easein", text="Ease In")
  134. col.prop(bbone, "bbone_easeout", text="Out")
  135. col = topcol.column(align=True)
  136. col.prop(bone, "bbone_handle_type_start", text="Start Handle")
  137. col = col.column(align=True)
  138. col.active = (bone.bbone_handle_type_start != 'AUTO')
  139. col.prop_search(bone, "bbone_custom_handle_start", arm, bone_list, text="Custom")
  140. col = topcol.column(align=True)
  141. col.prop(bone, "bbone_handle_type_end", text="End Handle")
  142. col = col.column(align=True)
  143. col.active = (bone.bbone_handle_type_end != 'AUTO')
  144. col.prop_search(bone, "bbone_custom_handle_end", arm, bone_list, text="Custom")
  145. class BONE_PT_relations(BoneButtonsPanel, Panel):
  146. bl_options = {'DEFAULT_CLOSED'}
  147. bl_label = "Relations"
  148. def draw(self, context):
  149. layout = self.layout
  150. layout.use_property_split = True
  151. ob = context.object
  152. bone = context.bone
  153. arm = context.armature
  154. pchan = None
  155. if ob and bone:
  156. pchan = ob.pose.bones[bone.name]
  157. elif bone is None:
  158. bone = context.edit_bone
  159. col = layout.column()
  160. col.use_property_split = False
  161. col.prop(bone, "layers", text="")
  162. col.use_property_split = True
  163. col = layout.column()
  164. col.separator()
  165. if context.bone:
  166. col.prop(bone, "parent")
  167. else:
  168. col.prop_search(bone, "parent", arm, "edit_bones")
  169. if ob and pchan:
  170. col.prop(bone, "use_relative_parent")
  171. col.prop_search(pchan, "bone_group", ob.pose, "bone_groups", text="Bone Group")
  172. sub = col.column()
  173. sub.active = (bone.parent is not None)
  174. sub.prop(bone, "use_connect")
  175. sub.prop(bone, "use_inherit_rotation")
  176. sub.prop(bone, "use_inherit_scale")
  177. sub = col.column()
  178. sub.active = (not bone.parent or not bone.use_connect)
  179. sub.prop(bone, "use_local_location")
  180. class BONE_PT_display(BoneButtonsPanel, Panel):
  181. bl_label = "Viewport Display"
  182. bl_options = {'DEFAULT_CLOSED'}
  183. @classmethod
  184. def poll(cls, context):
  185. return context.bone
  186. def draw(self, context):
  187. # note. this works ok in edit-mode but isn't
  188. # all that useful so disabling for now.
  189. layout = self.layout
  190. layout.use_property_split = True
  191. ob = context.object
  192. bone = context.bone
  193. pchan = None
  194. if ob and bone:
  195. pchan = ob.pose.bones[bone.name]
  196. elif bone is None:
  197. bone = context.edit_bone
  198. if bone:
  199. col = layout.column()
  200. col.prop(bone, "hide", text="Hide")
  201. sub = col.column()
  202. sub.active = bool(pchan and pchan.custom_shape)
  203. sub.prop(bone, "show_wire", text="Wireframe")
  204. if pchan:
  205. col = layout.column()
  206. col.prop(pchan, "custom_shape")
  207. if pchan.custom_shape:
  208. col.prop(pchan, "use_custom_shape_bone_size", text="Bone Size")
  209. col.prop(pchan, "custom_shape_scale", text="Scale")
  210. col.prop_search(pchan, "custom_shape_transform", ob.pose, "bones")
  211. class BONE_PT_inverse_kinematics(BoneButtonsPanel, Panel):
  212. bl_label = "Inverse Kinematics"
  213. bl_options = {'DEFAULT_CLOSED'}
  214. @classmethod
  215. def poll(cls, context):
  216. ob = context.object
  217. return ob and ob.mode == 'POSE' and context.bone
  218. def draw(self, context):
  219. layout = self.layout
  220. layout.use_property_split = True
  221. ob = context.object
  222. bone = context.bone
  223. pchan = ob.pose.bones[bone.name]
  224. active = pchan.is_in_ik_chain
  225. col = layout.column()
  226. col.prop(pchan, "ik_stretch", slider=True)
  227. col.active = active
  228. layout.separator()
  229. col = layout.column(align=True)
  230. col.prop(pchan, "lock_ik_x", text="Lock IK X")
  231. col.prop(pchan, "lock_ik_y", text="Y")
  232. col.prop(pchan, "lock_ik_z", text="Z")
  233. col = layout.column(align=True)
  234. sub = col.column(align=True)
  235. sub.active = pchan.lock_ik_x is False and active
  236. sub.prop(pchan, "ik_stiffness_x", text="Stiffness X", slider=True)
  237. sub = col.column(align=True)
  238. sub.active = pchan.lock_ik_y is False and active
  239. sub.prop(pchan, "ik_stiffness_y", text="Y", slider=True)
  240. sub = col.column(align=True)
  241. sub.active = pchan.lock_ik_z is False and active
  242. sub.prop(pchan, "ik_stiffness_z", text="Z", slider=True)
  243. col = layout.column(align=True)
  244. sub = col.column()
  245. sub.active = pchan.lock_ik_x is False and active
  246. sub.prop(pchan, "use_ik_limit_x", text="Limit X")
  247. sub = col.column(align=True)
  248. sub.active = pchan.lock_ik_x is False and pchan.use_ik_limit_x and active
  249. sub.prop(pchan, "ik_min_x", text="Min")
  250. sub.prop(pchan, "ik_max_x", text="Max")
  251. col.separator()
  252. sub = col.column()
  253. sub.active = pchan.lock_ik_y is False and active
  254. sub.prop(pchan, "use_ik_limit_y", text="Limit Y")
  255. sub = col.column(align=True)
  256. sub.active = pchan.lock_ik_y is False and pchan.use_ik_limit_y and active
  257. sub.prop(pchan, "ik_min_y", text="Min")
  258. sub.prop(pchan, "ik_max_y", text="Max")
  259. col.separator()
  260. sub = col.column()
  261. sub.active = pchan.lock_ik_z is False and active
  262. sub.prop(pchan, "use_ik_limit_z", text="Limit Z")
  263. sub = col.column(align=True)
  264. sub.active = pchan.lock_ik_z is False and pchan.use_ik_limit_z and active
  265. sub.prop(pchan, "ik_min_z", text="Min")
  266. sub.prop(pchan, "ik_max_z", text="Max")
  267. col.separator()
  268. if ob.pose.ik_solver == 'ITASC':
  269. col = layout.column()
  270. col.prop(pchan, "use_ik_rotation_control", text="Control Rotation")
  271. col.active = active
  272. col = layout.column()
  273. col.prop(pchan, "ik_rotation_weight", text="IK Rotation Weight", slider=True)
  274. col.active = active
  275. # not supported yet
  276. #row = layout.row()
  277. #row.prop(pchan, "use_ik_linear_control", text="Joint Size")
  278. #row.prop(pchan, "ik_linear_weight", text="Weight", slider=True)
  279. class BONE_PT_deform(BoneButtonsPanel, Panel):
  280. bl_label = "Deform"
  281. bl_options = {'DEFAULT_CLOSED'}
  282. def draw_header(self, context):
  283. bone = context.bone
  284. if not bone:
  285. bone = context.edit_bone
  286. self.layout.prop(bone, "use_deform", text="")
  287. def draw(self, context):
  288. layout = self.layout
  289. layout.use_property_split = True
  290. bone = context.bone
  291. if not bone:
  292. bone = context.edit_bone
  293. layout.active = bone.use_deform
  294. col = layout.column()
  295. col.prop(bone, "envelope_distance", text="Envelope Distance")
  296. col.prop(bone, "envelope_weight", text="Envelope Weight")
  297. col.prop(bone, "use_envelope_multiply", text="Envelope Multiply")
  298. col.separator()
  299. col = layout.column(align=True)
  300. col.prop(bone, "head_radius", text="Radius Head")
  301. col.prop(bone, "tail_radius", text="Tail")
  302. class BONE_PT_custom_props(BoneButtonsPanel, PropertyPanel, Panel):
  303. COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
  304. _property_type = bpy.types.Bone, bpy.types.EditBone, bpy.types.PoseBone
  305. @property
  306. def _context_path(self):
  307. obj = bpy.context.object
  308. if obj and obj.mode == 'POSE':
  309. return "active_pose_bone"
  310. else:
  311. return "active_bone"
  312. classes = (
  313. BONE_PT_context_bone,
  314. BONE_PT_transform,
  315. BONE_PT_curved,
  316. BONE_PT_relations,
  317. BONE_PT_inverse_kinematics,
  318. BONE_PT_deform,
  319. BONE_PT_display,
  320. BONE_PT_custom_props,
  321. )
  322. if __name__ == "__main__": # only for live edit.
  323. from bpy.utils import register_class
  324. for cls in classes:
  325. register_class(cls)