import bpy from .main import ToolPanel from ..operators import retargeting, detector from ..core.icon_manager import Icons from ..core.retargeting import get_target_armature, get_source_armature from bpy.types import PropertyGroup, UIList from bpy.props import StringProperty, BoolProperty # Retargeting panel class RetargetingPanel(ToolPanel, bpy.types.Panel): bl_idname = 'VIEW3D_PT_rsl_retargeting_v2' bl_label = 'Retargeting' bl_options = {'DEFAULT_CLOSED'} def draw(self, context): layout = self.layout layout.use_property_split = False row = layout.row(align=True) row.label(text='Select the armatures:') row = layout.row(align=True) row.prop(context.scene, 'rsl_retargeting_armature_source', icon='ARMATURE_DATA') row = layout.row(align=True) row.prop(context.scene, 'rsl_retargeting_armature_target', icon='ARMATURE_DATA') anim_exists = False for obj in bpy.data.objects: if obj.animation_data and obj.animation_data.action: anim_exists = True if not anim_exists: row = layout.row(align=True) row.label(text='No animated armature found!', icon='INFO') return if not context.scene.rsl_retargeting_armature_source or not context.scene.rsl_retargeting_armature_target: self.draw_import_export(layout) return if not context.scene.rsl_retargeting_bone_list: row = layout.row(align=True) row.scale_y = 1.2 row.operator(retargeting.BuildBoneList.bl_idname, icon_value=Icons.CALIBRATE.get_icon()) self.draw_import_export(layout) return subrow = layout.row(align=True) row = subrow.row(align=True) row.scale_y = 1.2 row.operator(retargeting.BuildBoneList.bl_idname, text='Rebuild Bone List', icon_value=Icons.CALIBRATE.get_icon()) row = subrow.row(align=True) row.scale_y = 1.2 row.alignment = 'RIGHT' row.operator(retargeting.ClearBoneList.bl_idname, text="", icon='X') layout.separator() row = layout.row(align=True) row.template_list("RSL_UL_BoneList", "Bone List", context.scene, "rsl_retargeting_bone_list", context.scene, "rsl_retargeting_bone_list_index", rows=1, maxrows=10) row = layout.row(align=True) row.operator(retargeting.AddBoneListItem.bl_idname, text="Add Custom Entry", icon='ADD') row = layout.row(align=True) row.prop(context.scene, 'rsl_retargeting_auto_scaling') row = layout.row(align=True) row.label(text='Use Pose:') row.prop(context.scene, 'rsl_retargeting_use_pose', expand=True) row = layout.row(align=True) row.scale_y = 1.4 row.operator(retargeting.RetargetAnimation.bl_idname, icon_value=Icons.CALIBRATE.get_icon()) self.draw_import_export(layout) def draw_import_export(self, layout): layout.separator() row = layout.row(align=True) row.label(text='Custom Naming Schemes:') subrow = layout.row(align=True) row = subrow.row(align=True) row.scale_y = 0.9 row.operator(detector.SaveCustomBonesRetargeting.bl_idname, text='Save') row.operator(detector.ImportCustomBones.bl_idname, text='Import') row.operator(detector.ExportCustomBones.bl_idname, text='Export') row = subrow.row(align=True) row.scale_y = 0.9 row.alignment = 'RIGHT' row.operator(detector.ClearCustomBones.bl_idname, text='', icon='X') class BoneListItem(PropertyGroup): """Properties of the bone list items""" bone_name_source: StringProperty( name="Source Bone", description="The source bone name", default="") bone_name_target: StringProperty( name="Target Bone", description="The target bone name", default="") bone_name_key: StringProperty( name="Auto Detection Key", description="The automatically detected bone key", default="") is_custom: BoolProperty( description="This determines if the field is a custom one source bone one", default=False) class RSL_UL_BoneList(UIList): def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index): armature_target = get_target_armature() armature_source = get_source_armature() layout = layout.split(factor=0.36, align=True) # Displays source bone if item.is_custom: layout.prop_search(item, 'bone_name_source', armature_source.pose, "bones", text='') else: layout.label(text=item.bone_name_source) # Displays target bone if armature_target: layout.prop_search(item, 'bone_name_target', armature_target.pose, "bones", text='')