This issue occurred only on Mac which has to circumvent
geometry shaders lacking support for them.
This patch reverts the vertex shader for Mac devices to
how it was before f9ea64b0ba. (and uses the frag shader from before that commit)
In order to communicate that to the user I added a label
in the GUI when the platform is Mac.
Co-authored-by: Clément Foucault <foucault.clem@gmail.com>
Pull Request: https://projects.blender.org/blender/blender/pulls/125967
627 lines
21 KiB
Python
627 lines
21 KiB
Python
# SPDX-FileCopyrightText: 2009-2023 Blender Authors
|
|
#
|
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
import bpy
|
|
from bpy.types import Panel
|
|
import rna_prop_ui
|
|
|
|
from bpy.app.translations import contexts as i18n_contexts
|
|
|
|
|
|
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)
|
|
|
|
row = col.row(align=True)
|
|
row.prop(pchan, "location")
|
|
row.use_property_decorate = False
|
|
row.prop(pchan, "lock_location", text="", emboss=False, icon='DECORATE_UNLOCKED')
|
|
|
|
rotation_mode = pchan.rotation_mode
|
|
if rotation_mode == 'QUATERNION':
|
|
col = layout.column()
|
|
row = col.row(align=True)
|
|
row.prop(pchan, "rotation_quaternion", text="Rotation")
|
|
sub = row.column(align=True)
|
|
sub.use_property_decorate = False
|
|
sub.prop(pchan, "lock_rotation_w", text="", emboss=False, icon='DECORATE_UNLOCKED')
|
|
sub.prop(pchan, "lock_rotation", text="", emboss=False, icon='DECORATE_UNLOCKED')
|
|
elif rotation_mode == 'AXIS_ANGLE':
|
|
col = layout.column()
|
|
row = col.row(align=True)
|
|
row.prop(pchan, "rotation_axis_angle", text="Rotation")
|
|
|
|
sub = row.column(align=True)
|
|
sub.use_property_decorate = False
|
|
sub.prop(pchan, "lock_rotation_w", text="", emboss=False, icon='DECORATE_UNLOCKED')
|
|
sub.prop(pchan, "lock_rotation", text="", emboss=False, icon='DECORATE_UNLOCKED')
|
|
else:
|
|
col = layout.column()
|
|
row = col.row(align=True)
|
|
row.prop(pchan, "rotation_euler", text="Rotation")
|
|
row.use_property_decorate = False
|
|
row.prop(pchan, "lock_rotation", text="", emboss=False, icon='DECORATE_UNLOCKED')
|
|
row = layout.row(align=True)
|
|
row.prop(pchan, "rotation_mode", text="Mode")
|
|
row.label(text="", icon='BLANK1')
|
|
|
|
col = layout.column()
|
|
row = col.row(align=True)
|
|
row.prop(pchan, "scale")
|
|
row.use_property_decorate = False
|
|
row.prop(pchan, "lock_scale", text="", emboss=False, icon='DECORATE_UNLOCKED')
|
|
|
|
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, "length")
|
|
col.prop(bone, "lock")
|
|
|
|
|
|
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")
|
|
|
|
col = layout.column(align=True)
|
|
col.prop(bone, "bbone_x", text="Display Size X")
|
|
col.prop(bone, "bbone_z", text="Z")
|
|
|
|
topcol = layout.column()
|
|
topcol.active = bone.bbone_segments > 1
|
|
|
|
topcol.prop(bone, "bbone_mapping_mode", text="Vertex Mapping")
|
|
|
|
col = topcol.column(align=True)
|
|
col.prop(bbone, "bbone_curveinx", text="Curve In X")
|
|
col.prop(bbone, "bbone_curveinz", text="Z")
|
|
|
|
col = topcol.column(align=True)
|
|
col.prop(bbone, "bbone_curveoutx", text="Curve Out X")
|
|
col.prop(bbone, "bbone_curveoutz", text="Z")
|
|
|
|
col = topcol.column(align=True)
|
|
col.prop(bbone, "bbone_rollin", text="Roll In")
|
|
col.prop(bbone, "bbone_rollout", text="Out", text_ctxt=i18n_contexts.id_armature)
|
|
col.prop(bone, "use_endroll_as_inroll")
|
|
|
|
col = topcol.column(align=True)
|
|
col.prop(bbone, "bbone_scalein", text="Scale In")
|
|
|
|
col = topcol.column(align=True)
|
|
col.prop(bbone, "bbone_scaleout", text="Scale Out")
|
|
|
|
col = topcol.column(align=True)
|
|
col.prop(bbone, "bbone_easein", text="Ease In", text_ctxt=i18n_contexts.id_armature)
|
|
col.prop(bbone, "bbone_easeout", text="Out", text_ctxt=i18n_contexts.id_armature)
|
|
col.prop(bone, "use_scale_easing")
|
|
|
|
col = topcol.column(align=True)
|
|
col.prop(bone, "bbone_handle_type_start", text="Start Handle")
|
|
|
|
col2 = col.column(align=True)
|
|
col2.active = (bone.bbone_handle_type_start != 'AUTO')
|
|
col2.prop_search(bone, "bbone_custom_handle_start", arm, bone_list, text="Custom")
|
|
|
|
row = col.row(align=True)
|
|
row.use_property_split = False
|
|
split = row.split(factor=0.4)
|
|
split.alignment = 'RIGHT'
|
|
split.label(text="Scale")
|
|
split2 = split.split(factor=0.7)
|
|
row2 = split2.row(align=True)
|
|
row2.prop(bone, "bbone_handle_use_scale_start", index=0, text="X", toggle=True)
|
|
row2.prop(bone, "bbone_handle_use_scale_start", index=1, text="Y", toggle=True)
|
|
row2.prop(bone, "bbone_handle_use_scale_start", index=2, text="Z", toggle=True)
|
|
split2.prop(bone, "bbone_handle_use_ease_start", text="Ease", text_ctxt=i18n_contexts.id_armature, toggle=True)
|
|
row.label(icon='BLANK1')
|
|
|
|
col = topcol.column(align=True)
|
|
col.prop(bone, "bbone_handle_type_end", text="End Handle")
|
|
|
|
col2 = col.column(align=True)
|
|
col2.active = (bone.bbone_handle_type_end != 'AUTO')
|
|
col2.prop_search(bone, "bbone_custom_handle_end", arm, bone_list, text="Custom")
|
|
|
|
row = col.row(align=True)
|
|
row.use_property_split = False
|
|
split = row.split(factor=0.4)
|
|
split.alignment = 'RIGHT'
|
|
split.label(text="Scale")
|
|
split2 = split.split(factor=0.7)
|
|
row2 = split2.row(align=True)
|
|
row2.prop(bone, "bbone_handle_use_scale_end", index=0, text="X", toggle=True)
|
|
row2.prop(bone, "bbone_handle_use_scale_end", index=1, text="Y", toggle=True)
|
|
row2.prop(bone, "bbone_handle_use_scale_end", index=2, text="Z", toggle=True)
|
|
split2.prop(bone, "bbone_handle_use_ease_end", text="Ease", text_ctxt=i18n_contexts.id_armature, toggle=True)
|
|
row.label(icon='BLANK1')
|
|
|
|
|
|
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()
|
|
|
|
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")
|
|
|
|
sub = col.column()
|
|
sub.active = (bone.parent is not None)
|
|
sub.prop(bone, "use_connect")
|
|
sub = col.column()
|
|
sub.active = (not bone.parent or not bone.use_connect)
|
|
sub.prop(bone, "use_local_location")
|
|
sub = col.column()
|
|
sub.active = (bone.parent is not None)
|
|
sub.prop(bone, "use_inherit_rotation")
|
|
sub.prop(bone, "inherit_scale")
|
|
|
|
|
|
class BONE_PT_collections(BoneButtonsPanel, Panel):
|
|
bl_label = "Bone Collections"
|
|
bl_parent_id = "BONE_PT_relations"
|
|
|
|
@classmethod
|
|
def poll(cls, context):
|
|
return context.bone or context.edit_bone
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
layout.use_property_split = False
|
|
|
|
bone = context.bone or context.edit_bone
|
|
object = context.pose_object or context.edit_object or context.object
|
|
if not object:
|
|
layout.active = False
|
|
sub = layout.column(align=True)
|
|
sub.label(text="Cannot figure out which object this bone belongs to.")
|
|
sub.label(text="Please file a bug report.")
|
|
return
|
|
|
|
armature = object.data
|
|
is_solo_active = armature.collections.is_solo_active
|
|
|
|
if not bone.collections:
|
|
layout.active = False
|
|
layout.label(text="Not assigned to any bone collection.")
|
|
return
|
|
|
|
box = layout.box()
|
|
sub = box.column(align=True)
|
|
for bcoll in bone.collections:
|
|
bcoll_row = sub.row()
|
|
bcoll_row.emboss = 'NONE'
|
|
|
|
# Name & visibility of bcoll. Safe things, so aligned together.
|
|
row = bcoll_row.row(align=True)
|
|
row.label(text=bcoll.name)
|
|
|
|
# Sub-layout that's dimmed when the bone collection's own visibility flag doesn't matter.
|
|
sub_visible = row.row(align=True)
|
|
sub_visible.active = (not is_solo_active) and bcoll.is_visible_ancestors
|
|
sub_visible.prop(bcoll, "is_visible", text="", icon='HIDE_OFF' if bcoll.is_visible else 'HIDE_ON')
|
|
|
|
row.prop(bcoll, "is_solo", text="", icon='SOLO_ON' if bcoll.is_solo else 'SOLO_OFF')
|
|
|
|
# Unassignment operator, less safe so with a bit of spacing.
|
|
props = bcoll_row.operator("armature.collection_unassign_named", text="", icon='X')
|
|
props.name = bcoll.name
|
|
props.bone_name = bone.name
|
|
|
|
|
|
class BONE_PT_display(BoneButtonsPanel, Panel):
|
|
bl_label = "Viewport Display"
|
|
bl_options = {'DEFAULT_CLOSED'}
|
|
|
|
@classmethod
|
|
def poll(cls, context):
|
|
return context.bone or context.edit_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
|
|
|
|
if context.bone is None:
|
|
self.draw_edit_bone(context, layout)
|
|
else:
|
|
self.draw_bone(context, layout)
|
|
|
|
def draw_bone(self, context, layout):
|
|
bone = context.bone
|
|
|
|
col = layout.column()
|
|
col.prop(bone, "hide", text="Hide", toggle=False)
|
|
|
|
# Figure out the pose bone.
|
|
ob = context.object
|
|
if not ob:
|
|
return
|
|
pose_bone = ob.pose.bones[bone.name]
|
|
|
|
# Allow the layout to use the space normally occupied by the 'set a key' diamond.
|
|
layout.use_property_decorate = False
|
|
|
|
row = layout.row(align=True)
|
|
row.prop(bone.color, "palette", text="Bone Color")
|
|
props = row.operator("armature.copy_bone_color_to_selected", text="", icon='UV_SYNC_SELECT')
|
|
props.bone_type = 'EDIT'
|
|
self.draw_bone_color_ui(layout, bone.color)
|
|
|
|
row = layout.row(align=True)
|
|
row.prop(pose_bone.color, "palette", text="Pose Bone Color")
|
|
props = row.operator("armature.copy_bone_color_to_selected", text="", icon='UV_SYNC_SELECT')
|
|
props.bone_type = 'POSE'
|
|
self.draw_bone_color_ui(layout, pose_bone.color)
|
|
|
|
def draw_edit_bone(self, context, layout):
|
|
bone = context.edit_bone
|
|
if bone is None:
|
|
return
|
|
|
|
col = layout.column()
|
|
col.prop(bone, "hide", text="Hide", toggle=False)
|
|
layout.prop(bone.color, "palette", text="Bone Color")
|
|
self.draw_bone_color_ui(layout, bone.color)
|
|
|
|
def draw_bone_color_ui(self, layout, bone_color):
|
|
if not bone_color.is_custom:
|
|
return
|
|
|
|
split = layout.split(factor=0.401)
|
|
|
|
col = split.column()
|
|
row = col.row()
|
|
row.alignment = 'RIGHT'
|
|
row.label(text="Custom Colors")
|
|
|
|
col = split.column(align=True)
|
|
row = col.row(align=True)
|
|
row.use_property_split = False
|
|
row.prop(bone_color.custom, "normal", text="")
|
|
row.prop(bone_color.custom, "select", text="")
|
|
row.prop(bone_color.custom, "active", text="")
|
|
|
|
|
|
class BONE_PT_display_custom_shape(BoneButtonsPanel, Panel):
|
|
bl_label = "Custom Shape"
|
|
bl_parent_id = "BONE_PT_display"
|
|
|
|
@classmethod
|
|
def poll(cls, context):
|
|
return context.bone
|
|
|
|
def draw(self, context):
|
|
import platform
|
|
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 and pchan:
|
|
col = layout.column()
|
|
col.prop(pchan, "custom_shape")
|
|
|
|
sub = col.column()
|
|
sub.active = bool(pchan and pchan.custom_shape)
|
|
sub.separator()
|
|
|
|
sub.prop(pchan, "custom_shape_scale_xyz", text="Scale")
|
|
sub.prop(pchan, "custom_shape_translation", text="Translation")
|
|
sub.prop(pchan, "custom_shape_rotation_euler", text="Rotation")
|
|
|
|
sub.prop_search(pchan, "custom_shape_transform", ob.pose, "bones", text="Override Transform")
|
|
sub.prop(pchan, "use_custom_shape_bone_size")
|
|
|
|
sub.separator()
|
|
sub.prop(bone, "show_wire", text="Wireframe")
|
|
|
|
# Disabled on Mac due to drawing issues with lacking geometry shader support. See #124691.
|
|
is_darwin = platform.system() == "Darwin"
|
|
|
|
width_sub = sub.column()
|
|
width_sub.active = not is_darwin
|
|
width_sub.prop(pchan, "custom_shape_wire_width")
|
|
|
|
if is_darwin:
|
|
sub.label(text="Custom wire width not available on MacOS", icon='INFO')
|
|
|
|
|
|
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, rna_prop_ui.PropertyPanel, Panel):
|
|
COMPAT_ENGINES = {
|
|
'BLENDER_RENDER',
|
|
'BLENDER_EEVEE',
|
|
'BLENDER_EEVEE_NEXT',
|
|
'BLENDER_WORKBENCH',
|
|
}
|
|
_property_type = bpy.types.Bone, bpy.types.EditBone, bpy.types.PoseBone
|
|
|
|
@classmethod
|
|
def _poll(cls, context):
|
|
context_path = cls._get_context_path(context)
|
|
rna_item, _context_member = rna_prop_ui.rna_idprop_context_value(context, context_path, cls._property_type)
|
|
return bool(rna_item)
|
|
|
|
def draw(self, context):
|
|
context_path = self._get_context_path(context)
|
|
rna_prop_ui.draw(self.layout, context, context_path, self._property_type)
|
|
|
|
@classmethod
|
|
def _get_context_path(self, context):
|
|
if context.mode == 'EDIT_ARMATURE':
|
|
# This also accounts for pinned armatures.
|
|
return "edit_bone"
|
|
|
|
obj = context.object
|
|
if not obj:
|
|
# We have to return _something_. If there is some bone by some
|
|
# miracle, just use it.
|
|
return "bone"
|
|
|
|
if obj.mode != 'POSE':
|
|
# Outside of pose mode, active_bone is the one to use. It's either a
|
|
# Bone or an EditBone, depending on the mode.
|
|
return "active_bone"
|
|
|
|
if context.active_pose_bone is not None:
|
|
# There is an active pose bone, so use it.
|
|
return "active_pose_bone"
|
|
|
|
# When the active bone is hidden, `context.active_pose_bone` is None, but
|
|
# `context.bone` still points to it. Use that to still get the pose bone.
|
|
if context.bone is None:
|
|
# If there is no active bone, let the rest of the code refer to the
|
|
# also-None active pose bone, as that's more appropriate given we're
|
|
# currently in pose mode.
|
|
return "active_pose_bone"
|
|
|
|
bone_path = obj.pose.bones[context.bone.name].path_from_id()
|
|
return "object." + bone_path
|
|
|
|
|
|
classes = (
|
|
BONE_PT_context_bone,
|
|
BONE_PT_transform,
|
|
BONE_PT_curved,
|
|
BONE_PT_relations,
|
|
BONE_PT_collections,
|
|
BONE_PT_inverse_kinematics,
|
|
BONE_PT_deform,
|
|
BONE_PT_display,
|
|
BONE_PT_display_custom_shape,
|
|
BONE_PT_custom_props,
|
|
)
|
|
|
|
if __name__ == "__main__": # only for live edit.
|
|
from bpy.utils import register_class
|
|
for cls in classes:
|
|
register_class(cls)
|