ff23d23cfc
I decided to go through each function and UI section one by one, improving and overhauling things. Each function and section is going to be fully tested and not rushed out. This is the best way to catch things, but also include the code base as much as possible.
133 lines
5.2 KiB
Python
133 lines
5.2 KiB
Python
import bpy
|
|
from typing import Set, Optional, List, Tuple
|
|
from bpy.types import Operator, Panel, Menu, Context, UILayout
|
|
from .main_panel import AvatarToolKit_PT_AvatarToolkitPanel, CATEGORY_NAME
|
|
from ..core.translations import t
|
|
from ..core.common import (
|
|
get_active_armature,
|
|
clear_default_objects,
|
|
validate_armature,
|
|
get_armature_list,
|
|
get_armature_stats
|
|
)
|
|
from ..core.importers.importer import import_types, imports
|
|
from ..functions.pose_mode import (
|
|
AvatarToolkit_OT_StartPoseMode,
|
|
AvatarToolkit_OT_StopPoseMode,
|
|
AvatarToolkit_OT_ApplyPoseAsShapekey,
|
|
AvatarToolkit_OT_ApplyPoseAsRest
|
|
)
|
|
|
|
class AvatarToolKit_OT_Import(Operator):
|
|
"""Import FBX files into Blender with Avatar Toolkit settings"""
|
|
bl_idname = "avatar_toolkit.import"
|
|
bl_label = t("QuickAccess.import")
|
|
|
|
def execute(self, context: Context) -> Set[str]:
|
|
clear_default_objects()
|
|
bpy.ops.import_scene.fbx('INVOKE_DEFAULT', filter_glob=imports)
|
|
return {'FINISHED'}
|
|
|
|
class AvatarToolKit_OT_ExportFBX(Operator):
|
|
"""Export selected objects as FBX"""
|
|
bl_idname = "avatar_toolkit.export_fbx"
|
|
bl_label = t("QuickAccess.export_fbx")
|
|
|
|
def execute(self, context: Context) -> Set[str]:
|
|
bpy.ops.export_scene.fbx('INVOKE_DEFAULT')
|
|
return {'FINISHED'}
|
|
|
|
class AvatarToolKit_MT_ExportMenu(Menu):
|
|
"""Export menu containing various export options"""
|
|
bl_idname = "AVATAR_TOOLKIT_MT_export_menu"
|
|
bl_label = t("QuickAccess.export")
|
|
|
|
def draw(self, context: Context) -> None:
|
|
layout: UILayout = self.layout
|
|
layout.operator("avatar_toolkit.export_fbx", text=t("QuickAccess.export_fbx"))
|
|
layout.operator("avatar_toolkit.export_resonite", text=t("QuickAccess.export_resonite"))
|
|
|
|
class AvatarToolKit_OT_ExportMenu(Operator):
|
|
"""Open the export menu"""
|
|
bl_idname = "avatar_toolkit.export"
|
|
bl_label = t("QuickAccess.export")
|
|
|
|
def execute(self, context: Context) -> Set[str]:
|
|
bpy.ops.wm.call_menu(name=AvatarToolKit_MT_ExportMenu.bl_idname)
|
|
return {'FINISHED'}
|
|
|
|
class AvatarToolKit_PT_QuickAccessPanel(Panel):
|
|
"""Quick access panel for common Avatar Toolkit operations"""
|
|
bl_label = t("QuickAccess.label")
|
|
bl_idname = "OBJECT_PT_avatar_toolkit_quick_access"
|
|
bl_space_type = 'VIEW_3D'
|
|
bl_region_type = 'UI'
|
|
bl_category = CATEGORY_NAME
|
|
bl_parent_id = AvatarToolKit_PT_AvatarToolkitPanel.bl_idname
|
|
bl_order = 0
|
|
|
|
@classmethod
|
|
def poll(cls, context: Context) -> bool:
|
|
"""Only show panel in Object or Pose mode"""
|
|
return context.mode in {'OBJECT', 'POSE'}
|
|
|
|
def draw(self, context: Context) -> None:
|
|
"""Draw the panel layout"""
|
|
layout: UILayout = self.layout
|
|
|
|
# Armature Selection Box
|
|
armature_box: UILayout = layout.box()
|
|
col: UILayout = armature_box.column(align=True)
|
|
col.label(text=t("QuickAccess.select_armature"), icon='ARMATURE_DATA')
|
|
col.separator(factor=0.5)
|
|
|
|
# Armature Selection
|
|
col.prop(context.scene.avatar_toolkit, "active_armature", text="")
|
|
|
|
# Armature Validation
|
|
active_armature = get_active_armature(context)
|
|
if active_armature:
|
|
is_valid: bool
|
|
message: str
|
|
is_valid, message = validate_armature(active_armature)
|
|
|
|
if is_valid:
|
|
info_box: UILayout = col.box()
|
|
row: UILayout = info_box.row()
|
|
split: UILayout = row.split(factor=0.6)
|
|
split.label(text=t("QuickAccess.valid_armature"), icon='CHECKMARK')
|
|
stats: dict = get_armature_stats(active_armature)
|
|
split.label(text=t("QuickAccess.bones_count", count=stats['bone_count']))
|
|
|
|
if stats['has_pose']:
|
|
info_box.label(text=t("QuickAccess.pose_bones_available"), icon='POSE_HLT')
|
|
else:
|
|
col.separator(factor=0.5)
|
|
col.label(text=message, icon='ERROR')
|
|
|
|
# Pose Mode Controls
|
|
pose_box: UILayout = layout.box()
|
|
col = pose_box.column(align=True)
|
|
col.label(text=t("QuickAccess.pose_controls"), icon='ARMATURE_DATA')
|
|
col.separator(factor=0.5)
|
|
|
|
if context.mode == "POSE":
|
|
col.operator(AvatarToolkit_OT_StopPoseMode.bl_idname, icon='POSE_HLT')
|
|
col.separator(factor=0.5)
|
|
col.operator(AvatarToolkit_OT_ApplyPoseAsRest.bl_idname, icon='MOD_ARMATURE')
|
|
col.operator(AvatarToolkit_OT_ApplyPoseAsShapekey.bl_idname, icon='MOD_ARMATURE')
|
|
else:
|
|
col.operator(AvatarToolkit_OT_StartPoseMode.bl_idname, icon='POSE_HLT')
|
|
|
|
# Import/Export Box
|
|
import_box: UILayout = layout.box()
|
|
col = import_box.column(align=True)
|
|
col.label(text=t("QuickAccess.import_export"), icon='IMPORT')
|
|
col.separator(factor=0.5)
|
|
|
|
# Import/Export Buttons
|
|
button_row: UILayout = col.row(align=True)
|
|
button_row.scale_y = 1.5
|
|
button_row.operator("avatar_toolkit.import", text=t("QuickAccess.import"), icon='IMPORT')
|
|
button_row.operator("avatar_toolkit.export", text=t("QuickAccess.export"), icon='EXPORT')
|