123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431 |
- # ##### BEGIN GPL LICENSE BLOCK #####
- #
- # This program is free software; you can redistribute it and/or
- # modify it under the terms of the GNU General Public License
- # as published by the Free Software Foundation; either version 2
- # of the License, or (at your option) any later version.
- #
- # This program is distributed in the hope that it will be useful,
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- # GNU General Public License for more details.
- #
- # You should have received a copy of the GNU General Public License
- # along with this program; if not, write to the Free Software Foundation,
- # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- #
- # ##### END GPL LICENSE BLOCK #####
- # <pep8 compliant>
- import bpy
- from bpy.types import Panel
- from rna_prop_ui import PropertyPanel
- class BoneButtonsPanel:
- bl_space_type = 'PROPERTIES'
- bl_region_type = 'WINDOW'
- bl_context = "bone"
- @classmethod
- def poll(cls, context):
- return (context.bone or context.edit_bone)
- class BONE_PT_context_bone(BoneButtonsPanel, Panel):
- bl_label = ""
- bl_options = {'HIDE_HEADER'}
- def draw(self, context):
- layout = self.layout
- bone = context.bone
- if not bone:
- bone = context.edit_bone
- row = layout.row()
- row.label(text="", icon='BONE_DATA')
- row.prop(bone, "name", text="")
- class BONE_PT_transform(BoneButtonsPanel, Panel):
- bl_label = "Transform"
- @classmethod
- def poll(cls, context):
- if context.edit_bone:
- return True
- ob = context.object
- return ob and ob.mode == 'POSE' and context.bone
- def draw(self, context):
- layout = self.layout
- layout.use_property_split = True
- ob = context.object
- bone = context.bone
- col = layout.column()
- if bone and ob:
- pchan = ob.pose.bones[bone.name]
- col.active = not (bone.parent and bone.use_connect)
- sub = col.row(align=True)
- sub.prop(pchan, "location")
- sub.prop(pchan, "lock_location", text="")
- col = layout.column()
- rotation_mode = pchan.rotation_mode
- if rotation_mode == 'QUATERNION':
- sub = col.row(align=True)
- sub.prop(pchan, "rotation_quaternion", text="Rotation")
- subsub = sub.column(align=True)
- subsub.prop(pchan, "lock_rotation_w", text="")
- subsub.prop(pchan, "lock_rotation", text="")
- elif rotation_mode == 'AXIS_ANGLE':
- sub = col.row(align=True)
- sub.prop(pchan, "rotation_axis_angle", text="Rotation")
- subsub = sub.column(align=True)
- subsub.prop(pchan, "lock_rotation_w", text="")
- subsub.prop(pchan, "lock_rotation", text="")
- else:
- sub = col.row(align=True)
- sub.prop(pchan, "rotation_euler", text="Rotation")
- sub.prop(pchan, "lock_rotation", text="")
- col = layout.column()
- sub = col.row(align=True)
- sub.prop(pchan, "scale")
- sub.prop(pchan, "lock_scale", text="")
- col = layout.column()
- col.prop(pchan, "rotation_mode")
- elif context.edit_bone:
- bone = context.edit_bone
- col = layout.column()
- col.prop(bone, "head")
- col.prop(bone, "tail")
- col = layout.column()
- col.prop(bone, "roll")
- col.prop(bone, "lock")
- col = layout.column()
- col.prop(bone, "tail_radius")
- col.prop(bone, "envelope_distance")
- class BONE_PT_curved(BoneButtonsPanel, Panel):
- bl_label = "Bendy Bones"
- bl_options = {'DEFAULT_CLOSED'}
- def draw(self, context):
- ob = context.object
- bone = context.bone
- arm = context.armature
- bone_list = "bones"
- if ob and bone:
- bbone = ob.pose.bones[bone.name]
- elif bone is None:
- bone = context.edit_bone
- bbone = bone
- bone_list = "edit_bones"
- else:
- bbone = bone
- layout = self.layout
- layout.use_property_split = True
- layout.prop(bone, "bbone_segments", text="Segments")
- topcol = layout.column()
- topcol.active = bone.bbone_segments > 1
- col = topcol.column(align=True)
- col.prop(bbone, "bbone_curveinx", text="Curve In X")
- col.prop(bbone, "bbone_curveiny", text="In Y")
- col = topcol.column(align=True)
- col.prop(bbone, "bbone_curveoutx", text="Curve Out X")
- col.prop(bbone, "bbone_curveouty", text="Out Y")
- col = topcol.column(align=True)
- col.prop(bbone, "bbone_rollin", text="Roll In")
- col.prop(bbone, "bbone_rollout", text="Out")
- col.prop(bone, "use_endroll_as_inroll")
- col = topcol.column(align=True)
- col.prop(bbone, "bbone_scaleinx", text="Scale In X")
- col.prop(bbone, "bbone_scaleiny", text="In Y")
- col = topcol.column(align=True)
- col.prop(bbone, "bbone_scaleoutx", text="Scale Out X")
- col.prop(bbone, "bbone_scaleouty", text="Out Y")
- col = topcol.column(align=True)
- col.prop(bbone, "bbone_easein", text="Ease In")
- col.prop(bbone, "bbone_easeout", text="Out")
- col = topcol.column(align=True)
- col.prop(bone, "bbone_handle_type_start", text="Start Handle")
- col = col.column(align=True)
- col.active = (bone.bbone_handle_type_start != 'AUTO')
- col.prop_search(bone, "bbone_custom_handle_start", arm, bone_list, text="Custom")
- col = topcol.column(align=True)
- col.prop(bone, "bbone_handle_type_end", text="End Handle")
- col = col.column(align=True)
- col.active = (bone.bbone_handle_type_end != 'AUTO')
- col.prop_search(bone, "bbone_custom_handle_end", arm, bone_list, text="Custom")
- class BONE_PT_relations(BoneButtonsPanel, Panel):
- bl_options = {'DEFAULT_CLOSED'}
- bl_label = "Relations"
- def draw(self, context):
- layout = self.layout
- layout.use_property_split = True
- ob = context.object
- bone = context.bone
- arm = context.armature
- pchan = None
- if ob and bone:
- pchan = ob.pose.bones[bone.name]
- elif bone is None:
- bone = context.edit_bone
- col = layout.column()
- col.use_property_split = False
- col.prop(bone, "layers", text="")
- col.use_property_split = True
- col = layout.column()
- col.separator()
- if context.bone:
- col.prop(bone, "parent")
- else:
- col.prop_search(bone, "parent", arm, "edit_bones")
- if ob and pchan:
- col.prop(bone, "use_relative_parent")
- col.prop_search(pchan, "bone_group", ob.pose, "bone_groups", text="Bone Group")
- sub = col.column()
- sub.active = (bone.parent is not None)
- sub.prop(bone, "use_connect")
- sub.prop(bone, "use_inherit_rotation")
- sub.prop(bone, "use_inherit_scale")
- sub = col.column()
- sub.active = (not bone.parent or not bone.use_connect)
- sub.prop(bone, "use_local_location")
- class BONE_PT_display(BoneButtonsPanel, Panel):
- bl_label = "Viewport Display"
- bl_options = {'DEFAULT_CLOSED'}
- @classmethod
- def poll(cls, context):
- return context.bone
- def draw(self, context):
- # note. this works ok in edit-mode but isn't
- # all that useful so disabling for now.
- layout = self.layout
- layout.use_property_split = True
- ob = context.object
- bone = context.bone
- pchan = None
- if ob and bone:
- pchan = ob.pose.bones[bone.name]
- elif bone is None:
- bone = context.edit_bone
- if bone:
- col = layout.column()
- col.prop(bone, "hide", text="Hide")
- sub = col.column()
- sub.active = bool(pchan and pchan.custom_shape)
- sub.prop(bone, "show_wire", text="Wireframe")
- if pchan:
- col = layout.column()
- col.prop(pchan, "custom_shape")
- if pchan.custom_shape:
- col.prop(pchan, "use_custom_shape_bone_size", text="Bone Size")
- col.prop(pchan, "custom_shape_scale", text="Scale")
- col.prop_search(pchan, "custom_shape_transform", ob.pose, "bones")
- class BONE_PT_inverse_kinematics(BoneButtonsPanel, Panel):
- bl_label = "Inverse Kinematics"
- bl_options = {'DEFAULT_CLOSED'}
- @classmethod
- def poll(cls, context):
- ob = context.object
- return ob and ob.mode == 'POSE' and context.bone
- def draw(self, context):
- layout = self.layout
- layout.use_property_split = True
- ob = context.object
- bone = context.bone
- pchan = ob.pose.bones[bone.name]
- active = pchan.is_in_ik_chain
- col = layout.column()
- col.prop(pchan, "ik_stretch", slider=True)
- col.active = active
- layout.separator()
- col = layout.column(align=True)
- col.prop(pchan, "lock_ik_x", text="Lock IK X")
- col.prop(pchan, "lock_ik_y", text="Y")
- col.prop(pchan, "lock_ik_z", text="Z")
- col = layout.column(align=True)
- sub = col.column(align=True)
- sub.active = pchan.lock_ik_x is False and active
- sub.prop(pchan, "ik_stiffness_x", text="Stiffness X", slider=True)
- sub = col.column(align=True)
- sub.active = pchan.lock_ik_y is False and active
- sub.prop(pchan, "ik_stiffness_y", text="Y", slider=True)
- sub = col.column(align=True)
- sub.active = pchan.lock_ik_z is False and active
- sub.prop(pchan, "ik_stiffness_z", text="Z", slider=True)
- col = layout.column(align=True)
- sub = col.column()
- sub.active = pchan.lock_ik_x is False and active
- sub.prop(pchan, "use_ik_limit_x", text="Limit X")
- sub = col.column(align=True)
- sub.active = pchan.lock_ik_x is False and pchan.use_ik_limit_x and active
- sub.prop(pchan, "ik_min_x", text="Min")
- sub.prop(pchan, "ik_max_x", text="Max")
- col.separator()
- sub = col.column()
- sub.active = pchan.lock_ik_y is False and active
- sub.prop(pchan, "use_ik_limit_y", text="Limit Y")
- sub = col.column(align=True)
- sub.active = pchan.lock_ik_y is False and pchan.use_ik_limit_y and active
- sub.prop(pchan, "ik_min_y", text="Min")
- sub.prop(pchan, "ik_max_y", text="Max")
- col.separator()
- sub = col.column()
- sub.active = pchan.lock_ik_z is False and active
- sub.prop(pchan, "use_ik_limit_z", text="Limit Z")
- sub = col.column(align=True)
- sub.active = pchan.lock_ik_z is False and pchan.use_ik_limit_z and active
- sub.prop(pchan, "ik_min_z", text="Min")
- sub.prop(pchan, "ik_max_z", text="Max")
- col.separator()
- if ob.pose.ik_solver == 'ITASC':
- col = layout.column()
- col.prop(pchan, "use_ik_rotation_control", text="Control Rotation")
- col.active = active
- col = layout.column()
- col.prop(pchan, "ik_rotation_weight", text="IK Rotation Weight", slider=True)
- col.active = active
- # not supported yet
- #row = layout.row()
- #row.prop(pchan, "use_ik_linear_control", text="Joint Size")
- #row.prop(pchan, "ik_linear_weight", text="Weight", slider=True)
- class BONE_PT_deform(BoneButtonsPanel, Panel):
- bl_label = "Deform"
- bl_options = {'DEFAULT_CLOSED'}
- def draw_header(self, context):
- bone = context.bone
- if not bone:
- bone = context.edit_bone
- self.layout.prop(bone, "use_deform", text="")
- def draw(self, context):
- layout = self.layout
- layout.use_property_split = True
- bone = context.bone
- if not bone:
- bone = context.edit_bone
- layout.active = bone.use_deform
- col = layout.column()
- col.prop(bone, "envelope_distance", text="Envelope Distance")
- col.prop(bone, "envelope_weight", text="Envelope Weight")
- col.prop(bone, "use_envelope_multiply", text="Envelope Multiply")
- col.separator()
- col = layout.column(align=True)
- col.prop(bone, "head_radius", text="Radius Head")
- col.prop(bone, "tail_radius", text="Tail")
- class BONE_PT_custom_props(BoneButtonsPanel, PropertyPanel, Panel):
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_EEVEE', 'BLENDER_WORKBENCH'}
- _property_type = bpy.types.Bone, bpy.types.EditBone, bpy.types.PoseBone
- @property
- def _context_path(self):
- obj = bpy.context.object
- if obj and obj.mode == 'POSE':
- return "active_pose_bone"
- else:
- return "active_bone"
- classes = (
- BONE_PT_context_bone,
- BONE_PT_transform,
- BONE_PT_curved,
- BONE_PT_relations,
- BONE_PT_inverse_kinematics,
- BONE_PT_deform,
- BONE_PT_display,
- BONE_PT_custom_props,
- )
- if __name__ == "__main__": # only for live edit.
- from bpy.utils import register_class
- for cls in classes:
- register_class(cls)
|