diff options
Diffstat (limited to 'pose_library/gui.py')
-rw-r--r-- | pose_library/gui.py | 221 |
1 files changed, 221 insertions, 0 deletions
diff --git a/pose_library/gui.py b/pose_library/gui.py new file mode 100644 index 00000000..268c71cb --- /dev/null +++ b/pose_library/gui.py @@ -0,0 +1,221 @@ +# ##### 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 ##### + +""" +Pose Library - GUI definition. +""" + +import bpy +from bpy.types import ( + AssetHandle, + Context, + Panel, + UIList, + WindowManager, + WorkSpace, +) + +from bpy_extras import asset_utils + + +class VIEW3D_PT_pose_library(Panel): + bl_space_type = "VIEW_3D" + bl_region_type = "UI" + bl_category = "Animation" + bl_label = "Pose Library" + + @classmethod + def poll(cls, context: Context) -> bool: + return context.preferences.experimental.use_asset_browser + + def draw(self, context: Context) -> None: + layout = self.layout + + row = layout.row(align=True) + row.operator("poselib.create_pose_asset").activate_new_action = False + if bpy.types.POSELIB_OT_restore_previous_action.poll(context): + row.operator("poselib.restore_previous_action", text="", icon='LOOP_BACK') + row.operator("poselib.copy_as_asset", icon="COPYDOWN", text="") + + wm = context.window_manager + layout.prop(wm, "poselib_flipped") + + if hasattr(layout, "template_asset_view"): + workspace = context.workspace + activate_op_props, drag_op_props = layout.template_asset_view( + "pose_assets", + workspace, + "active_asset_library", + wm, + "pose_assets", + workspace, + "active_pose_asset_index", + filter_id_types={"filter_action"}, + activate_operator="poselib.apply_pose_asset", + drag_operator="poselib.blend_pose_asset", + ) + drag_op_props.release_confirm = True + drag_op_props.flipped = wm.poselib_flipped + activate_op_props.flipped = wm.poselib_flipped + + +def pose_library_list_item_context_menu(self: UIList, context: Context) -> None: + def is_pose_asset_view() -> bool: + # Important: Must check context first, or the menu is added for every kind of list. + list = getattr(context, "ui_list", None) + if not list or list.bl_idname != "UI_UL_asset_view" or list.list_id != "pose_assets": + return False + if not context.asset_handle: + return False + return True + + def is_pose_library_asset_browser() -> bool: + asset_library = getattr(context, "asset_library", None) + if not asset_library: + return False + asset = getattr(context, "asset_file_handle", None) + if not asset: + return False + return bool(asset.id_type == 'ACTION') + + if not is_pose_asset_view() and not is_pose_library_asset_browser(): + return + + layout = self.layout + wm = context.window_manager + + layout.separator() + + layout.operator("poselib.apply_pose_asset", text="Apply Pose") + + old_op_ctx = layout.operator_context + layout.operator_context = 'INVOKE_DEFAULT' + props = layout.operator("poselib.blend_pose_asset", text="Blend Pose") + props.flipped = wm.poselib_flipped + layout.operator_context = old_op_ctx + + props = layout.operator("poselib.pose_asset_select_bones", text="Select Pose Bones") + props.select = True + props = layout.operator("poselib.pose_asset_select_bones", text="Deselect Pose Bones") + props.select = False + + layout.separator() + layout.operator("asset.open_containing_blend_file") + + +class ASSETBROWSER_PT_pose_library_usage(asset_utils.AssetBrowserSpecificCategoryPanel, Panel): + bl_region_type = "TOOLS" + bl_label = "Pose Library" + asset_categories = {'ANIMATIONS'} + + def draw(self, context: Context) -> None: + layout = self.layout + wm = context.window_manager + + col = layout.column(align=True) + col.label(text="Use Pose Asset") + col.prop(wm, "poselib_flipped") + props = col.operator("poselib.apply_pose_asset") + props.flipped = wm.poselib_flipped + props = col.operator("poselib.blend_pose_asset") + props.flipped = wm.poselib_flipped + + row = col.row(align=True) + props = row.operator("poselib.pose_asset_select_bones", text="Select", icon="BONE_DATA") + props.flipped = wm.poselib_flipped + props.select = True + props = row.operator("poselib.pose_asset_select_bones", text="Deselect") + props.flipped = wm.poselib_flipped + props.select = False + + +class ASSETBROWSER_PT_pose_library_editing(asset_utils.AssetBrowserSpecificCategoryPanel, Panel): + bl_region_type = "TOOL_PROPS" + bl_label = "Pose Library" + asset_categories = {'ANIMATIONS'} + + def draw(self, context: Context) -> None: + layout = self.layout + + col = layout.column(align=True) + col.enabled = bpy.types.ASSET_OT_assign_action.poll(context) + col.label(text="Activate & Edit") + col.operator("asset.assign_action") + + # Creation + col = layout.column(align=True) + col.enabled = bpy.types.POSELIB_OT_paste_asset.poll(context) + col.label(text="Create Pose Asset") + col.operator("poselib.paste_asset", icon="PASTEDOWN") + + +class DOPESHEET_PT_asset_panel(Panel): + bl_space_type = "DOPESHEET_EDITOR" + bl_region_type = "UI" + bl_label = "Create Pose Asset" + + @classmethod + def poll(cls, context: Context) -> bool: + return context.preferences.experimental.use_asset_browser + + def draw(self, context: Context) -> None: + layout = self.layout + col = layout.column(align=True) + row = col.row(align=True) + row.operator("poselib.create_pose_asset").activate_new_action = True + if bpy.types.POSELIB_OT_restore_previous_action.poll(context): + row.operator("poselib.restore_previous_action", text="", icon='LOOP_BACK') + col.operator("poselib.copy_as_asset", icon="COPYDOWN") + + layout.operator("poselib.convert_old_poselib") + + +classes = ( + ASSETBROWSER_PT_pose_library_editing, + ASSETBROWSER_PT_pose_library_usage, + DOPESHEET_PT_asset_panel, + VIEW3D_PT_pose_library, +) + +_register, _unregister = bpy.utils.register_classes_factory(classes) + + +def register() -> None: + _register() + + WorkSpace.active_pose_asset_index = bpy.props.IntProperty( + name="Active Pose Asset", + # TODO explain which list the index belongs to, or how it can be used to get the pose. + description="Per workspace index of the active pose asset" + ) + # Register for window-manager. This is a global property that shouldn't be + # written to files. + WindowManager.pose_assets = bpy.props.CollectionProperty(type=AssetHandle) + + bpy.types.UI_MT_list_item_context_menu.prepend(pose_library_list_item_context_menu) + bpy.types.FILEBROWSER_MT_context_menu.prepend(pose_library_list_item_context_menu) + + +def unregister() -> None: + _unregister() + + del WorkSpace.active_pose_asset_index + del WindowManager.pose_assets + + bpy.types.UI_MT_list_item_context_menu.remove(pose_library_list_item_context_menu) + bpy.types.FILEBROWSER_MT_context_menu.remove(pose_library_list_item_context_menu) |